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

From: Jiaming Zhang

Date: Thu Aug 06 2026 - 03:56:22 EST


Jiaming Zhang <r772577952@xxxxxxxxx> 于2026年7月23日周四 15:10写道:
>
> Jiaming Zhang <r772577952@xxxxxxxxx> 于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@xxxxxxxxxxxxxx/
> > Assisted-by: Codex:gpt-5.5-xhigh
> > Cc: stable@xxxxxxxxxxxxxxx
> > Signed-off-by: Jiaming Zhang <r772577952@xxxxxxxxx>
> > ---
> > 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