smc_llc_link_active() marks a link active before scheduling its testlink work. The first-link confirmation paths call it without llc_conf_mutex, allowing link-down processing to clear the link between these operations: Connection setup Link-down worker smc_llc_link_active() link->state = SMC_LNK_ACTIVE smcr_link_clear() link->clearing = 1 smc_llc_link_clear() cancel_delayed_work_sync() schedule_delayed_work() The connection reference keeps the link alive during activation, but the newly queued work outlives that reference. Later cleanup skips clearing an already-clearing link, leaving its timer armed when the link group is freed. KASAN reported: BUG: KASAN: use-after-free in __run_timers+0x723/0x8d0 Write of size 8 at addr ffff88810f108810 by task swapper/1/0 Call Trace: __run_timers+0x723/0x8d0 timer_expire_remote+0xd3/0x120 tmigr_handle_remote_up+0x4f4/0xab0 __walk_groups_from+0x40/0x150 tmigr_handle_remote+0x229/0x2c0 run_timer_softirq+0x1f5/0x250 Hold llc_conf_mutex around first-link activation on both sides so that link-down processing cannot cancel the work before it is queued. Also protect the client's initial optional add-link processing, which can activate a second link without the lock. The other add-link paths already hold llc_conf_mutex. This serializes every activation with link teardown without changing the handshake sequence or error handling. Fixes: 877ae5be421d ("net/smc: periodic testlink support") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye --- net/smc/af_smc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index e9f93b3ab435..221643624ace 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -665,8 +665,10 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc) if (rc < 0) return SMC_CLC_DECL_TIMEOUT_CL; + down_write(&link->lgr->llc_conf_mutex); smc_llc_link_active(link); smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE); + up_write(&link->lgr->llc_conf_mutex); if (link->lgr->max_links > 1) { /* optional 2nd link, receive ADD LINK request from server */ @@ -682,7 +684,9 @@ static int smcr_clnt_conf_first_link(struct smc_sock *smc) return rc; } smc_llc_flow_qentry_clr(&link->lgr->llc_flow_lcl); + down_write(&link->lgr->llc_conf_mutex); smc_llc_cli_add_link(link, qentry); + up_write(&link->lgr->llc_conf_mutex); } return 0; } @@ -1909,8 +1913,10 @@ static int smcr_serv_conf_first_link(struct smc_sock *smc) /* confirm_rkey is implicit on 1st contact */ smc->conn.rmb_desc->is_conf_rkey = true; + down_write(&link->lgr->llc_conf_mutex); smc_llc_link_active(link); smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE); + up_write(&link->lgr->llc_conf_mutex); if (link->lgr->max_links > 1) { down_write(&link->lgr->llc_conf_mutex); -- 2.43.0