71 lines
2.7 KiB
Diff
71 lines
2.7 KiB
Diff
From 3fe0cc7e4d24b0a152798ec17ceed4156fe96033 Mon Sep 17 00:00:00 2001
|
|
From: Norbert Szetei <norbert@doyensec.com>
|
|
Date: Sat, 29 Mar 2025 06:58:15 +0000
|
|
Subject: ksmbd: fix overflow in dacloffset bounds check
|
|
|
|
The dacloffset field was originally typed as int and used in an
|
|
unchecked addition, which could overflow and bypass the existing
|
|
bounds check in both smb_check_perm_dacl() and smb_inherit_dacl().
|
|
|
|
This could result in out-of-bounds memory access and a kernel crash
|
|
when dereferencing the DACL pointer.
|
|
|
|
This patch converts dacloffset to unsigned int and uses
|
|
check_add_overflow() to validate access to the DACL.
|
|
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Norbert Szetei <norbert@doyensec.com>
|
|
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
---
|
|
fs/smb/server/smbacl.c | 16 ++++++++++++----
|
|
1 file changed, 12 insertions(+), 4 deletions(-)
|
|
|
|
--- a/fs/smb/server/smbacl.c
|
|
+++ b/fs/smb/server/smbacl.c
|
|
@@ -1026,7 +1026,9 @@ int smb_inherit_dacl(struct ksmbd_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, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
|
|
+ int rc = 0, pntsd_type, pntsd_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);
|
|
@@ -1035,8 +1037,11 @@ int smb_inherit_dacl(struct ksmbd_conn *
|
|
parent, &parent_pntsd);
|
|
if (pntsd_size <= 0)
|
|
return -ENOENT;
|
|
+
|
|
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
|
|
- if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
|
|
+ if (!dacloffset ||
|
|
+ check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
|
|
+ dacl_struct_end > (size_t)pntsd_size) {
|
|
rc = -EINVAL;
|
|
goto free_parent_pntsd;
|
|
}
|
|
@@ -1240,7 +1245,9 @@ int smb_check_perm_dacl(struct ksmbd_con
|
|
struct smb_ntsd *pntsd = NULL;
|
|
struct smb_acl *pdacl;
|
|
struct posix_acl *posix_acls;
|
|
- int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
|
|
+ int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size;
|
|
+ unsigned int dacl_offset;
|
|
+ size_t dacl_struct_end;
|
|
struct smb_sid sid;
|
|
int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
|
|
struct smb_ace *ace;
|
|
@@ -1259,7 +1266,8 @@ int smb_check_perm_dacl(struct ksmbd_con
|
|
|
|
dacl_offset = le32_to_cpu(pntsd->dacloffset);
|
|
if (!dacl_offset ||
|
|
- (dacl_offset + sizeof(struct smb_acl) > pntsd_size))
|
|
+ check_add_overflow(dacl_offset, sizeof(struct smb_acl), &dacl_struct_end) ||
|
|
+ dacl_struct_end > (size_t)pntsd_size)
|
|
goto err_out;
|
|
|
|
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
|