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
>
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.