From: Chengfeng Ye <nicoyip.dev@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>,
Florian Westphal <fw@strlen.de>, Phil Sutter <phil@nwl.cc>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Gao feng <gaofeng@cn.fujitsu.com>
Cc: netfilter-devel@vger.kernel.org, coreteam@netfilter.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
Chengfeng Ye <nicoyip.dev@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH] netfilter: nf_log: clear per-net loggers on unregister
Date: Sun, 23 Aug 2026 02:46:58 +0800 [thread overview]
Message-ID: <20260822184658.3787672-1-nicoyip.dev@gmail.com> (raw)
Logger backends unregister their per-network namespace operations before
unregistering their global logger. This leaves a window where a sysctl or
netlink writer can rebind a per-net logger after the old per-net
selection was cleared, but before the global logger registration is
removed.
The race looks like this:
CPU 0 CPU 1
---- ----
unregister_pernet_subsys()
nf_log_unset(net, logger)
net->nf.nf_loggers[pf] = NULL
lock nf_log_mutex
find logger in loggers[][]
net->nf.nf_loggers[pf] = logger
unlock nf_log_mutex
nf_log_unregister(logger)
lock nf_log_mutex
loggers[pf][type] = NULL
unlock nf_log_mutex
synchronize_rcu()
module exit returns
module core frees backend memory
Later, a sysctl read or nf_log_packet() reads net->nf.nf_loggers[pf]
and dereferences the stale logger.
nf_log_unregister() only removes the backend from the global logger
table. It does not clear matching net->nf.nf_loggers[] entries that were
rebound by CPU 1 after per-net teardown. Once module unload completes,
those per-net pointers can still reference static data from the unloaded
logger backend, and later readers can dereference freed module memory.
The kernel reported:
BUG: unable to handle page fault for address: fffffbfff806d2f4
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
Oops: Oops: 0000 [#1] SMP KASAN NOPTI
RIP: 0010:nf_log_proc_dostring+0x2aa/0x4d0
Call Trace:
proc_sys_call_handler+0x325/0x540
vfs_read+0x6e1/0xa20
ksys_read+0xf7/0x1c0
do_syscall_64+0xf9/0x520
Modules linked in: [last unloaded: nf_log_syslog]
Fix this by clearing matching per-net logger selections in every live
network namespace while holding nf_log_mutex after removing the global
registrations. Writers that run before this pass are covered by the
per-net clears, and writes that run later can no longer find the logger
in loggers[][]. The existing synchronize_rcu() then covers readers of
both the global and per-net pointers before module memory is released.
Fixes: 5b023fc8d8e0 ("netfilter: enable per netns support for nf_loggers")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
net/netfilter/nf_log.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index f4d80654dfe6..442c69f544a1 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -42,6 +42,18 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger)
return NULL;
}
+static void __nf_log_unset(struct net *net, const struct nf_logger *logger)
+{
+ const struct nf_logger *log;
+ int i;
+
+ for (i = 0; i < NFPROTO_NUMPROTO; i++) {
+ log = nft_log_dereference(net->nf.nf_loggers[i]);
+ if (log == logger)
+ RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
+ }
+}
+
int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
{
const struct nf_logger *log;
@@ -62,15 +74,8 @@ EXPORT_SYMBOL(nf_log_set);
void nf_log_unset(struct net *net, const struct nf_logger *logger)
{
- int i;
- const struct nf_logger *log;
-
mutex_lock(&nf_log_mutex);
- for (i = 0; i < NFPROTO_NUMPROTO; i++) {
- log = nft_log_dereference(net->nf.nf_loggers[i]);
- if (log == logger)
- RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
- }
+ __nf_log_unset(net, logger);
mutex_unlock(&nf_log_mutex);
}
EXPORT_SYMBOL(nf_log_unset);
@@ -112,6 +117,7 @@ EXPORT_SYMBOL(nf_log_register);
void nf_log_unregister(struct nf_logger *logger)
{
const struct nf_logger *log;
+ struct net *net;
int i;
mutex_lock(&nf_log_mutex);
@@ -120,6 +126,10 @@ void nf_log_unregister(struct nf_logger *logger)
if (log == logger)
RCU_INIT_POINTER(loggers[i][logger->type], NULL);
}
+ rcu_read_lock();
+ for_each_net_rcu(net)
+ __nf_log_unset(net, logger);
+ rcu_read_unlock();
mutex_unlock(&nf_log_mutex);
synchronize_rcu();
}
--
2.43.0
next reply other threads:[~2026-08-22 18:47 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-22 18:46 Chengfeng Ye [this message]
2026-08-23 15:51 ` [PATCH] netfilter: nf_log: clear per-net loggers on unregister Florian Westphal
2026-08-23 16:40 ` Chengfeng Ye
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260822184658.3787672-1-nicoyip.dev@gmail.com \
--to=nicoyip.dev@gmail.com \
--cc=coreteam@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=gaofeng@cn.fujitsu.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.