Skip to content

Commit a30f15a

Browse files
committed
smb: client: validate dacloffset before building DACL pointers
jira VULN-188328 cve CVE-2026-46195 commit-author Michael Bommarito <michael.bommarito@gmail.com> commit f98b481 upstream-diff Used linux-5.15.y backport 5de2665e913a10ad70aaeecf736b97276e83d995 for the clean pick 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: bc3e9dd ("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> (cherry picked from commit 5de2665e913a10ad70aaeecf736b97276e83d995) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent ad60db4 commit a30f15a

1 file changed

Lines changed: 32 additions & 3 deletions

File tree

fs/cifs/cifsacl.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,17 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
12541254
return 0;
12551255
}
12561256

1257+
static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset)
1258+
{
1259+
if (acl_len < sizeof(struct cifs_acl))
1260+
return false;
1261+
1262+
if (dacloffset < sizeof(struct cifs_ntsd))
1263+
return false;
1264+
1265+
return dacloffset <= acl_len - sizeof(struct cifs_acl);
1266+
}
1267+
12571268

12581269
/* Convert CIFS ACL to POSIX form */
12591270
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
@@ -1274,7 +1285,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
12741285
group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
12751286
le32_to_cpu(pntsd->gsidoffset));
12761287
dacloffset = le32_to_cpu(pntsd->dacloffset);
1277-
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
12781288
cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
12791289
pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
12801290
le32_to_cpu(pntsd->gsidoffset),
@@ -1305,11 +1315,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
13051315
return rc;
13061316
}
13071317

1308-
if (dacloffset)
1318+
if (dacloffset) {
1319+
if (!dacl_offset_valid(acl_len, dacloffset)) {
1320+
cifs_dbg(VFS, "Server returned illegal DACL offset\n");
1321+
return -EINVAL;
1322+
}
1323+
1324+
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
13091325
parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
13101326
group_sid_ptr, fattr, get_mode_from_special_sid);
1311-
else
1327+
} else {
13121328
cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
1329+
}
13131330

13141331
return rc;
13151332
}
@@ -1332,6 +1349,11 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
13321349

13331350
dacloffset = le32_to_cpu(pntsd->dacloffset);
13341351
if (dacloffset) {
1352+
if (!dacl_offset_valid(secdesclen, dacloffset)) {
1353+
cifs_dbg(VFS, "Server returned illegal DACL offset\n");
1354+
return -EINVAL;
1355+
}
1356+
13351357
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
13361358
rc = validate_dacl(dacl_ptr, end_of_acl);
13371359
if (rc)
@@ -1696,6 +1718,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
16961718
nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
16971719
dacloffset = le32_to_cpu(pntsd->dacloffset);
16981720
if (dacloffset) {
1721+
if (!dacl_offset_valid(secdesclen, dacloffset)) {
1722+
cifs_dbg(VFS, "Server returned illegal DACL offset\n");
1723+
rc = -EINVAL;
1724+
goto id_mode_to_cifs_acl_exit;
1725+
}
1726+
16991727
dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
17001728
rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
17011729
if (rc) {
@@ -1738,6 +1766,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
17381766
rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
17391767
cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
17401768
}
1769+
id_mode_to_cifs_acl_exit:
17411770
cifs_put_tlink(tlink);
17421771

17431772
kfree(pnntsd);

0 commit comments

Comments
 (0)