diff options
author | Namjae Jeon <linkinjeon@kernel.org> | 2022-07-25 07:36:52 +0300 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2022-08-01 07:14:32 +0300 |
commit | af7c39d971e43cd0af488729bca362427ad99488 (patch) | |
tree | 3c174aa7d504f663a6741a5dffee77666f86df65 /fs/ksmbd/auth.c | |
parent | a14c573870a664386adc10526a6c2648ea56dae1 (diff) | |
download | linux-af7c39d971e43cd0af488729bca362427ad99488.tar.xz |
ksmbd: fix racy issue while destroying session on multichannel
After multi-channel connection with windows, Several channels of
session are connected. Among them, if there is a problem in one channel,
Windows connects again after disconnecting the channel. In this process,
the session is released and a kernel oop can occurs while processing
requests to other channels. When the channel is disconnected, if other
channels still exist in the session after deleting the channel from
the channel list in the session, the session should not be released.
Finally, the session will be released after all channels are disconnected.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/ksmbd/auth.c')
-rw-r--r-- | fs/ksmbd/auth.c | 56 |
1 files changed, 31 insertions, 25 deletions
diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c index 911444d21267..c5a5c7b90d72 100644 --- a/fs/ksmbd/auth.c +++ b/fs/ksmbd/auth.c @@ -121,8 +121,8 @@ out: return rc; } -static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, - char *dname) +static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, + char *ntlmv2_hash, char *dname) { int ret, len, conv_len; wchar_t *domain = NULL; @@ -158,7 +158,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, } conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len, - sess->conn->local_nls); + conn->local_nls); if (conv_len < 0 || conv_len > len) { ret = -EINVAL; goto out; @@ -182,7 +182,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, } conv_len = smb_strtoUTF16((__le16 *)domain, dname, len, - sess->conn->local_nls); + conn->local_nls); if (conv_len < 0 || conv_len > len) { ret = -EINVAL; goto out; @@ -215,8 +215,9 @@ out: * * Return: 0 on success, error number on error */ -int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2, - int blen, char *domain_name, char *cryptkey) +int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, + struct ntlmv2_resp *ntlmv2, int blen, char *domain_name, + char *cryptkey) { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; @@ -230,7 +231,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2, return -ENOMEM; } - rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name); + rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); if (rc) { ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); goto out; @@ -333,7 +334,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, /* process NTLMv2 authentication */ ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n", domain_name); - ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off), + ret = ksmbd_auth_ntlmv2(conn, sess, + (struct ntlmv2_resp *)((char *)authblob + nt_off), nt_len - CIFS_ENCPWD_SIZE, domain_name, conn->ntlmssp.cryptkey); kfree(domain_name); @@ -659,8 +661,9 @@ struct derivation { bool binding; }; -static int generate_key(struct ksmbd_session *sess, struct kvec label, - struct kvec context, __u8 *key, unsigned int key_size) +static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, + struct kvec label, struct kvec context, __u8 *key, + unsigned int key_size) { unsigned char zero = 0x0; __u8 i[4] = {0, 0, 0, 1}; @@ -720,8 +723,8 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label, goto smb3signkey_ret; } - if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || - sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) + if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || + conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); else rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); @@ -756,17 +759,17 @@ static int generate_smb3signingkey(struct ksmbd_session *sess, if (!chann) return 0; - if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding) + if (conn->dialect >= SMB30_PROT_ID && signing->binding) key = chann->smb3signingkey; else key = sess->smb3signingkey; - rc = generate_key(sess, signing->label, signing->context, key, + rc = generate_key(conn, sess, signing->label, signing->context, key, SMB3_SIGN_KEY_SIZE); if (rc) return rc; - if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding)) + if (!(conn->dialect >= SMB30_PROT_ID && signing->binding)) memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE); ksmbd_debug(AUTH, "dumping generated AES signing keys\n"); @@ -820,30 +823,31 @@ struct derivation_twin { struct derivation decryption; }; -static int generate_smb3encryptionkey(struct ksmbd_session *sess, +static int generate_smb3encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess, const struct derivation_twin *ptwin) { int rc; - rc = generate_key(sess, ptwin->encryption.label, + rc = generate_key(conn, sess, ptwin->encryption.label, ptwin->encryption.context, sess->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE); if (rc) return rc; - rc = generate_key(sess, ptwin->decryption.label, + rc = generate_key(conn, sess, ptwin->decryption.label, ptwin->decryption.context, sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); if (rc) return rc; ksmbd_debug(AUTH, "dumping generated AES encryption keys\n"); - ksmbd_debug(AUTH, "Cipher type %d\n", sess->conn->cipher_type); + ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type); ksmbd_debug(AUTH, "Session Id %llu\n", sess->id); ksmbd_debug(AUTH, "Session Key %*ph\n", SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key); - if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || - sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { + if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || + conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { ksmbd_debug(AUTH, "ServerIn Key %*ph\n", SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey); ksmbd_debug(AUTH, "ServerOut Key %*ph\n", @@ -857,7 +861,8 @@ static int generate_smb3encryptionkey(struct ksmbd_session *sess, return 0; } -int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess) +int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess) { struct derivation_twin twin; struct derivation *d; @@ -874,10 +879,11 @@ int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess) d->context.iov_base = "ServerIn "; d->context.iov_len = 10; - return generate_smb3encryptionkey(sess, &twin); + return generate_smb3encryptionkey(conn, sess, &twin); } -int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess) +int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess) { struct derivation_twin twin; struct derivation *d; @@ -894,7 +900,7 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess) d->context.iov_base = sess->Preauth_HashValue; d->context.iov_len = 64; - return generate_smb3encryptionkey(sess, &twin); + return generate_smb3encryptionkey(conn, sess, &twin); } int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, |