]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: validate ACE size against SID sub-authorities
authorNamjae Jeon <linkinjeon@kernel.org>
Sat, 4 Jul 2026 02:07:51 +0000 (11:07 +0900)
committerSteve French <stfrench@microsoft.com>
Wed, 22 Jul 2026 14:54:10 +0000 (09:54 -0500)
set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but
does not verify that the declared ACE size contains all sub-authorities
described by that field. An undersized ACE can therefore be copied
and later make the POSIX ACL deduplication walk inspect data beyond
the copied ACE boundary.

The existing initial bound check is also too small. It only ensures
that the ACE size field is accessible before set_ntacl_dacl() reads
sid.num_subauth farther into the input buffer.

Require enough input for the fixed SID header before accessing
num_subauth, reject ACEs smaller than that header, and skip ACEs
whose declared size cannot contain the complete SID. This makes the
validation consistent with the other ACE walk paths.

Reported-by: LocalHost <localhost.detect@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/smbacl.c

index f285b4f24a5bd2a988584a7dfe4d99b00799d515..c13f07a09ab8b4529506ddc343f26855063d8c94 100644 (file)
@@ -756,15 +756,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
                for (i = 0; i < nt_num_aces; i++) {
                        unsigned short nt_ace_size;
 
-                       if (offsetof(struct smb_ace, access_req) > aces_size)
+                       if (aces_size < offsetof(struct smb_ace, sid) +
+                                       CIFS_SID_BASE_SIZE)
                                break;
 
                        nt_ace_size = le16_to_cpu(ntace->size);
-                       if (nt_ace_size > aces_size)
+                       if (nt_ace_size > aces_size ||
+                           nt_ace_size < offsetof(struct smb_ace, sid) +
+                                         CIFS_SID_BASE_SIZE)
                                break;
 
                        if (ntace->sid.num_subauth == 0 ||
-                           ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
+                           ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
+                           nt_ace_size < offsetof(struct smb_ace, sid) +
+                                         CIFS_SID_BASE_SIZE +
+                                         sizeof(__le32) *
+                                         ntace->sid.num_subauth)
                                goto next_ace;
 
                        memcpy((char *)pndace + size, ntace, nt_ace_size);