Skip to content

Commit

Permalink
ksmbd: fix overflow in dacloffset bounds check
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Norbert Szetei authored and Steve French committed Apr 1, 2025
1 parent fa4cdb8 commit beff0bc
Showing 1 changed file with 12 additions and 4 deletions.
16 changes: 12 additions & 4 deletions fs/smb/server/smbacl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,9 @@ 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, 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);
Expand All @@ -1035,8 +1037,11 @@ int smb_inherit_dacl(struct ksmbd_conn *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;
}
Expand Down Expand Up @@ -1240,7 +1245,9 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
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;
Expand All @@ -1259,7 +1266,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,

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));
Expand Down

0 comments on commit beff0bc

Please sign in to comment.