Netdev List
 help / color / mirror / Atom feed
* [PATCH v2 net 0/2] tipc: syzbot related fixes
@ 2026-06-23 17:30 Eric Dumazet
  2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Eric Dumazet @ 2026-06-23 17:30 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion, netdev, eric.dumazet, Eric Dumazet

First patch fixes a recent syzbot report.

Second patch is inspired by numerous syzbot soft lockup
reports with RTNL pressure.

Eric Dumazet (2):
  tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  tipc: avoid busy looping in tipc_exit_net()

 net/tipc/core.c      |  4 ++--
 net/tipc/udp_media.c | 19 ++++++++++++++-----
 2 files changed, 16 insertions(+), 7 deletions(-)

-- 
2.55.0.rc0.799.gd6f94ed593-goog


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  2026-06-23 17:30 [PATCH v2 net 0/2] tipc: syzbot related fixes Eric Dumazet
@ 2026-06-23 17:30 ` Eric Dumazet
  2026-06-24 12:04   ` Tung Quang Nguyen
  2026-06-24 18:37   ` Xin Long
  2026-06-23 17:30 ` [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net() Eric Dumazet
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 11+ messages in thread
From: Eric Dumazet @ 2026-06-23 17:30 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion, netdev, eric.dumazet, Eric Dumazet,
	syzbot+e14bc5d4942756023b77

TIPC UDP media bearer teardown calls dst_cache_destroy() on its
replicast caches before calling synchronize_net() to wait for
concurrent RCU readers (transmitters) to finish:

static void cleanup_bearer(struct work_struct *work)
{
...
	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
		dst_cache_destroy(&rcast->dst_cache);
		list_del_rcu(&rcast->list);
		kfree_rcu(rcast, rcu);
	}
...
	dst_cache_destroy(&ub->rcast.dst_cache);
	udp_tunnel_sock_release(ub->sk);
	synchronize_net();
...
}

This is highly buggy because dst_cache_destroy() immediately frees the
per-CPU cache memory (free_percpu()) and releases the cached dst
entries without any synchronization.

If a concurrent transmitter (e.g., tipc_udp_xmit()) is running on another
CPU under RCU protection, it can call dst_cache_get() concurrently,
leading to:
1. Use-After-Free on the per-CPU cache pointer itself (crash).
2. "rcuref - imbalanced put()" warning if it attempts to release a
   dst that was concurrently released by dst_cache_destroy().

Furthermore, calling kfree(ub) immediately after synchronize_net() without
closing the socket first (or waiting after closing it) leaves a window
where a concurrent receiver (tipc_udp_recv()) could start after
synchronize_net(), access ub, and suffer a UAF when kfree(ub) runs.

To fix this, we must defer dst_cache_destroy() and kfree(ub) until after
we have ensured that no more readers can see the bearer/socket and all
existing readers have finished:

1. Defer rcast entry destruction (both dst_cache_destroy() and kfree())
   to an RCU callback using call_rcu_hurry().
   Using call_rcu_hurry() ensures the dst entries are released quickly.

2. Release the bearer socket using udp_tunnel_sock_release() (stops
   new receive readers).

3. Call synchronize_net() to wait for all outstanding RCU readers
   (both transmit and receive) to finish.

4. Now that it is safe, call dst_cache_destroy() on the main bearer
   cache, and free ub.

Note: 3) and 4) can be changed later in net-next to also use
call_rcu_hurry() and get rid of the synchronize_net() latency.

Fixes: e9c1a793210f ("tipc: add dst_cache support for udp media")
Reported-by: syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a396a66.52ae72c2.136ac7.0003.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Xin Long <lucien.xin@gmail.com>
Cc: Jon Maloy <jmaloy@redhat.com>
Cc: tipc-discussion@lists.sourceforge.net
---
v2: addressed Xin Long feedback
v1: https://lore.kernel.org/netdev/CANn89i+dkbrSAwvaWXW7yWMfcwUebuTBLG5T7AGZaZcpVYGyfQ@mail.gmail.com/T/#m7bbeedffe3bedb69e33236410e3833c7ce809850
 net/tipc/udp_media.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 988b8a7f953ad6da860e6190f1f244650f121dce..66f3cb87a0aaaac8f40e8f237ab9a44d539b1cd8 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -803,6 +803,14 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
 	return err;
 }
 
+static void rcast_free_rcu(struct rcu_head *rcu)
+{
+	struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu);
+
+	dst_cache_destroy(&rcast->dst_cache);
+	kfree(rcast);
+}
+
 /* cleanup_bearer - break the socket/bearer association */
 static void cleanup_bearer(struct work_struct *work)
 {
@@ -811,18 +819,17 @@ static void cleanup_bearer(struct work_struct *work)
 	struct tipc_net *tn;
 
 	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
-		dst_cache_destroy(&rcast->dst_cache);
 		list_del_rcu(&rcast->list);
-		kfree_rcu(rcast, rcu);
+		call_rcu_hurry(&rcast->rcu, rcast_free_rcu);
 	}
 
 	tn = tipc_net(sock_net(ub->sk));
 
-	dst_cache_destroy(&ub->rcast.dst_cache);
 	udp_tunnel_sock_release(ub->sk);
 
-	/* Note: could use a call_rcu() to avoid another synchronize_net() */
 	synchronize_net();
+
+	dst_cache_destroy(&ub->rcast.dst_cache);
 	atomic_dec(&tn->wq_count);
 	kfree(ub);
 }
-- 
2.55.0.rc0.799.gd6f94ed593-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net()
  2026-06-23 17:30 [PATCH v2 net 0/2] tipc: syzbot related fixes Eric Dumazet
  2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
@ 2026-06-23 17:30 ` Eric Dumazet
  2026-06-24 12:07   ` Tung Quang Nguyen
  2026-06-24 19:07 ` [PATCH v2 net 0/2] tipc: syzbot related fixes Xin Long
  2026-06-25 16:20 ` patchwork-bot+netdevbpf
  3 siblings, 1 reply; 11+ messages in thread
From: Eric Dumazet @ 2026-06-23 17:30 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion, netdev, eric.dumazet, Eric Dumazet

Blamed commit introduced a busy-wait loop in tipc_exit_net()
to wait for pending UDP bearer cleanup works to complete:

       while (atomic_read(&tn->wq_count))
               cond_resched();

This loop can busy-wait for a long time if cond_resched() is a NOP. This
typically happens if the netns exit is executed by a high priority task,
or under kernels configured without preemption (CONFIG_PREEMPT_NONE). In
such cases, it wastes CPU cycles and can lead to soft lockups.

Fix this by replacing the busy loop with wait_var_event(), allowing the
thread to sleep properly until the work queue count reaches zero.

Accordingly, update cleanup_bearer() to use atomic_dec_and_test() and
wake_up_var() to wake up the waiter when the count drops to zero.

This uses the global wait queue hash table, avoiding the need to bloat
struct tipc_net with a wait_queue_head_t. The atomic_dec_and_test()
provides the necessary memory barrier to ensure the wakeup is not missed.

Fixes: 04c26faa51d1 ("tipc: wait and exit until all work queues are done")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Xin Long <lucien.xin@gmail.com>
Cc: Jon Maloy <jmaloy@redhat.com>
Cc: tipc-discussion@lists.sourceforge.net
---
 net/tipc/core.c      | 4 ++--
 net/tipc/udp_media.c | 4 +++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/tipc/core.c b/net/tipc/core.c
index 1ddecea1df6e9100334c47a28ff6c065292fb9ad..315975c3be8186784e9c44c9ff69d62c17ffd4b9 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -45,6 +45,7 @@
 #include "crypto.h"
 
 #include <linux/module.h>
+#include <linux/wait_bit.h>
 
 /* configurable TIPC parameters */
 unsigned int tipc_net_id __read_mostly;
@@ -118,8 +119,7 @@ static void __net_exit tipc_exit_net(struct net *net)
 #ifdef CONFIG_TIPC_CRYPTO
 	tipc_crypto_stop(&tipc_net(net)->crypto_tx);
 #endif
-	while (atomic_read(&tn->wq_count))
-		cond_resched();
+	wait_var_event(&tn->wq_count, atomic_read(&tn->wq_count) == 0);
 }
 
 static void __net_exit tipc_pernet_pre_exit(struct net *net)
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 66f3cb87a0aaaac8f40e8f237ab9a44d539b1cd8..62ae7f5b58409c89798c915dee752ac42487581f 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -40,6 +40,7 @@
 #include <linux/igmp.h>
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
+#include <linux/wait_bit.h>
 #include <linux/list.h>
 #include <net/sock.h>
 #include <net/ip.h>
@@ -830,7 +831,8 @@ static void cleanup_bearer(struct work_struct *work)
 	synchronize_net();
 
 	dst_cache_destroy(&ub->rcast.dst_cache);
-	atomic_dec(&tn->wq_count);
+	if (atomic_dec_and_test(&tn->wq_count))
+		wake_up_var(&tn->wq_count);
 	kfree(ub);
 }
 
-- 
2.55.0.rc0.799.gd6f94ed593-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* RE: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
@ 2026-06-24 12:04   ` Tung Quang Nguyen
  2026-06-24 12:42     ` Eric Dumazet
  2026-06-24 18:37   ` Xin Long
  1 sibling, 1 reply; 11+ messages in thread
From: Tung Quang Nguyen @ 2026-06-24 12:04 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion@lists.sourceforge.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com,
	syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com,
	David S . Miller, Jakub Kicinski, Paolo Abeni

>Subject: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature
>dst_cache_destroy()
>
>TIPC UDP media bearer teardown calls dst_cache_destroy() on its replicast
>caches before calling synchronize_net() to wait for concurrent RCU readers
>(transmitters) to finish:
>
>static void cleanup_bearer(struct work_struct *work) { ...
>	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
>		dst_cache_destroy(&rcast->dst_cache);
>		list_del_rcu(&rcast->list);
>		kfree_rcu(rcast, rcu);
>	}
>...
>	dst_cache_destroy(&ub->rcast.dst_cache);
>	udp_tunnel_sock_release(ub->sk);
>	synchronize_net();
>...
>}
>
>This is highly buggy because dst_cache_destroy() immediately frees the per-
>CPU cache memory (free_percpu()) and releases the cached dst entries
>without any synchronization.
>
>If a concurrent transmitter (e.g., tipc_udp_xmit()) is running on another CPU
>under RCU protection, it can call dst_cache_get() concurrently, leading to:
>1. Use-After-Free on the per-CPU cache pointer itself (crash).
>2. "rcuref - imbalanced put()" warning if it attempts to release a
>   dst that was concurrently released by dst_cache_destroy().
>
>Furthermore, calling kfree(ub) immediately after synchronize_net() without
>closing the socket first (or waiting after closing it) leaves a window where a
>concurrent receiver (tipc_udp_recv()) could start after synchronize_net(),
>access ub, and suffer a UAF when kfree(ub) runs.
>
>To fix this, we must defer dst_cache_destroy() and kfree(ub) until after we have
>ensured that no more readers can see the bearer/socket and all existing
>readers have finished:
>
>1. Defer rcast entry destruction (both dst_cache_destroy() and kfree())
>   to an RCU callback using call_rcu_hurry().
>   Using call_rcu_hurry() ensures the dst entries are released quickly.
>
>2. Release the bearer socket using udp_tunnel_sock_release() (stops
>   new receive readers).
>
>3. Call synchronize_net() to wait for all outstanding RCU readers
>   (both transmit and receive) to finish.
>
>4. Now that it is safe, call dst_cache_destroy() on the main bearer
>   cache, and free ub.
>
>Note: 3) and 4) can be changed later in net-next to also use
>call_rcu_hurry() and get rid of the synchronize_net() latency.
>
>Fixes: e9c1a793210f ("tipc: add dst_cache support for udp media")
>Reported-by: syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com
>Closes:
>https://lore.kernel.org/netdev/6a396a66.52ae72c2.136ac7.0003.GAE@google.
>com/T/#u
>Signed-off-by: Eric Dumazet <edumazet@google.com>
>Cc: Xin Long <lucien.xin@gmail.com>
>Cc: Jon Maloy <jmaloy@redhat.com>
>Cc: tipc-discussion@lists.sourceforge.net
>---
>v2: addressed Xin Long feedback
>v1:
>https://lore.kernel.org/netdev/CANn89i+dkbrSAwvaWXW7yWMfcwUebuTBLG
>5T7AGZaZcpVYGyfQ@mail.gmail.com/T/#m7bbeedffe3bedb69e33236410e383
>3c7ce809850
> net/tipc/udp_media.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)
>
>diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index
>988b8a7f953ad6da860e6190f1f244650f121dce..66f3cb87a0aaaac8f40e8f237a
>b9a44d539b1cd8 100644
>--- a/net/tipc/udp_media.c
>+++ b/net/tipc/udp_media.c
>@@ -803,6 +803,14 @@ static int tipc_udp_enable(struct net *net, struct
>tipc_bearer *b,
> 	return err;
> }
>
>+static void rcast_free_rcu(struct rcu_head *rcu) {
>+	struct udp_replicast *rcast = container_of(rcu, struct udp_replicast,
>+rcu);

This line is long (over 80 columns). Please break it into 2 lines (refer to linux/Documentation/process/coding-style.rst).

>+
>+	dst_cache_destroy(&rcast->dst_cache);
>+	kfree(rcast);
>+}
>+
> /* cleanup_bearer - break the socket/bearer association */  static void
>cleanup_bearer(struct work_struct *work)  { @@ -811,18 +819,17 @@ static
>void cleanup_bearer(struct work_struct *work)
> 	struct tipc_net *tn;
>
> 	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
>-		dst_cache_destroy(&rcast->dst_cache);
> 		list_del_rcu(&rcast->list);
>-		kfree_rcu(rcast, rcu);
>+		call_rcu_hurry(&rcast->rcu, rcast_free_rcu);
> 	}
>
> 	tn = tipc_net(sock_net(ub->sk));
>
>-	dst_cache_destroy(&ub->rcast.dst_cache);
> 	udp_tunnel_sock_release(ub->sk);
>
>-	/* Note: could use a call_rcu() to avoid another synchronize_net() */
> 	synchronize_net();
>+
>+	dst_cache_destroy(&ub->rcast.dst_cache);
> 	atomic_dec(&tn->wq_count);
> 	kfree(ub);
> }
>--
>2.55.0.rc0.799.gd6f94ed593-goog
>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net()
  2026-06-23 17:30 ` [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net() Eric Dumazet
@ 2026-06-24 12:07   ` Tung Quang Nguyen
  2026-06-24 12:48     ` Eric Dumazet
  0 siblings, 1 reply; 11+ messages in thread
From: Tung Quang Nguyen @ 2026-06-24 12:07 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion@lists.sourceforge.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com, David S . Miller, Jakub Kicinski,
	Paolo Abeni

>Subject: [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net()
>
>Blamed commit introduced a busy-wait loop in tipc_exit_net() to wait for
>pending UDP bearer cleanup works to complete:
>
>       while (atomic_read(&tn->wq_count))
>               cond_resched();
>
>This loop can busy-wait for a long time if cond_resched() is a NOP. This
>typically happens if the netns exit is executed by a high priority task, or under
>kernels configured without preemption (CONFIG_PREEMPT_NONE). In such
>cases, it wastes CPU cycles and can lead to soft lockups.
>
>Fix this by replacing the busy loop with wait_var_event(), allowing the thread
>to sleep properly until the work queue count reaches zero.
>
>Accordingly, update cleanup_bearer() to use atomic_dec_and_test() and
>wake_up_var() to wake up the waiter when the count drops to zero.
>
>This uses the global wait queue hash table, avoiding the need to bloat struct
>tipc_net with a wait_queue_head_t. The atomic_dec_and_test() provides the
>necessary memory barrier to ensure the wakeup is not missed.
>
>Fixes: 04c26faa51d1 ("tipc: wait and exit until all work queues are done")
>Signed-off-by: Eric Dumazet <edumazet@google.com>
>Cc: Xin Long <lucien.xin@gmail.com>
>Cc: Jon Maloy <jmaloy@redhat.com>
>Cc: tipc-discussion@lists.sourceforge.net
>---
> net/tipc/core.c      | 4 ++--
> net/tipc/udp_media.c | 4 +++-
> 2 files changed, 5 insertions(+), 3 deletions(-)
>
>diff --git a/net/tipc/core.c b/net/tipc/core.c index
>1ddecea1df6e9100334c47a28ff6c065292fb9ad..315975c3be8186784e9c44c9ff
>69d62c17ffd4b9 100644
>--- a/net/tipc/core.c
>+++ b/net/tipc/core.c
>@@ -45,6 +45,7 @@
> #include "crypto.h"
>
> #include <linux/module.h>
>+#include <linux/wait_bit.h>
>
> /* configurable TIPC parameters */
> unsigned int tipc_net_id __read_mostly; @@ -118,8 +119,7 @@ static void
>__net_exit tipc_exit_net(struct net *net)  #ifdef CONFIG_TIPC_CRYPTO
> 	tipc_crypto_stop(&tipc_net(net)->crypto_tx);
> #endif
>-	while (atomic_read(&tn->wq_count))
>-		cond_resched();
>+	wait_var_event(&tn->wq_count, atomic_read(&tn->wq_count) == 0);

It could be nicer if you change to this simple call:
wait_var_event(&tn->wq_count, !atomic_read(&tn->wq_count));

> }
>
> static void __net_exit tipc_pernet_pre_exit(struct net *net) diff --git
>a/net/tipc/udp_media.c b/net/tipc/udp_media.c index
>66f3cb87a0aaaac8f40e8f237ab9a44d539b1cd8..62ae7f5b58409c89798c915de
>e752ac42487581f 100644
>--- a/net/tipc/udp_media.c
>+++ b/net/tipc/udp_media.c
>@@ -40,6 +40,7 @@
> #include <linux/igmp.h>
> #include <linux/kernel.h>
> #include <linux/workqueue.h>
>+#include <linux/wait_bit.h>
> #include <linux/list.h>
> #include <net/sock.h>
> #include <net/ip.h>
>@@ -830,7 +831,8 @@ static void cleanup_bearer(struct work_struct *work)
> 	synchronize_net();
>
> 	dst_cache_destroy(&ub->rcast.dst_cache);
>-	atomic_dec(&tn->wq_count);
>+	if (atomic_dec_and_test(&tn->wq_count))
>+		wake_up_var(&tn->wq_count);
> 	kfree(ub);
> }
>
>--
>2.55.0.rc0.799.gd6f94ed593-goog
>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  2026-06-24 12:04   ` Tung Quang Nguyen
@ 2026-06-24 12:42     ` Eric Dumazet
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Dumazet @ 2026-06-24 12:42 UTC (permalink / raw)
  To: Tung Quang Nguyen
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion@lists.sourceforge.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com,
	syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com,
	David S . Miller, Jakub Kicinski, Paolo Abeni

On Wed, Jun 24, 2026 at 5:04 AM Tung Quang Nguyen
<tung.quang.nguyen@est.tech> wrote:
>
> >Subject: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature
> >dst_cache_destroy()
> >
> >TIPC UDP media bearer teardown calls dst_cache_destroy() on its replicast
> >caches before calling synchronize_net() to wait for concurrent RCU readers
> >(transmitters) to finish:
> >
> >static void cleanup_bearer(struct work_struct *work) { ...
> >       list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
> >               dst_cache_destroy(&rcast->dst_cache);
> >               list_del_rcu(&rcast->list);
> >               kfree_rcu(rcast, rcu);
> >       }
> >...
> >       dst_cache_destroy(&ub->rcast.dst_cache);
> >       udp_tunnel_sock_release(ub->sk);
> >       synchronize_net();
> >...
> >}
> >
> >This is highly buggy because dst_cache_destroy() immediately frees the per-
> >CPU cache memory (free_percpu()) and releases the cached dst entries
> >without any synchronization.
> >
> >If a concurrent transmitter (e.g., tipc_udp_xmit()) is running on another CPU
> >under RCU protection, it can call dst_cache_get() concurrently, leading to:
> >1. Use-After-Free on the per-CPU cache pointer itself (crash).
> >2. "rcuref - imbalanced put()" warning if it attempts to release a
> >   dst that was concurrently released by dst_cache_destroy().
> >
> >Furthermore, calling kfree(ub) immediately after synchronize_net() without
> >closing the socket first (or waiting after closing it) leaves a window where a
> >concurrent receiver (tipc_udp_recv()) could start after synchronize_net(),
> >access ub, and suffer a UAF when kfree(ub) runs.
> >
> >To fix this, we must defer dst_cache_destroy() and kfree(ub) until after we have
> >ensured that no more readers can see the bearer/socket and all existing
> >readers have finished:
> >
> >1. Defer rcast entry destruction (both dst_cache_destroy() and kfree())
> >   to an RCU callback using call_rcu_hurry().
> >   Using call_rcu_hurry() ensures the dst entries are released quickly.
> >
> >2. Release the bearer socket using udp_tunnel_sock_release() (stops
> >   new receive readers).
> >
> >3. Call synchronize_net() to wait for all outstanding RCU readers
> >   (both transmit and receive) to finish.
> >
> >4. Now that it is safe, call dst_cache_destroy() on the main bearer
> >   cache, and free ub.
> >
> >Note: 3) and 4) can be changed later in net-next to also use
> >call_rcu_hurry() and get rid of the synchronize_net() latency.
> >
> >Fixes: e9c1a793210f ("tipc: add dst_cache support for udp media")
> >Reported-by: syzbot+e14bc5d4942756023b77@syzkaller.appspotmail.com
> >Closes:
> >https://lore.kernel.org/netdev/6a396a66.52ae72c2.136ac7.0003.GAE@google.
> >com/T/#u
> >Signed-off-by: Eric Dumazet <edumazet@google.com>
> >Cc: Xin Long <lucien.xin@gmail.com>
> >Cc: Jon Maloy <jmaloy@redhat.com>
> >Cc: tipc-discussion@lists.sourceforge.net
> >---
> >v2: addressed Xin Long feedback
> >v1:
> >https://lore.kernel.org/netdev/CANn89i+dkbrSAwvaWXW7yWMfcwUebuTBLG
> >5T7AGZaZcpVYGyfQ@mail.gmail.com/T/#m7bbeedffe3bedb69e33236410e383
> >3c7ce809850
> > net/tipc/udp_media.c | 15 +++++++++++----
> > 1 file changed, 11 insertions(+), 4 deletions(-)
> >
> >diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index
> >988b8a7f953ad6da860e6190f1f244650f121dce..66f3cb87a0aaaac8f40e8f237a
> >b9a44d539b1cd8 100644
> >--- a/net/tipc/udp_media.c
> >+++ b/net/tipc/udp_media.c
> >@@ -803,6 +803,14 @@ static int tipc_udp_enable(struct net *net, struct
> >tipc_bearer *b,
> >       return err;
> > }
> >
> >+static void rcast_free_rcu(struct rcu_head *rcu) {
> >+      struct udp_replicast *rcast = container_of(rcu, struct udp_replicast,
> >+rcu);
>
> This line is long (over 80 columns). Please break it into 2 lines (refer to linux/Documentation/process/coding-style.rst).

I prefer it this way.

BTW:

commit bdc48fa11e46f867ea4d75fa59ee87a7f48be144
Author: Joe Perches <joe@perches.com>
Date:   Fri May 29 16:12:21 2020 -0700

    checkpatch/coding-style: deprecate 80-column warning

    Yes, staying withing 80 columns is certainly still _preferred_.  But
    it's not the hard limit that the checkpatch warnings imply, and other
    concerns can most certainly dominate.

    Increase the default limit to 100 characters.  Not because 100
    characters is some hard limit either, but that's certainly a "what are
    you doing" kind of value and less likely to be about the occasional
    slightly longer lines.

    Miscellanea:

     - to avoid unnecessary whitespace changes in files, checkpatch will no
       longer emit a warning about line length when scanning files unless
       --strict is also used

     - Add a bit to coding-style about alignment to open parenthesis

    Signed-off-by: Joe Perches <joe@perches.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net()
  2026-06-24 12:07   ` Tung Quang Nguyen
@ 2026-06-24 12:48     ` Eric Dumazet
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Dumazet @ 2026-06-24 12:48 UTC (permalink / raw)
  To: Tung Quang Nguyen
  Cc: Simon Horman, Kuniyuki Iwashima, Xin Long, Jon Maloy,
	tipc-discussion@lists.sourceforge.net, netdev@vger.kernel.org,
	eric.dumazet@gmail.com, David S . Miller, Jakub Kicinski,
	Paolo Abeni

On Wed, Jun 24, 2026 at 5:07 AM Tung Quang Nguyen
<tung.quang.nguyen@est.tech> wrote:
>

> It could be nicer if you change to this simple call:
> wait_var_event(&tn->wq_count, !atomic_read(&tn->wq_count));

Given the amount of work we currently have with various AI reports, I
will keep it this way to avoid unnecessary noise.

Thank you,

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
  2026-06-24 12:04   ` Tung Quang Nguyen
@ 2026-06-24 18:37   ` Xin Long
  2026-06-24 18:49     ` Eric Dumazet
  1 sibling, 1 reply; 11+ messages in thread
From: Xin Long @ 2026-06-24 18:37 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Jon Maloy, tipc-discussion, netdev,
	eric.dumazet, syzbot+e14bc5d4942756023b77

> diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
> index 988b8a7f953ad..66f3cb87a0aaa 100644
> --- a/net/tipc/udp_media.c
> +++ b/net/tipc/udp_media.c
> @@ -803,6 +803,14 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
> return err;
> }
>
> +static void rcast_free_rcu(struct rcu_head *rcu)
> +{
> + struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu);
> +
> + dst_cache_destroy(&rcast->dst_cache);
> + kfree(rcast);
> +}
> +
Since this adds a module-specific callback rcast_free_rcu registered with RCU
via call_rcu_hurry(), is an rcu_barrier() needed in the TIPC module exit
function?
If the module is unloaded, the RCU grace period might expire after the module
memory is freed.
net/tipc/core.c:tipc_exit() {
tipc_netlink_compat_stop();
...
pr_info("Deactivated\n");
}
Could this result in a kernel panic when RCU attempts to execute the unloaded
rcast_free_rcu function?

This sashiko report looks legit.

I think synchronize_net() doesn't guarantee rcast_free_rcu() to be done.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
  2026-06-24 18:37   ` Xin Long
@ 2026-06-24 18:49     ` Eric Dumazet
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Dumazet @ 2026-06-24 18:49 UTC (permalink / raw)
  To: Xin Long
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Jon Maloy, tipc-discussion, netdev,
	eric.dumazet, syzbot+e14bc5d4942756023b77

On Wed, Jun 24, 2026 at 11:37 AM Xin Long <lucien.xin@gmail.com> wrote:
>
> > diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
> > index 988b8a7f953ad..66f3cb87a0aaa 100644
> > --- a/net/tipc/udp_media.c
> > +++ b/net/tipc/udp_media.c
> > @@ -803,6 +803,14 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
> > return err;
> > }
> >
> > +static void rcast_free_rcu(struct rcu_head *rcu)
> > +{
> > + struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu);
> > +
> > + dst_cache_destroy(&rcast->dst_cache);
> > + kfree(rcast);
> > +}
> > +
> Since this adds a module-specific callback rcast_free_rcu registered with RCU
> via call_rcu_hurry(), is an rcu_barrier() needed in the TIPC module exit
> function?

There is one already, this was one of my feedback for this patch:

commit 1579342d71133da7f00daa02c75cebec7372097b
Author: Weiming Shi <bestswngs@gmail.com>
Date:   Wed Jun 17 21:57:45 2026 +0800

    tipc: fix use-after-free of the discoverer in tipc_disc_rcv()



> If the module is unloaded, the RCU grace period might expire after the module
> memory is freed.
> net/tipc/core.c:tipc_exit() {
> tipc_netlink_compat_stop();
> ...
> pr_info("Deactivated\n");
> }
> Could this result in a kernel panic when RCU attempts to execute the unloaded
> rcast_free_rcu function?
>
> This sashiko report looks legit.
>
> I think synchronize_net() doesn't guarantee rcast_free_rcu() to be done.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 0/2] tipc: syzbot related fixes
  2026-06-23 17:30 [PATCH v2 net 0/2] tipc: syzbot related fixes Eric Dumazet
  2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
  2026-06-23 17:30 ` [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net() Eric Dumazet
@ 2026-06-24 19:07 ` Xin Long
  2026-06-25 16:20 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 11+ messages in thread
From: Xin Long @ 2026-06-24 19:07 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Jon Maloy, tipc-discussion, netdev,
	eric.dumazet

On Tue, Jun 23, 2026 at 1:30 PM Eric Dumazet <edumazet@google.com> wrote:
>
> First patch fixes a recent syzbot report.
>
> Second patch is inspired by numerous syzbot soft lockup
> reports with RTNL pressure.
>
> Eric Dumazet (2):
>   tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
>   tipc: avoid busy looping in tipc_exit_net()
>
>  net/tipc/core.c      |  4 ++--
>  net/tipc/udp_media.c | 19 ++++++++++++++-----
>  2 files changed, 16 insertions(+), 7 deletions(-)
>
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>

Reviewed-by: Xin Long <lucien.xin@gmail.com>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 net 0/2] tipc: syzbot related fixes
  2026-06-23 17:30 [PATCH v2 net 0/2] tipc: syzbot related fixes Eric Dumazet
                   ` (2 preceding siblings ...)
  2026-06-24 19:07 ` [PATCH v2 net 0/2] tipc: syzbot related fixes Xin Long
@ 2026-06-25 16:20 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 11+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-25 16:20 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, kuba, pabeni, horms, kuniyu, lucien.xin, jmaloy,
	tipc-discussion, netdev, eric.dumazet

Hello:

This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Tue, 23 Jun 2026 17:30:28 +0000 you wrote:
> First patch fixes a recent syzbot report.
> 
> Second patch is inspired by numerous syzbot soft lockup
> reports with RTNL pressure.
> 
> Eric Dumazet (2):
>   tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
>   tipc: avoid busy looping in tipc_exit_net()
> 
> [...]

Here is the summary with links:
  - [v2,net,1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy()
    https://git.kernel.org/netdev/net/c/7116764ca53f
  - [v2,net,2/2] tipc: avoid busy looping in tipc_exit_net()
    https://git.kernel.org/netdev/net/c/c1481c94e74c

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-06-25 16:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-23 17:30 [PATCH v2 net 0/2] tipc: syzbot related fixes Eric Dumazet
2026-06-23 17:30 ` [PATCH v2 net 1/2] tipc: fix UAF in cleanup_bearer() due to premature dst_cache_destroy() Eric Dumazet
2026-06-24 12:04   ` Tung Quang Nguyen
2026-06-24 12:42     ` Eric Dumazet
2026-06-24 18:37   ` Xin Long
2026-06-24 18:49     ` Eric Dumazet
2026-06-23 17:30 ` [PATCH v2 net 2/2] tipc: avoid busy looping in tipc_exit_net() Eric Dumazet
2026-06-24 12:07   ` Tung Quang Nguyen
2026-06-24 12:48     ` Eric Dumazet
2026-06-24 19:07 ` [PATCH v2 net 0/2] tipc: syzbot related fixes Xin Long
2026-06-25 16:20 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox