[PATCH net v2] netfilter: nf_log: unregister loggers before per-net teardown
Chengfeng Ye <[email protected]>
| Newsgroups | org.kernel.vger.netdev,org.kernel.vger.linux-kernel,org.kernel.vger.netfilter-devel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
nf_log_syslog and nfnetlink_log unregister their per-network namespace
operations before unregistering their global logger backends. This
leaves a window where a sysctl or netlink writer can rebind the still-
registered logger after the per-net pre-exit callback cleared the old
selection.
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 packet logging operation can dereference the
stale per-net logger pointer.
Fix this by unregistering the global logger backends before tearing down
per-net state. Once the global registrations are gone, later writers can
no longer rebind the logger. unregister_pernet_subsys() already waits
for an RCU grace period after the pre-exit callback clears the per-net
selection, while nf_log_unregister() continues to cover readers of the
global logger table.
Apply this ordering fix to both nf_log backends that combine per-net
teardown with global logger registration.
Fixes: 5b023fc8d8e0 ("netfilter: enable per netns support for nf_loggers")
Cc: [email protected]
Signed-off-by: Chengfeng Ye <[email protected]>
---
Changes in v2:
- Rework the fix around backend teardown ordering instead of clearing
per-net bindings from nf_log_unregister().
- Apply the ordering fix to both nf_log_syslog and nfnetlink_log.
- Drop the redundant trailing synchronize_rcu().
Link: https://lore.kernel.org/netdev/[email protected]/ [v1]
---
net/netfilter/nf_log_syslog.c | 2 +-
net/netfilter/nfnetlink_log.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c
--- a/net/netfilter/nf_log_syslog.c
+++ b/net/netfilter/nf_log_syslog.c
@@ -1073,12 +1073,12 @@
static void __exit nf_log_syslog_exit(void)
{
- unregister_pernet_subsys(&nf_log_syslog_net_ops);
nf_log_unregister(&nf_ip_logger);
nf_log_unregister(&nf_arp_logger);
nf_log_unregister(&nf_ip6_logger);
nf_log_unregister(&nf_netdev_logger);
nf_log_unregister(&nf_bridge_logger);
+ unregister_pernet_subsys(&nf_log_syslog_net_ops);
}
module_init(nf_log_syslog_init);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1233,8 +1233,8 @@
{
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
- unregister_pernet_subsys(&nfnl_log_net_ops);
nf_log_unregister(&nfulnl_logger);
+ unregister_pernet_subsys(&nfnl_log_net_ops);
}
MODULE_DESCRIPTION("netfilter userspace logging");
--
2.43.0