Re: [PATCH] ocfs2: fix out-of-bounds write in ocfs2_write_end_inline
Heming Zhao <[email protected]>
| Newsgroups | dev.linux.lists.ocfs2-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <wetkjod2dfsl2ffszxpse5pf7lmzmz3kkq74ygn2kbu7nq2rdh@lpb3dvfmeetv> |
On Fri, Apr 03, 2026 at 02:38:30PM +0800, Joseph Qi wrote: > KASAN reports a use-after-free write of 4086 bytes in > ocfs2_write_end_inline, called from ocfs2_write_end_nolock during a > copy_file_range splice fallback on a corrupted ocfs2 filesystem mounted > on a loop device. The actual bug is an out-of-bounds write past the > inode block buffer, not a true use-after-free. The write overflows into > an adjacent freed page, which KASAN reports as UAF. > > The root cause is that ocfs2_try_to_write_inline_data trusts the > on-disk id_count field to determine whether a write fits in inline > data. On a corrupted filesystem, id_count can exceed the physical > maximum inline data capacity, causing writes to overflow the inode > block buffer. > > Call trace (crash path): > > vfs_copy_file_range (fs/read_write.c:1634) > do_splice_direct > splice_direct_to_actor > iter_file_splice_write > ocfs2_file_write_iter > generic_perform_write > ocfs2_write_end > ocfs2_write_end_nolock (fs/ocfs2/aops.c:1949) > ocfs2_write_end_inline (fs/ocfs2/aops.c:1915) > memcpy_from_folio <-- KASAN: write OOB > > So add id_count upper bound check in ocfs2_validate_inode_block() to > alongside the existing i_size check to fix it. > > Reported-by: [email protected] > Closes: https://syzkaller.appspot.com/bug?extid=62c1793956716ea8b28a > Cc: <[email protected]> > Signed-off-by: Joseph Qi <[email protected]> Looks good to me. Reviewed-by: Heming Zhao <[email protected]> > --- > fs/ocfs2/inode.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c > index 03a51662ea8e..a2ccd8011706 100644 > --- a/fs/ocfs2/inode.c > +++ b/fs/ocfs2/inode.c > @@ -1505,6 +1505,16 @@ int ocfs2_validate_inode_block(struct super_block *sb, > goto bail; > } > > + if (le16_to_cpu(data->id_count) > > + ocfs2_max_inline_data_with_xattr(sb, di)) { > + rc = ocfs2_error(sb, > + "Invalid dinode #%llu: inline data id_count %u exceeds max %d\n", > + (unsigned long long)bh->b_blocknr, > + le16_to_cpu(data->id_count), > + ocfs2_max_inline_data_with_xattr(sb, di)); > + goto bail; > + } > + > if (le64_to_cpu(di->i_size) > le16_to_cpu(data->id_count)) { > rc = ocfs2_error(sb, > "Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n", > -- > 2.39.3 >