From: Namjae Jeon linkinjeon@kernel.org
mainline inclusion from mainline-6.0-rc1 commit 8e06b31e348107c5d78e2c90bb7e69388cb97fb6 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I60T7G CVE: NA
Reference: https://git.kernel.org/torvalds/linux/c/8e06b31e3481
-------------------------------
Add missing rwlock for channel list in session.
Signed-off-by: Namjae Jeon linkinjeon@kernel.org Reviewed-by: Hyunchul Lee hyc.lee@gmail.com Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- fs/ksmbd/mgmt/user_session.c | 3 +++ fs/ksmbd/mgmt/user_session.h | 1 + fs/ksmbd/smb2pdu.c | 20 ++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/fs/ksmbd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c index 8d8ffd8c6f19..e963433a645c 100644 --- a/fs/ksmbd/mgmt/user_session.c +++ b/fs/ksmbd/mgmt/user_session.c @@ -32,11 +32,13 @@ static void free_channel_list(struct ksmbd_session *sess) { struct channel *chann, *tmp;
+ write_lock(&sess->chann_lock); list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, chann_list) { list_del(&chann->chann_list); kfree(chann); } + write_unlock(&sess->chann_lock); }
static void __session_rpc_close(struct ksmbd_session *sess, @@ -320,6 +322,7 @@ static struct ksmbd_session *__session_create(int protocol) INIT_LIST_HEAD(&sess->rpc_handle_list); sess->sequence_number = 1; atomic_set(&sess->refcnt, 1); + rwlock_init(&sess->chann_lock);
switch (protocol) { case CIFDS_SESSION_FLAG_SMB2: diff --git a/fs/ksmbd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h index e241f16a3851..67f5c4106528 100644 --- a/fs/ksmbd/mgmt/user_session.h +++ b/fs/ksmbd/mgmt/user_session.h @@ -48,6 +48,7 @@ struct ksmbd_session { char sess_key[CIFS_KEY_SIZE];
struct hlist_node hlist; + rwlock_t chann_lock; struct list_head ksmbd_chann_list; struct xarray tree_conns; struct ida tree_conn_ida; diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index f118cbf00cac..39a49010e3b9 100644 --- a/fs/ksmbd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -1509,7 +1509,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
binding_session: if (conn->dialect >= SMB30_PROT_ID) { + read_lock(&sess->chann_lock); chann = lookup_chann_list(sess, conn); + read_unlock(&sess->chann_lock); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) @@ -1517,7 +1519,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
chann->conn = conn; INIT_LIST_HEAD(&chann->chann_list); + write_lock(&sess->chann_lock); list_add(&chann->chann_list, &sess->ksmbd_chann_list); + write_unlock(&sess->chann_lock); } }
@@ -1591,7 +1595,9 @@ static int krb5_authenticate(struct ksmbd_work *work) }
if (conn->dialect >= SMB30_PROT_ID) { + read_lock(&sess->chann_lock); chann = lookup_chann_list(sess, conn); + read_unlock(&sess->chann_lock); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) @@ -1599,7 +1605,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
chann->conn = conn; INIT_LIST_HEAD(&chann->chann_list); + write_lock(&sess->chann_lock); list_add(&chann->chann_list, &sess->ksmbd_chann_list); + write_unlock(&sess->chann_lock); } }
@@ -8303,10 +8311,14 @@ int smb3_check_sign_req(struct ksmbd_work *work) if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; } else { + read_lock(&work->sess->chann_lock); chann = lookup_chann_list(work->sess, conn); - if (!chann) + if (!chann) { + read_unlock(&work->sess->chann_lock); return 0; + } signing_key = chann->smb3signingkey; + read_unlock(&work->sess->chann_lock); }
if (!signing_key) { @@ -8366,10 +8378,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; } else { + read_lock(&work->sess->chann_lock); chann = lookup_chann_list(work->sess, work->conn); - if (!chann) + if (!chann) { + read_unlock(&work->sess->chann_lock); return; + } signing_key = chann->smb3signingkey; + read_unlock(&work->sess->chann_lock); }
if (!signing_key)