]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nf_conntrack_expect: store netns and zone in expectation
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 25 Mar 2026 21:39:55 +0000 (22:39 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 26 Mar 2026 12:24:40 +0000 (13:24 +0100)
__nf_ct_expect_find() and nf_ct_expect_find_get() are called under
rcu_read_lock() but they dereference the master conntrack via
exp->master.

Since the expectation does not hold a reference on the master conntrack,
this could be dying conntrack or different recycled conntrack than the
real master due to SLAB_TYPESAFE_RCU.

Store the netns, the master_tuple and the zone in struct
nf_conntrack_expect as a safety measure.

This patch is required by the follow up fix not to dump expectations
that do not belong to this netns.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack_expect.h
net/netfilter/nf_conntrack_broadcast.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c

index 1b01400b10bdb298351505e585d2129adf48d3c8..e9a8350e7ccfb030eb79951f9ac1dc457325a040 100644 (file)
@@ -22,10 +22,16 @@ struct nf_conntrack_expect {
        /* Hash member */
        struct hlist_node hnode;
 
+       /* Network namespace */
+       possible_net_t net;
+
        /* We expect this tuple, with the following mask */
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_tuple_mask mask;
 
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       struct nf_conntrack_zone zone;
+#endif
        /* Usage count. */
        refcount_t use;
 
@@ -62,7 +68,17 @@ struct nf_conntrack_expect {
 
 static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
 {
-       return nf_ct_net(exp->master);
+       return read_pnet(&exp->net);
+}
+
+static inline bool nf_ct_exp_zone_equal_any(const struct nf_conntrack_expect *a,
+                                           const struct nf_conntrack_zone *b)
+{
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       return a->zone.id == b->id;
+#else
+       return true;
+#endif
 }
 
 #define NF_CT_EXP_POLICY_NAME_LEN      16
index 1964c596c6468f544764bf31792e7901db2269d2..4f39bf7c843f2df0a55443f187a17eb3c5d6fc12 100644 (file)
@@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
                                unsigned int timeout)
 {
        const struct nf_conntrack_helper *helper;
+       struct net *net = read_pnet(&ct->ct_net);
        struct nf_conntrack_expect *exp;
        struct iphdr *iph = ip_hdr(skb);
        struct rtable *rt = skb_rtable(skb);
@@ -71,7 +72,10 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
        exp->flags                = NF_CT_EXPECT_PERMANENT;
        exp->class                = NF_CT_EXPECT_CLASS_DEFAULT;
        rcu_assign_pointer(exp->helper, helper);
-
+       write_pnet(&exp->net, net);
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       exp->zone = ct->zone;
+#endif
        nf_ct_expect_related(exp, 0);
        nf_ct_expect_put(exp);
 
index 1cbe5f1108c2fa53dc51c482c00559db0f7955eb..db28801b1688a9cd84f63a72552bde089366a1df 100644 (file)
@@ -113,8 +113,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
                const struct net *net)
 {
        return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
-              net_eq(net, nf_ct_net(i->master)) &&
-              nf_ct_zone_equal_any(i->master, zone);
+              net_eq(net, read_pnet(&i->net)) &&
+              nf_ct_exp_zone_equal_any(i, zone);
 }
 
 bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
@@ -326,6 +326,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
 {
        struct nf_conntrack_helper *helper = NULL;
        struct nf_conn *ct = exp->master;
+       struct net *net = read_pnet(&ct->ct_net);
        struct nf_conn_help *help;
        int len;
 
@@ -343,6 +344,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
                helper = rcu_dereference(help->helper);
 
        rcu_assign_pointer(exp->helper, helper);
+       write_pnet(&exp->net, net);
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       exp->zone = ct->zone;
+#endif
        exp->tuple.src.l3num = family;
        exp->tuple.dst.protonum = proto;
 
index 89540112d165fd6b7f5c540923e89161f24cad76..6e6aeb0ab0a1bd1779eed6ee7cf7db4b397d6da3 100644 (file)
@@ -3538,6 +3538,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
                       struct nf_conntrack_tuple *tuple,
                       struct nf_conntrack_tuple *mask)
 {
+       struct net *net = read_pnet(&ct->ct_net);
        struct nf_conntrack_expect *exp;
        struct nf_conn_help *help;
        u32 class = 0;
@@ -3577,6 +3578,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
 
        exp->class = class;
        exp->master = ct;
+       write_pnet(&exp->net, net);
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+       exp->zone = ct->zone;
+#endif
        if (!helper)
                helper = rcu_dereference(help->helper);
        rcu_assign_pointer(exp->helper, helper);