mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
smc_cdc_rx_handler() looks up the connection by token under the link
group's conns_lock, drops the lock, and then dereferences conn and the
smc_sock derived from it, ending in sock_hold(&smc->sk) inside
smc_cdc_msg_recv(). No reference is held across the lock release.
The only reference pinning the socket while the connection is
discoverable in the link group is taken in smc_lgr_register_conn()
(sock_hold) and dropped in __smc_lgr_unregister_conn() (sock_put), both
under conns_lock. Once the handler drops conns_lock, a concurrent
close() -> smc_release() -> smc_conn_free() -> smc_lgr_unregister_conn()
can drop that reference and free the smc_sock, so the handler's later
sock_hold() runs on freed memory:
WARNING: lib/refcount.c:25 at refcount_warn_saturate
Workqueue: rxe_wq do_work
refcount_warn_saturate (lib/refcount.c:25)
smc_cdc_msg_recv (net/smc/smc_cdc.c:430)
smc_cdc_rx_handler (net/smc/smc_cdc.c:502)
smc_wr_rx_tasklet_fn (net/smc/smc_wr.c:445)
tasklet_action_common (kernel/softirq.c:938)
handle_softirqs (kernel/softirq.c:622)
Kernel panic - not syncing: panic_on_warn set
Only SMC-R is affected. The SMC-D receive tasklet is stopped by
tasklet_kill(&conn->rx_tsklet) in smc_conn_free() before the connection
is unregistered, so it cannot run concurrently with the free.
Take the socket reference while still holding conns_lock, so the
registration reference can no longer be the last one, and drop it once
the handler is done.
Fixes:
|
||
|---|---|---|
| .. | ||
| af_smc.c | ||
| Kconfig | ||
| Makefile | ||
| smc_cdc.c | ||
| smc_cdc.h | ||
| smc_clc.c | ||
| smc_clc.h | ||
| smc_close.c | ||
| smc_close.h | ||
| smc_core.c | ||
| smc_core.h | ||
| smc_diag.c | ||
| smc_hs_bpf.c | ||
| smc_hs_bpf.h | ||
| smc_ib.c | ||
| smc_ib.h | ||
| smc_inet.c | ||
| smc_inet.h | ||
| smc_ism.c | ||
| smc_ism.h | ||
| smc_llc.c | ||
| smc_llc.h | ||
| smc_netlink.c | ||
| smc_netlink.h | ||
| smc_netns.h | ||
| smc_pnet.c | ||
| smc_pnet.h | ||
| smc_rx.c | ||
| smc_rx.h | ||
| smc_stats.c | ||
| smc_stats.h | ||
| smc_sysctl.c | ||
| smc_sysctl.h | ||
| smc_tracepoint.c | ||
| smc_tracepoint.h | ||
| smc_tx.c | ||
| smc_tx.h | ||
| smc_wr.c | ||
| smc_wr.h | ||
| smc.h | ||