]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: nfnetlink_log: wait for rcu grace period before freeing pernet state
authorFlorian Westphal <fw@strlen.de>
Mon, 3 Aug 2026 08:43:27 +0000 (10:43 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 10 Aug 2026 18:26:37 +0000 (20:26 +0200)
sashiko reports: "nfnl_log_net_exit() calls nf_log_unset(), which
clears the logger pointer without an RCU grace period.  Immediately after,
ops_free_list() frees the per-net state while concurrent packets might
still be executing nf_log_packet() under rcu_read_lock()."

Clear the pointer via .pre_exit to make sure rcu readers have completed
before pernet storage is free'd.  The change in nf_log_syslog.c is only
done for consistency: it doesn't use pernet data.

Link: https://sashiko.dev/#/patchset/20260731151806.849724-1-pablo%40netfilter.org
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_log_syslog.c
net/netfilter/nfnetlink_log.c

index e37b09b3203b750cdb0e309fc3aea939410ead02..5ffde27d450a75e68a169b2ea7e34548b2d2b518 100644 (file)
@@ -1014,7 +1014,7 @@ err1:
        return ret;
 }
 
-static void __net_exit nf_log_syslog_net_exit(struct net *net)
+static void __net_exit nf_log_syslog_net_pre_exit(struct net *net)
 {
        nf_log_unset(net, &nf_ip_logger);
        nf_log_unset(net, &nf_arp_logger);
@@ -1025,7 +1025,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
 
 static struct pernet_operations nf_log_syslog_net_ops = {
        .init = nf_log_syslog_net_init,
-       .exit = nf_log_syslog_net_exit,
+       .pre_exit = nf_log_syslog_net_pre_exit,
 };
 
 static int __init nf_log_syslog_init(void)
index 5fee61b3813cbc146ce98e9cc0bfa24b115768e5..6c7fa2ed34f5c01383dde31b9edb5be713074892 100644 (file)
@@ -1170,21 +1170,26 @@ static int __net_init nfnl_log_net_init(struct net *net)
        return 0;
 }
 
-static void __net_exit nfnl_log_net_exit(struct net *net)
+static void __net_exit nfnl_log_net_pre_exit(struct net *net)
 {
-       struct nfnl_log_net *log = nfnl_log_pernet(net);
-       unsigned int i;
-
 #ifdef CONFIG_PROC_FS
        remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
 #endif
        nf_log_unset(net, &nfulnl_logger);
+}
+
+static void __net_exit nfnl_log_net_exit(struct net *net)
+{
+       struct nfnl_log_net *log = nfnl_log_pernet(net);
+       unsigned int i;
+
        for (i = 0; i < INSTANCE_BUCKETS; i++)
                WARN_ON_ONCE(!hlist_empty(&log->instance_table[i]));
 }
 
 static struct pernet_operations nfnl_log_net_ops = {
        .init   = nfnl_log_net_init,
+       .pre_exit = nfnl_log_net_pre_exit,
        .exit   = nfnl_log_net_exit,
        .id     = &nfnl_log_net_id,
        .size   = sizeof(struct nfnl_log_net),