126 lines
4.1 KiB
Diff
126 lines
4.1 KiB
Diff
From 21715f2a6462476a4196725e436c4b0d968390ce Mon Sep 17 00:00:00 2001
|
|
From: Namjae Jeon <linkinjeon@kernel.org>
|
|
Date: Wed, 2 Apr 2025 09:11:23 +0900
|
|
Subject: ksmbd: fix null pointer dereference in alloc_preauth_hash()
|
|
|
|
The Client send malformed smb2 negotiate request. ksmbd return error
|
|
response. Subsequently, the client can send smb2 session setup even
|
|
thought conn->preauth_info is not allocated.
|
|
This patch add KSMBD_SESS_NEED_SETUP status of connection to ignore
|
|
session setup request if smb2 negotiate phase is not complete.
|
|
|
|
Cc: stable@vger.kernel.org
|
|
Tested-by: Steve French <stfrench@microsoft.com>
|
|
Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-26505
|
|
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
---
|
|
fs/smb/server/connection.h | 11 +++++++++++
|
|
fs/smb/server/mgmt/user_session.c | 4 ++--
|
|
fs/smb/server/smb2pdu.c | 14 +++++++++++---
|
|
3 files changed, 24 insertions(+), 5 deletions(-)
|
|
|
|
--- a/fs/smb/server/connection.h
|
|
+++ b/fs/smb/server/connection.h
|
|
@@ -27,6 +27,7 @@ enum {
|
|
KSMBD_SESS_EXITING,
|
|
KSMBD_SESS_NEED_RECONNECT,
|
|
KSMBD_SESS_NEED_NEGOTIATE,
|
|
+ KSMBD_SESS_NEED_SETUP,
|
|
KSMBD_SESS_RELEASING
|
|
};
|
|
|
|
@@ -187,6 +188,11 @@ static inline bool ksmbd_conn_need_negot
|
|
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
|
|
}
|
|
|
|
+static inline bool ksmbd_conn_need_setup(struct ksmbd_conn *conn)
|
|
+{
|
|
+ return READ_ONCE(conn->status) == KSMBD_SESS_NEED_SETUP;
|
|
+}
|
|
+
|
|
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
|
|
{
|
|
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
|
|
@@ -217,6 +223,11 @@ static inline void ksmbd_conn_set_need_n
|
|
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
|
|
}
|
|
|
|
+static inline void ksmbd_conn_set_need_setup(struct ksmbd_conn *conn)
|
|
+{
|
|
+ WRITE_ONCE(conn->status, KSMBD_SESS_NEED_SETUP);
|
|
+}
|
|
+
|
|
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
|
|
{
|
|
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);
|
|
--- a/fs/smb/server/mgmt/user_session.c
|
|
+++ b/fs/smb/server/mgmt/user_session.c
|
|
@@ -358,13 +358,13 @@ void destroy_previous_session(struct ksm
|
|
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT);
|
|
err = ksmbd_conn_wait_idle_sess_id(conn, id);
|
|
if (err) {
|
|
- ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE);
|
|
+ ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
|
|
goto out;
|
|
}
|
|
|
|
ksmbd_destroy_file_table(&prev_sess->file_table);
|
|
prev_sess->state = SMB2_SESSION_EXPIRED;
|
|
- ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE);
|
|
+ ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
|
|
ksmbd_launch_ksmbd_durable_scavenger();
|
|
out:
|
|
up_write(&conn->session_lock);
|
|
--- a/fs/smb/server/smb2pdu.c
|
|
+++ b/fs/smb/server/smb2pdu.c
|
|
@@ -1249,7 +1249,7 @@ int smb2_handle_negotiate(struct ksmbd_w
|
|
}
|
|
|
|
conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);
|
|
- ksmbd_conn_set_need_negotiate(conn);
|
|
+ ksmbd_conn_set_need_setup(conn);
|
|
|
|
err_out:
|
|
ksmbd_conn_unlock(conn);
|
|
@@ -1271,6 +1271,9 @@ static int alloc_preauth_hash(struct ksm
|
|
if (sess->Preauth_HashValue)
|
|
return 0;
|
|
|
|
+ if (!conn->preauth_info)
|
|
+ return -ENOMEM;
|
|
+
|
|
sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue,
|
|
PREAUTH_HASHVALUE_SIZE, KSMBD_DEFAULT_GFP);
|
|
if (!sess->Preauth_HashValue)
|
|
@@ -1674,6 +1677,11 @@ int smb2_sess_setup(struct ksmbd_work *w
|
|
|
|
ksmbd_debug(SMB, "Received smb2 session setup request\n");
|
|
|
|
+ if (!ksmbd_conn_need_setup(conn) && !ksmbd_conn_good(conn)) {
|
|
+ work->send_no_response = 1;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
WORK_BUFFERS(work, req, rsp);
|
|
|
|
rsp->StructureSize = cpu_to_le16(9);
|
|
@@ -1913,7 +1921,7 @@ out_err:
|
|
if (try_delay) {
|
|
ksmbd_conn_set_need_reconnect(conn);
|
|
ssleep(5);
|
|
- ksmbd_conn_set_need_negotiate(conn);
|
|
+ ksmbd_conn_set_need_setup(conn);
|
|
}
|
|
}
|
|
smb2_set_err_rsp(work);
|
|
@@ -2247,7 +2255,7 @@ int smb2_session_logoff(struct ksmbd_wor
|
|
ksmbd_free_user(sess->user);
|
|
sess->user = NULL;
|
|
}
|
|
- ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
|
|
+ ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP);
|
|
|
|
rsp->StructureSize = cpu_to_le16(4);
|
|
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
|