A packet queued to userspace keeps its conntrack reference in
skb->_nfct until the verdict arrives. The conntrack hooks sit at
prerouting, local in, local out and postrouting; a packet queued from
the forward hook point is covered by none of them.

Until commit 72ac1c0937df ("netfilter: nf_queue: limit the hook drop
flush to the unregistered hook point") unregistering the conntrack hooks
flushed every queued packet of the network namespace and released those
references. The flush now only covers the hook points of the removed
hooks. Packets queued from forward keep their nf_conn alive, and
nf_conntrack_cleanup_net_list() loops on cnet->count, with
pernet_ops_rwsem held for write, until userspace sends a verdict or
closes the queue.

Flush every queued packet of the namespaces being cleaned up in
nf_conntrack_cleanup_net_list(), after the synchronize_rcu_expedited()
that waits for the packets still inside the hooks, so that a packet a
hook was processing while the hooks were removed is dropped as well.

Reproduced in virtme-ng with nf_conntrack built as a module and loaded
with enable_hooks=1: two network namespaces routed through the host
namespace, an ip forward chain that sends udp dport 12345 to queue 1,
and the nf_queue selftest helper holding the verdicts (-H). With 10
packets queued and 10 conntrack entries, rmmod nf_conntrack blocks until
the verdicts are sent, 15 s later in the test. With this patch rmmod
returns at once, the 10 entries are dropped and the verdict fails with
-ENOENT. nft_queue.sh passes.

The code and this commit message were written with an LLM coding
assistant from the review linked below. The author reviewed the result
and validated it with the reproducer and the selftest.

Fixes: 72ac1c0937df ("netfilter: nf_queue: limit the hook drop flush to the 
unregistered hook point")
Reported-by: Sashiko (nipa) <[email protected]>
Closes: 
https://lore.kernel.org/netfilter-devel/[email protected]/
Suggested-by: Florian Westphal <[email protected]>
Assisted-by: LLM
Signed-off-by: Antonio Ojea <[email protected]>
---
 net/netfilter/nf_conntrack_core.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/net/netfilter/nf_conntrack_core.c 
b/net/netfilter/nf_conntrack_core.c
index 42a7cbdbd7d5..3ccee38beb1f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -2490,6 +2490,12 @@ void nf_conntrack_cleanup_net_list(struct list_head 
*net_exit_list)
         *  delete...
         */
        synchronize_rcu_expedited();
+
+       /* Packets queued to userspace hold nf_conn references; the hook
+        * removal only flushed the hook points conntrack was registered at.
+        */
+       list_for_each_entry(net, net_exit_list, exit_list)
+               nf_queue_nf_hook_drop(net, NULL);
 i_see_dead_people:
        busy = 0;
        list_for_each_entry(net, net_exit_list, exit_list) {
-- 
2.56.0.218.g1ec904b173-goog


Reply via email to