mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
ksmbd: add buffer validation in session setup
Make sure the security buffer's length/offset are valid with regards to the packet length. Acked-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
621be84a9d
commit
0d994cd482
@ -298,8 +298,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||
int blob_len, struct ksmbd_session *sess)
|
||||
{
|
||||
char *domain_name;
|
||||
unsigned int lm_off, nt_off;
|
||||
unsigned short nt_len;
|
||||
unsigned int nt_off, dn_off;
|
||||
unsigned short nt_len, dn_len;
|
||||
int ret;
|
||||
|
||||
if (blob_len < sizeof(struct authenticate_message)) {
|
||||
@ -314,15 +314,17 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lm_off = le32_to_cpu(authblob->LmChallengeResponse.BufferOffset);
|
||||
nt_off = le32_to_cpu(authblob->NtChallengeResponse.BufferOffset);
|
||||
nt_len = le16_to_cpu(authblob->NtChallengeResponse.Length);
|
||||
dn_off = le32_to_cpu(authblob->DomainName.BufferOffset);
|
||||
dn_len = le16_to_cpu(authblob->DomainName.Length);
|
||||
|
||||
if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO : use domain name that imported from configuration file */
|
||||
domain_name = smb_strndup_from_utf16((const char *)authblob +
|
||||
le32_to_cpu(authblob->DomainName.BufferOffset),
|
||||
le16_to_cpu(authblob->DomainName.Length), true,
|
||||
sess->conn->local_nls);
|
||||
domain_name = smb_strndup_from_utf16((const char *)authblob + dn_off,
|
||||
dn_len, true, sess->conn->local_nls);
|
||||
if (IS_ERR(domain_name))
|
||||
return PTR_ERR(domain_name);
|
||||
|
||||
|
@ -1257,19 +1257,13 @@ static int generate_preauth_hash(struct ksmbd_work *work)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_negotiation_token(struct ksmbd_work *work,
|
||||
struct negotiate_message *negblob)
|
||||
static int decode_negotiation_token(struct ksmbd_conn *conn,
|
||||
struct negotiate_message *negblob,
|
||||
size_t sz)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct smb2_sess_setup_req *req;
|
||||
int sz;
|
||||
|
||||
if (!conn->use_spnego)
|
||||
return -EINVAL;
|
||||
|
||||
req = work->request_buf;
|
||||
sz = le16_to_cpu(req->SecurityBufferLength);
|
||||
|
||||
if (ksmbd_decode_negTokenInit((char *)negblob, sz, conn)) {
|
||||
if (ksmbd_decode_negTokenTarg((char *)negblob, sz, conn)) {
|
||||
conn->auth_mechs |= KSMBD_AUTH_NTLMSSP;
|
||||
@ -1281,9 +1275,9 @@ static int decode_negotiation_token(struct ksmbd_work *work,
|
||||
}
|
||||
|
||||
static int ntlm_negotiate(struct ksmbd_work *work,
|
||||
struct negotiate_message *negblob)
|
||||
struct negotiate_message *negblob,
|
||||
size_t negblob_len)
|
||||
{
|
||||
struct smb2_sess_setup_req *req = work->request_buf;
|
||||
struct smb2_sess_setup_rsp *rsp = work->response_buf;
|
||||
struct challenge_message *chgblob;
|
||||
unsigned char *spnego_blob = NULL;
|
||||
@ -1292,8 +1286,7 @@ static int ntlm_negotiate(struct ksmbd_work *work,
|
||||
int sz, rc;
|
||||
|
||||
ksmbd_debug(SMB, "negotiate phase\n");
|
||||
sz = le16_to_cpu(req->SecurityBufferLength);
|
||||
rc = ksmbd_decode_ntlmssp_neg_blob(negblob, sz, work->sess);
|
||||
rc = ksmbd_decode_ntlmssp_neg_blob(negblob, negblob_len, work->sess);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -1361,12 +1354,23 @@ static struct ksmbd_user *session_user(struct ksmbd_conn *conn,
|
||||
struct authenticate_message *authblob;
|
||||
struct ksmbd_user *user;
|
||||
char *name;
|
||||
int sz;
|
||||
unsigned int auth_msg_len, name_off, name_len, secbuf_len;
|
||||
|
||||
secbuf_len = le16_to_cpu(req->SecurityBufferLength);
|
||||
if (secbuf_len < sizeof(struct authenticate_message)) {
|
||||
ksmbd_debug(SMB, "blob len %d too small\n", secbuf_len);
|
||||
return NULL;
|
||||
}
|
||||
authblob = user_authblob(conn, req);
|
||||
sz = le32_to_cpu(authblob->UserName.BufferOffset);
|
||||
name = smb_strndup_from_utf16((const char *)authblob + sz,
|
||||
le16_to_cpu(authblob->UserName.Length),
|
||||
name_off = le32_to_cpu(authblob->UserName.BufferOffset);
|
||||
name_len = le16_to_cpu(authblob->UserName.Length);
|
||||
auth_msg_len = le16_to_cpu(req->SecurityBufferOffset) + secbuf_len;
|
||||
|
||||
if (auth_msg_len < (u64)name_off + name_len)
|
||||
return NULL;
|
||||
|
||||
name = smb_strndup_from_utf16((const char *)authblob + name_off,
|
||||
name_len,
|
||||
true,
|
||||
conn->local_nls);
|
||||
if (IS_ERR(name)) {
|
||||
@ -1612,6 +1616,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
struct smb2_sess_setup_rsp *rsp = work->response_buf;
|
||||
struct ksmbd_session *sess;
|
||||
struct negotiate_message *negblob;
|
||||
unsigned int negblob_len, negblob_off;
|
||||
int rc = 0;
|
||||
|
||||
ksmbd_debug(SMB, "Received request for session setup\n");
|
||||
@ -1692,10 +1697,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
if (sess->state == SMB2_SESSION_EXPIRED)
|
||||
sess->state = SMB2_SESSION_IN_PROGRESS;
|
||||
|
||||
negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
|
||||
le16_to_cpu(req->SecurityBufferOffset));
|
||||
negblob_off = le16_to_cpu(req->SecurityBufferOffset);
|
||||
negblob_len = le16_to_cpu(req->SecurityBufferLength);
|
||||
if (negblob_off < (offsetof(struct smb2_sess_setup_req, Buffer) - 4) ||
|
||||
negblob_len < offsetof(struct negotiate_message, NegotiateFlags))
|
||||
return -EINVAL;
|
||||
|
||||
if (decode_negotiation_token(work, negblob) == 0) {
|
||||
negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
|
||||
negblob_off);
|
||||
|
||||
if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {
|
||||
if (conn->mechToken)
|
||||
negblob = (struct negotiate_message *)conn->mechToken;
|
||||
}
|
||||
@ -1719,7 +1730,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
sess->Preauth_HashValue = NULL;
|
||||
} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
|
||||
if (negblob->MessageType == NtLmNegotiate) {
|
||||
rc = ntlm_negotiate(work, negblob);
|
||||
rc = ntlm_negotiate(work, negblob, negblob_len);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
rsp->hdr.Status =
|
||||
|
Loading…
Reference in New Issue
Block a user