mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git
synced 2026-04-03 23:38:12 -04:00
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:
committed by
Florian Westphal
parent
55ded7aac3
commit
56a72b3817
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user