summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsung byeongchan <tjdqudcks0424@naver.com>2026-10-08 15:07:38 +0900
committerIlya Dryomov <idryomov@gmail.com>2026-10-26 14:15:48 +0100
commit166375898d29fea050a9abec855da6075050d5c9 (patch)
tree79686d77646f2482ced29ddfcc6bd25ec0620a30
parent8cab7e7461f81ea1e0fd45082b50bb3c04c0bb10 (diff)
downloadlinux-166375898d29fea050a9abec855da6075050d5c9.tar.gz
linux-166375898d29fea050a9abec855da6075050d5c9.zip
ceph: validate encoded xattr name lengths
__build_xattrs() advances over an MDS-provided name length before checking that the name remains in the encoded xattr blob. On 32-bit clients, UINT_MAX wraps the cursor and is stored as a negative internal name length. A later ordinary listxattr() converts it back to a UINT_MAX memcpy size and corrupts kernel memory. Check the name range before advancing and reject name, value, or aggregate sizes that overflow the signed internal accounting. The malformed blob corrupted kernel state in two baseline boots. It was rejected cleanly twice with this change, while normal and length-only controls remained safe. Cc: stable@vger.kernel.org Fixes: 355da1eb7a1f ("ceph: inode operations") Assisted-by: LLM Signed-off-by: sung byeongchan <tjdqudcks0424@naver.com> Reviewed-by: Alex Markuze <amarkuze@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r--fs/ceph/xattr.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 1da6deea2c24..bdd280856d86 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -11,6 +11,7 @@
#include <linux/security.h>
#include <linux/posix_acl_xattr.h>
#include <linux/slab.h>
+#include <linux/overflow.h>
#define XATTR_CEPH_PREFIX "ceph."
#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
@@ -843,14 +844,23 @@ start:
}
err = -EIO;
while (numattr--) {
+ int names_size, vals_size;
+
ceph_decode_32_safe(&p, end, len, bad);
namelen = len;
name = p;
+ ceph_decode_need(&p, end, namelen, bad);
p += len;
ceph_decode_32_safe(&p, end, len, bad);
ceph_decode_need(&p, end, len, bad);
val = p;
p += len;
+ if (namelen > INT_MAX || len > INT_MAX ||
+ check_add_overflow(ci->i_xattrs.names_size,
+ (int)namelen, &names_size) ||
+ check_add_overflow(ci->i_xattrs.vals_size,
+ (int)len, &vals_size))
+ goto bad;
err = __set_xattr(ci, name, namelen, val, len,
0, 0, &xattrs[numattr]);