Commit 38166934 authored by Cong Wang's avatar Cong Wang Committed by Greg Kroah-Hartman

net_sched: fix a NULL pointer deref in ipt action

[ Upstream commit 981471bd ]

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: 0c66dc1e ("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: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5ff0ab0c
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
struct tcf_idrinfo { struct tcf_idrinfo {
spinlock_t lock; spinlock_t lock;
struct idr action_idr; struct idr action_idr;
struct net *net;
}; };
struct tc_action_ops; struct tc_action_ops;
...@@ -107,7 +108,7 @@ struct tc_action_net { ...@@ -107,7 +108,7 @@ struct tc_action_net {
}; };
static inline 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) const struct tc_action_ops *ops)
{ {
int err = 0; int err = 0;
...@@ -116,6 +117,7 @@ int tc_action_net_init(struct tc_action_net *tn, ...@@ -116,6 +117,7 @@ int tc_action_net_init(struct tc_action_net *tn,
if (!tn->idrinfo) if (!tn->idrinfo)
return -ENOMEM; return -ENOMEM;
tn->ops = ops; tn->ops = ops;
tn->idrinfo->net = net;
spin_lock_init(&tn->idrinfo->lock); spin_lock_init(&tn->idrinfo->lock);
idr_init(&tn->idrinfo->action_idr); idr_init(&tn->idrinfo->action_idr);
return err; return err;
......
...@@ -413,7 +413,7 @@ static __net_init int bpf_init_net(struct net *net) ...@@ -413,7 +413,7 @@ static __net_init int bpf_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, bpf_net_id); 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) static void __net_exit bpf_exit_net(struct list_head *net_list)
......
...@@ -215,7 +215,7 @@ static __net_init int connmark_init_net(struct net *net) ...@@ -215,7 +215,7 @@ static __net_init int connmark_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, connmark_net_id); 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) static void __net_exit connmark_exit_net(struct list_head *net_list)
......
...@@ -678,7 +678,7 @@ static __net_init int csum_init_net(struct net *net) ...@@ -678,7 +678,7 @@ static __net_init int csum_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, csum_net_id); 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) static void __net_exit csum_exit_net(struct list_head *net_list)
......
...@@ -263,7 +263,7 @@ static __net_init int gact_init_net(struct net *net) ...@@ -263,7 +263,7 @@ static __net_init int gact_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, gact_net_id); 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) static void __net_exit gact_exit_net(struct list_head *net_list)
......
...@@ -887,7 +887,7 @@ static __net_init int ife_init_net(struct net *net) ...@@ -887,7 +887,7 @@ static __net_init int ife_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ife_net_id); 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) static void __net_exit ife_exit_net(struct list_head *net_list)
......
...@@ -65,12 +65,13 @@ static int ipt_init_target(struct net *net, struct xt_entry_target *t, ...@@ -65,12 +65,13 @@ static int ipt_init_target(struct net *net, struct xt_entry_target *t,
return 0; 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 = { struct xt_tgdtor_param par = {
.target = t->u.kernel.target, .target = t->u.kernel.target,
.targinfo = t->data, .targinfo = t->data,
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.net = net,
}; };
if (par.target->destroy != NULL) if (par.target->destroy != NULL)
par.target->destroy(&par); par.target->destroy(&par);
...@@ -82,7 +83,7 @@ static void tcf_ipt_release(struct tc_action *a) ...@@ -82,7 +83,7 @@ static void tcf_ipt_release(struct tc_action *a)
struct tcf_ipt *ipt = to_ipt(a); struct tcf_ipt *ipt = to_ipt(a);
if (ipt->tcfi_t) { 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_t);
} }
kfree(ipt->tcfi_tname); kfree(ipt->tcfi_tname);
...@@ -182,7 +183,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, ...@@ -182,7 +183,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
spin_lock_bh(&ipt->tcf_lock); spin_lock_bh(&ipt->tcf_lock);
if (ret != ACT_P_CREATED) { 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_tname);
kfree(ipt->tcfi_t); kfree(ipt->tcfi_t);
} }
...@@ -353,7 +354,7 @@ static __net_init int ipt_init_net(struct net *net) ...@@ -353,7 +354,7 @@ static __net_init int ipt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, ipt_net_id); 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) static void __net_exit ipt_exit_net(struct list_head *net_list)
...@@ -403,7 +404,7 @@ static __net_init int xt_init_net(struct net *net) ...@@ -403,7 +404,7 @@ static __net_init int xt_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, xt_net_id); 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) static void __net_exit xt_exit_net(struct list_head *net_list)
......
...@@ -419,7 +419,7 @@ static __net_init int mirred_init_net(struct net *net) ...@@ -419,7 +419,7 @@ static __net_init int mirred_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, mirred_net_id); 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) static void __net_exit mirred_exit_net(struct list_head *net_list)
......
...@@ -317,7 +317,7 @@ static __net_init int nat_init_net(struct net *net) ...@@ -317,7 +317,7 @@ static __net_init int nat_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, nat_net_id); 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) static void __net_exit nat_exit_net(struct list_head *net_list)
......
...@@ -488,7 +488,7 @@ static __net_init int pedit_init_net(struct net *net) ...@@ -488,7 +488,7 @@ static __net_init int pedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, pedit_net_id); 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) static void __net_exit pedit_exit_net(struct list_head *net_list)
......
...@@ -342,7 +342,7 @@ static __net_init int police_init_net(struct net *net) ...@@ -342,7 +342,7 @@ static __net_init int police_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, police_net_id); 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) static void __net_exit police_exit_net(struct list_head *net_list)
......
...@@ -258,7 +258,7 @@ static __net_init int sample_init_net(struct net *net) ...@@ -258,7 +258,7 @@ static __net_init int sample_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, sample_net_id); 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) static void __net_exit sample_exit_net(struct list_head *net_list)
......
...@@ -215,7 +215,7 @@ static __net_init int simp_init_net(struct net *net) ...@@ -215,7 +215,7 @@ static __net_init int simp_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, simp_net_id); 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) static void __net_exit simp_exit_net(struct list_head *net_list)
......
...@@ -316,7 +316,7 @@ static __net_init int skbedit_init_net(struct net *net) ...@@ -316,7 +316,7 @@ static __net_init int skbedit_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbedit_net_id); 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) static void __net_exit skbedit_exit_net(struct list_head *net_list)
......
...@@ -277,7 +277,7 @@ static __net_init int skbmod_init_net(struct net *net) ...@@ -277,7 +277,7 @@ static __net_init int skbmod_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, skbmod_net_id); 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) static void __net_exit skbmod_exit_net(struct list_head *net_list)
......
...@@ -579,7 +579,7 @@ static __net_init int tunnel_key_init_net(struct net *net) ...@@ -579,7 +579,7 @@ static __net_init int tunnel_key_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); 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) static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
......
...@@ -324,7 +324,7 @@ static __net_init int vlan_init_net(struct net *net) ...@@ -324,7 +324,7 @@ static __net_init int vlan_init_net(struct net *net)
{ {
struct tc_action_net *tn = net_generic(net, vlan_net_id); 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) static void __net_exit vlan_exit_net(struct list_head *net_list)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment