Merge tag 'v6.15-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix three potential use after frees: in session logoff, in krb5 auth,
   and in RPC open

 - Fix missing rc check in session setup authentication

* tag 'v6.15-rc4-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix use-after-free in session logoff
  ksmbd: fix use-after-free in kerberos authentication
  ksmbd: fix use-after-free in ksmbd_session_rpc_open
  smb: server: smb2pdu: check return value of xa_store()
This commit is contained in:
Linus Torvalds
2025-04-28 16:56:01 -07:00
4 changed files with 35 additions and 18 deletions
+13 -1
View File
@@ -550,7 +550,19 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
retval = -ENOMEM;
goto out;
}
sess->user = user;
if (!sess->user) {
/* First successful authentication */
sess->user = user;
} else {
if (!ksmbd_compare_user(sess->user, user)) {
ksmbd_debug(AUTH, "different user tried to reuse session\n");
retval = -EPERM;
ksmbd_free_user(user);
goto out;
}
ksmbd_free_user(user);
}
memcpy(sess->sess_key, resp->payload, resp->session_key_len);
memcpy(out_blob, resp->payload + resp->session_key_len,
+14 -6
View File
@@ -59,10 +59,12 @@ static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
struct ksmbd_session_rpc *entry;
long index;
down_write(&sess->rpc_lock);
xa_for_each(&sess->rpc_handle_list, index, entry) {
xa_erase(&sess->rpc_handle_list, index);
__session_rpc_close(sess, entry);
}
up_write(&sess->rpc_lock);
xa_destroy(&sess->rpc_handle_list);
}
@@ -92,7 +94,7 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
{
struct ksmbd_session_rpc *entry, *old;
struct ksmbd_rpc_command *resp;
int method;
int method, id;
method = __rpc_method(rpc_name);
if (!method)
@@ -102,26 +104,29 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
if (!entry)
return -ENOMEM;
down_read(&sess->rpc_lock);
entry->method = method;
entry->id = ksmbd_ipc_id_alloc();
if (entry->id < 0)
entry->id = id = ksmbd_ipc_id_alloc();
if (id < 0)
goto free_entry;
old = xa_store(&sess->rpc_handle_list, entry->id, entry, KSMBD_DEFAULT_GFP);
old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
if (xa_is_err(old))
goto free_id;
resp = ksmbd_rpc_open(sess, entry->id);
resp = ksmbd_rpc_open(sess, id);
if (!resp)
goto erase_xa;
up_read(&sess->rpc_lock);
kvfree(resp);
return entry->id;
return id;
erase_xa:
xa_erase(&sess->rpc_handle_list, entry->id);
free_id:
ksmbd_rpc_id_free(entry->id);
free_entry:
kfree(entry);
up_read(&sess->rpc_lock);
return -EINVAL;
}
@@ -129,9 +134,11 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
{
struct ksmbd_session_rpc *entry;
down_write(&sess->rpc_lock);
entry = xa_erase(&sess->rpc_handle_list, id);
if (entry)
__session_rpc_close(sess, entry);
up_write(&sess->rpc_lock);
}
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
@@ -439,6 +446,7 @@ static struct ksmbd_session *__session_create(int protocol)
sess->sequence_number = 1;
rwlock_init(&sess->tree_conns_lock);
atomic_set(&sess->refcnt, 2);
init_rwsem(&sess->rpc_lock);
ret = __init_smb2_session(sess);
if (ret)
+1
View File
@@ -63,6 +63,7 @@ struct ksmbd_session {
rwlock_t tree_conns_lock;
atomic_t refcnt;
struct rw_semaphore rpc_lock;
};
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
+7 -11
View File
@@ -1445,7 +1445,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
{
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
struct channel *chann = NULL;
struct channel *chann = NULL, *old;
struct ksmbd_user *user;
u64 prev_id;
int sz, rc;
@@ -1557,7 +1557,12 @@ binding_session:
return -ENOMEM;
chann->conn = conn;
xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP);
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
KSMBD_DEFAULT_GFP);
if (xa_is_err(old)) {
kfree(chann);
return xa_err(old);
}
}
}
@@ -1602,11 +1607,6 @@ static int krb5_authenticate(struct ksmbd_work *work,
if (prev_sess_id && prev_sess_id != sess->id)
destroy_previous_session(conn, sess->user, prev_sess_id);
if (sess->state == SMB2_SESSION_VALID) {
ksmbd_free_user(sess->user);
sess->user = NULL;
}
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
out_blob, &out_len);
if (retval) {
@@ -2249,10 +2249,6 @@ int smb2_session_logoff(struct ksmbd_work *work)
sess->state = SMB2_SESSION_EXPIRED;
up_write(&conn->session_lock);
if (sess->user) {
ksmbd_free_user(sess->user);
sess->user = NULL;
}
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_SETUP);
rsp->StructureSize = cpu_to_le16(4);