Skip to content

Commit

Permalink
ksmbd: fix null pointer dereference in alloc_preauth_hash()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Namjae Jeon authored and Steve French committed Apr 2, 2025
1 parent bf21e29 commit c8b5b7c
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
11 changes: 11 additions & 0 deletions fs/smb/server/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ enum {
KSMBD_SESS_EXITING,
KSMBD_SESS_NEED_RECONNECT,
KSMBD_SESS_NEED_NEGOTIATE,
KSMBD_SESS_NEED_SETUP,
KSMBD_SESS_RELEASING
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions fs/smb/server/mgmt/user_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 11 additions & 3 deletions fs/smb/server/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1909,7 +1917,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
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);
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit c8b5b7c

Please sign in to comment.