mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02: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: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
bffcaad9af
commit
02a3231b6d
|
|
@ -22,10 +22,16 @@ struct nf_conntrack_expect {
|
||||||
/* Hash member */
|
/* Hash member */
|
||||||
struct hlist_node hnode;
|
struct hlist_node hnode;
|
||||||
|
|
||||||
|
/* Network namespace */
|
||||||
|
possible_net_t net;
|
||||||
|
|
||||||
/* We expect this tuple, with the following mask */
|
/* We expect this tuple, with the following mask */
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
struct nf_conntrack_tuple_mask mask;
|
struct nf_conntrack_tuple_mask mask;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
||||||
|
struct nf_conntrack_zone zone;
|
||||||
|
#endif
|
||||||
/* Usage count. */
|
/* Usage count. */
|
||||||
refcount_t use;
|
refcount_t use;
|
||||||
|
|
||||||
|
|
@ -62,7 +68,17 @@ struct nf_conntrack_expect {
|
||||||
|
|
||||||
static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
|
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
|
#define NF_CT_EXP_POLICY_NAME_LEN 16
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
|
||||||
unsigned int timeout)
|
unsigned int timeout)
|
||||||
{
|
{
|
||||||
const struct nf_conntrack_helper *helper;
|
const struct nf_conntrack_helper *helper;
|
||||||
|
struct net *net = read_pnet(&ct->ct_net);
|
||||||
struct nf_conntrack_expect *exp;
|
struct nf_conntrack_expect *exp;
|
||||||
struct iphdr *iph = ip_hdr(skb);
|
struct iphdr *iph = ip_hdr(skb);
|
||||||
struct rtable *rt = skb_rtable(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->flags = NF_CT_EXPECT_PERMANENT;
|
||||||
exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
|
exp->class = NF_CT_EXPECT_CLASS_DEFAULT;
|
||||||
rcu_assign_pointer(exp->helper, helper);
|
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_related(exp, 0);
|
||||||
nf_ct_expect_put(exp);
|
nf_ct_expect_put(exp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,8 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple,
|
||||||
const struct net *net)
|
const struct net *net)
|
||||||
{
|
{
|
||||||
return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
|
return nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
|
||||||
net_eq(net, nf_ct_net(i->master)) &&
|
net_eq(net, read_pnet(&i->net)) &&
|
||||||
nf_ct_zone_equal_any(i->master, zone);
|
nf_ct_exp_zone_equal_any(i, zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
|
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_conntrack_helper *helper = NULL;
|
||||||
struct nf_conn *ct = exp->master;
|
struct nf_conn *ct = exp->master;
|
||||||
|
struct net *net = read_pnet(&ct->ct_net);
|
||||||
struct nf_conn_help *help;
|
struct nf_conn_help *help;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
|
@ -343,6 +344,10 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
|
||||||
helper = rcu_dereference(help->helper);
|
helper = rcu_dereference(help->helper);
|
||||||
|
|
||||||
rcu_assign_pointer(exp->helper, 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.src.l3num = family;
|
||||||
exp->tuple.dst.protonum = proto;
|
exp->tuple.dst.protonum = proto;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 *tuple,
|
||||||
struct nf_conntrack_tuple *mask)
|
struct nf_conntrack_tuple *mask)
|
||||||
{
|
{
|
||||||
|
struct net *net = read_pnet(&ct->ct_net);
|
||||||
struct nf_conntrack_expect *exp;
|
struct nf_conntrack_expect *exp;
|
||||||
struct nf_conn_help *help;
|
struct nf_conn_help *help;
|
||||||
u32 class = 0;
|
u32 class = 0;
|
||||||
|
|
@ -3577,6 +3578,10 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
|
||||||
|
|
||||||
exp->class = class;
|
exp->class = class;
|
||||||
exp->master = ct;
|
exp->master = ct;
|
||||||
|
write_pnet(&exp->net, net);
|
||||||
|
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
||||||
|
exp->zone = ct->zone;
|
||||||
|
#endif
|
||||||
if (!helper)
|
if (!helper)
|
||||||
helper = rcu_dereference(help->helper);
|
helper = rcu_dereference(help->helper);
|
||||||
rcu_assign_pointer(exp->helper, helper);
|
rcu_assign_pointer(exp->helper, helper);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user