Skip to content

Commit 65d7ca5

Browse files
committed
Merge tag '6.4-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: "Five smb3 server fixes, all also for stable: - Fix four slab out of bounds warnings: improve checks for protocol id, and for small packet length, and for create context parsing, and for negotiate context parsing - Fix for incorrect dereferencing POSIX ACLs" * tag '6.4-rc5-smb3-server-fixes' of git://git.samba.org/ksmbd: ksmbd: validate smb request protocol id ksmbd: check the validation of pdu_size in ksmbd_conn_handler_loop ksmbd: fix posix_acls and acls dereferencing possible ERR_PTR() ksmbd: fix out-of-bound read in parse_lease_state() ksmbd: fix out-of-bound read in deassemble_neg_contexts()
2 parents 022ce88 + 1c1bcf2 commit 65d7ca5

File tree

6 files changed

+62
-56
lines changed

6 files changed

+62
-56
lines changed

fs/smb/server/connection.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
294294
return true;
295295
}
296296

297+
#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
298+
#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
299+
297300
/**
298301
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests
299302
* @p: connection instance
@@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p)
350353
if (pdu_size > MAX_STREAM_PROT_LEN)
351354
break;
352355

356+
if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
357+
break;
358+
353359
/* 4 for rfc1002 length field */
354360
/* 1 for implied bcc[0] */
355361
size = pdu_size + 4 + 1;
@@ -358,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p)
358364
break;
359365

360366
memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
361-
if (!ksmbd_smb_request(conn))
362-
break;
363367

364368
/*
365369
* We already read 4 bytes to find out PDU size, now
@@ -377,6 +381,15 @@ int ksmbd_conn_handler_loop(void *p)
377381
continue;
378382
}
379383

384+
if (!ksmbd_smb_request(conn))
385+
break;
386+
387+
if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
388+
SMB2_PROTO_NUMBER) {
389+
if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
390+
break;
391+
}
392+
380393
if (!default_conn_ops.process_fn) {
381394
pr_err("No connection request callback\n");
382395
break;

fs/smb/server/oplock.c

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,56 +1415,38 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
14151415
*/
14161416
struct lease_ctx_info *parse_lease_state(void *open_req)
14171417
{
1418-
char *data_offset;
14191418
struct create_context *cc;
1420-
unsigned int next = 0;
1421-
char *name;
1422-
bool found = false;
14231419
struct smb2_create_req *req = (struct smb2_create_req *)open_req;
1424-
struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info),
1425-
GFP_KERNEL);
1420+
struct lease_ctx_info *lreq;
1421+
1422+
cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
1423+
if (IS_ERR_OR_NULL(cc))
1424+
return NULL;
1425+
1426+
lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);
14261427
if (!lreq)
14271428
return NULL;
14281429

1429-
data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset);
1430-
cc = (struct create_context *)data_offset;
1431-
do {
1432-
cc = (struct create_context *)((char *)cc + next);
1433-
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
1434-
if (le16_to_cpu(cc->NameLength) != 4 ||
1435-
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
1436-
next = le32_to_cpu(cc->Next);
1437-
continue;
1438-
}
1439-
found = true;
1440-
break;
1441-
} while (next != 0);
1430+
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
1431+
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
14421432

1443-
if (found) {
1444-
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
1445-
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
1446-
1447-
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1448-
lreq->req_state = lc->lcontext.LeaseState;
1449-
lreq->flags = lc->lcontext.LeaseFlags;
1450-
lreq->duration = lc->lcontext.LeaseDuration;
1451-
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
1452-
SMB2_LEASE_KEY_SIZE);
1453-
lreq->version = 2;
1454-
} else {
1455-
struct create_lease *lc = (struct create_lease *)cc;
1433+
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1434+
lreq->req_state = lc->lcontext.LeaseState;
1435+
lreq->flags = lc->lcontext.LeaseFlags;
1436+
lreq->duration = lc->lcontext.LeaseDuration;
1437+
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
1438+
SMB2_LEASE_KEY_SIZE);
1439+
lreq->version = 2;
1440+
} else {
1441+
struct create_lease *lc = (struct create_lease *)cc;
14561442

1457-
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1458-
lreq->req_state = lc->lcontext.LeaseState;
1459-
lreq->flags = lc->lcontext.LeaseFlags;
1460-
lreq->duration = lc->lcontext.LeaseDuration;
1461-
lreq->version = 1;
1462-
}
1463-
return lreq;
1443+
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
1444+
lreq->req_state = lc->lcontext.LeaseState;
1445+
lreq->flags = lc->lcontext.LeaseFlags;
1446+
lreq->duration = lc->lcontext.LeaseDuration;
1447+
lreq->version = 1;
14641448
}
1465-
1466-
kfree(lreq);
1467-
return NULL;
1449+
return lreq;
14681450
}
14691451

14701452
/**

fs/smb/server/smb2pdu.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -963,13 +963,13 @@ static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
963963

964964
static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
965965
struct smb2_negotiate_req *req,
966-
int len_of_smb)
966+
unsigned int len_of_smb)
967967
{
968968
/* +4 is to account for the RFC1001 len field */
969969
struct smb2_neg_context *pctx = (struct smb2_neg_context *)req;
970970
int i = 0, len_of_ctxts;
971-
int offset = le32_to_cpu(req->NegotiateContextOffset);
972-
int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
971+
unsigned int offset = le32_to_cpu(req->NegotiateContextOffset);
972+
unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
973973
__le32 status = STATUS_INVALID_PARAMETER;
974974

975975
ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);
@@ -983,7 +983,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
983983
while (i++ < neg_ctxt_cnt) {
984984
int clen, ctxt_len;
985985

986-
if (len_of_ctxts < sizeof(struct smb2_neg_context))
986+
if (len_of_ctxts < (int)sizeof(struct smb2_neg_context))
987987
break;
988988

989989
pctx = (struct smb2_neg_context *)((char *)pctx + offset);
@@ -1038,9 +1038,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
10381038
}
10391039

10401040
/* offsets must be 8 byte aligned */
1041-
clen = (clen + 7) & ~0x7;
1042-
offset = clen + sizeof(struct smb2_neg_context);
1043-
len_of_ctxts -= clen + sizeof(struct smb2_neg_context);
1041+
offset = (ctxt_len + 7) & ~0x7;
1042+
len_of_ctxts -= offset;
10441043
}
10451044
return status;
10461045
}

fs/smb/server/smb_common.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
158158
*/
159159
bool ksmbd_smb_request(struct ksmbd_conn *conn)
160160
{
161-
return conn->request_buf[0] == 0;
161+
__le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf);
162+
163+
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
164+
pr_err_ratelimited("smb2 compression not support yet");
165+
return false;
166+
}
167+
168+
if (*proto != SMB1_PROTO_NUMBER &&
169+
*proto != SMB2_PROTO_NUMBER &&
170+
*proto != SMB2_TRANSFORM_PROTO_NUM)
171+
return false;
172+
173+
return true;
162174
}
163175

164176
static bool supported_protocol(int idx)

fs/smb/server/smbacl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
12901290

12911291
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
12921292
posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
1293-
if (posix_acls && !found) {
1293+
if (!IS_ERR_OR_NULL(posix_acls) && !found) {
12941294
unsigned int id = -1;
12951295

12961296
pa_entry = posix_acls->a_entries;
@@ -1314,7 +1314,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
13141314
}
13151315
}
13161316
}
1317-
if (posix_acls)
1317+
if (!IS_ERR_OR_NULL(posix_acls))
13181318
posix_acl_release(posix_acls);
13191319
}
13201320

fs/smb/server/vfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id
13211321
return NULL;
13221322

13231323
posix_acls = get_inode_acl(inode, acl_type);
1324-
if (!posix_acls)
1324+
if (IS_ERR_OR_NULL(posix_acls))
13251325
return NULL;
13261326

13271327
smb_acl = kzalloc(sizeof(struct xattr_smb_acl) +
@@ -1830,7 +1830,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
18301830
return -EOPNOTSUPP;
18311831

18321832
acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
1833-
if (!acls)
1833+
if (IS_ERR_OR_NULL(acls))
18341834
return -ENOENT;
18351835
pace = acls->a_entries;
18361836

0 commit comments

Comments
 (0)