Skip to content

Commit fdf6491

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: ctnetlink: make event listener tracking global
pernet tracking doesn't work correctly because other netns might have set NETLINK_LISTEN_ALL_NSID on its event socket. In this case its expected that events originating in other net namespaces are also received. Making pernet-tracking work while also honoring NETLINK_LISTEN_ALL_NSID requires much more intrusive changes both in netlink and nfnetlink, f.e. adding a 'setsockopt' callback that lets nfnetlink know that the event socket entered (or left) ALL_NSID mode. Move to global tracking instead: if there is an event socket anywhere on the system, all net namespaces which have conntrack enabled and use autobind mode will allocate the ecache extension. netlink_has_listeners() returns false only if the given group has no subscribers in any net namespace, the 'net' argument passed to nfnetlink_has_listeners is only used to derive the protocol (nfnetlink), it has no other effect. For proper NETLINK_LISTEN_ALL_NSID-aware pernet tracking of event listeners a new netlink_has_net_listeners() is also needed. Fixes: 90d1daa ("netfilter: conntrack: add nf_conntrack_events autodetect mode") Reported-by: Bryce Kahle <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 05c07c0 commit fdf6491

File tree

5 files changed

+14
-6
lines changed

5 files changed

+14
-6
lines changed

include/linux/netfilter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,9 @@ extern const struct nfnl_ct_hook __rcu *nfnl_ct_hook;
488488
*/
489489
DECLARE_PER_CPU(bool, nf_skb_duplicated);
490490

491+
/**
492+
* Contains bitmask of ctnetlink event subscribers, if any.
493+
* Can't be pernet due to NETLINK_LISTEN_ALL_NSID setsockopt flag.
494+
*/
495+
extern u8 nf_ctnetlink_has_listener;
491496
#endif /*__LINUX_NETFILTER_H*/

include/net/netns/conntrack.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ struct nf_ip_net {
9595

9696
struct netns_ct {
9797
#ifdef CONFIG_NF_CONNTRACK_EVENTS
98-
u8 ctnetlink_has_listener;
9998
bool ecache_dwork_pending;
10099
#endif
101100
u8 sysctl_log_invalid; /* Log invalid packets */

net/netfilter/core.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ const struct nf_ct_hook __rcu *nf_ct_hook __read_mostly;
669669
EXPORT_SYMBOL_GPL(nf_ct_hook);
670670

671671
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
672+
u8 nf_ctnetlink_has_listener;
673+
EXPORT_SYMBOL_GPL(nf_ctnetlink_has_listener);
674+
672675
const struct nf_nat_hook __rcu *nf_nat_hook __read_mostly;
673676
EXPORT_SYMBOL_GPL(nf_nat_hook);
674677

net/netfilter/nf_conntrack_ecache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp
309309
break;
310310
return true;
311311
case 2: /* autodetect: no event listener, don't allocate extension. */
312-
if (!READ_ONCE(net->ct.ctnetlink_has_listener))
312+
if (!READ_ONCE(nf_ctnetlink_has_listener))
313313
return true;
314314
fallthrough;
315315
case 1:

net/netfilter/nfnetlink.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <net/netlink.h>
3131
#include <net/netns/generic.h>
32+
#include <linux/netfilter.h>
3233
#include <linux/netfilter/nfnetlink.h>
3334

3435
MODULE_LICENSE("GPL");
@@ -685,12 +686,12 @@ static void nfnetlink_bind_event(struct net *net, unsigned int group)
685686
group_bit = (1 << group);
686687

687688
spin_lock(&nfnl_grp_active_lock);
688-
v = READ_ONCE(net->ct.ctnetlink_has_listener);
689+
v = READ_ONCE(nf_ctnetlink_has_listener);
689690
if ((v & group_bit) == 0) {
690691
v |= group_bit;
691692

692693
/* read concurrently without nfnl_grp_active_lock held. */
693-
WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
694+
WRITE_ONCE(nf_ctnetlink_has_listener, v);
694695
}
695696

696697
spin_unlock(&nfnl_grp_active_lock);
@@ -744,12 +745,12 @@ static void nfnetlink_unbind(struct net *net, int group)
744745

745746
spin_lock(&nfnl_grp_active_lock);
746747
if (!nfnetlink_has_listeners(net, group)) {
747-
u8 v = READ_ONCE(net->ct.ctnetlink_has_listener);
748+
u8 v = READ_ONCE(nf_ctnetlink_has_listener);
748749

749750
v &= ~group_bit;
750751

751752
/* read concurrently without nfnl_grp_active_lock held. */
752-
WRITE_ONCE(net->ct.ctnetlink_has_listener, v);
753+
WRITE_ONCE(nf_ctnetlink_has_listener, v);
753754
}
754755
spin_unlock(&nfnl_grp_active_lock);
755756
#endif

0 commit comments

Comments
 (0)