[PATCH] netfilter: conntrack: wait for RCU readers before freeing the hash

From: Chengfeng Ye

Date: Sat Sep 26 2026 - 13:53:09 EST


nf_ct_get_tuple_skb() calls into conntrack under rcu_read_lock() without
holding a module reference. CAKE can use this hook to look up a packet
without an attached conntrack, even during nf_conntrack module teardown.

nf_conntrack_cleanup_end() clears nf_ct_hook but frees nf_conntrack_hash
without waiting for existing readers. The grace period in per-net cleanup
runs while the hook is still published, so a later reader can race as
follows:

CPU 0 (packet path) CPU 1 (module teardown)
rcu_read_lock()
ct_hook = rcu_dereference(nf_ct_hook)
RCU_INIT_POINTER(nf_ct_hook, NULL)
kvfree(nf_conntrack_hash)
ct_hook->get_tuple_skb()
nf_conntrack_find_get()
access freed hash bucket
rcu_read_unlock()

The same missing grace period affects initialization failure after
nf_conntrack_init_end() publishes the hook. During module teardown,
KASAN reported:

BUG: KASAN: vmalloc-out-of-bounds in __nf_conntrack_find_get.isra.0
Read of size 8 at addr ffffc900012e2ae0 by task poc/90
Call Trace:
__nf_conntrack_find_get.isra.0+0xf87/0x10c0 [nf_conntrack]
nf_conntrack_get_tuple_skb+0x255/0x400 [nf_conntrack]
nf_ct_get_tuple_skb+0x75/0xb0
cake_hash+0xfdb/0x1e10
cake_enqueue+0x5cd/0x36e0
dev_qdisc_enqueue+0x40/0x170
__dev_queue_xmit+0x1e90/0x3110

Wait for an RCU grace period after clearing nf_ct_hook, before releasing
the hash table and the remaining conntrack resources.

Fixes: b60a60405fb9 ("netfilter: Add nf_ct_get_tuple_skb global lookup function")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Chengfeng Ye <nicoyip.dev@xxxxxxxxx>
---
net/netfilter/nf_conntrack_core.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index d0d9e5ea84a0..b07e94e75d4d 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -2455,6 +2455,7 @@ void nf_conntrack_cleanup_start(void)
void nf_conntrack_cleanup_end(void)
{
RCU_INIT_POINTER(nf_ct_hook, NULL);
+ synchronize_rcu();
cancel_delayed_work_sync(&conntrack_gc_work.dwork);
kvfree(nf_conntrack_hash);

--
2.43.0