Merge tag '5.15-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull ksmbd fixes from Steve French:
"Ten fixes for the ksmbd kernel server, for improved security and
additional buffer overflow checks:

- a security improvement to session establishment to reduce the
possibility of dictionary attacks

- fix to ensure that maximum i/o size negotiated in the protocol is
not less than 64K and not more than 8MB to better match expected
behavior

- fix for crediting (flow control) important to properly verify that
sufficient credits are available for the requested operation

- seven additional buffer overflow, buffer validation checks"

* tag '5.15-rc6-ksmbd-fixes' of git://git.samba.org/ksmbd:
ksmbd: add buffer validation in session setup
ksmbd: throttle session setup failures to avoid dictionary attacks
ksmbd: validate OutputBufferLength of QUERY_DIR, QUERY_INFO, IOCTL requests
ksmbd: validate credit charge after validating SMB2 PDU body size
ksmbd: add buffer validation for smb direct
ksmbd: limit read/write/trans buffer size not to exceed 8MB
ksmbd: validate compound response buffer
ksmbd: fix potencial 32bit overflow from data area check in smb2_write
ksmbd: improve credits management
ksmbd: add validation in smb2_ioctl

+309 -156
+9 -7
fs/ksmbd/auth.c
··· 298 298 int blob_len, struct ksmbd_session *sess) 299 299 { 300 300 char *domain_name; 301 - unsigned int lm_off, nt_off; 302 - unsigned short nt_len; 301 + unsigned int nt_off, dn_off; 302 + unsigned short nt_len, dn_len; 303 303 int ret; 304 304 305 305 if (blob_len < sizeof(struct authenticate_message)) { ··· 314 314 return -EINVAL; 315 315 } 316 316 317 - lm_off = le32_to_cpu(authblob->LmChallengeResponse.BufferOffset); 318 317 nt_off = le32_to_cpu(authblob->NtChallengeResponse.BufferOffset); 319 318 nt_len = le16_to_cpu(authblob->NtChallengeResponse.Length); 319 + dn_off = le32_to_cpu(authblob->DomainName.BufferOffset); 320 + dn_len = le16_to_cpu(authblob->DomainName.Length); 321 + 322 + if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len) 323 + return -EINVAL; 320 324 321 325 /* TODO : use domain name that imported from configuration file */ 322 - domain_name = smb_strndup_from_utf16((const char *)authblob + 323 - le32_to_cpu(authblob->DomainName.BufferOffset), 324 - le16_to_cpu(authblob->DomainName.Length), true, 325 - sess->conn->local_nls); 326 + domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off, 327 + dn_len, true, sess->conn->local_nls); 326 328 if (IS_ERR(domain_name)) 327 329 return PTR_ERR(domain_name); 328 330
+2
fs/ksmbd/connection.c
··· 61 61 conn->local_nls = load_nls_default(); 62 62 atomic_set(&conn->req_running, 0); 63 63 atomic_set(&conn->r_count, 0); 64 + conn->total_credits = 1; 65 + 64 66 init_waitqueue_head(&conn->req_running_q); 65 67 INIT_LIST_HEAD(&conn->conns_list); 66 68 INIT_LIST_HEAD(&conn->sessions);
+2
fs/ksmbd/ksmbd_netlink.h
··· 211 211 */ 212 212 struct ksmbd_logout_request { 213 213 __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ 214 + __u32 account_flags; 214 215 }; 215 216 216 217 /* ··· 318 317 #define KSMBD_USER_FLAG_BAD_UID BIT(2) 319 318 #define KSMBD_USER_FLAG_BAD_USER BIT(3) 320 319 #define KSMBD_USER_FLAG_GUEST_ACCOUNT BIT(4) 320 + #define KSMBD_USER_FLAG_DELAY_SESSION BIT(5) 321 321 322 322 /* 323 323 * Share config flags.
+1 -1
fs/ksmbd/mgmt/user_config.c
··· 55 55 56 56 void ksmbd_free_user(struct ksmbd_user *user) 57 57 { 58 - ksmbd_ipc_logout_request(user->name); 58 + ksmbd_ipc_logout_request(user->name, user->flags); 59 59 kfree(user->name); 60 60 kfree(user->passkey); 61 61 kfree(user);
+1
fs/ksmbd/mgmt/user_config.h
··· 18 18 19 19 size_t passkey_sz; 20 20 char *passkey; 21 + unsigned int failed_login_count; 21 22 }; 22 23 23 24 static inline bool user_guest(struct ksmbd_user *user)
+37 -18
fs/ksmbd/smb2misc.c
··· 284 284 le32_to_cpu(h->MaxOutputResponse); 285 285 } 286 286 287 - static int smb2_validate_credit_charge(struct smb2_hdr *hdr) 287 + static int smb2_validate_credit_charge(struct ksmbd_conn *conn, 288 + struct smb2_hdr *hdr) 288 289 { 289 - int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len; 290 - int credit_charge = le16_to_cpu(hdr->CreditCharge); 290 + unsigned int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len; 291 + unsigned short credit_charge = le16_to_cpu(hdr->CreditCharge); 291 292 void *__hdr = hdr; 293 + int ret; 292 294 293 295 switch (hdr->Command) { 294 296 case SMB2_QUERY_INFO: ··· 312 310 req_len = smb2_ioctl_req_len(__hdr); 313 311 expect_resp_len = smb2_ioctl_resp_len(__hdr); 314 312 break; 315 - default: 313 + case SMB2_CANCEL: 316 314 return 0; 315 + default: 316 + req_len = 1; 317 + break; 317 318 } 318 319 319 - credit_charge = max(1, credit_charge); 320 - max_len = max(req_len, expect_resp_len); 320 + credit_charge = max_t(unsigned short, credit_charge, 1); 321 + max_len = max_t(unsigned int, req_len, expect_resp_len); 321 322 calc_credit_num = DIV_ROUND_UP(max_len, SMB2_MAX_BUFFER_SIZE); 322 323 323 324 if (credit_charge < calc_credit_num) { 324 - pr_err("Insufficient credit charge, given: %d, needed: %d\n", 325 - credit_charge, calc_credit_num); 325 + ksmbd_debug(SMB, "Insufficient credit charge, given: %d, needed: %d\n", 326 + credit_charge, calc_credit_num); 327 + return 1; 328 + } else if (credit_charge > conn->max_credits) { 329 + ksmbd_debug(SMB, "Too large credit charge: %d\n", credit_charge); 326 330 return 1; 327 331 } 328 332 329 - return 0; 333 + spin_lock(&conn->credits_lock); 334 + if (credit_charge <= conn->total_credits) { 335 + conn->total_credits -= credit_charge; 336 + ret = 0; 337 + } else { 338 + ksmbd_debug(SMB, "Insufficient credits granted, given: %u, granted: %u\n", 339 + credit_charge, conn->total_credits); 340 + ret = 1; 341 + } 342 + spin_unlock(&conn->credits_lock); 343 + return ret; 330 344 } 331 345 332 346 int ksmbd_smb2_check_message(struct ksmbd_work *work) ··· 400 382 } 401 383 } 402 384 403 - if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && 404 - smb2_validate_credit_charge(hdr)) { 405 - work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); 406 - return 1; 407 - } 408 - 409 385 if (smb2_calc_size(hdr, &clc_len)) 410 386 return 1; 411 387 412 388 if (len != clc_len) { 413 389 /* client can return one byte more due to implied bcc[0] */ 414 390 if (clc_len == len + 1) 415 - return 0; 391 + goto validate_credit; 416 392 417 393 /* 418 394 * Some windows servers (win2016) will pad also the final 419 395 * PDU in a compound to 8 bytes. 420 396 */ 421 397 if (ALIGN(clc_len, 8) == len) 422 - return 0; 398 + goto validate_credit; 423 399 424 400 /* 425 401 * windows client also pad up to 8 bytes when compounding. ··· 426 414 "cli req padded more than expected. Length %d not %d for cmd:%d mid:%llu\n", 427 415 len, clc_len, command, 428 416 le64_to_cpu(hdr->MessageId)); 429 - return 0; 417 + goto validate_credit; 430 418 } 431 419 432 420 ksmbd_debug(SMB, ··· 434 422 len, clc_len, command, 435 423 le64_to_cpu(hdr->MessageId)); 436 424 425 + return 1; 426 + } 427 + 428 + validate_credit: 429 + if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && 430 + smb2_validate_credit_charge(work->conn, hdr)) { 431 + work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); 437 432 return 1; 438 433 } 439 434
+3
fs/ksmbd/smb2ops.c
··· 284 284 285 285 void init_smb2_max_read_size(unsigned int sz) 286 286 { 287 + sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); 287 288 smb21_server_values.max_read_size = sz; 288 289 smb30_server_values.max_read_size = sz; 289 290 smb302_server_values.max_read_size = sz; ··· 293 292 294 293 void init_smb2_max_write_size(unsigned int sz) 295 294 { 295 + sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); 296 296 smb21_server_values.max_write_size = sz; 297 297 smb30_server_values.max_write_size = sz; 298 298 smb302_server_values.max_write_size = sz; ··· 302 300 303 301 void init_smb2_max_trans_size(unsigned int sz) 304 302 { 303 + sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); 305 304 smb21_server_values.max_trans_size = sz; 306 305 smb30_server_values.max_trans_size = sz; 307 306 smb302_server_values.max_trans_size = sz;
+228 -124
fs/ksmbd/smb2pdu.c
··· 292 292 return 0; 293 293 } 294 294 295 - static int smb2_consume_credit_charge(struct ksmbd_work *work, 296 - unsigned short credit_charge) 297 - { 298 - struct ksmbd_conn *conn = work->conn; 299 - unsigned int rsp_credits = 1; 300 - 301 - if (!conn->total_credits) 302 - return 0; 303 - 304 - if (credit_charge > 0) 305 - rsp_credits = credit_charge; 306 - 307 - conn->total_credits -= rsp_credits; 308 - return rsp_credits; 309 - } 310 - 311 295 /** 312 296 * smb2_set_rsp_credits() - set number of credits in response buffer 313 297 * @work: smb work containing smb response buffer ··· 301 317 struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); 302 318 struct smb2_hdr *hdr = ksmbd_resp_buf_next(work); 303 319 struct ksmbd_conn *conn = work->conn; 304 - unsigned short credits_requested = le16_to_cpu(req_hdr->CreditRequest); 305 - unsigned short credit_charge = 1, credits_granted = 0; 306 - unsigned short aux_max, aux_credits, min_credits; 307 - int rsp_credit_charge; 320 + unsigned short credits_requested; 321 + unsigned short credit_charge, credits_granted = 0; 322 + unsigned short aux_max, aux_credits; 308 323 309 - if (hdr->Command == SMB2_CANCEL) 310 - goto out; 324 + if (work->send_no_response) 325 + return 0; 311 326 312 - /* get default minimum credits by shifting maximum credits by 4 */ 313 - min_credits = conn->max_credits >> 4; 327 + hdr->CreditCharge = req_hdr->CreditCharge; 314 328 315 - if (conn->total_credits >= conn->max_credits) { 329 + if (conn->total_credits > conn->max_credits) { 330 + hdr->CreditRequest = 0; 316 331 pr_err("Total credits overflow: %d\n", conn->total_credits); 317 - conn->total_credits = min_credits; 318 - } 319 - 320 - rsp_credit_charge = 321 - smb2_consume_credit_charge(work, le16_to_cpu(req_hdr->CreditCharge)); 322 - if (rsp_credit_charge < 0) 323 332 return -EINVAL; 324 - 325 - hdr->CreditCharge = cpu_to_le16(rsp_credit_charge); 326 - 327 - if (credits_requested > 0) { 328 - aux_credits = credits_requested - 1; 329 - aux_max = 32; 330 - if (hdr->Command == SMB2_NEGOTIATE) 331 - aux_max = 0; 332 - aux_credits = (aux_credits < aux_max) ? aux_credits : aux_max; 333 - credits_granted = aux_credits + credit_charge; 334 - 335 - /* if credits granted per client is getting bigger than default 336 - * minimum credits then we should wrap it up within the limits. 337 - */ 338 - if ((conn->total_credits + credits_granted) > min_credits) 339 - credits_granted = min_credits - conn->total_credits; 340 - /* 341 - * TODO: Need to adjuct CreditRequest value according to 342 - * current cpu load 343 - */ 344 - } else if (conn->total_credits == 0) { 345 - credits_granted = 1; 346 333 } 334 + 335 + credit_charge = max_t(unsigned short, 336 + le16_to_cpu(req_hdr->CreditCharge), 1); 337 + credits_requested = max_t(unsigned short, 338 + le16_to_cpu(req_hdr->CreditRequest), 1); 339 + 340 + /* according to smb2.credits smbtorture, Windows server 341 + * 2016 or later grant up to 8192 credits at once. 342 + * 343 + * TODO: Need to adjuct CreditRequest value according to 344 + * current cpu load 345 + */ 346 + aux_credits = credits_requested - 1; 347 + if (hdr->Command == SMB2_NEGOTIATE) 348 + aux_max = 0; 349 + else 350 + aux_max = conn->max_credits - credit_charge; 351 + aux_credits = min_t(unsigned short, aux_credits, aux_max); 352 + credits_granted = credit_charge + aux_credits; 353 + 354 + if (conn->max_credits - conn->total_credits < credits_granted) 355 + credits_granted = conn->max_credits - 356 + conn->total_credits; 347 357 348 358 conn->total_credits += credits_granted; 349 359 work->credits_granted += credits_granted; ··· 346 368 /* Update CreditRequest in last request */ 347 369 hdr->CreditRequest = cpu_to_le16(work->credits_granted); 348 370 } 349 - out: 350 371 ksmbd_debug(SMB, 351 372 "credits: requested[%d] granted[%d] total_granted[%d]\n", 352 373 credits_requested, credits_granted, ··· 449 472 return false; 450 473 } 451 474 475 + if ((u64)get_rfc1002_len(work->response_buf) + MAX_CIFS_SMALL_BUFFER_SIZE > 476 + work->response_sz) { 477 + pr_err("next response offset exceeds response buffer size\n"); 478 + return false; 479 + } 480 + 452 481 ksmbd_debug(SMB, "got SMB2 chained command\n"); 453 482 init_chained_smb2_rsp(work); 454 483 return true; ··· 524 541 { 525 542 struct smb2_hdr *hdr = work->request_buf; 526 543 size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE; 527 - size_t large_sz = work->conn->vals->max_trans_size + MAX_SMB2_HDR_SIZE; 544 + size_t large_sz = small_sz + work->conn->vals->max_trans_size; 528 545 size_t sz = small_sz; 529 546 int cmd = le16_to_cpu(hdr->Command); 530 547 ··· 1257 1274 return 0; 1258 1275 } 1259 1276 1260 - static int decode_negotiation_token(struct ksmbd_work *work, 1261 - struct negotiate_message *negblob) 1277 + static int decode_negotiation_token(struct ksmbd_conn *conn, 1278 + struct negotiate_message *negblob, 1279 + size_t sz) 1262 1280 { 1263 - struct ksmbd_conn *conn = work->conn; 1264 - struct smb2_sess_setup_req *req; 1265 - int sz; 1266 - 1267 1281 if (!conn->use_spnego) 1268 1282 return -EINVAL; 1269 - 1270 - req = work->request_buf; 1271 - sz = le16_to_cpu(req->SecurityBufferLength); 1272 1283 1273 1284 if (ksmbd_decode_negTokenInit((char *)negblob, sz, conn)) { 1274 1285 if (ksmbd_decode_negTokenTarg((char *)negblob, sz, conn)) { ··· 1275 1298 } 1276 1299 1277 1300 static int ntlm_negotiate(struct ksmbd_work *work, 1278 - struct negotiate_message *negblob) 1301 + struct negotiate_message *negblob, 1302 + size_t negblob_len) 1279 1303 { 1280 - struct smb2_sess_setup_req *req = work->request_buf; 1281 1304 struct smb2_sess_setup_rsp *rsp = work->response_buf; 1282 1305 struct challenge_message *chgblob; 1283 1306 unsigned char *spnego_blob = NULL; ··· 1286 1309 int sz, rc; 1287 1310 1288 1311 ksmbd_debug(SMB, "negotiate phase\n"); 1289 - sz = le16_to_cpu(req->SecurityBufferLength); 1290 - rc = ksmbd_decode_ntlmssp_neg_blob(negblob, sz, work->sess); 1312 + rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->sess); 1291 1313 if (rc) 1292 1314 return rc; 1293 1315 ··· 1354 1378 struct authenticate_message *authblob; 1355 1379 struct ksmbd_user *user; 1356 1380 char *name; 1357 - int sz; 1381 + unsigned int auth_msg_len, name_off, name_len, secbuf_len; 1358 1382 1383 + secbuf_len = le16_to_cpu(req->SecurityBufferLength); 1384 + if (secbuf_len < sizeof(struct authenticate_message)) { 1385 + ksmbd_debug(SMB, "blob len %d too small\n", secbuf_len); 1386 + return NULL; 1387 + } 1359 1388 authblob = user_authblob(conn, req); 1360 - sz = le32_to_cpu(authblob->UserName.BufferOffset); 1361 - name = smb_strndup_from_utf16((const char *)authblob + sz, 1362 - le16_to_cpu(authblob->UserName.Length), 1389 + name_off = le32_to_cpu(authblob->UserName.BufferOffset); 1390 + name_len = le16_to_cpu(authblob->UserName.Length); 1391 + auth_msg_len = le16_to_cpu(req->SecurityBufferOffset) + secbuf_len; 1392 + 1393 + if (auth_msg_len < (u64)name_off + name_len) 1394 + return NULL; 1395 + 1396 + name = smb_strndup_from_utf16((const char *)authblob + name_off, 1397 + name_len, 1363 1398 true, 1364 1399 conn->local_nls); 1365 1400 if (IS_ERR(name)) { ··· 1616 1629 struct smb2_sess_setup_rsp *rsp = work->response_buf; 1617 1630 struct ksmbd_session *sess; 1618 1631 struct negotiate_message *negblob; 1632 + unsigned int negblob_len, negblob_off; 1619 1633 int rc = 0; 1620 1634 1621 1635 ksmbd_debug(SMB, "Received request for session setup\n"); ··· 1697 1709 if (sess->state == SMB2_SESSION_EXPIRED) 1698 1710 sess->state = SMB2_SESSION_IN_PROGRESS; 1699 1711 1700 - negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId + 1701 - le16_to_cpu(req->SecurityBufferOffset)); 1712 + negblob_off = le16_to_cpu(req->SecurityBufferOffset); 1713 + negblob_len = le16_to_cpu(req->SecurityBufferLength); 1714 + if (negblob_off < (offsetof(struct smb2_sess_setup_req, Buffer) - 4) || 1715 + negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) 1716 + return -EINVAL; 1702 1717 1703 - if (decode_negotiation_token(work, negblob) == 0) { 1718 + negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId + 1719 + negblob_off); 1720 + 1721 + if (decode_negotiation_token(conn, negblob, negblob_len) == 0) { 1704 1722 if (conn->mechToken) 1705 1723 negblob = (struct negotiate_message *)conn->mechToken; 1706 1724 } ··· 1730 1736 sess->Preauth_HashValue = NULL; 1731 1737 } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { 1732 1738 if (negblob->MessageType == NtLmNegotiate) { 1733 - rc = ntlm_negotiate(work, negblob); 1739 + rc = ntlm_negotiate(work, negblob, negblob_len); 1734 1740 if (rc) 1735 1741 goto out_err; 1736 1742 rsp->hdr.Status = ··· 1790 1796 conn->mechToken = NULL; 1791 1797 } 1792 1798 1793 - if (rc < 0 && sess) { 1794 - ksmbd_session_destroy(sess); 1795 - work->sess = NULL; 1799 + if (rc < 0) { 1800 + /* 1801 + * SecurityBufferOffset should be set to zero 1802 + * in session setup error response. 1803 + */ 1804 + rsp->SecurityBufferOffset = 0; 1805 + 1806 + if (sess) { 1807 + bool try_delay = false; 1808 + 1809 + /* 1810 + * To avoid dictionary attacks (repeated session setups rapidly sent) to 1811 + * connect to server, ksmbd make a delay of a 5 seconds on session setup 1812 + * failure to make it harder to send enough random connection requests 1813 + * to break into a server. 1814 + */ 1815 + if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) 1816 + try_delay = true; 1817 + 1818 + ksmbd_session_destroy(sess); 1819 + work->sess = NULL; 1820 + if (try_delay) 1821 + ssleep(5); 1822 + } 1796 1823 } 1797 1824 1798 1825 return rc; ··· 3794 3779 return 0; 3795 3780 } 3796 3781 3782 + static int smb2_calc_max_out_buf_len(struct ksmbd_work *work, 3783 + unsigned short hdr2_len, 3784 + unsigned int out_buf_len) 3785 + { 3786 + int free_len; 3787 + 3788 + if (out_buf_len > work->conn->vals->max_trans_size) 3789 + return -EINVAL; 3790 + 3791 + free_len = (int)(work->response_sz - 3792 + (get_rfc1002_len(work->response_buf) + 4)) - 3793 + hdr2_len; 3794 + if (free_len < 0) 3795 + return -EINVAL; 3796 + 3797 + return min_t(int, out_buf_len, free_len); 3798 + } 3799 + 3797 3800 int smb2_query_dir(struct ksmbd_work *work) 3798 3801 { 3799 3802 struct ksmbd_conn *conn = work->conn; ··· 3888 3855 memset(&d_info, 0, sizeof(struct ksmbd_dir_info)); 3889 3856 d_info.wptr = (char *)rsp->Buffer; 3890 3857 d_info.rptr = (char *)rsp->Buffer; 3891 - d_info.out_buf_len = (work->response_sz - (get_rfc1002_len(rsp_org) + 4)); 3892 - d_info.out_buf_len = min_t(int, d_info.out_buf_len, le32_to_cpu(req->OutputBufferLength)) - 3893 - sizeof(struct smb2_query_directory_rsp); 3858 + d_info.out_buf_len = 3859 + smb2_calc_max_out_buf_len(work, 8, 3860 + le32_to_cpu(req->OutputBufferLength)); 3861 + if (d_info.out_buf_len < 0) { 3862 + rc = -EINVAL; 3863 + goto err_out; 3864 + } 3894 3865 d_info.flags = srch_flag; 3895 3866 3896 3867 /* ··· 4128 4091 le32_to_cpu(req->Flags)); 4129 4092 } 4130 4093 4131 - buf_free_len = work->response_sz - 4132 - (get_rfc1002_len(rsp_org) + 4) - 4133 - sizeof(struct smb2_query_info_rsp); 4134 - 4135 - if (le32_to_cpu(req->OutputBufferLength) < buf_free_len) 4136 - buf_free_len = le32_to_cpu(req->OutputBufferLength); 4094 + buf_free_len = 4095 + smb2_calc_max_out_buf_len(work, 8, 4096 + le32_to_cpu(req->OutputBufferLength)); 4097 + if (buf_free_len < 0) 4098 + return -EINVAL; 4137 4099 4138 4100 rc = ksmbd_vfs_listxattr(path->dentry, &xattr_list); 4139 4101 if (rc < 0) { ··· 4443 4407 struct path *path = &fp->filp->f_path; 4444 4408 ssize_t xattr_list_len; 4445 4409 int nbytes = 0, streamlen, stream_name_len, next, idx = 0; 4410 + int buf_free_len; 4411 + struct smb2_query_info_req *req = ksmbd_req_buf_next(work); 4446 4412 4447 4413 generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), 4448 4414 &stat); ··· 4457 4419 ksmbd_debug(SMB, "empty xattr in the file\n"); 4458 4420 goto out; 4459 4421 } 4422 + 4423 + buf_free_len = 4424 + smb2_calc_max_out_buf_len(work, 8, 4425 + le32_to_cpu(req->OutputBufferLength)); 4426 + if (buf_free_len < 0) 4427 + goto out; 4460 4428 4461 4429 while (idx < xattr_list_len) { 4462 4430 stream_name = xattr_list + idx; ··· 4488 4444 streamlen = snprintf(stream_buf, streamlen + 1, 4489 4445 ":%s", &stream_name[XATTR_NAME_STREAM_LEN]); 4490 4446 4447 + next = sizeof(struct smb2_file_stream_info) + streamlen * 2; 4448 + if (next > buf_free_len) 4449 + break; 4450 + 4491 4451 file_info = (struct smb2_file_stream_info *)&rsp->Buffer[nbytes]; 4492 4452 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName, 4493 4453 stream_buf, streamlen, ··· 4502 4454 file_info->StreamSize = cpu_to_le64(stream_name_len); 4503 4455 file_info->StreamAllocationSize = cpu_to_le64(stream_name_len); 4504 4456 4505 - next = sizeof(struct smb2_file_stream_info) + streamlen; 4506 4457 nbytes += next; 4458 + buf_free_len -= next; 4507 4459 file_info->NextEntryOffset = cpu_to_le32(next); 4508 4460 } 4509 4461 4510 - if (!S_ISDIR(stat.mode)) { 4462 + if (!S_ISDIR(stat.mode) && 4463 + buf_free_len >= sizeof(struct smb2_file_stream_info) + 7 * 2) { 4511 4464 file_info = (struct smb2_file_stream_info *) 4512 4465 &rsp->Buffer[nbytes]; 4513 4466 streamlen = smbConvertToUTF16((__le16 *)file_info->StreamName, ··· 6269 6220 (offsetof(struct smb2_write_req, Buffer) - 4)) { 6270 6221 data_buf = (char *)&req->Buffer[0]; 6271 6222 } else { 6272 - if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) || 6273 - (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) { 6223 + if ((u64)le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req)) { 6274 6224 pr_err("invalid write data offset %u, smb_len %u\n", 6275 6225 le16_to_cpu(req->DataOffset), 6276 6226 get_rfc1002_len(req)); ··· 6427 6379 (offsetof(struct smb2_write_req, Buffer) - 4)) { 6428 6380 data_buf = (char *)&req->Buffer[0]; 6429 6381 } else { 6430 - if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) || 6431 - (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) { 6382 + if ((u64)le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req)) { 6432 6383 pr_err("invalid write data offset %u, smb_len %u\n", 6433 6384 le16_to_cpu(req->DataOffset), 6434 6385 get_rfc1002_len(req)); ··· 7070 7023 return err; 7071 7024 } 7072 7025 7073 - static int fsctl_copychunk(struct ksmbd_work *work, struct smb2_ioctl_req *req, 7026 + static int fsctl_copychunk(struct ksmbd_work *work, 7027 + struct copychunk_ioctl_req *ci_req, 7028 + unsigned int cnt_code, 7029 + unsigned int input_count, 7030 + unsigned long long volatile_id, 7031 + unsigned long long persistent_id, 7074 7032 struct smb2_ioctl_rsp *rsp) 7075 7033 { 7076 - struct copychunk_ioctl_req *ci_req; 7077 7034 struct copychunk_ioctl_rsp *ci_rsp; 7078 7035 struct ksmbd_file *src_fp = NULL, *dst_fp = NULL; 7079 7036 struct srv_copychunk *chunks; 7080 7037 unsigned int i, chunk_count, chunk_count_written = 0; 7081 7038 unsigned int chunk_size_written = 0; 7082 7039 loff_t total_size_written = 0; 7083 - int ret, cnt_code; 7040 + int ret = 0; 7084 7041 7085 - cnt_code = le32_to_cpu(req->CntCode); 7086 - ci_req = (struct copychunk_ioctl_req *)&req->Buffer[0]; 7087 7042 ci_rsp = (struct copychunk_ioctl_rsp *)&rsp->Buffer[0]; 7088 7043 7089 - rsp->VolatileFileId = req->VolatileFileId; 7090 - rsp->PersistentFileId = req->PersistentFileId; 7044 + rsp->VolatileFileId = cpu_to_le64(volatile_id); 7045 + rsp->PersistentFileId = cpu_to_le64(persistent_id); 7091 7046 ci_rsp->ChunksWritten = 7092 7047 cpu_to_le32(ksmbd_server_side_copy_max_chunk_count()); 7093 7048 ci_rsp->ChunkBytesWritten = ··· 7099 7050 7100 7051 chunks = (struct srv_copychunk *)&ci_req->Chunks[0]; 7101 7052 chunk_count = le32_to_cpu(ci_req->ChunkCount); 7053 + if (chunk_count == 0) 7054 + goto out; 7102 7055 total_size_written = 0; 7103 7056 7104 7057 /* verify the SRV_COPYCHUNK_COPY packet */ 7105 7058 if (chunk_count > ksmbd_server_side_copy_max_chunk_count() || 7106 - le32_to_cpu(req->InputCount) < 7107 - offsetof(struct copychunk_ioctl_req, Chunks) + 7059 + input_count < offsetof(struct copychunk_ioctl_req, Chunks) + 7108 7060 chunk_count * sizeof(struct srv_copychunk)) { 7109 7061 rsp->hdr.Status = STATUS_INVALID_PARAMETER; 7110 7062 return -EINVAL; ··· 7126 7076 7127 7077 src_fp = ksmbd_lookup_foreign_fd(work, 7128 7078 le64_to_cpu(ci_req->ResumeKey[0])); 7129 - dst_fp = ksmbd_lookup_fd_slow(work, 7130 - le64_to_cpu(req->VolatileFileId), 7131 - le64_to_cpu(req->PersistentFileId)); 7079 + dst_fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id); 7132 7080 ret = -EINVAL; 7133 7081 if (!src_fp || 7134 7082 src_fp->persistent_id != le64_to_cpu(ci_req->ResumeKey[1])) { ··· 7201 7153 } 7202 7154 7203 7155 static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, 7204 - struct smb2_ioctl_req *req, 7205 - struct smb2_ioctl_rsp *rsp) 7156 + struct smb2_ioctl_rsp *rsp, 7157 + unsigned int out_buf_len) 7206 7158 { 7207 7159 struct network_interface_info_ioctl_rsp *nii_rsp = NULL; 7208 7160 int nbytes = 0; ··· 7214 7166 7215 7167 rtnl_lock(); 7216 7168 for_each_netdev(&init_net, netdev) { 7169 + if (out_buf_len < 7170 + nbytes + sizeof(struct network_interface_info_ioctl_rsp)) { 7171 + rtnl_unlock(); 7172 + return -ENOSPC; 7173 + } 7174 + 7217 7175 if (netdev->type == ARPHRD_LOOPBACK) 7218 7176 continue; 7219 7177 ··· 7299 7245 if (nii_rsp) 7300 7246 nii_rsp->Next = 0; 7301 7247 7302 - if (!nbytes) { 7303 - rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL; 7304 - return -EINVAL; 7305 - } 7306 - 7307 7248 rsp->PersistentFileId = cpu_to_le64(SMB2_NO_FID); 7308 7249 rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID); 7309 7250 return nbytes; ··· 7306 7257 7307 7258 static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn, 7308 7259 struct validate_negotiate_info_req *neg_req, 7309 - struct validate_negotiate_info_rsp *neg_rsp) 7260 + struct validate_negotiate_info_rsp *neg_rsp, 7261 + unsigned int in_buf_len) 7310 7262 { 7311 7263 int ret = 0; 7312 7264 int dialect; 7265 + 7266 + if (in_buf_len < sizeof(struct validate_negotiate_info_req) + 7267 + le16_to_cpu(neg_req->DialectCount) * sizeof(__le16)) 7268 + return -EINVAL; 7313 7269 7314 7270 dialect = ksmbd_lookup_dialect_by_id(neg_req->Dialects, 7315 7271 neg_req->DialectCount); ··· 7349 7295 static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id, 7350 7296 struct file_allocated_range_buffer *qar_req, 7351 7297 struct file_allocated_range_buffer *qar_rsp, 7352 - int in_count, int *out_count) 7298 + unsigned int in_count, unsigned int *out_count) 7353 7299 { 7354 7300 struct ksmbd_file *fp; 7355 7301 loff_t start, length; ··· 7376 7322 } 7377 7323 7378 7324 static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id, 7379 - int out_buf_len, struct smb2_ioctl_req *req, 7325 + unsigned int out_buf_len, 7326 + struct smb2_ioctl_req *req, 7380 7327 struct smb2_ioctl_rsp *rsp) 7381 7328 { 7382 7329 struct ksmbd_rpc_command *rpc_resp; ··· 7491 7436 { 7492 7437 struct smb2_ioctl_req *req; 7493 7438 struct smb2_ioctl_rsp *rsp, *rsp_org; 7494 - int cnt_code, nbytes = 0; 7495 - int out_buf_len; 7439 + unsigned int cnt_code, nbytes = 0, out_buf_len, in_buf_len; 7496 7440 u64 id = KSMBD_NO_FID; 7497 7441 struct ksmbd_conn *conn = work->conn; 7498 7442 int ret = 0; ··· 7519 7465 } 7520 7466 7521 7467 cnt_code = le32_to_cpu(req->CntCode); 7522 - out_buf_len = le32_to_cpu(req->MaxOutputResponse); 7523 - out_buf_len = min(KSMBD_IPC_MAX_PAYLOAD, out_buf_len); 7468 + ret = smb2_calc_max_out_buf_len(work, 48, 7469 + le32_to_cpu(req->MaxOutputResponse)); 7470 + if (ret < 0) { 7471 + rsp->hdr.Status = STATUS_INVALID_PARAMETER; 7472 + goto out; 7473 + } 7474 + out_buf_len = (unsigned int)ret; 7475 + in_buf_len = le32_to_cpu(req->InputCount); 7524 7476 7525 7477 switch (cnt_code) { 7526 7478 case FSCTL_DFS_GET_REFERRALS: ··· 7554 7494 break; 7555 7495 } 7556 7496 case FSCTL_PIPE_TRANSCEIVE: 7497 + out_buf_len = min_t(u32, KSMBD_IPC_MAX_PAYLOAD, out_buf_len); 7557 7498 nbytes = fsctl_pipe_transceive(work, id, out_buf_len, req, rsp); 7558 7499 break; 7559 7500 case FSCTL_VALIDATE_NEGOTIATE_INFO: ··· 7563 7502 goto out; 7564 7503 } 7565 7504 7505 + if (in_buf_len < sizeof(struct validate_negotiate_info_req)) 7506 + return -EINVAL; 7507 + 7508 + if (out_buf_len < sizeof(struct validate_negotiate_info_rsp)) 7509 + return -EINVAL; 7510 + 7566 7511 ret = fsctl_validate_negotiate_info(conn, 7567 7512 (struct validate_negotiate_info_req *)&req->Buffer[0], 7568 - (struct validate_negotiate_info_rsp *)&rsp->Buffer[0]); 7513 + (struct validate_negotiate_info_rsp *)&rsp->Buffer[0], 7514 + in_buf_len); 7569 7515 if (ret < 0) 7570 7516 goto out; 7571 7517 ··· 7581 7513 rsp->VolatileFileId = cpu_to_le64(SMB2_NO_FID); 7582 7514 break; 7583 7515 case FSCTL_QUERY_NETWORK_INTERFACE_INFO: 7584 - nbytes = fsctl_query_iface_info_ioctl(conn, req, rsp); 7585 - if (nbytes < 0) 7516 + ret = fsctl_query_iface_info_ioctl(conn, rsp, out_buf_len); 7517 + if (ret < 0) 7586 7518 goto out; 7519 + nbytes = ret; 7587 7520 break; 7588 7521 case FSCTL_REQUEST_RESUME_KEY: 7589 7522 if (out_buf_len < sizeof(struct resume_key_ioctl_rsp)) { ··· 7609 7540 goto out; 7610 7541 } 7611 7542 7543 + if (in_buf_len < sizeof(struct copychunk_ioctl_req)) { 7544 + ret = -EINVAL; 7545 + goto out; 7546 + } 7547 + 7612 7548 if (out_buf_len < sizeof(struct copychunk_ioctl_rsp)) { 7613 7549 ret = -EINVAL; 7614 7550 goto out; 7615 7551 } 7616 7552 7617 7553 nbytes = sizeof(struct copychunk_ioctl_rsp); 7618 - fsctl_copychunk(work, req, rsp); 7554 + rsp->VolatileFileId = req->VolatileFileId; 7555 + rsp->PersistentFileId = req->PersistentFileId; 7556 + fsctl_copychunk(work, 7557 + (struct copychunk_ioctl_req *)&req->Buffer[0], 7558 + le32_to_cpu(req->CntCode), 7559 + le32_to_cpu(req->InputCount), 7560 + le64_to_cpu(req->VolatileFileId), 7561 + le64_to_cpu(req->PersistentFileId), 7562 + rsp); 7619 7563 break; 7620 7564 case FSCTL_SET_SPARSE: 7565 + if (in_buf_len < sizeof(struct file_sparse)) { 7566 + ret = -EINVAL; 7567 + goto out; 7568 + } 7569 + 7621 7570 ret = fsctl_set_sparse(work, id, 7622 7571 (struct file_sparse *)&req->Buffer[0]); 7623 7572 if (ret < 0) ··· 7651 7564 ksmbd_debug(SMB, 7652 7565 "User does not have write permission\n"); 7653 7566 ret = -EACCES; 7567 + goto out; 7568 + } 7569 + 7570 + if (in_buf_len < sizeof(struct file_zero_data_information)) { 7571 + ret = -EINVAL; 7654 7572 goto out; 7655 7573 } 7656 7574 ··· 7678 7586 break; 7679 7587 } 7680 7588 case FSCTL_QUERY_ALLOCATED_RANGES: 7589 + if (in_buf_len < sizeof(struct file_allocated_range_buffer)) { 7590 + ret = -EINVAL; 7591 + goto out; 7592 + } 7593 + 7681 7594 ret = fsctl_query_allocated_ranges(work, id, 7682 7595 (struct file_allocated_range_buffer *)&req->Buffer[0], 7683 7596 (struct file_allocated_range_buffer *)&rsp->Buffer[0], ··· 7722 7625 struct ksmbd_file *fp_in, *fp_out = NULL; 7723 7626 struct duplicate_extents_to_file *dup_ext; 7724 7627 loff_t src_off, dst_off, length, cloned; 7628 + 7629 + if (in_buf_len < sizeof(struct duplicate_extents_to_file)) { 7630 + ret = -EINVAL; 7631 + goto out; 7632 + } 7725 7633 7726 7634 dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0]; 7727 7635 ··· 7798 7696 rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND; 7799 7697 else if (ret == -EOPNOTSUPP) 7800 7698 rsp->hdr.Status = STATUS_NOT_SUPPORTED; 7699 + else if (ret == -ENOSPC) 7700 + rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL; 7801 7701 else if (ret < 0 || rsp->hdr.Status == 0) 7802 7702 rsp->hdr.Status = STATUS_INVALID_PARAMETER; 7803 7703 smb2_set_err_rsp(work);
+2
fs/ksmbd/smb2pdu.h
··· 113 113 #define SMB21_DEFAULT_IOSIZE (1024 * 1024) 114 114 #define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024) 115 115 #define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024) 116 + #define SMB3_MIN_IOSIZE (64 * 1024) 117 + #define SMB3_MAX_IOSIZE (8 * 1024 * 1024) 116 118 117 119 /* 118 120 * SMB2 Header Definition
+2 -1
fs/ksmbd/transport_ipc.c
··· 601 601 return ret; 602 602 } 603 603 604 - int ksmbd_ipc_logout_request(const char *account) 604 + int ksmbd_ipc_logout_request(const char *account, int flags) 605 605 { 606 606 struct ksmbd_ipc_msg *msg; 607 607 struct ksmbd_logout_request *req; ··· 616 616 617 617 msg->type = KSMBD_EVENT_LOGOUT_REQUEST; 618 618 req = (struct ksmbd_logout_request *)msg->payload; 619 + req->account_flags = flags; 619 620 strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 620 621 621 622 ret = ipc_msg_send(msg);
+1 -1
fs/ksmbd/transport_ipc.h
··· 25 25 struct sockaddr *peer_addr); 26 26 int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, 27 27 unsigned long long connect_id); 28 - int ksmbd_ipc_logout_request(const char *account); 28 + int ksmbd_ipc_logout_request(const char *account, int flags); 29 29 struct ksmbd_share_config_response * 30 30 ksmbd_ipc_share_config_request(const char *name); 31 31 struct ksmbd_spnego_authen_response *
+19 -2
fs/ksmbd/transport_rdma.c
··· 549 549 550 550 switch (recvmsg->type) { 551 551 case SMB_DIRECT_MSG_NEGOTIATE_REQ: 552 + if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) { 553 + put_empty_recvmsg(t, recvmsg); 554 + return; 555 + } 552 556 t->negotiation_requested = true; 553 557 t->full_packet_received = true; 554 558 wake_up_interruptible(&t->wait_status); ··· 560 556 case SMB_DIRECT_MSG_DATA_TRANSFER: { 561 557 struct smb_direct_data_transfer *data_transfer = 562 558 (struct smb_direct_data_transfer *)recvmsg->packet; 563 - int data_length = le32_to_cpu(data_transfer->data_length); 559 + unsigned int data_length; 564 560 int avail_recvmsg_count, receive_credits; 565 561 562 + if (wc->byte_len < 563 + offsetof(struct smb_direct_data_transfer, padding)) { 564 + put_empty_recvmsg(t, recvmsg); 565 + return; 566 + } 567 + 568 + data_length = le32_to_cpu(data_transfer->data_length); 566 569 if (data_length) { 570 + if (wc->byte_len < sizeof(struct smb_direct_data_transfer) + 571 + (u64)data_length) { 572 + put_empty_recvmsg(t, recvmsg); 573 + return; 574 + } 575 + 567 576 if (t->full_packet_received) 568 577 recvmsg->first_segment = true; 569 578 ··· 585 568 else 586 569 t->full_packet_received = true; 587 570 588 - enqueue_reassembly(t, recvmsg, data_length); 571 + enqueue_reassembly(t, recvmsg, (int)data_length); 589 572 wake_up_interruptible(&t->wait_reassembly_queue); 590 573 591 574 spin_lock(&t->receive_credit_lock);
+1 -1
fs/ksmbd/vfs.c
··· 1023 1023 1024 1024 int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, 1025 1025 struct file_allocated_range_buffer *ranges, 1026 - int in_count, int *out_count) 1026 + unsigned int in_count, unsigned int *out_count) 1027 1027 { 1028 1028 struct file *f = fp->filp; 1029 1029 struct inode *inode = file_inode(fp->filp);
+1 -1
fs/ksmbd/vfs.h
··· 166 166 struct file_allocated_range_buffer; 167 167 int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, 168 168 struct file_allocated_range_buffer *ranges, 169 - int in_count, int *out_count); 169 + unsigned int in_count, unsigned int *out_count); 170 170 int ksmbd_vfs_unlink(struct user_namespace *user_ns, 171 171 struct dentry *dir, struct dentry *dentry); 172 172 void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat);