diff mbox series

[v3] ksmbd: add buffer validation in session setup

Message ID 20211019083641.116783-1-mmakassikis@freebox.fr (mailing list archive)
State New, archived
Headers show
Series [v3] ksmbd: add buffer validation in session setup | expand

Commit Message

Marios Makassikis Oct. 19, 2021, 8:36 a.m. UTC
Make sure the security buffer's length/offset are valid with regards to
the packet length.

Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
---
 Changes since v2:
 - check that negblob in smb2_sess_setup() is large enough to access the
   MessageType field

fs/ksmbd/auth.c    | 18 ++++++++++------
 fs/ksmbd/smb2pdu.c | 51 ++++++++++++++++++++++++++++------------------
 2 files changed, 43 insertions(+), 26 deletions(-)

Comments

Namjae Jeon Oct. 19, 2021, 2:34 p.m. UTC | #1
2021-10-19 17:36 GMT+09:00, Marios Makassikis <mmakassikis@freebox.fr>:
> Make sure the security buffer's length/offset are valid with regards to
> the packet length.
>
> Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> ---
>  Changes since v2:
>  - check that negblob in smb2_sess_setup() is large enough to access the
>    MessageType field
>
> fs/ksmbd/auth.c    | 18 ++++++++++------
>  fs/ksmbd/smb2pdu.c | 51 ++++++++++++++++++++++++++++------------------
>  2 files changed, 43 insertions(+), 26 deletions(-)
>
> diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
> index 71c989f1568d..c9d32fea5669 100644
> --- a/fs/ksmbd/auth.c
> +++ b/fs/ksmbd/auth.c
> @@ -298,8 +298,9 @@ 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;
> +	uintptr_t auth_msg_off;
> +	unsigned int lm_off, nt_off, dn_off;
> +	unsigned short nt_len, dn_len;
>  	int ret;
>
>  	if (blob_len < sizeof(struct authenticate_message)) {
> @@ -314,15 +315,20 @@ int ksmbd_decode_ntlmssp_auth_blob(struct
> authenticate_message *authblob,
>  		return -EINVAL;
>  	}
>
> +	auth_msg_off = (uintptr_t)((char *)authblob + blob_len);
>  	lm_off = le32_to_cpu(authblob->LmChallengeResponse.BufferOffset);
Let's remove unused lm_off.
>  	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 (auth_msg_off < (u64)dn_off + dn_len ||
It should be blob_len instead of auth_msg_off ?
> +	    auth_msg_off < (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);
>
> diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
> index 005aa93a49d6..f02766b1e9ce 100644
> --- a/fs/ksmbd/smb2pdu.c
> +++ b/fs/ksmbd/smb2pdu.c
> @@ -1274,19 +1274,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;
> @@ -1298,9 +1292,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;
> @@ -1309,8 +1303,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;
>
> @@ -1378,12 +1371,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)) {
> @@ -1629,6 +1633,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");
> @@ -1709,10 +1714,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
>  	if (sess->state == SMB2_SESSION_EXPIRED)
>  		sess->state = SMB2_SESSION_IN_PROGRESS;
>
> +	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;
> +
>  	negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
> -			le16_to_cpu(req->SecurityBufferOffset));
> +			negblob_off);
>
> -	if (decode_negotiation_token(work, negblob) == 0) {
> +	if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {
>  		if (conn->mechToken)
>  			negblob = (struct negotiate_message *)conn->mechToken;
>  	}
> @@ -1736,7 +1747,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 =
> --
> 2.25.1
>
>
Marios Makassikis Oct. 19, 2021, 3:33 p.m. UTC | #2
On Tue, Oct 19, 2021 at 4:35 PM Namjae Jeon <linkinjeon@kernel.org> wrote:
>
> 2021-10-19 17:36 GMT+09:00, Marios Makassikis <mmakassikis@freebox.fr>:
> > Make sure the security buffer's length/offset are valid with regards to
> > the packet length.
> >
> > Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
> > ---
> >  Changes since v2:
> >  - check that negblob in smb2_sess_setup() is large enough to access the
> >    MessageType field
> >
> > fs/ksmbd/auth.c    | 18 ++++++++++------
> >  fs/ksmbd/smb2pdu.c | 51 ++++++++++++++++++++++++++++------------------
> >  2 files changed, 43 insertions(+), 26 deletions(-)
> >
> > diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
> > index 71c989f1568d..c9d32fea5669 100644
> > --- a/fs/ksmbd/auth.c
> > +++ b/fs/ksmbd/auth.c
> > @@ -298,8 +298,9 @@ 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;
> > +     uintptr_t auth_msg_off;
> > +     unsigned int lm_off, nt_off, dn_off;
> > +     unsigned short nt_len, dn_len;
> >       int ret;
> >
> >       if (blob_len < sizeof(struct authenticate_message)) {
> > @@ -314,15 +315,20 @@ int ksmbd_decode_ntlmssp_auth_blob(struct
> > authenticate_message *authblob,
> >               return -EINVAL;
> >       }
> >
> > +     auth_msg_off = (uintptr_t)((char *)authblob + blob_len);
> >       lm_off = le32_to_cpu(authblob->LmChallengeResponse.BufferOffset);
> Let's remove unused lm_off.
ok

> >       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 (auth_msg_off < (u64)dn_off + dn_len ||
> It should be blob_len instead of auth_msg_off ?

Good catch, auth_msg_off is completely wrong here.

> > +         auth_msg_off < (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);
> >
> > diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
> > index 005aa93a49d6..f02766b1e9ce 100644
> > --- a/fs/ksmbd/smb2pdu.c
> > +++ b/fs/ksmbd/smb2pdu.c
> > @@ -1274,19 +1274,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;
> > @@ -1298,9 +1292,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;
> > @@ -1309,8 +1303,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;
> >
> > @@ -1378,12 +1371,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)) {
> > @@ -1629,6 +1633,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");
> > @@ -1709,10 +1714,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
> >       if (sess->state == SMB2_SESSION_EXPIRED)
> >               sess->state = SMB2_SESSION_IN_PROGRESS;
> >
> > +     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;
> > +
> >       negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
> > -                     le16_to_cpu(req->SecurityBufferOffset));
> > +                     negblob_off);
> >
> > -     if (decode_negotiation_token(work, negblob) == 0) {
> > +     if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {
> >               if (conn->mechToken)
> >                       negblob = (struct negotiate_message *)conn->mechToken;
> >       }
> > @@ -1736,7 +1747,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 =
> > --
> > 2.25.1
> >
> >
diff mbox series

Patch

diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c
index 71c989f1568d..c9d32fea5669 100644
--- a/fs/ksmbd/auth.c
+++ b/fs/ksmbd/auth.c
@@ -298,8 +298,9 @@  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;
+	uintptr_t auth_msg_off;
+	unsigned int lm_off, nt_off, dn_off;
+	unsigned short nt_len, dn_len;
 	int ret;
 
 	if (blob_len < sizeof(struct authenticate_message)) {
@@ -314,15 +315,20 @@  int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
 		return -EINVAL;
 	}
 
+	auth_msg_off = (uintptr_t)((char *)authblob + blob_len);
 	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 (auth_msg_off < (u64)dn_off + dn_len ||
+	    auth_msg_off < (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);
 
diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
index 005aa93a49d6..f02766b1e9ce 100644
--- a/fs/ksmbd/smb2pdu.c
+++ b/fs/ksmbd/smb2pdu.c
@@ -1274,19 +1274,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;
@@ -1298,9 +1292,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;
@@ -1309,8 +1303,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;
 
@@ -1378,12 +1371,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)) {
@@ -1629,6 +1633,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");
@@ -1709,10 +1714,16 @@  int smb2_sess_setup(struct ksmbd_work *work)
 	if (sess->state == SMB2_SESSION_EXPIRED)
 		sess->state = SMB2_SESSION_IN_PROGRESS;
 
+	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;
+
 	negblob = (struct negotiate_message *)((char *)&req->hdr.ProtocolId +
-			le16_to_cpu(req->SecurityBufferOffset));
+			negblob_off);
 
-	if (decode_negotiation_token(work, negblob) == 0) {
+	if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {
 		if (conn->mechToken)
 			negblob = (struct negotiate_message *)conn->mechToken;
 	}
@@ -1736,7 +1747,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 =