Skip to content

Commit 1238f0a

Browse files
committed
Merge tag 'v6.14-rc5-smb3-fixes' of git://git.samba.org/ksmbd
Pull smb fixes from Steve French: "Five SMB server fixes, two related client fixes, and minor MAINTAINERS update: - Two SMB3 lock fixes fixes (including use after free and bug on fix) - Fix to race condition that can happen in processing IPC responses - Four ACL related fixes: one related to endianness of num_aces, and two related fixes to the checks for num_aces (for both client and server), and one fixing missing check for num_subauths which can cause memory corruption - And minor update to email addresses in MAINTAINERS file" * tag 'v6.14-rc5-smb3-fixes' of git://git.samba.org/ksmbd: cifs: fix incorrect validation for num_aces field of smb_acl ksmbd: fix incorrect validation for num_aces field of smb_acl smb: common: change the data type of num_aces to le16 ksmbd: fix bug on trap in smb2_lock ksmbd: fix use-after-free in smb2_lock ksmbd: fix type confusion via race condition when using ipc_msg_send_request ksmbd: fix out-of-bounds in parse_sec_desc() MAINTAINERS: update email address in cifs and ksmbd entry
2 parents 5872cca + aa2a739 commit 1238f0a

File tree

7 files changed

+66
-37
lines changed

7 files changed

+66
-37
lines changed

MAINTAINERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5775,6 +5775,7 @@ X: drivers/clk/clkdev.c
57755775

57765776
COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
57775777
M: Steve French <sfrench@samba.org>
5778+
M: Steve French <smfrench@gmail.com>
57785779
R: Paulo Alcantara <pc@manguebit.com> (DFS, global name space)
57795780
R: Ronnie Sahlberg <ronniesahlberg@gmail.com> (directory leases, sparse files)
57805781
R: Shyam Prasad N <sprasad@microsoft.com> (multichannel)
@@ -12655,7 +12656,9 @@ F: tools/testing/selftests/
1265512656

1265612657
KERNEL SMB3 SERVER (KSMBD)
1265712658
M: Namjae Jeon <linkinjeon@kernel.org>
12659+
M: Namjae Jeon <linkinjeon@samba.org>
1265812660
M: Steve French <sfrench@samba.org>
12661+
M: Steve French <smfrench@gmail.com>
1265912662
R: Sergey Senozhatsky <senozhatsky@chromium.org>
1266012663
R: Tom Talpey <tom@talpey.com>
1266112664
L: linux-cifs@vger.kernel.org

fs/smb/client/cifsacl.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
763763
struct cifs_fattr *fattr, bool mode_from_special_sid)
764764
{
765765
int i;
766-
int num_aces = 0;
766+
u16 num_aces = 0;
767767
int acl_size;
768768
char *acl_base;
769769
struct smb_ace **ppace;
@@ -778,14 +778,15 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
778778
}
779779

780780
/* validate that we do not go past end of acl */
781-
if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
781+
if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
782+
end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
782783
cifs_dbg(VFS, "ACL too small to parse DACL\n");
783784
return;
784785
}
785786

786787
cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
787788
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
788-
le32_to_cpu(pdacl->num_aces));
789+
le16_to_cpu(pdacl->num_aces));
789790

790791
/* reset rwx permissions for user/group/other.
791792
Also, if num_aces is 0 i.e. DACL has no ACEs,
@@ -795,12 +796,15 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
795796
acl_base = (char *)pdacl;
796797
acl_size = sizeof(struct smb_acl);
797798

798-
num_aces = le32_to_cpu(pdacl->num_aces);
799+
num_aces = le16_to_cpu(pdacl->num_aces);
799800
if (num_aces > 0) {
800801
umode_t denied_mode = 0;
801802

802-
if (num_aces > ULONG_MAX / sizeof(struct smb_ace *))
803+
if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
804+
(offsetof(struct smb_ace, sid) +
805+
offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
803806
return;
807+
804808
ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *),
805809
GFP_KERNEL);
806810
if (!ppace)
@@ -937,12 +941,12 @@ unsigned int setup_special_user_owner_ACE(struct smb_ace *pntace)
937941
static void populate_new_aces(char *nacl_base,
938942
struct smb_sid *pownersid,
939943
struct smb_sid *pgrpsid,
940-
__u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
944+
__u64 *pnmode, u16 *pnum_aces, u16 *pnsize,
941945
bool modefromsid,
942946
bool posix)
943947
{
944948
__u64 nmode;
945-
u32 num_aces = 0;
949+
u16 num_aces = 0;
946950
u16 nsize = 0;
947951
__u64 user_mode;
948952
__u64 group_mode;
@@ -1050,15 +1054,15 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
10501054
u16 size = 0;
10511055
struct smb_ace *pntace = NULL;
10521056
char *acl_base = NULL;
1053-
u32 src_num_aces = 0;
1057+
u16 src_num_aces = 0;
10541058
u16 nsize = 0;
10551059
struct smb_ace *pnntace = NULL;
10561060
char *nacl_base = NULL;
10571061
u16 ace_size = 0;
10581062

10591063
acl_base = (char *)pdacl;
10601064
size = sizeof(struct smb_acl);
1061-
src_num_aces = le32_to_cpu(pdacl->num_aces);
1065+
src_num_aces = le16_to_cpu(pdacl->num_aces);
10621066

10631067
nacl_base = (char *)pndacl;
10641068
nsize = sizeof(struct smb_acl);
@@ -1090,11 +1094,11 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
10901094
u16 size = 0;
10911095
struct smb_ace *pntace = NULL;
10921096
char *acl_base = NULL;
1093-
u32 src_num_aces = 0;
1097+
u16 src_num_aces = 0;
10941098
u16 nsize = 0;
10951099
struct smb_ace *pnntace = NULL;
10961100
char *nacl_base = NULL;
1097-
u32 num_aces = 0;
1101+
u16 num_aces = 0;
10981102
bool new_aces_set = false;
10991103

11001104
/* Assuming that pndacl and pnmode are never NULL */
@@ -1112,7 +1116,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
11121116

11131117
acl_base = (char *)pdacl;
11141118
size = sizeof(struct smb_acl);
1115-
src_num_aces = le32_to_cpu(pdacl->num_aces);
1119+
src_num_aces = le16_to_cpu(pdacl->num_aces);
11161120

11171121
/* Retain old ACEs which we can retain */
11181122
for (i = 0; i < src_num_aces; ++i) {
@@ -1158,7 +1162,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
11581162
}
11591163

11601164
finalize_dacl:
1161-
pndacl->num_aces = cpu_to_le32(num_aces);
1165+
pndacl->num_aces = cpu_to_le16(num_aces);
11621166
pndacl->size = cpu_to_le16(nsize);
11631167

11641168
return 0;
@@ -1293,7 +1297,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
12931297
dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
12941298

12951299
ndacl_ptr->size = cpu_to_le16(0);
1296-
ndacl_ptr->num_aces = cpu_to_le32(0);
1300+
ndacl_ptr->num_aces = cpu_to_le16(0);
12971301

12981302
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
12991303
pnmode, mode_from_sid, posix);
@@ -1653,7 +1657,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
16531657
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
16541658
if (mode_from_sid)
16551659
nsecdesclen +=
1656-
le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
1660+
le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
16571661
else /* cifsacl */
16581662
nsecdesclen += le16_to_cpu(dacl_ptr->size);
16591663
}

fs/smb/common/smbacl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ struct smb_sid {
107107
struct smb_acl {
108108
__le16 revision; /* revision level */
109109
__le16 size;
110-
__le32 num_aces;
110+
__le16 num_aces;
111+
__le16 reserved;
111112
} __attribute__((packed));
112113

113114
struct smb_ace {

fs/smb/server/smb2pdu.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7458,17 +7458,17 @@ int smb2_lock(struct ksmbd_work *work)
74587458
}
74597459

74607460
no_check_cl:
7461+
flock = smb_lock->fl;
7462+
list_del(&smb_lock->llist);
7463+
74617464
if (smb_lock->zero_len) {
74627465
err = 0;
74637466
goto skip;
74647467
}
7465-
7466-
flock = smb_lock->fl;
7467-
list_del(&smb_lock->llist);
74687468
retry:
74697469
rc = vfs_lock_file(filp, smb_lock->cmd, flock, NULL);
74707470
skip:
7471-
if (flags & SMB2_LOCKFLAG_UNLOCK) {
7471+
if (smb_lock->flags & SMB2_LOCKFLAG_UNLOCK) {
74727472
if (!rc) {
74737473
ksmbd_debug(SMB, "File unlocked\n");
74747474
} else if (rc == -ENOENT) {

fs/smb/server/smbacl.c

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ void posix_state_to_acl(struct posix_acl_state *state,
333333
pace->e_perm = state->other.allow;
334334
}
335335

336-
int init_acl_state(struct posix_acl_state *state, int cnt)
336+
int init_acl_state(struct posix_acl_state *state, u16 cnt)
337337
{
338338
int alloc;
339339

@@ -368,7 +368,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
368368
struct smb_fattr *fattr)
369369
{
370370
int i, ret;
371-
int num_aces = 0;
371+
u16 num_aces = 0;
372372
unsigned int acl_size;
373373
char *acl_base;
374374
struct smb_ace **ppace;
@@ -389,16 +389,18 @@ static void parse_dacl(struct mnt_idmap *idmap,
389389

390390
ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n",
391391
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
392-
le32_to_cpu(pdacl->num_aces));
392+
le16_to_cpu(pdacl->num_aces));
393393

394394
acl_base = (char *)pdacl;
395395
acl_size = sizeof(struct smb_acl);
396396

397-
num_aces = le32_to_cpu(pdacl->num_aces);
397+
num_aces = le16_to_cpu(pdacl->num_aces);
398398
if (num_aces <= 0)
399399
return;
400400

401-
if (num_aces > ULONG_MAX / sizeof(struct smb_ace *))
401+
if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
402+
(offsetof(struct smb_ace, sid) +
403+
offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
402404
return;
403405

404406
ret = init_acl_state(&acl_state, num_aces);
@@ -432,6 +434,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
432434
offsetof(struct smb_sid, sub_auth);
433435

434436
if (end_of_acl - acl_base < acl_size ||
437+
ppace[i]->sid.num_subauth == 0 ||
435438
ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
436439
(end_of_acl - acl_base <
437440
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
@@ -580,7 +583,7 @@ static void parse_dacl(struct mnt_idmap *idmap,
580583

581584
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
582585
struct smb_ace *pndace,
583-
struct smb_fattr *fattr, u32 *num_aces,
586+
struct smb_fattr *fattr, u16 *num_aces,
584587
u16 *size, u32 nt_aces_num)
585588
{
586589
struct posix_acl_entry *pace;
@@ -701,7 +704,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
701704
struct smb_fattr *fattr)
702705
{
703706
struct smb_ace *ntace, *pndace;
704-
int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0;
707+
u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
705708
unsigned short size = 0;
706709
int i;
707710

@@ -728,15 +731,15 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
728731

729732
set_posix_acl_entries_dacl(idmap, pndace, fattr,
730733
&num_aces, &size, nt_num_aces);
731-
pndacl->num_aces = cpu_to_le32(num_aces);
734+
pndacl->num_aces = cpu_to_le16(num_aces);
732735
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
733736
}
734737

735738
static void set_mode_dacl(struct mnt_idmap *idmap,
736739
struct smb_acl *pndacl, struct smb_fattr *fattr)
737740
{
738741
struct smb_ace *pace, *pndace;
739-
u32 num_aces = 0;
742+
u16 num_aces = 0;
740743
u16 size = 0, ace_size = 0;
741744
uid_t uid;
742745
const struct smb_sid *sid;
@@ -792,7 +795,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
792795
fattr->cf_mode, 0007);
793796

794797
out:
795-
pndacl->num_aces = cpu_to_le32(num_aces);
798+
pndacl->num_aces = cpu_to_le16(num_aces);
796799
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
797800
}
798801

@@ -807,6 +810,13 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl)
807810
return -EINVAL;
808811
}
809812

813+
if (!psid->num_subauth)
814+
return 0;
815+
816+
if (psid->num_subauth > SID_MAX_SUB_AUTHORITIES ||
817+
end_of_acl < (char *)psid + 8 + sizeof(__le32) * psid->num_subauth)
818+
return -EINVAL;
819+
810820
return 0;
811821
}
812822

@@ -848,6 +858,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
848858
pntsd->type = cpu_to_le16(DACL_PRESENT);
849859

850860
if (pntsd->osidoffset) {
861+
if (le32_to_cpu(pntsd->osidoffset) < sizeof(struct smb_ntsd))
862+
return -EINVAL;
863+
851864
rc = parse_sid(owner_sid_ptr, end_of_acl);
852865
if (rc) {
853866
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,
863876
}
864877

865878
if (pntsd->gsidoffset) {
879+
if (le32_to_cpu(pntsd->gsidoffset) < sizeof(struct smb_ntsd))
880+
return -EINVAL;
881+
866882
rc = parse_sid(group_sid_ptr, end_of_acl);
867883
if (rc) {
868884
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,
884900
pntsd->type |= cpu_to_le16(DACL_PROTECTED);
885901

886902
if (dacloffset) {
903+
if (dacloffset < sizeof(struct smb_ntsd))
904+
return -EINVAL;
905+
887906
parse_dacl(idmap, dacl_ptr, end_of_acl,
888907
owner_sid_ptr, group_sid_ptr, fattr);
889908
}
@@ -1006,8 +1025,9 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10061025
struct smb_sid owner_sid, group_sid;
10071026
struct dentry *parent = path->dentry->d_parent;
10081027
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
1009-
int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
1010-
int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
1028+
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;
1030+
u16 num_aces, ace_cnt = 0;
10111031
char *aces_base;
10121032
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
10131033

@@ -1023,7 +1043,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
10231043

10241044
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
10251045
acl_len = pntsd_size - dacloffset;
1026-
num_aces = le32_to_cpu(parent_pdacl->num_aces);
1046+
num_aces = le16_to_cpu(parent_pdacl->num_aces);
10271047
pntsd_type = le16_to_cpu(parent_pntsd->type);
10281048
pdacl_size = le16_to_cpu(parent_pdacl->size);
10291049

@@ -1183,7 +1203,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
11831203
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
11841204
pdacl->revision = cpu_to_le16(2);
11851205
pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size);
1186-
pdacl->num_aces = cpu_to_le32(ace_cnt);
1206+
pdacl->num_aces = cpu_to_le16(ace_cnt);
11871207
pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
11881208
memcpy(pace, aces_base, nt_size);
11891209
pntsd_size += sizeof(struct smb_acl) + nt_size;
@@ -1264,7 +1284,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12641284

12651285
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
12661286
aces_size = acl_size - sizeof(struct smb_acl);
1267-
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
1287+
for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
12681288
if (offsetof(struct smb_ace, access_req) > aces_size)
12691289
break;
12701290
ace_size = le16_to_cpu(ace->size);
@@ -1285,7 +1305,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12851305

12861306
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
12871307
aces_size = acl_size - sizeof(struct smb_acl);
1288-
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
1308+
for (i = 0; i < le16_to_cpu(pdacl->num_aces); i++) {
12891309
if (offsetof(struct smb_ace, access_req) > aces_size)
12901310
break;
12911311
ace_size = le16_to_cpu(ace->size);

fs/smb/server/smbacl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
8686
int build_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
8787
struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
8888
__u32 *secdesclen, struct smb_fattr *fattr);
89-
int init_acl_state(struct posix_acl_state *state, int cnt);
89+
int init_acl_state(struct posix_acl_state *state, u16 cnt);
9090
void free_acl_state(struct posix_acl_state *state);
9191
void posix_state_to_acl(struct posix_acl_state *state,
9292
struct posix_acl_entry *pace);

fs/smb/server/transport_ipc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ static int handle_response(int type, void *payload, size_t sz)
281281
if (entry->type + 1 != type) {
282282
pr_err("Waiting for IPC type %d, got %d. Ignore.\n",
283283
entry->type + 1, type);
284+
continue;
284285
}
285286

286287
entry->response = kvzalloc(sz, KSMBD_DEFAULT_GFP);

0 commit comments

Comments
 (0)