diff options
| author | sung byeongchan <tjdqudcks0424@naver.com> | 2026-10-08 15:07:38 +0900 |
|---|---|---|
| committer | Ilya Dryomov <idryomov@gmail.com> | 2026-10-26 14:15:48 +0100 |
| commit | 166375898d29fea050a9abec855da6075050d5c9 (patch) | |
| tree | 79686d77646f2482ced29ddfcc6bd25ec0620a30 | |
| parent | 8cab7e7461f81ea1e0fd45082b50bb3c04c0bb10 (diff) | |
| download | linux-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.c | 10 |
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]); |
