netfilter: nf_conntrack_expect: store netns and zone in expectation

__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: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
This commit is contained in:
Pablo Neira Ayuso
2026-03-20 13:59:46 +01:00
committed by Florian Westphal
parent 55ded7aac3
commit 56a72b3817
3 changed files with 27 additions and 4 deletions

View 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

View 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)
@@ -324,6 +324,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
const union nf_inet_addr *daddr,
u_int8_t proto, const __be16 *src, const __be16 *dst)
{
struct net *net = read_pnet(&exp->master->ct_net);
int len;
if (family == AF_INET)
@@ -335,6 +337,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
exp->class = class;
exp->expectfn = NULL;
rcu_assign_pointer(exp->helper, nfct_help(exp->master)->helper);
write_pnet(&exp->net, net);
exp->zone = exp->master->zone;
exp->tuple.src.l3num = family;
exp->tuple.dst.protonum = proto;

View File

@@ -3539,9 +3539,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple *mask)
{
u_int32_t class = 0;
struct net *net = read_pnet(&ct->ct_net);
struct nf_conntrack_expect *exp;
struct nf_conn_help *help;
u_int32_t class = 0;
int err;
help = nfct_help(ct);
@@ -3578,6 +3579,8 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp->class = class;
exp->master = ct;
write_pnet(&exp->net, net);
exp->zone = ct->zone;
rcu_assign_pointer(exp->helper, helper ? : help->helper);
exp->tuple = *tuple;
exp->mask.src.u3 = mask->src.u3;