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()

Changed files
+62 -56
fs
+15 -2
fs/smb/server/connection.c
··· 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 ··· 353 350 if (pdu_size > MAX_STREAM_PROT_LEN) 354 351 break; 355 352 353 + if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE) 354 + break; 355 + 356 356 /* 4 for rfc1002 length field */ 357 357 /* 1 for implied bcc[0] */ 358 358 size = pdu_size + 4 + 1; ··· 364 358 break; 365 359 366 360 memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf)); 367 - if (!ksmbd_smb_request(conn)) 368 - break; 369 361 370 362 /* 371 363 * We already read 4 bytes to find out PDU size, now ··· 379 375 pr_err("PDU error. Read: %d, Expected: %d\n", 380 376 size, pdu_size); 381 377 continue; 378 + } 379 + 380 + if (!ksmbd_smb_request(conn)) 381 + break; 382 + 383 + if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId == 384 + SMB2_PROTO_NUMBER) { 385 + if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE) 386 + break; 382 387 } 383 388 384 389 if (!default_conn_ops.process_fn) {
+24 -42
fs/smb/server/oplock.c
··· 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; 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; 1446 1442 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; 1456 - 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 /**
+6 -7
fs/smb/server/smb2pdu.c
··· 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 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 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 }
+13 -1
fs/smb/server/smb_common.c
··· 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)
+2 -2
fs/smb/server/smbacl.c
··· 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 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
+2 -2
fs/smb/server/vfs.c
··· 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 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