</code></pre><pre><code><code>Short description
=================
While one ksmbd worker thread is still executing requests that use
sess>user, another thread that processes an SMB2 LOGOFF for the same
session frees that structure. No synchronisation protects the pointer,
so the first thread dereferences freed memory – a classic
useafterfree that leads to kernel memory corruption and arbitrary code
execution in kernel context.
Affected code path
------------------
1. A second transport is bound to an existing session
(SMB 3.0 or later, `conn->binding == true`).
2. WorkerA (running on connection C2) receives any normal request
(e.g. WRITE).
`smb2_check_user_session()` stores a pointer to the already
existing `struct ksmbd_session` in `work->sess` and
increments the session refcount, **but it does not take
any reference on `sess->user`.**
The pointer to `sess` is kept for the whole request
processing; every helper that needs authentication data
accesses `sess->user` directly.
3. Before WorkerA finishes, WorkerB (running on the first connection
C1) processes an SMB2 LOGOFF for the same session and executes
`smb2_session_logoff()` (smb2pdu.c).
Relevant part of smb2_session_logoff()
--------------------------------------
```c
...
if (sess->user) {
ksmbd_free_user(sess->user); /* (1) frees memory */
sess->user = NULL; /* (2) clear the field */
}
...
```
`ksmbd_free_user()` ultimately ends in simple `kfree(user)`.
4. WorkerB **does not wait for the other connections that are still
using the session**; it only waits for running requests on *its own*
connection (`ksmbd_conn_wait_idle(conn)`).
5. WorkerA continues to execute (e.g. inside `smb2_open()`,
`smb2_write()`, …) and dereferences `sess->user`:
```c
/* examples (many of them) */
if (user_guest(sess->user)) ← dereference after free
ksmbd_compare_user(sess->user, …)
sess->user->uid
```
Because the memory was already `kfree()`ed in step (1) the access is to
freed memory. Depending on exact timing it is either:
a useafterfree (pointer still points into nowreused slab object),
enabling controlled kernelmemory overwrite, or
a NULL–deref (if WorkerA reads after step (2)), still a DoS.
</code></code></pre><pre>