Skip to content

Commit beff0bc

Browse files
nszeteiSteve French
authored andcommitted
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>
1 parent fa4cdb8 commit beff0bc

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

fs/smb/server/smbacl.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10261026
struct dentry *parent = path->dentry->d_parent;
10271027
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
10281028
int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
1029-
int rc = 0, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
1029+
int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size;
1030+
unsigned int dacloffset;
1031+
size_t dacl_struct_end;
10301032
u16 num_aces, ace_cnt = 0;
10311033
char *aces_base;
10321034
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
@@ -1035,8 +1037,11 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10351037
parent, &parent_pntsd);
10361038
if (pntsd_size <= 0)
10371039
return -ENOENT;
1040+
10381041
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
1039-
if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
1042+
if (!dacloffset ||
1043+
check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
1044+
dacl_struct_end > (size_t)pntsd_size) {
10401045
rc = -EINVAL;
10411046
goto free_parent_pntsd;
10421047
}
@@ -1240,7 +1245,9 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12401245
struct smb_ntsd *pntsd = NULL;
12411246
struct smb_acl *pdacl;
12421247
struct posix_acl *posix_acls;
1243-
int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
1248+
int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size;
1249+
unsigned int dacl_offset;
1250+
size_t dacl_struct_end;
12441251
struct smb_sid sid;
12451252
int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
12461253
struct smb_ace *ace;
@@ -1259,7 +1266,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12591266

12601267
dacl_offset = le32_to_cpu(pntsd->dacloffset);
12611268
if (!dacl_offset ||
1262-
(dacl_offset + sizeof(struct smb_acl) > pntsd_size))
1269+
check_add_overflow(dacl_offset, sizeof(struct smb_acl), &dacl_struct_end) ||
1270+
dacl_struct_end > (size_t)pntsd_size)
12631271
goto err_out;
12641272

12651273
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));

0 commit comments

Comments
 (0)