]> www.infradead.org Git - nvme.git/commitdiff
ksmbd: fix null pointer dereference in alloc_preauth_hash()
authorNamjae Jeon <linkinjeon@kernel.org>
Wed, 2 Apr 2025 00:11:23 +0000 (09:11 +0900)
committerSteve French <stfrench@microsoft.com>
Wed, 2 Apr 2025 04:02:20 +0000 (23:02 -0500)
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
fs/smb/server/mgmt/user_session.c
fs/smb/server/smb2pdu.c

index 91c2318639e76646ee1706bf2fb93c51bdeefb29..14620e147dda570bc8d48b48250aad5438d5d75d 100644 (file)
@@ -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_negotiate(struct ksmbd_conn *conn)
        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_negotiate(struct ksmbd_conn *conn)
        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);
index 7690f0187dac5fe429cb74287730c2072270a1ed..3f45f28f6f0f8e07179f61d595fb7e3fc56f7b28 100644 (file)
@@ -374,13 +374,13 @@ void destroy_previous_session(struct ksmbd_conn *conn,
        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);
index f3ca33d3b69a3093c603cf4152712750d0fca132..d24d95d15d876b325d25d7ca250503e889c3867c 100644 (file)
@@ -1249,7 +1249,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
        }
 
        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 ksmbd_session *sess,
        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 *work)
 
        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);
@@ -1909,7 +1917,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);
@@ -2243,7 +2251,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
                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));