Add the RHEL 211.19.1..211.20.1 backports (1245-1287) from centos-stream-10 and upstream, on top of 211.18.1, plus the dpll RHEL kABI adaptation (1287). RHEL now ships the smb cifs.spnego fix too; the existing ahead-fix 1105 is byte-identical, so RHEL's redundant copy is omitted. Bump to 211.20.1.
124 lines
4.4 KiB
Diff
124 lines
4.4 KiB
Diff
From eff4c8b51d7c82746c2efa0e4ba30576d1082169 Mon Sep 17 00:00:00 2001
|
|
From: Paulo Alcantara <paalcant@redhat.com>
|
|
Date: Sun, 10 May 2026 18:08:12 -0300
|
|
Subject: [PATCH] smb: client: validate dacloffset before building DACL
|
|
pointers
|
|
|
|
JIRA: https://issues.redhat.com/browse/RHEL-172829
|
|
|
|
commit f98b48151cc502ada59d9778f0112d21f2586ca3
|
|
Author: Michael Bommarito <michael.bommarito@gmail.com>
|
|
Date: Mon Apr 20 10:47:47 2026 -0400
|
|
|
|
smb: client: validate dacloffset before building DACL pointers
|
|
|
|
parse_sec_desc(), build_sec_desc(), and the chown path in
|
|
id_mode_to_cifs_acl() all add the server-supplied dacloffset to pntsd
|
|
before proving a DACL header fits inside the returned security
|
|
descriptor.
|
|
|
|
On 32-bit builds a malicious server can return dacloffset near
|
|
U32_MAX, wrap the derived DACL pointer below end_of_acl, and then slip
|
|
past the later pointer-based bounds checks. build_sec_desc() and
|
|
id_mode_to_cifs_acl() can then dereference DACL fields from the wrapped
|
|
pointer in the chmod/chown rewrite paths.
|
|
|
|
Validate dacloffset numerically before building any DACL pointer and
|
|
reuse the same helper at the three DACL entry points.
|
|
|
|
Fixes: bc3e9dd9d104 ("cifs: Change SIDs in ACEs while transferring file ownership.")
|
|
Cc: stable@vger.kernel.org
|
|
Assisted-by: Claude:claude-opus-4-6
|
|
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
|
|
Signed-off-by: Paulo Alcantara <paalcant@redhat.com>
|
|
|
|
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
|
|
index 03bad2885e96..7ed526d23d14 100644
|
|
--- a/fs/smb/client/cifsacl.c
|
|
+++ b/fs/smb/client/cifsacl.c
|
|
@@ -1266,6 +1266,17 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl)
|
|
return 0;
|
|
}
|
|
|
|
+static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
|
|
+{
|
|
+ if (acl_len < sizeof(struct smb_acl))
|
|
+ return false;
|
|
+
|
|
+ if (dacloffset < sizeof(struct smb_ntsd))
|
|
+ return false;
|
|
+
|
|
+ return dacloffset <= acl_len - sizeof(struct smb_acl);
|
|
+}
|
|
+
|
|
|
|
/* Convert CIFS ACL to POSIX form */
|
|
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|
@@ -1286,7 +1297,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|
group_sid_ptr = (struct smb_sid *)((char *)pntsd +
|
|
le32_to_cpu(pntsd->gsidoffset));
|
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
- dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
|
|
cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
|
|
pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
|
|
le32_to_cpu(pntsd->gsidoffset),
|
|
@@ -1317,11 +1327,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
|
return rc;
|
|
}
|
|
|
|
- if (dacloffset)
|
|
+ if (dacloffset) {
|
|
+ if (!dacl_offset_valid(acl_len, dacloffset)) {
|
|
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
|
|
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
|
|
group_sid_ptr, fattr, get_mode_from_special_sid);
|
|
- else
|
|
+ } else {
|
|
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
|
|
+ }
|
|
|
|
return rc;
|
|
}
|
|
@@ -1344,6 +1361,11 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
|
|
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
if (dacloffset) {
|
|
+ if (!dacl_offset_valid(secdesclen, dacloffset)) {
|
|
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
|
|
rc = validate_dacl(dacl_ptr, end_of_acl);
|
|
if (rc)
|
|
@@ -1719,6 +1741,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
|
nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
|
|
dacloffset = le32_to_cpu(pntsd->dacloffset);
|
|
if (dacloffset) {
|
|
+ if (!dacl_offset_valid(secdesclen, dacloffset)) {
|
|
+ cifs_dbg(VFS, "Server returned illegal DACL offset\n");
|
|
+ rc = -EINVAL;
|
|
+ goto id_mode_to_cifs_acl_exit;
|
|
+ }
|
|
+
|
|
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
|
|
rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
|
|
if (rc) {
|
|
@@ -1761,6 +1789,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
|
rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
|
|
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
|
|
}
|
|
+id_mode_to_cifs_acl_exit:
|
|
cifs_put_tlink(tlink);
|
|
|
|
kfree(pnntsd);
|
|
--
|
|
2.50.1 (Apple Git-155)
|
|
|