]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: use check_add_overflow() to prevent u16 DACL size overflow
authorTristan Madani <tristan@talencesecurity.com>
Fri, 17 Apr 2026 19:54:57 +0000 (19:54 +0000)
committerSteve French <stfrench@microsoft.com>
Sat, 18 Apr 2026 17:19:59 +0000 (12:19 -0500)
set_posix_acl_entries_dacl() and set_ntacl_dacl() accumulate ACE sizes
in u16 variables. When a file has many POSIX ACL entries, the
accumulated size can wrap past 65535, causing the pointer arithmetic
(char *)pndace + *size to land within already-written ACEs. Subsequent
writes then overwrite earlier entries, and pndacl->size gets a
truncated value.

Use check_add_overflow() at each accumulation point to detect the
wrap before it corrupts the buffer, consistent with existing
check_mul_overflow() usage elsewhere in smbacl.c.

Cc: stable@vger.kernel.org
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/smbacl.c

index a1de89cc09bee21d617c79147365c9ff89305b8f..4bbc2c27e6805ee12173a21d1cd13c8e5d7df349 100644 (file)
@@ -596,6 +596,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
        struct smb_sid *sid;
        struct smb_ace *ntace;
        int i, j;
+       u16 ace_sz;
 
        if (!fattr->cf_acls)
                goto posix_default_acl;
@@ -640,8 +641,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
                        flags = 0x03;
 
                ntace = (struct smb_ace *)((char *)pndace + *size);
-               *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+               ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
                                pace->e_perm, 0777);
+               if (check_add_overflow(*size, ace_sz, size))
+                       break;
                (*num_aces)++;
                if (pace->e_tag == ACL_USER)
                        ntace->access_req |=
@@ -650,8 +653,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
                if (S_ISDIR(fattr->cf_mode) &&
                    (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) {
                        ntace = (struct smb_ace *)((char *)pndace + *size);
-                       *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+                       ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
                                        0x03, pace->e_perm, 0777);
+                       if (check_add_overflow(*size, ace_sz, size))
+                               break;
                        (*num_aces)++;
                        if (pace->e_tag == ACL_USER)
                                ntace->access_req |=
@@ -691,8 +696,10 @@ posix_default_acl:
                }
 
                ntace = (struct smb_ace *)((char *)pndace + *size);
-               *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+               ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
                                pace->e_perm, 0777);
+               if (check_add_overflow(*size, ace_sz, size))
+                       break;
                (*num_aces)++;
                if (pace->e_tag == ACL_USER)
                        ntace->access_req |=
@@ -728,7 +735,8 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
                                break;
 
                        memcpy((char *)pndace + size, ntace, nt_ace_size);
-                       size += nt_ace_size;
+                       if (check_add_overflow(size, nt_ace_size, &size))
+                               break;
                        aces_size -= nt_ace_size;
                        ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
                        num_aces++;