]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: fix slab out of bounds write in smb_inherit_dacl()
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 5 Nov 2023 03:46:24 +0000 (12:46 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 16:56:33 +0000 (16:56 +0000)
[ Upstream commit eebff19acaa35820cb09ce2ccb3d21bee2156ffb ]

slab out-of-bounds write is caused by that offsets is bigger than pntsd
allocation size. This patch add the check to validate 3 offsets using
allocation size.

Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-22271
Cc: stable@vger.kernel.org
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ksmbd/smbacl.c

index 3781bca2c8fc470507d5239f6b7912604e4fa79a..83f805248a814c5775493bbf8767f17c7528cbb1 100644 (file)
@@ -1105,6 +1105,7 @@ pass:
                struct smb_acl *pdacl;
                struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL;
                int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
+               int pntsd_alloc_size;
 
                if (parent_pntsd->osidoffset) {
                        powner_sid = (struct smb_sid *)((char *)parent_pntsd +
@@ -1117,9 +1118,10 @@ pass:
                        pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4);
                }
 
-               pntsd = kzalloc(sizeof(struct smb_ntsd) + powner_sid_size +
-                               pgroup_sid_size + sizeof(struct smb_acl) +
-                               nt_size, GFP_KERNEL);
+               pntsd_alloc_size = sizeof(struct smb_ntsd) + powner_sid_size +
+                       pgroup_sid_size + sizeof(struct smb_acl) + nt_size;
+
+               pntsd = kzalloc(pntsd_alloc_size, GFP_KERNEL);
                if (!pntsd) {
                        rc = -ENOMEM;
                        goto free_aces_base;
@@ -1134,6 +1136,27 @@ pass:
                pntsd->gsidoffset = parent_pntsd->gsidoffset;
                pntsd->dacloffset = parent_pntsd->dacloffset;
 
+               if ((u64)le32_to_cpu(pntsd->osidoffset) + powner_sid_size >
+                   pntsd_alloc_size) {
+                       rc = -EINVAL;
+                       kfree(pntsd);
+                       goto free_aces_base;
+               }
+
+               if ((u64)le32_to_cpu(pntsd->gsidoffset) + pgroup_sid_size >
+                   pntsd_alloc_size) {
+                       rc = -EINVAL;
+                       kfree(pntsd);
+                       goto free_aces_base;
+               }
+
+               if ((u64)le32_to_cpu(pntsd->dacloffset) + sizeof(struct smb_acl) + nt_size >
+                   pntsd_alloc_size) {
+                       rc = -EINVAL;
+                       kfree(pntsd);
+                       goto free_aces_base;
+               }
+
                if (pntsd->osidoffset) {
                        struct smb_sid *owner_sid = (struct smb_sid *)((char *)pntsd +
                                        le32_to_cpu(pntsd->osidoffset));