]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: validate NTLMv2 response before updating session key
authorHaofeng Li <lihaofeng@kylinos.cn>
Tue, 23 Jun 2026 01:30:26 +0000 (09:30 +0800)
committerSteve French <stfrench@microsoft.com>
Tue, 23 Jun 2026 22:52:42 +0000 (17:52 -0500)
ksmbd_auth_ntlmv2() derives the NTLMv2 session key into
sess->sess_key before it verifies the NTLMv2 response.
ksmbd_decode_ntlmssp_auth_blob() then continues into KEY_XCH even
when ksmbd_auth_ntlmv2() failed.

With SMB3 multichannel binding, the failed authentication operates on
an existing session and the session setup error path does not expire
binding sessions. A client can send a binding session setup with a
bad NT proof and KEY_XCH and still modify sess->sess_key before
STATUS_LOGON_FAILURE is returned.

Relevant path:

  smb2_sess_setup()
    -> conn->binding = true
    -> ntlm_authenticate()
       -> session_user()
       -> ksmbd_decode_ntlmssp_auth_blob()
          -> ksmbd_auth_ntlmv2()
             -> calc_ntlmv2_hash()
             -> hmac_md5_usingrawkey(..., sess->sess_key)
             -> crypto_memneq() returns mismatch
          -> KEY_XCH arc4_crypt(..., sess->sess_key, ...)
    -> out_err without expiring the binding session

Derive the base session key into a local buffer and copy it to
sess->sess_key only after the proof matches. Return immediately on
authentication failure so KEY_XCH is only processed after successful
authentication.

Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Fixes: f9929ef6a2a5 ("ksmbd: add support for key exchange")
Cc: stable@vger.kernel.org
Signed-off-by: Haofeng Li <lihaofeng@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/auth.c

index e99409fa721cd0587d92a4339c520eba1214260a..86f521e849d5e235ea8e53551b0977cac5075f22 100644 (file)
@@ -142,6 +142,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
 {
        char ntlmv2_hash[CIFS_ENCPWD_SIZE];
        char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
+       char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
        struct hmac_md5_ctx ctx;
        int rc;
 
@@ -164,12 +165,21 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
        /* Generate the session key */
        hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
                             ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
-                            sess->sess_key);
+                            sess_key);
 
        if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
-                         CIFS_HMAC_MD5_HASH_SIZE))
-               return -EINVAL;
-       return 0;
+                         CIFS_HMAC_MD5_HASH_SIZE)) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       memcpy(sess->sess_key, sess_key, sizeof(sess_key));
+       rc = 0;
+out:
+       memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash));
+       memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp));
+       memzero_explicit(sess_key, sizeof(sess_key));
+       return rc;
 }
 
 /**
@@ -226,6 +236,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
                                nt_len - CIFS_ENCPWD_SIZE,
                                domain_name, conn->ntlmssp.cryptkey);
        kfree(domain_name);
+       if (ret)
+               return ret;
 
        /* The recovered secondary session key */
        if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {