ksmbd: validate mech token in session setup
authorNamjae Jeon <linkinjeon@kernel.org>
Sat, 13 Jan 2024 06:11:41 +0000 (15:11 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Jan 2024 23:35:44 +0000 (15:35 -0800)
commit 92e470163d96df8db6c4fa0f484e4a229edb903d upstream.

If client send invalid mech token in session setup request, ksmbd
validate and make the error if it is invalid.

Cc: stable@vger.kernel.org
Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-22890
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/server/asn1.c
fs/smb/server/connection.h
fs/smb/server/smb2pdu.c

index 4a4b2b0..b931a99 100644 (file)
@@ -214,10 +214,15 @@ static int ksmbd_neg_token_alloc(void *context, size_t hdrlen,
 {
        struct ksmbd_conn *conn = context;
 
+       if (!vlen)
+               return -EINVAL;
+
        conn->mechToken = kmemdup_nul(value, vlen, GFP_KERNEL);
        if (!conn->mechToken)
                return -ENOMEM;
 
+       conn->mechTokenLen = (unsigned int)vlen;
+
        return 0;
 }
 
index 3c00524..342f935 100644 (file)
@@ -88,6 +88,7 @@ struct ksmbd_conn {
        __u16                           dialect;
 
        char                            *mechToken;
+       unsigned int                    mechTokenLen;
 
        struct ksmbd_conn_ops   *conn_ops;
 
index 0e4d514..297ed5c 100644 (file)
@@ -1414,7 +1414,10 @@ static struct ksmbd_user *session_user(struct ksmbd_conn *conn,
        char *name;
        unsigned int name_off, name_len, secbuf_len;
 
-       secbuf_len = le16_to_cpu(req->SecurityBufferLength);
+       if (conn->use_spnego && conn->mechToken)
+               secbuf_len = conn->mechTokenLen;
+       else
+               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;
@@ -1505,7 +1508,10 @@ static int ntlm_authenticate(struct ksmbd_work *work,
                struct authenticate_message *authblob;
 
                authblob = user_authblob(conn, req);
-               sz = le16_to_cpu(req->SecurityBufferLength);
+               if (conn->use_spnego && conn->mechToken)
+                       sz = conn->mechTokenLen;
+               else
+                       sz = le16_to_cpu(req->SecurityBufferLength);
                rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess);
                if (rc) {
                        set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
@@ -1778,8 +1784,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
 
        negblob_off = le16_to_cpu(req->SecurityBufferOffset);
        negblob_len = le16_to_cpu(req->SecurityBufferLength);
-       if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) ||
-           negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) {
+       if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer)) {
                rc = -EINVAL;
                goto out_err;
        }
@@ -1788,8 +1793,15 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        negblob_off);
 
        if (decode_negotiation_token(conn, negblob, negblob_len) == 0) {
-               if (conn->mechToken)
+               if (conn->mechToken) {
                        negblob = (struct negotiate_message *)conn->mechToken;
+                       negblob_len = conn->mechTokenLen;
+               }
+       }
+
+       if (negblob_len < offsetof(struct negotiate_message, NegotiateFlags)) {
+               rc = -EINVAL;
+               goto out_err;
        }
 
        if (server_conf.auth_mechs & conn->auth_mechs) {