Commit 80055f78 authored by Jerome Marchand's avatar Jerome Marchand Committed by Ben Hutchings

cifs: dynamic allocation of ntlmssp blob

commit b8da344b upstream.

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: default avatarJerome Marchand <jmarchan@redhat.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
[bwh: Backported to 3.2:
 - Adjust context, indentation
 - build_ntlmssp_auth_blob() is static
 - Drop changes to smb2pdu.c
 - Use cERROR() instead of cifs_dbg(VFS, ...)
 - Use MAX_USERNAME_SIZE instead of CIFS_MAX_USERNAME_LEN]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent ef1b3224
......@@ -444,19 +444,43 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
sec_blob->DomainName.MaximumLength = 0;
}
/* We do not malloc the blob, it is passed in pbuffer, because its
maximum possible size is fixed and small, making this approach cleaner.
This function returns the length of the data in the blob */
static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
static int size_of_ntlmssp_blob(struct cifs_ses *ses)
{
int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len
- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
if (ses->domainName)
sz += 2 * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
else
sz += 2;
if (ses->user_name)
sz += 2 * strnlen(ses->user_name, MAX_USERNAME_SIZE);
else
sz += 2;
return sz;
}
static int build_ntlmssp_auth_blob(unsigned char **pbuffer,
u16 *buflen,
struct cifs_ses *ses,
const struct nls_table *nls_cp)
{
int rc;
AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
AUTHENTICATE_MESSAGE *sec_blob;
__u32 flags;
unsigned char *tmp;
rc = setup_ntlmv2_rsp(ses, nls_cp);
if (rc) {
cERROR(1, "Error %d during NTLMSSP authentication", rc);
*buflen = 0;
goto setup_ntlmv2_ret;
}
*pbuffer = kmalloc(size_of_ntlmssp_blob(ses), GFP_KERNEL);
sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer;
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
sec_blob->MessageType = NtLmAuthenticate;
......@@ -471,7 +495,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
}
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE);
tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
sec_blob->NegotiateFlags = cpu_to_le32(flags);
sec_blob->LmChallengeResponse.BufferOffset =
......@@ -479,13 +503,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
sec_blob->LmChallengeResponse.Length = 0;
sec_blob->LmChallengeResponse.MaximumLength = 0;
sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->NtChallengeResponse.BufferOffset =
cpu_to_le32(tmp - *pbuffer);
if (ses->user_name != NULL) {
rc = setup_ntlmv2_rsp(ses, nls_cp);
if (rc) {
cERROR(1, "Error %d during NTLMSSP authentication", rc);
goto setup_ntlmv2_ret;
}
memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
ses->auth_key.len - CIFS_SESS_KEY_SIZE);
tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
......@@ -503,7 +523,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
}
if (ses->domainName == NULL) {
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->DomainName.Length = 0;
sec_blob->DomainName.MaximumLength = 0;
tmp += 2;
......@@ -512,14 +532,14 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
MAX_USERNAME_SIZE, nls_cp);
len *= 2; /* unicode is 2 bytes each */
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->DomainName.Length = cpu_to_le16(len);
sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
tmp += len;
}
if (ses->user_name == NULL) {
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->UserName.Length = 0;
sec_blob->UserName.MaximumLength = 0;
tmp += 2;
......@@ -528,13 +548,13 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len = cifs_strtoUCS((__le16 *)tmp, ses->user_name,
MAX_USERNAME_SIZE, nls_cp);
len *= 2; /* unicode is 2 bytes each */
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->UserName.Length = cpu_to_le16(len);
sec_blob->UserName.MaximumLength = cpu_to_le16(len);
tmp += len;
}
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->WorkstationName.Length = 0;
sec_blob->WorkstationName.MaximumLength = 0;
tmp += 2;
......@@ -543,19 +563,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
&& !calc_seckey(ses)) {
memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
sec_blob->SessionKey.MaximumLength =
cpu_to_le16(CIFS_CPHTXT_SIZE);
tmp += CIFS_CPHTXT_SIZE;
} else {
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->SessionKey.Length = 0;
sec_blob->SessionKey.MaximumLength = 0;
}
*buflen = tmp - *pbuffer;
setup_ntlmv2_ret:
*buflen = tmp - pbuffer;
return rc;
}
......@@ -578,7 +598,7 @@ CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
struct key *spnego_key = NULL;
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
u16 blob_len;
char *ntlmsspblob = NULL;
unsigned char *ntlmsspblob = NULL;
if (ses == NULL)
return -EINVAL;
......@@ -832,21 +852,7 @@ CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
break;
case NtLmAuthenticate:
/*
* 5 is an empirical value, large enough to hold
* authenticate message plus max 10 of av paris,
* domain, user, workstation names, flags, etc.
*/
ntlmsspblob = kzalloc(
5*sizeof(struct _AUTHENTICATE_MESSAGE),
GFP_KERNEL);
if (!ntlmsspblob) {
cERROR(1, "Can't allocate NTLMSSP blob");
rc = -ENOMEM;
goto ssetup_exit;
}
rc = build_ntlmssp_auth_blob(ntlmsspblob,
rc = build_ntlmssp_auth_blob(&ntlmsspblob,
&blob_len, ses, nls_cp);
if (rc)
goto ssetup_exit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment