* [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
0 siblings, 1 reply; 2+ 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] 2+ 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
0 siblings, 0 replies; 2+ 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] 2+ messages in thread
end of thread, other threads:[~2026-06-10 17:36 UTC | newest]
Thread overview: 2+ 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox