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()
Unified · Split
| @@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn) · 293 unmodified lines | ||
| 294 | 294 | return true; |
| 295 | 295 | } |
| 296 | 296 | |
| 297 | +#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr)) | |
| 298 | +#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4) | |
| 299 | + | |
| 297 | 300 | /** |
| 298 | 301 | * ksmbd_conn_handler_loop() - session thread to listen on new smb requests |
| 299 | 302 | * @p: connection instance |
| @@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p) · 50 unmodified lines | ||
| 350 | 353 | if (pdu_size > MAX_STREAM_PROT_LEN) |
| 351 | 354 | break; |
| 352 | 355 | |
| 356 | + if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE) | |
| 357 | + break; | |
| 358 | + | |
| 353 | 359 | /* 4 for rfc1002 length field */ |
| 354 | 360 | /* 1 for implied bcc[0] */ |
| 355 | 361 | size = pdu_size + 4 + 1; |
| @@ -358,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p) · 2 unmodified lines | ||
| 358 | 364 | break; |
| 359 | 365 | |
| 360 | 366 | memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); |
| 361 | − if (!ksmbd_smb_request(conn)) | |
| 362 | − break; | |
| 363 | 367 | |
| 364 | 368 | /* |
| 365 | 369 | * We already read 4 bytes to find out PDU size, now |
| @@ -377,6 +381,15 @@ int ksmbd_conn_handler_loop(void *p) · 11 unmodified lines | ||
| 377 | 381 | continue; |
| 378 | 382 | } |
| 379 | 383 | |
| 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 | + | |
| 380 | 393 | if (!default_conn_ops.process_fn) { |
| 381 | 394 | pr_err("No connection request callback\n"); |
| 382 | 395 | break; |
| @@ -1415,56 +1415,38 @@ void create_lease_buf(u8 *rbuf, struct lease *lease) · 1414 unmodified lines | ||
| 1415 | 1415 | */ |
| 1416 | 1416 | struct lease_ctx_info *parse_lease_state(void *open_req) |
| 1417 | 1417 | { |
| 1418 | − char *data_offset; | |
| 1419 | 1418 | struct create_context *cc; |
| 1420 | − unsigned int next = 0; | |
| 1421 | − char *name; | |
| 1422 | − bool found = false; | |
| 1423 | 1419 | 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); | |
| 1426 | 1427 | if (!lreq) |
| 1427 | 1428 | return NULL; |
| 1428 | 1429 | |
| 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; | |
| 1442 | 1432 | |
| 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; | |
| 1456 | 1442 | |
| 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; | |
| 1464 | 1448 | } |
| 1465 | − | |
| 1466 | − kfree(lreq); | |
| 1467 | − return NULL; | |
| 1449 | + return lreq; | |
| 1468 | 1450 | } |
| 1469 | 1451 | |
| 1470 | 1452 | /** |
| @@ -963,13 +963,13 @@ static void decode_sign_cap_ctxt(struct ksmbd_conn *conn, · 962 unmodified lines | ||
| 963 | 963 | |
| 964 | 964 | static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, |
| 965 | 965 | struct smb2_negotiate_req *req, |
| 966 | − int len_of_smb) | |
| 966 | + unsigned int len_of_smb) | |
| 967 | 967 | { |
| 968 | 968 | /* +4 is to account for the RFC1001 len field */ |
| 969 | 969 | struct smb2_neg_context *pctx = (struct smb2_neg_context *)req; |
| 970 | 970 | 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); | |
| 973 | 973 | __le32 status = STATUS_INVALID_PARAMETER; |
| 974 | 974 | |
| 975 | 975 | ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); |
| @@ -983,7 +983,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, · 7 unmodified lines | ||
| 983 | 983 | while (i++ < neg_ctxt_cnt) { |
| 984 | 984 | int clen, ctxt_len; |
| 985 | 985 | |
| 986 | − if (len_of_ctxts < sizeof(struct smb2_neg_context)) | |
| 986 | + if (len_of_ctxts < (int)sizeof(struct smb2_neg_context)) | |
| 987 | 987 | break; |
| 988 | 988 | |
| 989 | 989 | pctx = (struct smb2_neg_context *)((char *)pctx + offset); |
| @@ -1038,9 +1038,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, · 48 unmodified lines | ||
| 1038 | 1038 | } |
| 1039 | 1039 | |
| 1040 | 1040 | /* 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; | |
| 1044 | 1043 | } |
| 1045 | 1044 | return status; |
| 1046 | 1045 | } |
| @@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work) · 157 unmodified lines | ||
| 158 | 158 | */ |
| 159 | 159 | bool ksmbd_smb_request(struct ksmbd_conn *conn) |
| 160 | 160 | { |
| 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; | |
| 162 | 174 | } |
| 163 | 175 | |
| 164 | 176 | static bool supported_protocol(int idx) |
| @@ -1290,7 +1290,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, · 1289 unmodified lines | ||
| 1290 | 1290 | |
| 1291 | 1291 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { |
| 1292 | 1292 | 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) { | |
| 1294 | 1294 | unsigned int id = -1; |
| 1295 | 1295 | |
| 1296 | 1296 | pa_entry = posix_acls->a_entries; |
| @@ -1314,7 +1314,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, · 17 unmodified lines | ||
| 1314 | 1314 | } |
| 1315 | 1315 | } |
| 1316 | 1316 | } |
| 1317 | − if (posix_acls) | |
| 1317 | + if (!IS_ERR_OR_NULL(posix_acls)) | |
| 1318 | 1318 | posix_acl_release(posix_acls); |
| 1319 | 1319 | } |
| 1320 | 1320 | |
| @@ -1321,7 +1321,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id · 1320 unmodified lines | ||
| 1321 | 1321 | return NULL; |
| 1322 | 1322 | |
| 1323 | 1323 | posix_acls = get_inode_acl(inode, acl_type); |
| 1324 | − if (!posix_acls) | |
| 1324 | + if (IS_ERR_OR_NULL(posix_acls)) | |
| 1325 | 1325 | return NULL; |
| 1326 | 1326 | |
| 1327 | 1327 | smb_acl = kzalloc(sizeof(struct xattr_smb_acl) + |
| @@ -1830,7 +1830,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap, · 502 unmodified lines | ||
| 1830 | 1830 | return -EOPNOTSUPP; |
| 1831 | 1831 | |
| 1832 | 1832 | acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT); |
| 1833 | − if (!acls) | |
| 1833 | + if (IS_ERR_OR_NULL(acls)) | |
| 1834 | 1834 | return -ENOENT; |
| 1835 | 1835 | pace = acls->a_entries; |
| 1836 | 1836 | |