]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nf_conntrack_expect: store master_tuple in expectation
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 22 Jun 2026 19:35:14 +0000 (21:35 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 23 Jun 2026 11:10:34 +0000 (13:10 +0200)
Store master conntrack tuple in the expectation since exp->master might
refer to a different conntrack when accessed from rcu read side lock
area due to typesafe rcu rules.

Fixes: 02a3231b6d82 ("netfilter: nf_conntrack_expect: store netns and zone in expectation")
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 be4a120d549eb3cc16378b2379257f3887c2e9ea..c024345c9bd862f5fa8e0d1e480a8ce220293c9e 100644 (file)
@@ -26,6 +26,7 @@ struct nf_conntrack_expect {
        possible_net_t net;
 
        /* We expect this tuple, with the following mask */
+       struct nf_conntrack_tuple master_tuple;
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_tuple_mask mask;
 
index 400119b6320e727460c2e2ab0b660f7f50fdfbcb..bf78828c7549d4e5b4041697af5e11e97048847d 100644 (file)
@@ -62,6 +62,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
        if (exp == NULL)
                goto out;
 
+       exp->master_tuple         = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
        exp->tuple                = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
 
        helper = rcu_dereference(help->helper);
index 49e18eda037ef16e88b971331d4c335a144f0742..9454913e1b337e8cb3c30d374b10f82e4179b80d 100644 (file)
@@ -355,6 +355,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
        exp->tuple.src.l3num = family;
        exp->tuple.dst.protonum = proto;
 
+       exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+
        if (saddr) {
                memcpy(&exp->tuple.src.u3, saddr, len);
                if (sizeof(exp->tuple.src.u3) > len)
index cb38ef42e9e6caa02e9933d3b07a897bcab2a670..4217715d42dc24486514125a25f590d6a80066a6 100644 (file)
@@ -3002,7 +3002,6 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
                          const struct nf_conntrack_expect *exp)
 {
        __s32 timeout = (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ;
-       struct nf_conn *master = exp->master;
        struct nf_conntrack_helper *helper;
 #if IS_ENABLED(CONFIG_NF_NAT)
        struct nlattr *nest_parms;
@@ -3017,9 +3016,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
                goto nla_put_failure;
        if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
                goto nla_put_failure;
-       if (ctnetlink_exp_dump_tuple(skb,
-                                &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
-                                CTA_EXPECT_MASTER) < 0)
+       if (ctnetlink_exp_dump_tuple(skb, &exp->master_tuple, CTA_EXPECT_MASTER) < 0)
                goto nla_put_failure;
 
 #if IS_ENABLED(CONFIG_NF_NAT)
@@ -3032,9 +3029,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
                if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
                        goto nla_put_failure;
 
-               nat_tuple.src.l3num = nf_ct_l3num(master);
+               nat_tuple.src.l3num = exp->master_tuple.src.l3num;
                nat_tuple.src.u3 = exp->saved_addr;
-               nat_tuple.dst.protonum = nf_ct_protonum(master);
+               nat_tuple.dst.protonum = exp->master_tuple.dst.protonum;
                nat_tuple.src.u = exp->saved_proto;
 
                if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
@@ -3576,6 +3573,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
 #endif
        rcu_assign_pointer(exp->helper, helper);
        rcu_assign_pointer(exp->assign_helper, assign_helper);
+       exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
        exp->tuple = *tuple;
        exp->mask.src.u3 = mask->src.u3;
        exp->mask.src.u.all = mask->src.u.all;