Skip to content

Commit b8da344

Browse files
jeromemarchandsmfrench
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]> CC: Stable <[email protected]>
1 parent 202d772 commit b8da344

File tree

3 files changed

+45
-43
lines changed

3 files changed

+45
-43
lines changed

fs/cifs/ntlmssp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,6 @@ typedef struct _AUTHENTICATE_MESSAGE {
133133

134134
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
135135
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,
137137
struct cifs_ses *ses,
138138
const struct nls_table *nls_cp);

fs/cifs/sess.c

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -364,19 +364,43 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
364364
sec_blob->DomainName.MaximumLength = 0;
365365
}
366366

367-
/* We do not malloc the blob, it is passed in pbuffer, because its
368-
maximum possible size is fixed and small, making this approach cleaner.
369-
This function returns the length of the data in the blob */
370-
int build_ntlmssp_auth_blob(unsigned char *pbuffer,
367+
static int size_of_ntlmssp_blob(struct cifs_ses *ses)
368+
{
369+
int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len
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,
371386
u16 *buflen,
372387
struct cifs_ses *ses,
373388
const struct nls_table *nls_cp)
374389
{
375390
int rc;
376-
AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
391+
AUTHENTICATE_MESSAGE *sec_blob;
377392
__u32 flags;
378393
unsigned char *tmp;
379394

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+
380404
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
381405
sec_blob->MessageType = NtLmAuthenticate;
382406

@@ -391,21 +415,17 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
391415
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
392416
}
393417

394-
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
418+
tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
395419
sec_blob->NegotiateFlags = cpu_to_le32(flags);
396420

397421
sec_blob->LmChallengeResponse.BufferOffset =
398422
cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
399423
sec_blob->LmChallengeResponse.Length = 0;
400424
sec_blob->LmChallengeResponse.MaximumLength = 0;
401425

402-
sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
426+
sec_blob->NtChallengeResponse.BufferOffset =
427+
cpu_to_le32(tmp - *pbuffer);
403428
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-
}
409429
memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
410430
ses->auth_key.len - CIFS_SESS_KEY_SIZE);
411431
tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
@@ -423,7 +443,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
423443
}
424444

425445
if (ses->domainName == NULL) {
426-
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
446+
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
427447
sec_blob->DomainName.Length = 0;
428448
sec_blob->DomainName.MaximumLength = 0;
429449
tmp += 2;
@@ -432,14 +452,14 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
432452
len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
433453
CIFS_MAX_DOMAINNAME_LEN, nls_cp);
434454
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);
436456
sec_blob->DomainName.Length = cpu_to_le16(len);
437457
sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
438458
tmp += len;
439459
}
440460

441461
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);
443463
sec_blob->UserName.Length = 0;
444464
sec_blob->UserName.MaximumLength = 0;
445465
tmp += 2;
@@ -448,13 +468,13 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
448468
len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
449469
CIFS_MAX_USERNAME_LEN, nls_cp);
450470
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);
452472
sec_blob->UserName.Length = cpu_to_le16(len);
453473
sec_blob->UserName.MaximumLength = cpu_to_le16(len);
454474
tmp += len;
455475
}
456476

457-
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer);
477+
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
458478
sec_blob->WorkstationName.Length = 0;
459479
sec_blob->WorkstationName.MaximumLength = 0;
460480
tmp += 2;
@@ -463,19 +483,19 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
463483
(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
464484
&& !calc_seckey(ses)) {
465485
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);
467487
sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
468488
sec_blob->SessionKey.MaximumLength =
469489
cpu_to_le16(CIFS_CPHTXT_SIZE);
470490
tmp += CIFS_CPHTXT_SIZE;
471491
} else {
472-
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
492+
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
473493
sec_blob->SessionKey.Length = 0;
474494
sec_blob->SessionKey.MaximumLength = 0;
475495
}
476496

497+
*buflen = tmp - *pbuffer;
477498
setup_ntlmv2_ret:
478-
*buflen = tmp - pbuffer;
479499
return rc;
480500
}
481501

@@ -1266,7 +1286,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
12661286
struct cifs_ses *ses = sess_data->ses;
12671287
__u16 bytes_remaining;
12681288
char *bcc_ptr;
1269-
char *ntlmsspblob = NULL;
1289+
unsigned char *ntlmsspblob = NULL;
12701290
u16 blob_len;
12711291

12721292
cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
@@ -1279,19 +1299,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
12791299
/* Build security blob before we assemble the request */
12801300
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
12811301
smb_buf = (struct smb_hdr *)pSMB;
1282-
/*
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,
1302+
rc = build_ntlmssp_auth_blob(&ntlmsspblob,
12951303
&blob_len, ses, sess_data->nls_cp);
12961304
if (rc)
12971305
goto out_free_ntlmsspblob;

fs/cifs/smb2pdu.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
588588
u16 blob_length = 0;
589589
struct key *spnego_key = NULL;
590590
char *security_blob = NULL;
591-
char *ntlmssp_blob = NULL;
591+
unsigned char *ntlmssp_blob = NULL;
592592
bool use_spnego = false; /* else use raw ntlmssp */
593593

594594
cifs_dbg(FYI, "Session Setup\n");
@@ -713,13 +713,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
713713
iov[1].iov_len = blob_length;
714714
} else if (phase == NtLmAuthenticate) {
715715
req->hdr.SessionId = ses->Suid;
716-
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
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,
716+
rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
723717
nls_cp);
724718
if (rc) {
725719
cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n",

0 commit comments

Comments
 (0)