6.6-stable review patch. If anyone has any objections, please let me know. ------------------ From: Haofeng Li [ Upstream commit 954d196bebb2b50151cb96454c72dc113b2af1ac ] 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 Reviewed-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/smb/server/auth.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index e5b77d8754787..c9892611b6e2f 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -72,13 +72,12 @@ void ksmbd_copy_gss_neg_header(void *buf) /** * ksmbd_gen_sess_key() - function to generate session key - * @sess: session of connection + * @sess_key: output buffer for the generated session key * @hash: source hash value to be used for find session key * @hmac: source hmac value to be used for finding session key * */ -static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, - char *hmac) +static int ksmbd_gen_sess_key(char *sess_key, char *hash, char *hmac) { struct ksmbd_crypto_ctx *ctx; int rc; @@ -111,7 +110,7 @@ static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, goto out; } - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess->sess_key); + rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess_key); if (rc) { ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", rc); goto out; @@ -224,6 +223,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 ksmbd_crypto_ctx *ctx = NULL; char *construct = NULL; int rc, len; @@ -278,19 +278,26 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, ksmbd_release_crypto_ctx(ctx); ctx = NULL; - rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); + rc = ksmbd_gen_sess_key(sess_key, ntlmv2_hash, ntlmv2_rsp); if (rc) { ksmbd_debug(AUTH, "Could not generate sess key\n"); goto out; } if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp, - CIFS_HMAC_MD5_HASH_SIZE)) + CIFS_HMAC_MD5_HASH_SIZE)) { rc = -EINVAL; + goto out; + } + + memcpy(sess->sess_key, sess_key, sizeof(sess_key)); out: if (ctx) ksmbd_release_crypto_ctx(ctx); kfree(construct); + memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash)); + memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp)); + memzero_explicit(sess_key, sizeof(sess_key)); return rc; } @@ -348,6 +355,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) { -- 2.53.0