| From c2f5d6d5fa9488a1bc15c7715ca87d0751f693ab Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 27 Nov 2024 21:30:14 +0800 |
| Subject: net/smc: fix LGR and link use-after-free issue |
| |
| From: Wen Gu <guwen@linux.alibaba.com> |
| |
| [ Upstream commit 2c7f14ed9c19ec0f149479d1c2842ec1f9bf76d7 ] |
| |
| We encountered a LGR/link use-after-free issue, which manifested as |
| the LGR/link refcnt reaching 0 early and entering the clear process, |
| making resource access unsafe. |
| |
| refcount_t: addition on 0; use-after-free. |
| WARNING: CPU: 14 PID: 107447 at lib/refcount.c:25 refcount_warn_saturate+0x9c/0x140 |
| Workqueue: events smc_lgr_terminate_work [smc] |
| Call trace: |
| refcount_warn_saturate+0x9c/0x140 |
| __smc_lgr_terminate.part.45+0x2a8/0x370 [smc] |
| smc_lgr_terminate_work+0x28/0x30 [smc] |
| process_one_work+0x1b8/0x420 |
| worker_thread+0x158/0x510 |
| kthread+0x114/0x118 |
| |
| or |
| |
| refcount_t: underflow; use-after-free. |
| WARNING: CPU: 6 PID: 93140 at lib/refcount.c:28 refcount_warn_saturate+0xf0/0x140 |
| Workqueue: smc_hs_wq smc_listen_work [smc] |
| Call trace: |
| refcount_warn_saturate+0xf0/0x140 |
| smcr_link_put+0x1cc/0x1d8 [smc] |
| smc_conn_free+0x110/0x1b0 [smc] |
| smc_conn_abort+0x50/0x60 [smc] |
| smc_listen_find_device+0x75c/0x790 [smc] |
| smc_listen_work+0x368/0x8a0 [smc] |
| process_one_work+0x1b8/0x420 |
| worker_thread+0x158/0x510 |
| kthread+0x114/0x118 |
| |
| It is caused by repeated release of LGR/link refcnt. One suspect is that |
| smc_conn_free() is called repeatedly because some smc_conn_free() from |
| server listening path are not protected by sock lock. |
| |
| e.g. |
| |
| Calls under socklock | smc_listen_work |
| ------------------------------------------------------- |
| lock_sock(sk) | smc_conn_abort |
| smc_conn_free | \- smc_conn_free |
| \- smcr_link_put | \- smcr_link_put (duplicated) |
| release_sock(sk) |
| |
| So here add sock lock protection in smc_listen_work() path, making it |
| exclusive with other connection operations. |
| |
| Fixes: 3b2dec2603d5 ("net/smc: restructure client and server code in af_smc") |
| Co-developed-by: Guangguan Wang <guangguan.wang@linux.alibaba.com> |
| Signed-off-by: Guangguan Wang <guangguan.wang@linux.alibaba.com> |
| Co-developed-by: Kai <KaiShen@linux.alibaba.com> |
| Signed-off-by: Kai <KaiShen@linux.alibaba.com> |
| Signed-off-by: Wen Gu <guwen@linux.alibaba.com> |
| Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com> |
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/smc/af_smc.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c |
| index d433b88e6a277..1072b32a1d75d 100644 |
| --- a/net/smc/af_smc.c |
| +++ b/net/smc/af_smc.c |
| @@ -1509,6 +1509,7 @@ static void smc_listen_out(struct smc_sock *new_smc) |
| if (tcp_sk(new_smc->clcsock->sk)->syn_smc) |
| atomic_dec(&lsmc->queued_smc_hs); |
| |
| + release_sock(newsmcsk); /* lock in smc_listen_work() */ |
| if (lsmc->sk.sk_state == SMC_LISTEN) { |
| lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); |
| smc_accept_enqueue(&lsmc->sk, newsmcsk); |
| @@ -1921,6 +1922,7 @@ static void smc_listen_work(struct work_struct *work) |
| struct smc_init_info *ini = NULL; |
| int rc = 0; |
| |
| + lock_sock(&new_smc->sk); /* release in smc_listen_out() */ |
| if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN) |
| return smc_listen_out_err(new_smc); |
| |
| -- |
| 2.43.0 |
| |