* [PATCH v2 0/2] tipc: fix topology server teardown @ 2026-10-04 21:00 Jérémy Jean 2026-10-04 21:00 ` [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown Jérémy Jean 2026-10-04 21:00 ` [PATCH v2 2/2] tipc: fix use-after-free in netns teardown Jérémy Jean 0 siblings, 2 replies; 7+ messages in thread From: Jérémy Jean @ 2026-10-04 21:00 UTC (permalink / raw) To: Tung Quang Nguyen, Jon Maloy Cc: netdev, tipc-discussion, linux-kernel, Jérémy Jean This series fixes a connection UAF and a NULL-socket dereference during topology-server teardown. Changes since v1, addressing Sashiko's review: - Add guard to con->sock to fix NULL dereference. - Walk forward through conn_idr before draining the workqueues. v1: https://lore.kernel.org/all/20261003192530.2414682-2-Jeremy.Jean@oss.cyber.gouv.fr/ Jérémy Jean (2): tipc: skip socketless connections in topsrv teardown tipc: fix use-after-free in netns teardown net/tipc/topsrv.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) -- 2.47.3 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown 2026-10-04 21:00 [PATCH v2 0/2] tipc: fix topology server teardown Jérémy Jean @ 2026-10-04 21:00 ` Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko 2026-10-04 21:00 ` [PATCH v2 2/2] tipc: fix use-after-free in netns teardown Jérémy Jean 1 sibling, 2 replies; 7+ messages in thread From: Jérémy Jean @ 2026-10-04 21:00 UTC (permalink / raw) To: Tung Quang Nguyen, Jon Maloy Cc: netdev, tipc-discussion, linux-kernel, Jérémy Jean, stable Kernel subscription connections have no socket but can remain in conn_idr after unsubscribe while send work is pending. Skip tipc_conn_close() for these entries to avoid a NULL dereference during netns teardown. Fixes: e88f2be83282 ("tipc: fix race condition at topology server receive") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> --- net/tipc/topsrv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index af530c9..01dd34b 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c @@ -706,7 +706,8 @@ static void tipc_topsrv_stop(struct net *net) if (con) { conn_get(con); spin_unlock_bh(&srv->idr_lock); - tipc_conn_close(con); + if (con->sock) + tipc_conn_close(con); conn_put(con); spin_lock_bh(&srv->idr_lock); } -- 2.47.3 ^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown 2026-10-04 21:00 ` [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown Jérémy Jean @ 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ messages in thread From: Tung Quang Nguyen @ 2026-10-05 1:45 UTC (permalink / raw) To: Jérémy Jean Cc: netdev, tipc-discussion, linux-kernel, stable, Jon Maloy >Subject: [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown > >Kernel subscription connections have no socket but can remain in conn_idr >after unsubscribe while send work is pending. > >Skip tipc_conn_close() for these entries to avoid a NULL dereference during >netns teardown. > This does not fix the root cause. I fixed the issue in this patch: https://git.kernel.org/netdev/net/c/3acdd44385bc Please update your net tree to check out the fix. -- pw-bot: rejected ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown 2026-10-04 21:00 ` [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen @ 2026-10-05 21:03 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-05 21:03 UTC (permalink / raw) To: Jeremy.Jean Cc: tung.quang.nguyen, jmaloy, netdev, tipc-discussion, linux-kernel, stable, kuba Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider. Critical: 0 · High: 1 (2) · Medium: 0 · Low: 0 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] This patch is not complete on its own. Pre-existing issues: - [High] This problem wasn't introduced by this patch, but the same livelock already exists for socket-backed conns. - [High] This problem wasn't introduced by this patch, but tipc_topsrv_stop() calls conn_get() (plain kref_get()) on any conn… -- tipc: skip socketless connections in topsrv teardown This patch makes tipc_topsrv_stop() skip tipc_conn_close() for kernel subscription connections, which have no socket. These connections can stay in conn_idr after unsubscribe while send work is still pending. Calling tipc_conn_close() on them dereferences a NULL con->sock during netns teardown. > diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c > index af530c9ed8402..01dd34b758f4b 100644 > --- a/net/tipc/topsrv.c > +++ b/net/tipc/topsrv.c > @@ -706,7 +706,8 @@ static void tipc_topsrv_stop(struct net *net) > if (con) { > conn_get(con); > spin_unlock_bh(&srv->idr_lock); > - tipc_conn_close(con); > + if (con->sock) > + tipc_conn_close(con); > conn_put(con); > spin_lock_bh(&srv->idr_lock); > } [Severity: High] This avoids the NULL dereference. In the scenario from the commit message, though, can netns teardown still stall and then hit a use-after-free on con? In that scenario, tipc_topsrv_queue_evt() passes its lookup reference to con->swork: if (queue_work(srv->send_wq, &con->swork)) return; tipc_topsrv_kern_unsubscr() then drops its two references: test_and_clear_bit(CF_CONNECTED, &con->flags); tipc_conn_delete_sub(con, NULL); conn_put(con); conn_put(con); After that, the pending swork holds the last reference. At this commit the loop in tipc_topsrv_stop() is: spin_lock_bh(&srv->idr_lock); for (id = 0; srv->idr_in_use; id++) { con = idr_find(&srv->conn_idr, id); if (con) { [ ... ] With the new check, the socketless conn gets conn_get() and conn_put(), which leaves the refcount at 1. The loop then retakes idr_lock and moves on. idr_find() returns NULL for every higher id. So idr_lock stays held with BH disabled and no cond_resched(). Meanwhile the send_wq worker runs: tipc_conn_send_work() conn_put(con) tipc_conn_kref_release() spin_lock_bh(&s->idr_lock); <- blocks on the stop loop tipc_conn_kref_release() is the only place that calls idr_remove() and decrements s->idr_in_use. So the loop only ends after int id wraps around, which takes about 2^32 lookups under the spinlock. Won't that cause soft lockup and RCU stall warnings? When id gets back to the conn's slot, conn_get() raises a zero refcount. After spin_unlock_bh(), the release path calls kfree(con). The stop path then reads con->sock and calls conn_put() on freed memory. The path is reachable from an unprivileged user in a user+net namespace: 1. TIPC_GROUP_JOIN (tipc_group_create()->tipc_topsrv_kern_subscr()). 2. Leave the group or close the socket while topology events are queued (tipc_group_delete()->tipc_topsrv_kern_unsubscr()). 3. Tear down the netns. The later patch in this series, "tipc: fix use-after-free in netns teardown", fixes this. Its loop uses idr_get_next_ul() with kref_get_unless_zero() and drops idr_lock with cond_resched() on every iteration. Remaining work references are left to tipc_topsrv_work_stop(). So the problem only exists at this commit. The two patches carry different Fixes: tags. Could that cause trouble for bisection, or for stable trees that take this patch without the follow-up? [Severity: High] This isn't a bug introduced by this patch, but the same livelock looks possible for socket-backed conns too. Suppose recv or send work already cleared CF_CONNECTED through tipc_conn_close(), while rwork or swork still holds a reference. The call to tipc_conn_close() from the stop loop then returns early without a conn_put(): disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags); [ ... ] if (!disconnect) return; The loop's own conn_get()/conn_put() pair leaves the work's reference in place. The loop then scans empty ids under idr_lock, waiting for idr_in_use to reach 0. The worker's final conn_put()->tipc_conn_kref_release() blocks in spin_lock_bh(&s->idr_lock). Can idr_in_use ever drop while the stop loop spins? The later patch in this series, "tipc: fix use-after-free in netns teardown", also fixes this. With it, the loop ends when idr_get_next_ul() returns NULL and drops idr_lock on every iteration. [Severity: High] This is a pre-existing issue, but can the conn_get() here bring back a zero refcount? conn_get() is a plain kref_get(): static void conn_get(struct tipc_conn *con) { kref_get(&con->kref); } tipc_conn_lookup() uses kref_get_unless_zero() instead. Say a final conn_put() from rwork, swork or tipc_conn_close() runs on another CPU while the stop loop holds idr_lock. The conn is then still visible in conn_idr with a refcount of 0: CPU1 CPU2 tipc_topsrv_stop() spin_lock_bh(&srv->idr_lock) conn_put(con) tipc_conn_kref_release() spin_lock_bh(&s->idr_lock) (blocks) con = idr_find(&srv->conn_idr, id) conn_get(con) <- refcount from 0 spin_unlock_bh(&srv->idr_lock) idr_remove(&s->conn_idr, ...) [ ... ] kfree(con) if (con->sock) <- freed memory tipc_conn_close(con) conn_put(con) Before this patch, tipc_conn_close() already dereferenced con->sock->sk on the same freed object. The new con->sock read touches the same memory. This seems to match the KASAN slab-use-after-free described in the next patch in the series, "tipc: fix use-after-free in netns teardown". That patch replaces conn_get() with kref_get_unless_zero() under idr_lock and sets con = NULL when it fails. -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261004210016.3051310-1-Jeremy.Jean%40oss.cyber.gouv.fr ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] tipc: fix use-after-free in netns teardown 2026-10-04 21:00 [PATCH v2 0/2] tipc: fix topology server teardown Jérémy Jean 2026-10-04 21:00 ` [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown Jérémy Jean @ 2026-10-04 21:00 ` Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko 1 sibling, 2 replies; 7+ messages in thread From: Jérémy Jean @ 2026-10-04 21:00 UTC (permalink / raw) To: Tung Quang Nguyen, Jon Maloy Cc: netdev, tipc-discussion, linux-kernel, Jérémy Jean, stable conn_put() decreases the reference count of a connection, and when it reaches zero, tipc_conn_kref_release() removes the connection from conn_idr and frees it. Removing the entry is protected by idr_lock, but decreasing the count is not. During netns dismantle, it may happen that a connection gets its count dropped to zero by conn_put() while tipc_topsrv_stop() still holds the lock idr_lock. tipc_topsrv_stop() calls conn_get() on that connection whose count is already zero, and then releases idr_lock. tipc_conn_kref_release() can then free the connection before tipc_conn_close() uses it. KASAN reports a UAF as: BUG: KASAN: slab-use-after-free in tipc_conn_close (net/tipc/topsrv.c:158) Read of size 8 at addr ff1100000cf4f408 by task kworker/u16:3/70 Stop accepting connections before walking conn_idr. Use kref_get_unless_zero() to avoid taking references when the count is zero. Walk forward through conn_idr to disconnect all connections before draining the workqueues. Fixes: 667eeab4999e ("tipc: Fix use-after-free in tipc_conn_close().") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> --- net/tipc/topsrv.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index 01dd34b..f3f32fd 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c @@ -698,19 +698,25 @@ static void tipc_topsrv_stop(struct net *net) struct tipc_topsrv *srv = tipc_topsrv(net); struct socket *lsock = srv->listener; struct tipc_conn *con; - int id; + unsigned long id; + + write_lock_bh(&lsock->sk->sk_callback_lock); + lsock->sk->sk_user_data = NULL; + write_unlock_bh(&lsock->sk->sk_callback_lock); + cancel_work_sync(&srv->awork); spin_lock_bh(&srv->idr_lock); - for (id = 0; srv->idr_in_use; id++) { - con = idr_find(&srv->conn_idr, id); + for (id = 0; (con = idr_get_next_ul(&srv->conn_idr, &id)); id++) { + if (!kref_get_unless_zero(&con->kref)) + con = NULL; + spin_unlock_bh(&srv->idr_lock); if (con) { - conn_get(con); - spin_unlock_bh(&srv->idr_lock); if (con->sock) tipc_conn_close(con); conn_put(con); - spin_lock_bh(&srv->idr_lock); } + cond_resched(); + spin_lock_bh(&srv->idr_lock); } __module_get(lsock->ops->owner); __module_get(lsock->sk->sk_prot_creator->owner); -- 2.47.3 ^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH v2 2/2] tipc: fix use-after-free in netns teardown 2026-10-04 21:00 ` [PATCH v2 2/2] tipc: fix use-after-free in netns teardown Jérémy Jean @ 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ messages in thread From: Tung Quang Nguyen @ 2026-10-05 1:45 UTC (permalink / raw) To: Jérémy Jean Cc: netdev, tipc-discussion, linux-kernel, stable, Jon Maloy >Subject: [PATCH v2 2/2] tipc: fix use-after-free in netns teardown > >conn_put() decreases the reference count of a connection, and when it >reaches zero, tipc_conn_kref_release() removes the connection from conn_idr >and frees it. Removing the entry is protected by idr_lock, but decreasing the >count is not. > >During netns dismantle, it may happen that a connection gets its count >dropped to zero by conn_put() while tipc_topsrv_stop() still holds the lock >idr_lock. tipc_topsrv_stop() calls conn_get() on that connection whose count is >already zero, and then releases idr_lock. >tipc_conn_kref_release() can then free the connection before >tipc_conn_close() uses it. KASAN reports a UAF as: > > BUG: KASAN: slab-use-after-free in tipc_conn_close (net/tipc/topsrv.c:158) > Read of size 8 at addr ff1100000cf4f408 by task kworker/u16:3/70 > >Stop accepting connections before walking conn_idr. Use >kref_get_unless_zero() to avoid taking references when the count is zero. >Walk forward through conn_idr to disconnect all connections before draining >the workqueues. This does not fix the root cause. I fixed the issue in this patch: https://git.kernel.org/netdev/net/c/3acdd44385bc Please update your net tree to check out the fix. -- pw-bot: rejected ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] tipc: fix use-after-free in netns teardown 2026-10-04 21:00 ` [PATCH v2 2/2] tipc: fix use-after-free in netns teardown Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen @ 2026-10-05 21:03 ` netdev-bot+sashiko 1 sibling, 0 replies; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-05 21:03 UTC (permalink / raw) To: Jeremy.Jean Cc: tung.quang.nguyen, jmaloy, netdev, tipc-discussion, linux-kernel, stable, kuba Thank you for your contribution! Sashiko AI review found more severe issue(s) in other patches of this series. This mail is only an FYI, in case you want to address the nit picks below when you respin. Low priority / nit picks for your consideration: - [Low] After this patch, `struct tipc_topsrv::idr_in_use` is dead state. -- tipc: fix use-after-free in netns teardown This patch stops the listener and cancels the accept work before tipc_topsrv_stop() walks conn_idr. The walk now goes forward with idr_get_next_ul() and uses kref_get_unless_zero(), so it no longer takes a reference on a connection whose count has already reached zero. Connections are disconnected before the workqueues are drained. > diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c > index 01dd34b758f4b..f3f32fd8134ac 100644 > --- a/net/tipc/topsrv.c > +++ b/net/tipc/topsrv.c [ ... ] > spin_lock_bh(&srv->idr_lock); > - for (id = 0; srv->idr_in_use; id++) { > - con = idr_find(&srv->conn_idr, id); > + for (id = 0; (con = idr_get_next_ul(&srv->conn_idr, &id)); id++) { [Severity: Low] This isn't a bug, but this loop condition was the only place that read srv->idr_in_use. Is the field still needed after this change? It is still declared and documented in struct tipc_topsrv: * @idr_in_use: amount of allocated identifier entry ... int idr_in_use; It is also still written under idr_lock. It is set to 0 in tipc_topsrv_start(), incremented in tipc_conn_alloc() and decremented in tipc_conn_kref_release(): s->idr_in_use++; ... s->idr_in_use--; Nothing reads it now. I checked whether dropping the old termination condition removes a guarantee that all connections are gone before kfree(srv), and it does not appear to. tipc_conn_close() unsubscribes synchronously via tipc_conn_delete_sub() ->tipc_sub_unsubscribe() before it drops its reference. That unsubscribe serializes on sc->lock and calls timer_delete_sync(). The get/put pairs in tipc_conn_data_ready() and tipc_conn_write_space() are bounded by sk_callback_lock. The remaining final puts run from rcv_wq/send_wq, and tipc_topsrv_work_stop() drains those. The old loop also held idr_lock while stepping over empty ids, so it could not act as a wait-for-empty barrier anyway. Could the field and its kernel-doc entry be removed in this patch? If it is kept, could the commit message say that the old idr_in_use termination condition was dropped on purpose? > + if (!kref_get_unless_zero(&con->kref)) > + con = NULL; > + spin_unlock_bh(&srv->idr_lock); > if (con) { [ ... ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261004210016.3051310-1-Jeremy.Jean%40oss.cyber.gouv.fr ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-05 21:03 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-04 21:00 [PATCH v2 0/2] tipc: fix topology server teardown Jérémy Jean 2026-10-04 21:00 ` [PATCH v2 1/2] tipc: skip socketless connections in topsrv teardown Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko 2026-10-04 21:00 ` [PATCH v2 2/2] tipc: fix use-after-free in netns teardown Jérémy Jean 2026-10-05 1:45 ` Tung Quang Nguyen 2026-10-05 21:03 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®