]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: validate SID in parent security descriptor during ACL inheritance
authorJunyi Liu <moss80199@gmail.com>
Tue, 19 May 2026 07:12:04 +0000 (16:12 +0900)
committerSteve French <stfrench@microsoft.com>
Thu, 21 May 2026 23:18:49 +0000 (18:18 -0500)
Introduce smb_validate_ntsd_sid() helper to safely validate Owner SID
and Group SID inside the NT Security Descriptor (smb_ntsd) retrieved
from the parent directory.

Cc: stable@vger.kernel.org
Signed-off-by: Junyi Liu <moss80199@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/smbacl.c

index 9161e9d7ed2477f8d359227c8ab11ab7e30b3277..c2d9be52a311fc1896395ab7c6f7c0585205c2d6 100644 (file)
@@ -1096,6 +1096,40 @@ static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size,
        return 0;
 }
 
+static int smb_validate_ntsd_sid(struct smb_ntsd *pntsd, size_t pntsd_size,
+                                 unsigned int sid_offset, struct smb_sid **sid,
+                                 size_t *sid_size)
+{
+       size_t sid_end;
+
+       *sid = NULL;
+       *sid_size = 0;
+
+       if (!sid_offset)
+               return 0;
+
+       if (sid_offset < sizeof(struct smb_ntsd) ||
+           check_add_overflow(sid_offset, (size_t)CIFS_SID_BASE_SIZE,
+                              &sid_end) ||
+           sid_end > pntsd_size)
+               return -EINVAL;
+
+       *sid = (struct smb_sid *)((char *)pntsd + sid_offset);
+       if ((*sid)->num_subauth > SID_MAX_SUB_AUTHORITIES)
+               return -EINVAL;
+
+       if (check_add_overflow((size_t)CIFS_SID_BASE_SIZE,
+                              sizeof(__le32) * (size_t)(*sid)->num_subauth,
+                              &sid_end))
+               return -EINVAL;
+
+       if (sid_offset > pntsd_size || sid_end > pntsd_size - sid_offset)
+               return -EINVAL;
+
+       *sid_size = sid_end;
+       return 0;
+}
+
 int smb_inherit_dacl(struct ksmbd_conn *conn,
                     const struct path *path,
                     unsigned int uid, unsigned int gid)
@@ -1108,28 +1142,28 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
        struct dentry *parent = path->dentry->d_parent;
        struct mnt_idmap *idmap = mnt_idmap(path->mnt);
        int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
-       int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size;
+       int rc = 0, pntsd_type, ppntsd_size, acl_len, aces_size;
        unsigned int dacloffset;
        size_t dacl_struct_end;
        u16 num_aces, ace_cnt = 0;
        char *aces_base;
        bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
 
-       pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
+       ppntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
                                            parent, &parent_pntsd);
-       if (pntsd_size <= 0)
+       if (ppntsd_size <= 0)
                return -ENOENT;
 
        dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
        if (!dacloffset ||
            check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
-           dacl_struct_end > (size_t)pntsd_size) {
+           dacl_struct_end > (size_t)ppntsd_size) {
                rc = -EINVAL;
                goto free_parent_pntsd;
        }
 
        parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
-       acl_len = pntsd_size - dacloffset;
+       acl_len = ppntsd_size - dacloffset;
        num_aces = le16_to_cpu(parent_pdacl->num_aces);
        pntsd_type = le16_to_cpu(parent_pntsd->type);
        pdacl_size = le16_to_cpu(parent_pdacl->size);
@@ -1243,19 +1277,19 @@ pass:
                struct smb_ntsd *pntsd;
                struct smb_acl *pdacl;
                struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL;
-               int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
+               size_t powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
                size_t pntsd_alloc_size;
 
-               if (parent_pntsd->osidoffset) {
-                       powner_sid = (struct smb_sid *)((char *)parent_pntsd +
-                                       le32_to_cpu(parent_pntsd->osidoffset));
-                       powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4);
-               }
-               if (parent_pntsd->gsidoffset) {
-                       pgroup_sid = (struct smb_sid *)((char *)parent_pntsd +
-                                       le32_to_cpu(parent_pntsd->gsidoffset));
-                       pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4);
-               }
+               rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
+                                          le32_to_cpu(parent_pntsd->osidoffset),
+                                          &powner_sid, &powner_sid_size);
+               if (rc)
+                       goto free_aces_base;
+               rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
+                                          le32_to_cpu(parent_pntsd->gsidoffset),
+                                          &pgroup_sid, &pgroup_sid_size);
+               if (rc)
+                       goto free_aces_base;
 
                if (check_add_overflow(sizeof(struct smb_ntsd),
                                       (size_t)powner_sid_size,