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>
This commit is contained in:
Родитель
202d772ba0
Коммит
b8da344b74
|
@ -133,6 +133,6 @@ typedef struct _AUTHENTICATE_MESSAGE {
|
|||
|
||||
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
|
||||
void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
|
||||
int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen,
|
||||
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
|
||||
struct cifs_ses *ses,
|
||||
const struct nls_table *nls_cp);
|
||||
|
|
|
@ -364,19 +364,43 @@ 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 */
|
||||
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, CIFS_MAX_USERNAME_LEN);
|
||||
else
|
||||
sz += 2;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
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) {
|
||||
cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", 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;
|
||||
|
||||
|
@ -391,7 +415,7 @@ 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 =
|
||||
|
@ -399,13 +423,9 @@ 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) {
|
||||
cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", 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;
|
||||
|
@ -423,7 +443,7 @@ 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;
|
||||
|
@ -432,14 +452,14 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
|||
len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
|
||||
CIFS_MAX_DOMAINNAME_LEN, 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;
|
||||
|
@ -448,13 +468,13 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
|
|||
len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
|
||||
CIFS_MAX_USERNAME_LEN, 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;
|
||||
|
@ -463,19 +483,19 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -1266,7 +1286,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
|
|||
struct cifs_ses *ses = sess_data->ses;
|
||||
__u16 bytes_remaining;
|
||||
char *bcc_ptr;
|
||||
char *ntlmsspblob = NULL;
|
||||
unsigned char *ntlmsspblob = NULL;
|
||||
u16 blob_len;
|
||||
|
||||
cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
|
||||
|
@ -1279,19 +1299,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
|
|||
/* Build security blob before we assemble the request */
|
||||
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||
smb_buf = (struct smb_hdr *)pSMB;
|
||||
/*
|
||||
* 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) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = build_ntlmssp_auth_blob(ntlmsspblob,
|
||||
rc = build_ntlmssp_auth_blob(&ntlmsspblob,
|
||||
&blob_len, ses, sess_data->nls_cp);
|
||||
if (rc)
|
||||
goto out_free_ntlmsspblob;
|
||||
|
|
|
@ -588,7 +588,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
|
|||
u16 blob_length = 0;
|
||||
struct key *spnego_key = NULL;
|
||||
char *security_blob = NULL;
|
||||
char *ntlmssp_blob = NULL;
|
||||
unsigned char *ntlmssp_blob = NULL;
|
||||
bool use_spnego = false; /* else use raw ntlmssp */
|
||||
|
||||
cifs_dbg(FYI, "Session Setup\n");
|
||||
|
@ -713,13 +713,7 @@ ssetup_ntlmssp_authenticate:
|
|||
iov[1].iov_len = blob_length;
|
||||
} else if (phase == NtLmAuthenticate) {
|
||||
req->hdr.SessionId = ses->Suid;
|
||||
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
|
||||
GFP_KERNEL);
|
||||
if (ntlmssp_blob == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses,
|
||||
rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
|
||||
nls_cp);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n",
|
||||
|
|
Загрузка…
Ссылка в новой задаче