Netdev List
 help / color / mirror / Atom feed
* [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
@ 2026-06-10 15:33 Weiming Shi
  2026-06-10 17:36 ` Eric Dumazet
  2026-06-12  8:53 ` Tung Quang Nguyen
  0 siblings, 2 replies; 4+ messages in thread
From: Weiming Shi @ 2026-06-10 15:33 UTC (permalink / raw)
  To: Jon Maloy, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel,
	Xiang Mei, Weiming Shi

bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(),
but tipc_disc_rcv() still dereferences b->disc in RX softirq under
rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).

L2 bearers are safe thanks to the synchronize_net() in
tipc_disable_l2_media(), but the UDP bearer defers that call to the
cleanup_bearer() workqueue, so the discoverer is freed with no grace
period:

 BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
 Read of size 8 at addr ffff88802348b728 by task poc_tipc/184
 <IRQ>
  tipc_disc_rcv (net/tipc/discover.c:149)
  tipc_rcv (net/tipc/node.c:2126)
  tipc_udp_recv (net/tipc/udp_media.c:391)
  udp_rcv (net/ipv4/udp.c:2643)
  ip_local_deliver_finish (net/ipv4/ip_input.c:241)
 </IRQ>
 Freed by task 181:
  kfree (mm/slub.c:6565)
  bearer_disable (net/tipc/bearer.c:418)
  tipc_nl_bearer_disable (net/tipc/bearer.c:1001)

The bearer is freed with kfree_rcu(); free the discoverer the same way.
Add an rcu_head to struct tipc_discoverer and free it and its skb from an
RCU callback.

Reachable from an unprivileged user namespace: the TIPCv2 genl family is
netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC
and CONFIG_TIPC_MEDIA_UDP.

Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
 net/tipc/discover.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 3e54d2df5683a..34dbe5ad10e09 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -58,6 +58,7 @@
  * @skb: request message to be (repeatedly) sent
  * @timer: timer governing period between requests
  * @timer_intv: current interval between requests (in ms)
+ * @rcu: RCU head for deferred freeing
  */
 struct tipc_discoverer {
 	u32 bearer_id;
@@ -69,6 +70,7 @@ struct tipc_discoverer {
 	struct sk_buff *skb;
 	struct timer_list timer;
 	unsigned long timer_intv;
+	struct rcu_head rcu;
 };
 
 /**
@@ -382,6 +384,14 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
 	return 0;
 }
 
+static void tipc_disc_free_rcu(struct rcu_head *rp)
+{
+	struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer, rcu);
+
+	kfree_skb(d->skb);
+	kfree(d);
+}
+
 /**
  * tipc_disc_delete - destroy object sending periodic link setup requests
  * @d: ptr to link dest structure
@@ -389,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
 void tipc_disc_delete(struct tipc_discoverer *d)
 {
 	timer_shutdown_sync(&d->timer);
-	kfree_skb(d->skb);
-	kfree(d);
+	call_rcu(&d->rcu, tipc_disc_free_rcu);
 }
 
 /**
-- 
2.43.0


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

* Re: [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
  2026-06-10 15:33 [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv() Weiming Shi
@ 2026-06-10 17:36 ` Eric Dumazet
  2026-06-12  8:53 ` Tung Quang Nguyen
  1 sibling, 0 replies; 4+ messages in thread
From: Eric Dumazet @ 2026-06-10 17:36 UTC (permalink / raw)
  To: Weiming Shi
  Cc: Jon Maloy, David S . Miller, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ying Xue, netdev, tipc-discussion, linux-kernel,
	Xiang Mei

On Wed, Jun 10, 2026 at 9:08 AM Weiming Shi <bestswngs@gmail.com> wrote:
>
> bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(),
> but tipc_disc_rcv() still dereferences b->disc in RX softirq under
> rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
>
> L2 bearers are safe thanks to the synchronize_net() in
> tipc_disable_l2_media(), but the UDP bearer defers that call to the
> cleanup_bearer() workqueue, so the discoverer is freed with no grace
> period:
>
>  BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
>  Read of size 8 at addr ffff88802348b728 by task poc_tipc/184
>  <IRQ>
>   tipc_disc_rcv (net/tipc/discover.c:149)
>   tipc_rcv (net/tipc/node.c:2126)
>   tipc_udp_recv (net/tipc/udp_media.c:391)
>   udp_rcv (net/ipv4/udp.c:2643)
>   ip_local_deliver_finish (net/ipv4/ip_input.c:241)
>  </IRQ>
>  Freed by task 181:
>   kfree (mm/slub.c:6565)
>   bearer_disable (net/tipc/bearer.c:418)
>   tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
>
> The bearer is freed with kfree_rcu(); free the discoverer the same way.
> Add an rcu_head to struct tipc_discoverer and free it and its skb from an
> RCU callback.
>
> Reachable from an unprivileged user namespace: the TIPCv2 genl family is
> netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC
> and CONFIG_TIPC_MEDIA_UDP.
>
> Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> ---
>  net/tipc/discover.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/net/tipc/discover.c b/net/tipc/discover.c
> index 3e54d2df5683a..34dbe5ad10e09 100644
> --- a/net/tipc/discover.c
> +++ b/net/tipc/discover.c
> @@ -58,6 +58,7 @@
>   * @skb: request message to be (repeatedly) sent
>   * @timer: timer governing period between requests
>   * @timer_intv: current interval between requests (in ms)
> + * @rcu: RCU head for deferred freeing
>   */
>  struct tipc_discoverer {
>         u32 bearer_id;
> @@ -69,6 +70,7 @@ struct tipc_discoverer {
>         struct sk_buff *skb;
>         struct timer_list timer;
>         unsigned long timer_intv;
> +       struct rcu_head rcu;
>  };
>
>  /**
> @@ -382,6 +384,14 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
>         return 0;
>  }
>
> +static void tipc_disc_free_rcu(struct rcu_head *rp)
> +{
> +       struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer, rcu);
> +
> +       kfree_skb(d->skb);
> +       kfree(d);
> +}
> +
>  /**
>   * tipc_disc_delete - destroy object sending periodic link setup requests
>   * @d: ptr to link dest structure
> @@ -389,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
>  void tipc_disc_delete(struct tipc_discoverer *d)
>  {
>         timer_shutdown_sync(&d->timer);
> -       kfree_skb(d->skb);
> -       kfree(d);
> +       call_rcu(&d->rcu, tipc_disc_free_rcu);
>  }


TIPC can be a module, what prevents this module being unloaded while
this call_rcu() is pending?

You probably need to add an rcu_barrier() in tipc_exit()

I see three pre-existing call_rcu() in net/tipc, so mayb tipc can't be
unloaded, I don't know.

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

* RE: [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
  2026-06-10 15:33 [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv() Weiming Shi
  2026-06-10 17:36 ` Eric Dumazet
@ 2026-06-12  8:53 ` Tung Quang Nguyen
  2026-06-16 12:28   ` Weiming Shi
  1 sibling, 1 reply; 4+ messages in thread
From: Tung Quang Nguyen @ 2026-06-12  8:53 UTC (permalink / raw)
  To: Weiming Shi
  Cc: Simon Horman, netdev@vger.kernel.org,
	tipc-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, Xiang Mei, Jon Maloy,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni

>Subject: [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
>
>bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(), but
>tipc_disc_rcv() still dereferences b->disc in RX softirq under
>rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
>
>L2 bearers are safe thanks to the synchronize_net() in tipc_disable_l2_media(),
>but the UDP bearer defers that call to the
>cleanup_bearer() workqueue, so the discoverer is freed with no grace
>period:
>
> BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
>Read of size 8 at addr ffff88802348b728 by task poc_tipc/184  <IRQ>
>  tipc_disc_rcv (net/tipc/discover.c:149)
>  tipc_rcv (net/tipc/node.c:2126)
>  tipc_udp_recv (net/tipc/udp_media.c:391)
>  udp_rcv (net/ipv4/udp.c:2643)
>  ip_local_deliver_finish (net/ipv4/ip_input.c:241)  </IRQ>  Freed by task 181:
>  kfree (mm/slub.c:6565)
>  bearer_disable (net/tipc/bearer.c:418)
>  tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
>
>The bearer is freed with kfree_rcu(); free the discoverer the same way.
>Add an rcu_head to struct tipc_discoverer and free it and its skb from an RCU
>callback.
>
>Reachable from an unprivileged user namespace: the TIPCv2 genl family is
>netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs
>CONFIG_TIPC and CONFIG_TIPC_MEDIA_UDP.
>
>Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash
>values")
>Reported-by: Xiang Mei <xmei5@asu.edu>
>Assisted-by: Claude:claude-opus-4-8
>Signed-off-by: Weiming Shi <bestswngs@gmail.com>
>---
> net/tipc/discover.c | 13 +++++++++++--
> 1 file changed, 11 insertions(+), 2 deletions(-)
>
>diff --git a/net/tipc/discover.c b/net/tipc/discover.c index
>3e54d2df5683a..34dbe5ad10e09 100644
>--- a/net/tipc/discover.c
>+++ b/net/tipc/discover.c
>@@ -58,6 +58,7 @@
>  * @skb: request message to be (repeatedly) sent
>  * @timer: timer governing period between requests
>  * @timer_intv: current interval between requests (in ms)
>+ * @rcu: RCU head for deferred freeing
>  */
> struct tipc_discoverer {
> 	u32 bearer_id;
>@@ -69,6 +70,7 @@ struct tipc_discoverer {
> 	struct sk_buff *skb;
> 	struct timer_list timer;
> 	unsigned long timer_intv;
>+	struct rcu_head rcu;
> };
>
> /**
>@@ -382,6 +384,14 @@ int tipc_disc_create(struct net *net, struct tipc_bearer
>*b,
> 	return 0;
> }
>
>+static void tipc_disc_free_rcu(struct rcu_head *rp) {
>+	struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
>+rcu);

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

>+
>+	kfree_skb(d->skb);
>+	kfree(d);
>+}
>+
> /**
>  * tipc_disc_delete - destroy object sending periodic link setup requests
>  * @d: ptr to link dest structure
>@@ -389,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer
>*b,  void tipc_disc_delete(struct tipc_discoverer *d)  {
> 	timer_shutdown_sync(&d->timer);
>-	kfree_skb(d->skb);
>-	kfree(d);
>+	call_rcu(&d->rcu, tipc_disc_free_rcu);
> }
>
> /**
>--
>2.43.0
>


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

* Re: [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
  2026-06-12  8:53 ` Tung Quang Nguyen
@ 2026-06-16 12:28   ` Weiming Shi
  0 siblings, 0 replies; 4+ messages in thread
From: Weiming Shi @ 2026-06-16 12:28 UTC (permalink / raw)
  To: Tung Quang Nguyen, Weiming Shi
  Cc: Simon Horman, netdev@vger.kernel.org,
	tipc-discussion@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, Xiang Mei, Jon Maloy,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni

On Fri Jun 12, 2026 at 4:53 PM CST, Tung Quang Nguyen wrote:
>>Subject: [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv()
>>
>>bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(), but
>>tipc_disc_rcv() still dereferences b->disc in RX softirq under
>>rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
>>
>>L2 bearers are safe thanks to the synchronize_net() in tipc_disable_l2_media(),
>>but the UDP bearer defers that call to the
>>cleanup_bearer() workqueue, so the discoverer is freed with no grace
>>period:
>>
>> BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149)
>>Read of size 8 at addr ffff88802348b728 by task poc_tipc/184  <IRQ>
>>  tipc_disc_rcv (net/tipc/discover.c:149)
>>  tipc_rcv (net/tipc/node.c:2126)
>>  tipc_udp_recv (net/tipc/udp_media.c:391)
>>  udp_rcv (net/ipv4/udp.c:2643)
>>  ip_local_deliver_finish (net/ipv4/ip_input.c:241)  </IRQ>  Freed by task 181:
>>  kfree (mm/slub.c:6565)
>>  bearer_disable (net/tipc/bearer.c:418)
>>  tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
>>
>>The bearer is freed with kfree_rcu(); free the discoverer the same way.
>>Add an rcu_head to struct tipc_discoverer and free it and its skb from an RCU
>>callback.
>>
>>Reachable from an unprivileged user namespace: the TIPCv2 genl family is
>>netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs
>>CONFIG_TIPC and CONFIG_TIPC_MEDIA_UDP.
>>
>>Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash
>>values")
>>Reported-by: Xiang Mei <xmei5@asu.edu>
>>Assisted-by: Claude:claude-opus-4-8
>>Signed-off-by: Weiming Shi <bestswngs@gmail.com>
>>---
>> net/tipc/discover.c | 13 +++++++++++--
>> 1 file changed, 11 insertions(+), 2 deletions(-)
>>
>>diff --git a/net/tipc/discover.c b/net/tipc/discover.c index
>>3e54d2df5683a..34dbe5ad10e09 100644
>>--- a/net/tipc/discover.c
>>+++ b/net/tipc/discover.c
>>@@ -58,6 +58,7 @@
>>  * @skb: request message to be (repeatedly) sent
>>  * @timer: timer governing period between requests
>>  * @timer_intv: current interval between requests (in ms)
>>+ * @rcu: RCU head for deferred freeing
>>  */
>> struct tipc_discoverer {
>> 	u32 bearer_id;
>>@@ -69,6 +70,7 @@ struct tipc_discoverer {
>> 	struct sk_buff *skb;
>> 	struct timer_list timer;
>> 	unsigned long timer_intv;
>>+	struct rcu_head rcu;
>> };
>>
>> /**
>>@@ -382,6 +384,14 @@ int tipc_disc_create(struct net *net, struct tipc_bearer
>>*b,
>> 	return 0;
>> }
>>
>>+static void tipc_disc_free_rcu(struct rcu_head *rp) {
>>+	struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
>>+rcu);
>
> This line is long (over 80 columns). Please break it into 2 lines (refer to linux/Documentation/process/coding-style.rst).
>
>>+
>>+	kfree_skb(d->skb);
>>+	kfree(d);
>>+}
>>+
>> /**
>>  * tipc_disc_delete - destroy object sending periodic link setup requests
>>  * @d: ptr to link dest structure
>>@@ -389,8 +399,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer
>>*b,  void tipc_disc_delete(struct tipc_discoverer *d)  {
>> 	timer_shutdown_sync(&d->timer);
>>-	kfree_skb(d->skb);
>>-	kfree(d);
>>+	call_rcu(&d->rcu, tipc_disc_free_rcu);
>> }
>>
>> /**
>>--
>>2.43.0
>>

Hi,

I’m sorry for taking so long to respond. The v2 version has already been sent.


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

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

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10 15:33 [PATCH net] tipc: fix use-after-free of discoverer in tipc_disc_rcv() Weiming Shi
2026-06-10 17:36 ` Eric Dumazet
2026-06-12  8:53 ` Tung Quang Nguyen
2026-06-16 12:28   ` Weiming Shi

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