Re: [PATCH v2] gfs2: reject oversized dinode sizes before i_size_write
Jiaming Zhang <[email protected]>
| Newsgroups | dev.linux.lists.gfs2,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <CANypQFbv4bDaN1eF+GYsHfJmeau_4d8fc=THSNq-rZNtqk8i-g@mail.gmail.com> |
Jiaming Zhang <[email protected]> 于2026年7月7日周二 02:00写道: > > 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