summaryrefslogtreecommitdiff
path: root/fs/smb/server/smbacl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/server/smbacl.c')
-rw-r--r--fs/smb/server/smbacl.c75
1 files changed, 48 insertions, 27 deletions
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 1c9775f1efa5..49b128698670 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -333,7 +333,7 @@ void posix_state_to_acl(struct posix_acl_state *state,
pace->e_perm = state->other.allow;
}
-int init_acl_state(struct posix_acl_state *state, int cnt)
+int init_acl_state(struct posix_acl_state *state, u16 cnt)
{
int alloc;
@@ -345,10 +345,10 @@ int init_acl_state(struct posix_acl_state *state, int cnt)
*/
alloc = sizeof(struct posix_ace_state_array)
+ cnt * sizeof(struct posix_user_ace_state);
- state->users = kzalloc(alloc, GFP_KERNEL);
+ state->users = kzalloc(alloc, KSMBD_DEFAULT_GFP);
if (!state->users)
return -ENOMEM;
- state->groups = kzalloc(alloc, GFP_KERNEL);
+ state->groups = kzalloc(alloc, KSMBD_DEFAULT_GFP);
if (!state->groups) {
kfree(state->users);
return -ENOMEM;
@@ -368,7 +368,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
struct smb_fattr *fattr)
{
int i, ret;
- int num_aces = 0;
+ u16 num_aces = 0;
unsigned int acl_size;
char *acl_base;
struct smb_ace **ppace;
@@ -389,16 +389,18 @@ static void parse_dacl(struct mnt_idmap *idmap,
ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n",
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
- le32_to_cpu(pdacl->num_aces));
+ le16_to_cpu(pdacl->num_aces));
acl_base = (char *)pdacl;
acl_size = sizeof(struct smb_acl);
- num_aces = le32_to_cpu(pdacl->num_aces);
+ num_aces = le16_to_cpu(pdacl->num_aces);
if (num_aces <= 0)
return;
- if (num_aces > ULONG_MAX / sizeof(struct smb_ace *))
+ if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
+ (offsetof(struct smb_ace, sid) +
+ offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
return;
ret = init_acl_state(&acl_state, num_aces);
@@ -410,7 +412,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
return;
}
- ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL);
+ ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), KSMBD_DEFAULT_GFP);
if (!ppace) {
free_acl_state(&default_acl_state);
free_acl_state(&acl_state);
@@ -432,6 +434,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
offsetof(struct smb_sid, sub_auth);
if (end_of_acl - acl_base < acl_size ||
+ ppace[i]->sid.num_subauth == 0 ||
ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
(end_of_acl - acl_base <
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
@@ -553,7 +556,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
fattr->cf_acls =
posix_acl_alloc(acl_state.users->n +
- acl_state.groups->n + 4, GFP_KERNEL);
+ acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
if (fattr->cf_acls) {
cf_pace = fattr->cf_acls->a_entries;
posix_state_to_acl(&acl_state, cf_pace);
@@ -567,7 +570,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
fattr->cf_dacls =
posix_acl_alloc(default_acl_state.users->n +
- default_acl_state.groups->n + 4, GFP_KERNEL);
+ default_acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
if (fattr->cf_dacls) {
cf_pdace = fattr->cf_dacls->a_entries;
posix_state_to_acl(&default_acl_state, cf_pdace);
@@ -580,7 +583,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
struct smb_ace *pndace,
- struct smb_fattr *fattr, u32 *num_aces,
+ struct smb_fattr *fattr, u16 *num_aces,
u16 *size, u32 nt_aces_num)
{
struct posix_acl_entry *pace;
@@ -595,7 +598,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
for (i = 0; i < fattr->cf_acls->a_count; i++, pace++) {
int flags = 0;
- sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL);
+ sid = kmalloc(sizeof(struct smb_sid), KSMBD_DEFAULT_GFP);
if (!sid)
break;
@@ -662,7 +665,7 @@ posix_default_acl:
pace = fattr->cf_dacls->a_entries;
for (i = 0; i < fattr->cf_dacls->a_count; i++, pace++) {
- sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL);
+ sid = kmalloc(sizeof(struct smb_sid), KSMBD_DEFAULT_GFP);
if (!sid)
break;
@@ -701,7 +704,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
struct smb_fattr *fattr)
{
struct smb_ace *ntace, *pndace;
- int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0;
+ u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
unsigned short size = 0;
int i;
@@ -728,7 +731,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
set_posix_acl_entries_dacl(idmap, pndace, fattr,
&num_aces, &size, nt_num_aces);
- pndacl->num_aces = cpu_to_le32(num_aces);
+ pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
}
@@ -736,7 +739,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
struct smb_acl *pndacl, struct smb_fattr *fattr)
{
struct smb_ace *pace, *pndace;
- u32 num_aces = 0;
+ u16 num_aces = 0;
u16 size = 0, ace_size = 0;
uid_t uid;
const struct smb_sid *sid;
@@ -792,7 +795,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
fattr->cf_mode, 0007);
out:
- pndacl->num_aces = cpu_to_le32(num_aces);
+ pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
}
@@ -807,6 +810,13 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl)
return -EINVAL;
}
+ if (!psid->num_subauth)
+ return 0;
+
+ if (psid->num_subauth > SID_MAX_SUB_AUTHORITIES ||
+ end_of_acl < (char *)psid + 8 + sizeof(__le32) * psid->num_subauth)
+ return -EINVAL;
+
return 0;
}
@@ -848,6 +858,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
pntsd->type = cpu_to_le16(DACL_PRESENT);
if (pntsd->osidoffset) {
+ if (le32_to_cpu(pntsd->osidoffset) < sizeof(struct smb_ntsd))
+ return -EINVAL;
+
rc = parse_sid(owner_sid_ptr, end_of_acl);
if (rc) {
pr_err("%s: Error %d parsing Owner SID\n", __func__, rc);
@@ -863,6 +876,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
}
if (pntsd->gsidoffset) {
+ if (le32_to_cpu(pntsd->gsidoffset) < sizeof(struct smb_ntsd))
+ return -EINVAL;
+
rc = parse_sid(group_sid_ptr, end_of_acl);
if (rc) {
pr_err("%s: Error %d mapping Owner SID to gid\n",
@@ -884,6 +900,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
pntsd->type |= cpu_to_le16(DACL_PROTECTED);
if (dacloffset) {
+ if (dacloffset < sizeof(struct smb_ntsd))
+ return -EINVAL;
+
parse_dacl(idmap, dacl_ptr, end_of_acl,
owner_sid_ptr, group_sid_ptr, fattr);
}
@@ -906,7 +925,7 @@ int build_sec_desc(struct mnt_idmap *idmap,
gid_t gid;
unsigned int sid_type = SIDOWNER;
- nowner_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL);
+ nowner_sid_ptr = kmalloc(sizeof(struct smb_sid), KSMBD_DEFAULT_GFP);
if (!nowner_sid_ptr)
return -ENOMEM;
@@ -915,7 +934,7 @@ int build_sec_desc(struct mnt_idmap *idmap,
sid_type = SIDUNIX_USER;
id_to_sid(uid, sid_type, nowner_sid_ptr);
- ngroup_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL);
+ ngroup_sid_ptr = kmalloc(sizeof(struct smb_sid), KSMBD_DEFAULT_GFP);
if (!ngroup_sid_ptr) {
kfree(nowner_sid_ptr);
return -ENOMEM;
@@ -1006,8 +1025,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
struct smb_sid owner_sid, group_sid;
struct dentry *parent = path->dentry->d_parent;
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
- int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
- int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
+ int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
+ int rc = 0, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
+ u16 num_aces, ace_cnt = 0;
char *aces_base;
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
@@ -1023,7 +1043,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
acl_len = pntsd_size - dacloffset;
- num_aces = le32_to_cpu(parent_pdacl->num_aces);
+ 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);
@@ -1032,7 +1052,8 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
goto free_parent_pntsd;
}
- aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
+ aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2,
+ KSMBD_DEFAULT_GFP);
if (!aces_base) {
rc = -ENOMEM;
goto free_parent_pntsd;
@@ -1126,7 +1147,7 @@ pass:
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);
+ pntsd = kzalloc(pntsd_alloc_size, KSMBD_DEFAULT_GFP);
if (!pntsd) {
rc = -ENOMEM;
goto free_aces_base;
@@ -1182,7 +1203,7 @@ pass:
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
pdacl->revision = cpu_to_le16(2);
pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size);
- pdacl->num_aces = cpu_to_le32(ace_cnt);
+ pdacl->num_aces = cpu_to_le16(ace_cnt);
pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
memcpy(pace, aces_base, nt_size);
pntsd_size += sizeof(struct smb_acl) + nt_size;
@@ -1263,7 +1284,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = acl_size - sizeof(struct smb_acl);
- for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+ for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
if (offsetof(struct smb_ace, access_req) > aces_size)
break;
ace_size = le16_to_cpu(ace->size);
@@ -1284,7 +1305,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
aces_size = acl_size - sizeof(struct smb_acl);
- for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
+ for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
if (offsetof(struct smb_ace, access_req) > aces_size)
break;
ace_size = le16_to_cpu(ace->size);