summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerome Marchand <jmarchan@redhat.com>2016-05-26 05:52:25 -0400
committerSteve French <smfrench@gmail.com>2016-06-24 00:45:07 -0400
commitb8da344b74c822e966c6d19d6b2321efe82c5d97 (patch)
treef4b6a50200af4e957e3ba0872e3555b74be21679
parent202d772ba02b1deb8835a631cd8255943d1906a0 (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.h2
-rw-r--r--fs/cifs/sess.c76
-rw-r--r--fs/cifs/smb2pdu.c10
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
134int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); 134int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
135void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); 135void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
136int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen, 136int 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 367static 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
370int 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
385int 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;
477setup_ntlmv2_ret: 498setup_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",