Re: [PATCH 5/5] ocfs2: validate inline xattr header before reflinking inline xattrs
From: Joseph Qi
Date: Mon May 11 2026 - 02:38:31 EST
On 5/8/26 4:59 PM, ZhengYuan Huang wrote:
> [BUG]
> A corrupt inline xattr header can make ocfs2_reflink_xattr_inline() lock,
> copy, and reflink xattr state from an unchecked ibody xattr header.
>
> [CAUSE]
> The inline reflink path still trusted di->i_xattr_inline_size to compute
> header_off, xh, and new_xh before handing the source header to the reflink
> allocator and copy logic.
>
> [FIX]
> Validate the source inode's inline xattr header with the shared helper
> first, then derive the reflink copy offsets from the validated inline
> size/header. This keeps the reflink path from traversing corrupt ibody
> xattr geometry.
>
> Signed-off-by: ZhengYuan Huang <gality369@xxxxxxxxx>
Looks fine.
Reviewed-by: Joseph Qi <joseph.qi@xxxxxxxxxxxxxxxxx>
> ---
> fs/ocfs2/xattr.c | 19 +++++++++++++------
> 1 file changed, 13 insertions(+), 6 deletions(-)
>
> diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
> index 4877406a83ce..fcddd3c13acd 100644
> --- a/fs/ocfs2/xattr.c
> +++ b/fs/ocfs2/xattr.c
> @@ -6511,12 +6511,10 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
> handle_t *handle;
> struct ocfs2_super *osb = OCFS2_SB(args->old_inode->i_sb);
> struct ocfs2_dinode *di = (struct ocfs2_dinode *)args->old_bh->b_data;
> - int inline_size = le16_to_cpu(di->i_xattr_inline_size);
> - int header_off = osb->sb->s_blocksize - inline_size;
> - struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)
> - (args->old_bh->b_data + header_off);
> - struct ocfs2_xattr_header *new_xh = (struct ocfs2_xattr_header *)
> - (args->new_bh->b_data + header_off);
> + int inline_size;
> + int header_off;
> + struct ocfs2_xattr_header *xh;
> + struct ocfs2_xattr_header *new_xh;
> struct ocfs2_alloc_context *meta_ac = NULL;
> struct ocfs2_inode_info *new_oi;
> struct ocfs2_dinode *new_di;
> @@ -6525,6 +6523,15 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
> .vb_access = ocfs2_journal_access_di,
> };
>
> + ret = ocfs2_xattr_ibody_lookup_header(args->old_inode, di, &xh);
> + if (ret)
> + goto out;
> +
> + inline_size = le16_to_cpu(di->i_xattr_inline_size);
> + header_off = osb->sb->s_blocksize - inline_size;
> + new_xh = (struct ocfs2_xattr_header *)
> + (args->new_bh->b_data + header_off);
> +
> ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh,
> &credits, &meta_ac);
> if (ret) {