Re: [PATCH v2] gfs2: reject oversized dinode sizes before i_size_write

Jiaming Zhang <[email protected]>
Newsgroups org.kernel.vger.stable,dev.linux.lists.gfs2,org.kernel.vger.linux-kernel
Message-ID <CANypQFaqi25O5jh16KfLxeA7QJZwEKaEgq-t-hw-ErxS8a34jg@mail.gmail.com>
Jiaming Zhang <[email protected]> 于2026年7月23日周四 15:10写道:
>
> Jiaming Zhang <[email protected]> 于2026年7月7日周二 02:00写道:
>
> Hi,
>
> >
> > A corrupted GFS2 image can store a dinode size that is larger than what VFS
> > i_size can represent. gfs2_dinode_in() reads the on-disk di_size as a u64 and
> > writes it directly into inode->i_size. If the value is larger than S64_MAX, the
> > incore i_size becomes negative. That negative value can bypass the existing
> > stuffed inode size check:
> >
> > inode->i_size > gfs2_max_stuffed_size(ip)
> >
> > Later, gfs2_quotad may try to sync the quota file and unstuff the quota inode.
> > gfs2_unstuffer_folio() reads the negative i_size into an unsigned length and
> > passes it to memcpy(), turning it into a huge copy size and triggering a
> > out-of-bound issue.
> >
> > Reject dinodes whose size exceeds sb->s_maxbytes before storing the value in
> > inode->i_size. Also make the stuffed inode check use the raw on-disk size while
> > it is still unsigned.
> >
> > Fixes: 70376c7ff312 ("gfs2: Always check inode size of inline inodes")
> > Closes: https://lore.kernel.org/lkml/CANypQFaF6bvORKKbRALvEL0k_epFaneFiOQqco4gjdmKVbdURg@mail.gmail.com/
> > Assisted-by: Codex:gpt-5.5-xhigh
> > Cc: [email protected]
> > Signed-off-by: Jiaming Zhang <[email protected]>
> > ---
> > Changes in v2:
> > - Drop the defensive unstuffing changes in bmap.c.
> >
> >  fs/gfs2/glops.c | 9 +++++++--
> >  1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
> > index 28f32424ee64..8c5d257451d5 100644
> > --- a/fs/gfs2/glops.c
> > +++ b/fs/gfs2/glops.c
> > @@ -393,11 +393,16 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
> >         umode_t mode = be32_to_cpu(str->di_mode);
> >         struct inode *inode = &ip->i_inode;
> >         bool is_new = inode_state_read_once(inode) & I_NEW;
> > +       u64 size = be64_to_cpu(str->di_size);
> >
> >         if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr))) {
> >                 gfs2_consist_inode(ip);
> >                 return -EIO;
> >         }
> > +       if (unlikely(size > (u64)inode->i_sb->s_maxbytes)) {
> > +               gfs2_consist_inode(ip);
> > +               return -EIO;
> > +       }
> >         if (unlikely(!is_new && inode_wrong_type(inode, mode))) {
> >                 gfs2_consist_inode(ip);
> >                 return -EIO;
> > @@ -418,7 +423,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
> >         i_uid_write(inode, be32_to_cpu(str->di_uid));
> >         i_gid_write(inode, be32_to_cpu(str->di_gid));
> >         set_nlink(inode, be32_to_cpu(str->di_nlink));
> > -       i_size_write(inode, be64_to_cpu(str->di_size));
> > +       i_size_write(inode, size);
> >         gfs2_set_inode_blocks(inode, be64_to_cpu(str->di_blocks));
> >         atime.tv_sec = be64_to_cpu(str->di_atime);
> >         atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
> > @@ -462,7 +467,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
> >                 return -EIO;
> >         }
> >
> > -       if (gfs2_is_stuffed(ip) && inode->i_size > gfs2_max_stuffed_size(ip)) {
> > +       if (gfs2_is_stuffed(ip) && size > gfs2_max_stuffed_size(ip)) {
> >                 gfs2_consist_inode(ip);
> >                 return -EIO;
> >         }
> > --
> > 2.43.0
> >
>
> Friendly ping. Please let me know if there's anything you'd like me to change.
>
> Best Regards,
> Jiaming Zhang

Friendly ping. Please let me know if there's anything you'd like me to change.

Best Regards,
Jiaming Zhang
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.