Since commit 03fc55adf876 ("rxrpc: Only disconnect calls in the I/O thread"), only the I/O thread disconnects a call from its connection channel, and hence, code that completes a call elsewhere must poke it with rxrpc_poke_call(), which queues the call for the I/O thread. rxrpc_abort_eproto(), which aborts a call when a DATA packet fails security verification in recvmsg() or rxrpc_kernel_recv_data(), marks the call as complete but doesn't poke it. The call is then never disconnected, not even when its socket is closed, because rxrpc_propose_abort() skips calls that are already complete. It stays in conn->channels[], and its call->socket pointer, which holds no reference on the socket, dangles once the socket is closed and freed. If the peer then sends an rxgk CHALLENGE on that connection, rxrpc_post_challenge() finds the call and reads the freed socket's flags. If the socket had enabled RXRPC_MANAGE_RESPONSE, the call is then passed to rxrpc_notify_socket_oob(), which takes the freed socket's lock: BUG: KASAN: slab-use-after-free in rxrpc_input_conn_packet+0x3b2/0x820 Read of size 8 at addr ff1100011b343328 by task krxrpcio/21029/1030 ... BUG: KASAN: slab-use-after-free in _raw_spin_lock_irq+0x72/0xe0 Write of size 4 at addr ff1100011b343308 by task krxrpcio/21029/1030 Call Trace: _raw_spin_lock_irq+0x72/0xe0 rxrpc_notify_socket_oob+0x54/0x3f0 rxrpc_input_conn_packet+0x682/0x820 rxrpc_input_packet_on_conn.part.0+0x5f4/0xc30 rxrpc_input_packet.constprop.0+0x8a2/0xea0 rxrpc_io_thread+0x944/0x1570 rxrpc_post_challenge() doesn't appear in the reports because the compiler inlined it into rxrpc_input_conn_packet(). Depending on the freed socket's contents, rxrpc_notify_socket_oob() can also call a function pointer obtained from it (sk->sk_data_ready() or rx->app_ops->notify_oob()). The use-after-free is deterministic, an unprivileged process can trigger it, and since the attacker controls when the CHALLENGE is sent, they can reclaim the freed memory first. These conditions make the bug reliably exploitable to hijack kernel control flow and escalate privileges. Note that without rxgk the stranded call still leaks. A client call pins its connection, so destroying the local endpoint hits the BUG() in rxrpc_destroy_client_conn_ids(); and for any stranded call, netns teardown hangs in rxrpc_destroy_all_calls() waiting for it to be freed. Fix this by poking the call from rxrpc_abort_eproto(), as rxrpc_abort_calls() already does. Fixes: 03fc55adf876 ("rxrpc: Only disconnect calls in the I/O thread") Cc: stable@vger.kernel.org Signed-off-by: Juan Agustin Niccolini --- A deterministic reproducer for the KASAN report above is available on request. A working privilege escalation exploit was sent to security@kernel.org on 20 October, and I can share it with the rxrpc and netdev maintainers upon request. The bug was first reported to the rxrpc maintainers and the security team on 11 October. rxrpc autoloads on Ubuntu, Fedora, and Arch when any process opens an AF_RXRPC socket. net/rxrpc/ar-internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 865f05fe37ab..31528b5e34cb 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -1455,6 +1455,7 @@ static inline int rxrpc_abort_eproto(struct rxrpc_call *call, struct rxrpc_skb_priv *sp = rxrpc_skb(skb); rxrpc_abort_call(call, sp->hdr.seq, abort_code, -EPROTO, why); + rxrpc_poke_call(call, rxrpc_call_poke_abort); return -EPROTO; } base-commit: fafbc4051123d5459ea6950899cec08ed946e278 -- 2.53.0