diff options
| author | Jerome Marchand <jmarchan@redhat.com> | 2016-05-26 05:52:25 -0400 |
|---|---|---|
| committer | Steve French <smfrench@gmail.com> | 2016-06-24 00:45:07 -0400 |
| commit | b8da344b74c822e966c6d19d6b2321efe82c5d97 (patch) | |
| tree | f4b6a50200af4e957e3ba0872e3555b74be21679 | |
| parent | 202d772ba02b1deb8835a631cd8255943d1906a0 (diff) | |
cifs: dynamic allocation of ntlmssp blob
In sess_auth_rawntlmssp_authenticate(), the ntlmssp blob is allocated
statically and its size is an "empirical" 5*sizeof(struct
_AUTHENTICATE_MESSAGE) (320B on x86_64). I don't know where this value
comes from or if it was ever appropriate, but it is currently
insufficient: the user and domain name in UTF16 could take 1kB by
themselves. Because of that, build_ntlmssp_auth_blob() might corrupt
memory (out-of-bounds write). The size of ntlmssp_blob in
SMB2_sess_setup() is too small too (sizeof(struct _NEGOTIATE_MESSAGE)
+ 500).
This patch allocates the blob dynamically in
build_ntlmssp_auth_blob().
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
CC: Stable <stable@vger.kernel.org>
| -rw-r--r-- | fs/cifs/ntlmssp.h | 2 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 76 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.c | 10 |
3 files changed, 45 insertions, 43 deletions
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 848249fa120f..3079b38f0afb 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
| @@ -133,6 +133,6 @@ typedef struct _AUTHENTICATE_MESSAGE { | |||
| 133 | 133 | ||
| 134 | int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); | 134 | int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); |
| 135 | void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); | 135 | void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); |
| 136 | int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen, | 136 | int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, |
| 137 | struct cifs_ses *ses, | 137 | struct cifs_ses *ses, |
| 138 | const struct nls_table *nls_cp); | 138 | const struct nls_table *nls_cp); |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c3d086e2bd56..a42e99c8e00e 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -364,19 +364,43 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
| 364 | sec_blob->DomainName.MaximumLength = 0; | 364 | sec_blob->DomainName.MaximumLength = 0; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | /* We do not malloc the blob, it is passed in pbuffer, because its | 367 | static int size_of_ntlmssp_blob(struct cifs_ses *ses) |
| 368 | maximum possible size is fixed and small, making this approach cleaner. | 368 | { |
| 369 | This function returns the length of the data in the blob */ | 369 | int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len |
| 370 | int build_ntlmssp_auth_blob(unsigned char *pbuffer, | 370 | - CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2; |
| 371 | |||
| 372 | if (ses->domainName) | ||
| 373 | sz += 2 * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN); | ||
| 374 | else | ||
| 375 | sz += 2; | ||
| 376 | |||
| 377 | if (ses->user_name) | ||
| 378 | sz += 2 * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN); | ||
| 379 | else | ||
| 380 | sz += 2; | ||
| 381 | |||
| 382 | return sz; | ||
| 383 | } | ||
| 384 | |||
| 385 | int build_ntlmssp_auth_blob(unsigned char **pbuffer, | ||
| 371 | u16 *buflen, | 386 | u16 *buflen, |
| 372 | struct cifs_ses *ses, | 387 | struct cifs_ses *ses, |
| 373 | const struct nls_table *nls_cp) | 388 | const struct nls_table *nls_cp) |
| 374 | { | 389 | { |
| 375 | int rc; | 390 | int rc; |
| 376 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 391 | AUTHENTICATE_MESSAGE *sec_blob; |
| 377 | __u32 flags; | 392 | __u32 flags; |
| 378 | unsigned char *tmp; | 393 | unsigned char *tmp; |
| 379 | 394 | ||
| 395 | rc = setup_ntlmv2_rsp(ses, nls_cp); | ||
| 396 | if (rc) { | ||
| 397 | cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); | ||
| 398 | *buflen = 0; | ||
| 399 | goto setup_ntlmv2_ret; | ||
| 400 | } | ||
| 401 | *pbuffer = kmalloc(size_of_ntlmssp_blob(ses), GFP_KERNEL); | ||
| 402 | sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer; | ||
| 403 | |||
| 380 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 404 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
| 381 | sec_blob->MessageType = NtLmAuthenticate; | 405 | sec_blob->MessageType = NtLmAuthenticate; |
| 382 | 406 | ||
| @@ -391,7 +415,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 391 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH; | 415 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH; |
| 392 | } | 416 | } |
| 393 | 417 | ||
| 394 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | 418 | tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE); |
| 395 | sec_blob->NegotiateFlags = cpu_to_le32(flags); | 419 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
| 396 | 420 | ||
| 397 | sec_blob->LmChallengeResponse.BufferOffset = | 421 | sec_blob->LmChallengeResponse.BufferOffset = |
| @@ -399,13 +423,9 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 399 | sec_blob->LmChallengeResponse.Length = 0; | 423 | sec_blob->LmChallengeResponse.Length = 0; |
| 400 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 424 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
| 401 | 425 | ||
| 402 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | 426 | sec_blob->NtChallengeResponse.BufferOffset = |
| 427 | cpu_to_le32(tmp - *pbuffer); | ||
| 403 | if (ses->user_name != NULL) { | 428 | if (ses->user_name != NULL) { |
| 404 | rc = setup_ntlmv2_rsp(ses, nls_cp); | ||
| 405 | if (rc) { | ||
| 406 | cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); | ||
| 407 | goto setup_ntlmv2_ret; | ||
| 408 | } | ||
| 409 | memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | 429 | memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
| 410 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); | 430 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
| 411 | tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; | 431 | tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; |
| @@ -423,7 +443,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 423 | } | 443 | } |
| 424 | 444 | ||
| 425 | if (ses->domainName == NULL) { | 445 | if (ses->domainName == NULL) { |
| 426 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 446 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 427 | sec_blob->DomainName.Length = 0; | 447 | sec_blob->DomainName.Length = 0; |
| 428 | sec_blob->DomainName.MaximumLength = 0; | 448 | sec_blob->DomainName.MaximumLength = 0; |
| 429 | tmp += 2; | 449 | tmp += 2; |
| @@ -432,14 +452,14 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 432 | len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName, | 452 | len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName, |
| 433 | CIFS_MAX_DOMAINNAME_LEN, nls_cp); | 453 | CIFS_MAX_DOMAINNAME_LEN, nls_cp); |
| 434 | len *= 2; /* unicode is 2 bytes each */ | 454 | len *= 2; /* unicode is 2 bytes each */ |
| 435 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 455 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 436 | sec_blob->DomainName.Length = cpu_to_le16(len); | 456 | sec_blob->DomainName.Length = cpu_to_le16(len); |
| 437 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | 457 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); |
| 438 | tmp += len; | 458 | tmp += len; |
| 439 | } | 459 | } |
| 440 | 460 | ||
| 441 | if (ses->user_name == NULL) { | 461 | if (ses->user_name == NULL) { |
| 442 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 462 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 443 | sec_blob->UserName.Length = 0; | 463 | sec_blob->UserName.Length = 0; |
| 444 | sec_blob->UserName.MaximumLength = 0; | 464 | sec_blob->UserName.MaximumLength = 0; |
| 445 | tmp += 2; | 465 | tmp += 2; |
| @@ -448,13 +468,13 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 448 | len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name, | 468 | len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name, |
| 449 | CIFS_MAX_USERNAME_LEN, nls_cp); | 469 | CIFS_MAX_USERNAME_LEN, nls_cp); |
| 450 | len *= 2; /* unicode is 2 bytes each */ | 470 | len *= 2; /* unicode is 2 bytes each */ |
| 451 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 471 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 452 | sec_blob->UserName.Length = cpu_to_le16(len); | 472 | sec_blob->UserName.Length = cpu_to_le16(len); |
| 453 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | 473 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); |
| 454 | tmp += len; | 474 | tmp += len; |
| 455 | } | 475 | } |
| 456 | 476 | ||
| 457 | sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 477 | sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 458 | sec_blob->WorkstationName.Length = 0; | 478 | sec_blob->WorkstationName.Length = 0; |
| 459 | sec_blob->WorkstationName.MaximumLength = 0; | 479 | sec_blob->WorkstationName.MaximumLength = 0; |
| 460 | tmp += 2; | 480 | tmp += 2; |
| @@ -463,19 +483,19 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 463 | (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) | 483 | (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) |
| 464 | && !calc_seckey(ses)) { | 484 | && !calc_seckey(ses)) { |
| 465 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); | 485 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
| 466 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 486 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 467 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | 487 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); |
| 468 | sec_blob->SessionKey.MaximumLength = | 488 | sec_blob->SessionKey.MaximumLength = |
| 469 | cpu_to_le16(CIFS_CPHTXT_SIZE); | 489 | cpu_to_le16(CIFS_CPHTXT_SIZE); |
| 470 | tmp += CIFS_CPHTXT_SIZE; | 490 | tmp += CIFS_CPHTXT_SIZE; |
| 471 | } else { | 491 | } else { |
| 472 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 492 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer); |
| 473 | sec_blob->SessionKey.Length = 0; | 493 | sec_blob->SessionKey.Length = 0; |
| 474 | sec_blob->SessionKey.MaximumLength = 0; | 494 | sec_blob->SessionKey.MaximumLength = 0; |
| 475 | } | 495 | } |
| 476 | 496 | ||
| 497 | *buflen = tmp - *pbuffer; | ||
| 477 | setup_ntlmv2_ret: | 498 | setup_ntlmv2_ret: |
| 478 | *buflen = tmp - pbuffer; | ||
| 479 | return rc; | 499 | return rc; |
| 480 | } | 500 | } |
| 481 | 501 | ||
| @@ -1266,7 +1286,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) | |||
| 1266 | struct cifs_ses *ses = sess_data->ses; | 1286 | struct cifs_ses *ses = sess_data->ses; |
| 1267 | __u16 bytes_remaining; | 1287 | __u16 bytes_remaining; |
| 1268 | char *bcc_ptr; | 1288 | char *bcc_ptr; |
| 1269 | char *ntlmsspblob = NULL; | 1289 | unsigned char *ntlmsspblob = NULL; |
| 1270 | u16 blob_len; | 1290 | u16 blob_len; |
| 1271 | 1291 | ||
| 1272 | cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n"); | 1292 | cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n"); |
| @@ -1279,19 +1299,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) | |||
| 1279 | /* Build security blob before we assemble the request */ | 1299 | /* Build security blob before we assemble the request */ |
| 1280 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | 1300 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
| 1281 | smb_buf = (struct smb_hdr *)pSMB; | 1301 | smb_buf = (struct smb_hdr *)pSMB; |
| 1282 | /* | 1302 | rc = build_ntlmssp_auth_blob(&ntlmsspblob, |
| 1283 | * 5 is an empirical value, large enough to hold | ||
| 1284 | * authenticate message plus max 10 of av paris, | ||
| 1285 | * domain, user, workstation names, flags, etc. | ||
| 1286 | */ | ||
| 1287 | ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
| 1288 | GFP_KERNEL); | ||
| 1289 | if (!ntlmsspblob) { | ||
| 1290 | rc = -ENOMEM; | ||
| 1291 | goto out; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | ||
| 1295 | &blob_len, ses, sess_data->nls_cp); | 1303 | &blob_len, ses, sess_data->nls_cp); |
| 1296 | if (rc) | 1304 | if (rc) |
| 1297 | goto out_free_ntlmsspblob; | 1305 | goto out_free_ntlmsspblob; |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 8f38e33d365b..c3e61a7a7c7c 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -588,7 +588,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | |||
| 588 | u16 blob_length = 0; | 588 | u16 blob_length = 0; |
| 589 | struct key *spnego_key = NULL; | 589 | struct key *spnego_key = NULL; |
| 590 | char *security_blob = NULL; | 590 | char *security_blob = NULL; |
| 591 | char *ntlmssp_blob = NULL; | 591 | unsigned char *ntlmssp_blob = NULL; |
| 592 | bool use_spnego = false; /* else use raw ntlmssp */ | 592 | bool use_spnego = false; /* else use raw ntlmssp */ |
| 593 | 593 | ||
| 594 | cifs_dbg(FYI, "Session Setup\n"); | 594 | cifs_dbg(FYI, "Session Setup\n"); |
| @@ -713,13 +713,7 @@ ssetup_ntlmssp_authenticate: | |||
| 713 | iov[1].iov_len = blob_length; | 713 | iov[1].iov_len = blob_length; |
| 714 | } else if (phase == NtLmAuthenticate) { | 714 | } else if (phase == NtLmAuthenticate) { |
| 715 | req->hdr.SessionId = ses->Suid; | 715 | req->hdr.SessionId = ses->Suid; |
| 716 | ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, | 716 | rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses, |
| 717 | GFP_KERNEL); | ||
| 718 | if (ntlmssp_blob == NULL) { | ||
| 719 | rc = -ENOMEM; | ||
| 720 | goto ssetup_exit; | ||
| 721 | } | ||
| 722 | rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses, | ||
| 723 | nls_cp); | 717 | nls_cp); |
| 724 | if (rc) { | 718 | if (rc) { |
| 725 | cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", | 719 | cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", |
