]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: flowtable: publish GC-visible tuple last
authorJérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Sat, 8 Aug 2026 12:40:02 +0000 (12:40 +0000)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 10 Aug 2026 18:27:50 +0000 (20:27 +0200)
nf_flow_table_iterate() only treats original-direction tuple nodes as
owning entries. Publishing the original node first lets GC observe and
free a flow while flow_offload_add() is still inserting the reply node.
Publish the reply node first and the original node last so GC never
sees a partially installed flow.

KASAN can trigger slab-use-after-free read and write reports in the
flowtable/rhashtable path (rht_deferred_worker, jhash, flow_offload_del,
flow_offload_lookup, etc.).

Fixes: ac2a66665e23 ("netfilter: add generic flow table infrastructure")
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
Assisted-by: Codex:gpt-5
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_flow_table_core.c

index b66e6543934117763bef14c550f8f09621d09ea1..8b1165f2b5a49d13083e5f9b3850c641e56807df 100644 (file)
@@ -332,17 +332,18 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
        flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
 
        err = rhashtable_insert_fast(&flow_table->rhashtable,
-                                    &flow->tuplehash[0].node,
+                                    &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
                                     nf_flow_offload_rhash_params);
        if (err < 0)
                return err;
 
+       /* GC only iterates original-direction entries; publish original last. */
        err = rhashtable_insert_fast(&flow_table->rhashtable,
-                                    &flow->tuplehash[1].node,
+                                    &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
                                     nf_flow_offload_rhash_params);
        if (err < 0) {
                rhashtable_remove_fast(&flow_table->rhashtable,
-                                      &flow->tuplehash[0].node,
+                                      &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
                                       nf_flow_offload_rhash_params);
                return err;
        }