106 lines
3.3 KiB
Diff
106 lines
3.3 KiB
Diff
From 13cf611fba8e4bcb60b66abb0c2a2456d7863c18 Mon Sep 17 00:00:00 2001
|
|
From: Namjae Jeon <linkinjeon@kernel.org>
|
|
Date: Thu, 27 Mar 2025 21:22:51 +0900
|
|
Subject: ksmbd: fix session use-after-free in multichannel connection
|
|
|
|
There is a race condition between session setup and
|
|
ksmbd_sessions_deregister. The session can be freed before the connection
|
|
is added to channel list of session.
|
|
This patch check reference count of session before freeing it.
|
|
|
|
Cc: stable@vger.kernel.org
|
|
Reported-by: Sean Heelan <seanheelan@gmail.com>
|
|
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
---
|
|
fs/smb/server/auth.c | 4 ++--
|
|
fs/smb/server/mgmt/user_session.c | 14 ++++++++------
|
|
fs/smb/server/smb2pdu.c | 7 ++++---
|
|
3 files changed, 14 insertions(+), 11 deletions(-)
|
|
|
|
--- a/fs/smb/server/auth.c
|
|
+++ b/fs/smb/server/auth.c
|
|
@@ -1016,9 +1016,9 @@ static int ksmbd_get_encryption_key(stru
|
|
|
|
ses_enc_key = enc ? sess->smb3encryptionkey :
|
|
sess->smb3decryptionkey;
|
|
- if (enc)
|
|
- ksmbd_user_session_get(sess);
|
|
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
|
|
+ if (!enc)
|
|
+ ksmbd_user_session_put(sess);
|
|
|
|
return 0;
|
|
}
|
|
--- a/fs/smb/server/mgmt/user_session.c
|
|
+++ b/fs/smb/server/mgmt/user_session.c
|
|
@@ -181,7 +181,7 @@ static void ksmbd_expire_session(struct
|
|
down_write(&sessions_table_lock);
|
|
down_write(&conn->session_lock);
|
|
xa_for_each(&conn->sessions, id, sess) {
|
|
- if (atomic_read(&sess->refcnt) == 0 &&
|
|
+ if (atomic_read(&sess->refcnt) <= 1 &&
|
|
(sess->state != SMB2_SESSION_VALID ||
|
|
time_after(jiffies,
|
|
sess->last_active + SMB2_SESSION_TIMEOUT))) {
|
|
@@ -233,7 +233,8 @@ void ksmbd_sessions_deregister(struct ks
|
|
down_write(&conn->session_lock);
|
|
xa_erase(&conn->sessions, sess->id);
|
|
up_write(&conn->session_lock);
|
|
- ksmbd_session_destroy(sess);
|
|
+ if (atomic_dec_and_test(&sess->refcnt))
|
|
+ ksmbd_session_destroy(sess);
|
|
}
|
|
}
|
|
}
|
|
@@ -252,7 +253,8 @@ void ksmbd_sessions_deregister(struct ks
|
|
if (xa_empty(&sess->ksmbd_chann_list)) {
|
|
xa_erase(&conn->sessions, sess->id);
|
|
hash_del(&sess->hlist);
|
|
- ksmbd_session_destroy(sess);
|
|
+ if (atomic_dec_and_test(&sess->refcnt))
|
|
+ ksmbd_session_destroy(sess);
|
|
}
|
|
}
|
|
up_write(&conn->session_lock);
|
|
@@ -312,8 +314,8 @@ void ksmbd_user_session_put(struct ksmbd
|
|
|
|
if (atomic_read(&sess->refcnt) <= 0)
|
|
WARN_ON(1);
|
|
- else
|
|
- atomic_dec(&sess->refcnt);
|
|
+ else if (atomic_dec_and_test(&sess->refcnt))
|
|
+ ksmbd_session_destroy(sess);
|
|
}
|
|
|
|
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
|
|
@@ -420,7 +422,7 @@ static struct ksmbd_session *__session_c
|
|
xa_init(&sess->rpc_handle_list);
|
|
sess->sequence_number = 1;
|
|
rwlock_init(&sess->tree_conns_lock);
|
|
- atomic_set(&sess->refcnt, 1);
|
|
+ atomic_set(&sess->refcnt, 2);
|
|
|
|
ret = __init_smb2_session(sess);
|
|
if (ret)
|
|
--- a/fs/smb/server/smb2pdu.c
|
|
+++ b/fs/smb/server/smb2pdu.c
|
|
@@ -2239,13 +2239,14 @@ int smb2_session_logoff(struct ksmbd_wor
|
|
return -ENOENT;
|
|
}
|
|
|
|
- ksmbd_destroy_file_table(&sess->file_table);
|
|
down_write(&conn->session_lock);
|
|
sess->state = SMB2_SESSION_EXPIRED;
|
|
up_write(&conn->session_lock);
|
|
|
|
- ksmbd_free_user(sess->user);
|
|
- sess->user = NULL;
|
|
+ if (sess->user) {
|
|
+ ksmbd_free_user(sess->user);
|
|
+ sess->user = NULL;
|
|
+ }
|
|
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
|
|
|
|
rsp->StructureSize = cpu_to_le16(4);
|