public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ocfs2: validate local xattr value bounds on lookup
@ 2026-04-29  2:20 ZhengYuan Huang
  0 siblings, 0 replies; only message in thread
From: ZhengYuan Huang @ 2026-04-29  2:20 UTC (permalink / raw)
  To: mark, jlbec, joseph.qi
  Cc: ocfs2-devel, linux-kernel, baijiaju1990, r33s3n6, zzzccc427,
	ZhengYuan Huang

[BUG]
A corrupted local xattr entry can crash ACL lookup during open.

BUG: KASAN: use-after-free in ocfs2_xattr_block_get fs/ocfs2/xattr.c:1261 [inline]
BUG: KASAN: use-after-free in ocfs2_xattr_get_nolock+0x8cb/0x1110 fs/ocfs2/xattr.c:1312
Read of size 252 at addr ffff88801e7dbfb8 by task syz.0.1/347

Call Trace:
 ...
 ocfs2_xattr_block_get fs/ocfs2/xattr.c:1261 [inline]
 ocfs2_xattr_get_nolock+0x8cb/0x1110 fs/ocfs2/xattr.c:1312
 ocfs2_get_acl_nolock+0xb1/0x3d0 fs/ocfs2/acl.c:137
 ocfs2_iop_get_acl+0x197/0x260 fs/ocfs2/acl.c:313
 __get_acl+0x33a/0x480 fs/posix_acl.c:159
 get_inode_acl+0x2b/0x40 fs/posix_acl.c:184
 check_acl fs/namei.c:333 [inline]
 acl_permission_check fs/namei.c:419 [inline]
 generic_permission+0x509/0x670 fs/namei.c:472
 ocfs2_permission+0xeb/0x1a0 fs/ocfs2/file.c:1366
 do_inode_permission fs/namei.c:526 [inline]
 inode_permission+0x317/0x5a0 fs/namei.c:593
 may_open+0x10e/0x350 fs/namei.c:3565
 do_open fs/namei.c:3973 [inline]
 path_openat+0x500/0x2ce0 fs/namei.c:4134
 do_filp_open+0x1f6/0x430 fs/namei.c:4161
 do_sys_openat2+0x117/0x1c0 fs/open.c:1437
 do_sys_open fs/open.c:1452 [inline]
 __do_sys_open fs/open.c:1460 [inline]
 __se_sys_open fs/open.c:1456 [inline]
 __x64_sys_open+0x12d/0x1e0 fs/open.c:1456
 ...

[CAUSE]
The lookup helpers only validate the entry position and the name bytes.
Once a name matches, ocfs2_xattr_block_get() trusts xe_value_size and
memcpy()s that many bytes from inline xattr storage.

A local xattr entry is only valid when its inline value both fits the
local size limit and stays inside the current xattr block or bucket
block. That invariant is never checked for matched local entries, so
corrupted metadata can inflate xe_value_size and drive memcpy() past the
end of the source block.

[FIX]
Validate matched local xattr entries before returning them from
ocfs2_xattr_find_entry() and ocfs2_find_xe_in_bucket(). Reject entries
whose inline value exceeds the local limit or crosses the current block
boundary, and route the failure through normal OCFS2 corruption
handling.

Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -237,6 +237,29 @@
 	return namevalue_size(xe->xe_name_len, value_len);
 }
 
+static int ocfs2_validate_local_xe(struct inode *inode,
+				   struct ocfs2_xattr_entry *xe,
+				   void *base,
+				   void *end)
+{
+	char *nameval = base + le16_to_cpu(xe->xe_name_offset);
+	size_t name_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+	u64 value_size = le64_to_cpu(xe->xe_value_size);
+
+	if (value_size > OCFS2_XATTR_INLINE_SIZE)
+		return ocfs2_error(inode->i_sb,
+				   "Inode %llu has invalid local xattr value size %llu\n",
+				   (unsigned long long)OCFS2_I(inode)->ip_blkno,
+				   (unsigned long long)value_size);
+
+	if (nameval + name_len + value_size > (char *)end)
+		return ocfs2_error(inode->i_sb,
+				   "Inode %llu has corrupt local xattr value bounds\n",
+				   (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	return 0;
+}
+
 
 static int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
 					     struct ocfs2_xattr_header *xh,
@@ -1098,7 +1121,7 @@
 {
 	struct ocfs2_xattr_entry *entry;
 	size_t name_len;
-	int i, name_offset, cmp = 1;
+	int i, name_offset, cmp = 1, ret;
 
 	if (name == NULL)
 		return -EINVAL;
@@ -1121,6 +1144,11 @@
 				return -EFSCORRUPTED;
 			}
 			cmp = memcmp(name, (xs->base + name_offset), name_len);
+			if (!cmp && ocfs2_xattr_is_local(entry)) {
+				ret = ocfs2_validate_local_xe(inode, entry, xs->base, xs->end);
+				if (ret)
+					return ret;
+			}
 		}
 		if (cmp == 0)
 			break;
@@ -3790,6 +3818,8 @@
 	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
 	size_t name_len = strlen(name);
 	struct ocfs2_xattr_entry *xe = NULL;
+	char *block;
+	char *block_end;
 	char *xe_name;
 
 	/*
@@ -3821,8 +3851,15 @@
 		}
 
 
-		xe_name = bucket_block(bucket, block_off) + new_offset;
+		block = bucket_block(bucket, block_off);
+		block_end = block + inode->i_sb->s_blocksize;
+		xe_name = block + new_offset;
 		if (!memcmp(name, xe_name, name_len)) {
+			if (ocfs2_xattr_is_local(xe)) {
+				ret = ocfs2_validate_local_xe(inode, xe, block, block_end);
+				if (ret)
+					break;
+			}
 			*xe_index = i;
 			*found = 1;
 			ret = 0;
-- 
2.43.0

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-04-29  2:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29  2:20 [PATCH] ocfs2: validate local xattr value bounds on lookup ZhengYuan Huang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox