net_sched: fix a NULL pointer deref in ipt action
The net pointer in struct xt_tgdtor_param is not explicitly
initialized therefore is still NULL when dereferencing it.
So we have to find a way to pass the correct net pointer to
ipt_destroy_target().
The best way I find is just saving the net pointer inside the per
netns struct tcf_idrinfo, which could make this patch smaller.
Fixes: 0c66dc1ea3
("netfilter: conntrack: register hooks in netns when needed by ruleset")
Reported-and-tested-by: itugrok@yahoo.com
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9e8312f5e1
commit
981471bd3a
|
@ -15,6 +15,7 @@
|
|||
struct tcf_idrinfo {
|
||||
struct mutex lock;
|
||||
struct idr action_idr;
|
||||
struct net *net;
|
||||
};
|
||||
|
||||
struct tc_action_ops;
|
||||
|
@ -108,7 +109,7 @@ struct tc_action_net {
|
|||
};
|
||||
|
||||
static inline
|
||||
int tc_action_net_init(struct tc_action_net *tn,
|
||||
int tc_action_net_init(struct net *net, struct tc_action_net *tn,
|
||||
const struct tc_action_ops *ops)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -117,6 +118,7 @@ int tc_action_net_init(struct tc_action_net *tn,
|
|||
if (!tn->idrinfo)
|
||||
return -ENOMEM;
|
||||
tn->ops = ops;
|
||||
tn->idrinfo->net = net;
|
||||
mutex_init(&tn->idrinfo->lock);
|
||||
idr_init(&tn->idrinfo->action_idr);
|
||||
return err;
|
||||
|
|
|
@ -422,7 +422,7 @@ static __net_init int bpf_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, bpf_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_bpf_ops);
|
||||
return tc_action_net_init(net, tn, &act_bpf_ops);
|
||||
}
|
||||
|
||||
static void __net_exit bpf_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -231,7 +231,7 @@ static __net_init int connmark_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, connmark_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_connmark_ops);
|
||||
return tc_action_net_init(net, tn, &act_connmark_ops);
|
||||
}
|
||||
|
||||
static void __net_exit connmark_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -714,7 +714,7 @@ static __net_init int csum_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, csum_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_csum_ops);
|
||||
return tc_action_net_init(net, tn, &act_csum_ops);
|
||||
}
|
||||
|
||||
static void __net_exit csum_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -939,7 +939,7 @@ static __net_init int ct_init_net(struct net *net)
|
|||
tn->labels = true;
|
||||
}
|
||||
|
||||
return tc_action_net_init(&tn->tn, &act_ct_ops);
|
||||
return tc_action_net_init(net, &tn->tn, &act_ct_ops);
|
||||
}
|
||||
|
||||
static void __net_exit ct_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -376,7 +376,7 @@ static __net_init int ctinfo_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_ctinfo_ops);
|
||||
return tc_action_net_init(net, tn, &act_ctinfo_ops);
|
||||
}
|
||||
|
||||
static void __net_exit ctinfo_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -278,7 +278,7 @@ static __net_init int gact_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, gact_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_gact_ops);
|
||||
return tc_action_net_init(net, tn, &act_gact_ops);
|
||||
}
|
||||
|
||||
static void __net_exit gact_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -890,7 +890,7 @@ static __net_init int ife_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, ife_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_ife_ops);
|
||||
return tc_action_net_init(net, tn, &act_ife_ops);
|
||||
}
|
||||
|
||||
static void __net_exit ife_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -61,12 +61,13 @@ static int ipt_init_target(struct net *net, struct xt_entry_target *t,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ipt_destroy_target(struct xt_entry_target *t)
|
||||
static void ipt_destroy_target(struct xt_entry_target *t, struct net *net)
|
||||
{
|
||||
struct xt_tgdtor_param par = {
|
||||
.target = t->u.kernel.target,
|
||||
.targinfo = t->data,
|
||||
.family = NFPROTO_IPV4,
|
||||
.net = net,
|
||||
};
|
||||
if (par.target->destroy != NULL)
|
||||
par.target->destroy(&par);
|
||||
|
@ -78,7 +79,7 @@ static void tcf_ipt_release(struct tc_action *a)
|
|||
struct tcf_ipt *ipt = to_ipt(a);
|
||||
|
||||
if (ipt->tcfi_t) {
|
||||
ipt_destroy_target(ipt->tcfi_t);
|
||||
ipt_destroy_target(ipt->tcfi_t, a->idrinfo->net);
|
||||
kfree(ipt->tcfi_t);
|
||||
}
|
||||
kfree(ipt->tcfi_tname);
|
||||
|
@ -180,7 +181,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
|
|||
|
||||
spin_lock_bh(&ipt->tcf_lock);
|
||||
if (ret != ACT_P_CREATED) {
|
||||
ipt_destroy_target(ipt->tcfi_t);
|
||||
ipt_destroy_target(ipt->tcfi_t, net);
|
||||
kfree(ipt->tcfi_tname);
|
||||
kfree(ipt->tcfi_t);
|
||||
}
|
||||
|
@ -350,7 +351,7 @@ static __net_init int ipt_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, ipt_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_ipt_ops);
|
||||
return tc_action_net_init(net, tn, &act_ipt_ops);
|
||||
}
|
||||
|
||||
static void __net_exit ipt_exit_net(struct list_head *net_list)
|
||||
|
@ -399,7 +400,7 @@ static __net_init int xt_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, xt_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_xt_ops);
|
||||
return tc_action_net_init(net, tn, &act_xt_ops);
|
||||
}
|
||||
|
||||
static void __net_exit xt_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -453,7 +453,7 @@ static __net_init int mirred_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, mirred_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_mirred_ops);
|
||||
return tc_action_net_init(net, tn, &act_mirred_ops);
|
||||
}
|
||||
|
||||
static void __net_exit mirred_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -375,7 +375,7 @@ static __net_init int mpls_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, mpls_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_mpls_ops);
|
||||
return tc_action_net_init(net, tn, &act_mpls_ops);
|
||||
}
|
||||
|
||||
static void __net_exit mpls_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -327,7 +327,7 @@ static __net_init int nat_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, nat_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_nat_ops);
|
||||
return tc_action_net_init(net, tn, &act_nat_ops);
|
||||
}
|
||||
|
||||
static void __net_exit nat_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -498,7 +498,7 @@ static __net_init int pedit_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, pedit_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_pedit_ops);
|
||||
return tc_action_net_init(net, tn, &act_pedit_ops);
|
||||
}
|
||||
|
||||
static void __net_exit pedit_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -371,7 +371,7 @@ static __net_init int police_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, police_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_police_ops);
|
||||
return tc_action_net_init(net, tn, &act_police_ops);
|
||||
}
|
||||
|
||||
static void __net_exit police_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -265,7 +265,7 @@ static __net_init int sample_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, sample_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_sample_ops);
|
||||
return tc_action_net_init(net, tn, &act_sample_ops);
|
||||
}
|
||||
|
||||
static void __net_exit sample_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -232,7 +232,7 @@ static __net_init int simp_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, simp_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_simp_ops);
|
||||
return tc_action_net_init(net, tn, &act_simp_ops);
|
||||
}
|
||||
|
||||
static void __net_exit simp_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -336,7 +336,7 @@ static __net_init int skbedit_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, skbedit_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_skbedit_ops);
|
||||
return tc_action_net_init(net, tn, &act_skbedit_ops);
|
||||
}
|
||||
|
||||
static void __net_exit skbedit_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -287,7 +287,7 @@ static __net_init int skbmod_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, skbmod_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_skbmod_ops);
|
||||
return tc_action_net_init(net, tn, &act_skbmod_ops);
|
||||
}
|
||||
|
||||
static void __net_exit skbmod_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -600,7 +600,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_tunnel_key_ops);
|
||||
return tc_action_net_init(net, tn, &act_tunnel_key_ops);
|
||||
}
|
||||
|
||||
static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
|
||||
|
|
|
@ -334,7 +334,7 @@ static __net_init int vlan_init_net(struct net *net)
|
|||
{
|
||||
struct tc_action_net *tn = net_generic(net, vlan_net_id);
|
||||
|
||||
return tc_action_net_init(tn, &act_vlan_ops);
|
||||
return tc_action_net_init(net, tn, &act_vlan_ops);
|
||||
}
|
||||
|
||||
static void __net_exit vlan_exit_net(struct list_head *net_list)
|
||||
|
|
Loading…
Reference in New Issue