Skip to content

Commit 7bc5da4

Browse files
josephhzakpm00
authored andcommitted
ocfs2: fix out-of-bounds write in ocfs2_write_end_inline
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. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Joseph Qi <[email protected]> Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=62c1793956716ea8b28a Cc: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Changwei Ge <[email protected]> Cc: Jun Piao <[email protected]> Cc: Heming Zhao <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 4c04c6b commit 7bc5da4

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

fs/ocfs2/inode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,16 @@ int ocfs2_validate_inode_block(struct super_block *sb,
15051505
goto bail;
15061506
}
15071507

1508+
if (le16_to_cpu(data->id_count) >
1509+
ocfs2_max_inline_data_with_xattr(sb, di)) {
1510+
rc = ocfs2_error(sb,
1511+
"Invalid dinode #%llu: inline data id_count %u exceeds max %d\n",
1512+
(unsigned long long)bh->b_blocknr,
1513+
le16_to_cpu(data->id_count),
1514+
ocfs2_max_inline_data_with_xattr(sb, di));
1515+
goto bail;
1516+
}
1517+
15081518
if (le64_to_cpu(di->i_size) > le16_to_cpu(data->id_count)) {
15091519
rc = ocfs2_error(sb,
15101520
"Invalid dinode #%llu: inline data i_size %llu exceeds id_count %u\n",

0 commit comments

Comments
 (0)