diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2016-06-06 12:54:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-06-07 19:38:59 -0400 |
commit | a03e6fe569713fb3ff0714f8fd7c8785c0ca9e22 (patch) | |
tree | 2503e58b9720cb4ee120033ab4df1bc97ba93c4c /net | |
parent | aafddbf0cffeb790f919436285328c762279b5d4 (diff) |
act_police: fix a crash during removal
The police action is using its own code to initialize tcf hash
info, which makes us to forgot to initialize a->hinfo correctly.
Fix this by calling the helper function tcf_hash_create() directly.
This patch fixed the following crash:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffff810c099f>] __lock_acquire+0xd3/0xf91
PGD d3c34067 PUD d3e18067 PMD 0
Oops: 0000 [#1] SMP
CPU: 2 PID: 853 Comm: tc Not tainted 4.6.0+ #87
Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
task: ffff8800d3e28040 ti: ffff8800d3f6c000 task.ti: ffff8800d3f6c000
RIP: 0010:[<ffffffff810c099f>] [<ffffffff810c099f>] __lock_acquire+0xd3/0xf91
RSP: 0000:ffff88011b203c80 EFLAGS: 00010002
RAX: 0000000000000046 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000028
RBP: ffff88011b203d40 R08: 0000000000000001 R09: 0000000000000000
R10: ffff88011b203d58 R11: ffff88011b208000 R12: 0000000000000001
R13: ffff8800d3e28040 R14: 0000000000000028 R15: 0000000000000000
FS: 0000000000000000(0000) GS:ffff88011b200000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000028 CR3: 00000000d4be1000 CR4: 00000000000006e0
Stack:
ffff8800d3e289c0 0000000000000046 000000001b203d60 ffffffff00000000
0000000000000000 ffff880000000000 0000000000000000 ffffffff00000000
ffffffff8187142c ffff88011b203ce8 ffff88011b203ce8 ffffffff8101dbfc
Call Trace:
<IRQ>
[<ffffffff8187142c>] ? __tcf_hash_release+0x77/0xd1
[<ffffffff8101dbfc>] ? native_sched_clock+0x1a/0x35
[<ffffffff8101dbfc>] ? native_sched_clock+0x1a/0x35
[<ffffffff810a9604>] ? sched_clock_local+0x11/0x78
[<ffffffff810bf6a1>] ? mark_lock+0x24/0x201
[<ffffffff810c1dbd>] lock_acquire+0x120/0x1b4
[<ffffffff810c1dbd>] ? lock_acquire+0x120/0x1b4
[<ffffffff8187142c>] ? __tcf_hash_release+0x77/0xd1
[<ffffffff81aad89f>] _raw_spin_lock_bh+0x3c/0x72
[<ffffffff8187142c>] ? __tcf_hash_release+0x77/0xd1
[<ffffffff8187142c>] __tcf_hash_release+0x77/0xd1
[<ffffffff81871a27>] tcf_action_destroy+0x49/0x7c
[<ffffffff81870b1c>] tcf_exts_destroy+0x20/0x2d
[<ffffffff8189273b>] u32_destroy_key+0x1b/0x4d
[<ffffffff81892788>] u32_delete_key_freepf_rcu+0x1b/0x1d
[<ffffffff810de3b8>] rcu_process_callbacks+0x610/0x82e
[<ffffffff8189276d>] ? u32_destroy_key+0x4d/0x4d
[<ffffffff81ab0bc1>] __do_softirq+0x191/0x3f4
Fixes: ddf97ccdd7cb ("net_sched: add network namespace support for tc actions")
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/act_police.c | 33 |
1 files changed, 11 insertions, 22 deletions
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index b884dae692a1..c557789765dc 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -38,7 +38,7 @@ struct tcf_police { | |||
38 | bool peak_present; | 38 | bool peak_present; |
39 | }; | 39 | }; |
40 | #define to_police(pc) \ | 40 | #define to_police(pc) \ |
41 | container_of(pc, struct tcf_police, common) | 41 | container_of(pc->priv, struct tcf_police, common) |
42 | 42 | ||
43 | #define POL_TAB_MASK 15 | 43 | #define POL_TAB_MASK 15 |
44 | 44 | ||
@@ -119,14 +119,12 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
119 | struct nlattr *est, struct tc_action *a, | 119 | struct nlattr *est, struct tc_action *a, |
120 | int ovr, int bind) | 120 | int ovr, int bind) |
121 | { | 121 | { |
122 | unsigned int h; | ||
123 | int ret = 0, err; | 122 | int ret = 0, err; |
124 | struct nlattr *tb[TCA_POLICE_MAX + 1]; | 123 | struct nlattr *tb[TCA_POLICE_MAX + 1]; |
125 | struct tc_police *parm; | 124 | struct tc_police *parm; |
126 | struct tcf_police *police; | 125 | struct tcf_police *police; |
127 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; | 126 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; |
128 | struct tc_action_net *tn = net_generic(net, police_net_id); | 127 | struct tc_action_net *tn = net_generic(net, police_net_id); |
129 | struct tcf_hashinfo *hinfo = tn->hinfo; | ||
130 | int size; | 128 | int size; |
131 | 129 | ||
132 | if (nla == NULL) | 130 | if (nla == NULL) |
@@ -145,7 +143,7 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
145 | 143 | ||
146 | if (parm->index) { | 144 | if (parm->index) { |
147 | if (tcf_hash_search(tn, a, parm->index)) { | 145 | if (tcf_hash_search(tn, a, parm->index)) { |
148 | police = to_police(a->priv); | 146 | police = to_police(a); |
149 | if (bind) { | 147 | if (bind) { |
150 | police->tcf_bindcnt += 1; | 148 | police->tcf_bindcnt += 1; |
151 | police->tcf_refcnt += 1; | 149 | police->tcf_refcnt += 1; |
@@ -156,16 +154,15 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla, | |||
156 | /* not replacing */ | 154 | /* not replacing */ |
157 | return -EEXIST; | 155 | return -EEXIST; |
158 | } | 156 | } |
157 | } else { | ||
158 | ret = tcf_hash_create(tn, parm->index, NULL, a, | ||
159 | sizeof(*police), bind, false); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | ret = ACT_P_CREATED; | ||
159 | } | 163 | } |
160 | 164 | ||
161 | police = kzalloc(sizeof(*police), GFP_KERNEL); | 165 | police = to_police(a); |
162 | if (police == NULL) | ||
163 | return -ENOMEM; | ||
164 | ret = ACT_P_CREATED; | ||
165 | police->tcf_refcnt = 1; | ||
166 | spin_lock_init(&police->tcf_lock); | ||
167 | if (bind) | ||
168 | police->tcf_bindcnt = 1; | ||
169 | override: | 166 | override: |
170 | if (parm->rate.rate) { | 167 | if (parm->rate.rate) { |
171 | err = -ENOMEM; | 168 | err = -ENOMEM; |
@@ -237,16 +234,8 @@ override: | |||
237 | return ret; | 234 | return ret; |
238 | 235 | ||
239 | police->tcfp_t_c = ktime_get_ns(); | 236 | police->tcfp_t_c = ktime_get_ns(); |
240 | police->tcf_index = parm->index ? parm->index : | 237 | tcf_hash_insert(tn, a); |
241 | tcf_hash_new_index(tn); | ||
242 | police->tcf_tm.install = jiffies; | ||
243 | police->tcf_tm.lastuse = jiffies; | ||
244 | h = tcf_hash(police->tcf_index, POL_TAB_MASK); | ||
245 | spin_lock_bh(&hinfo->lock); | ||
246 | hlist_add_head(&police->tcf_head, &hinfo->htab[h]); | ||
247 | spin_unlock_bh(&hinfo->lock); | ||
248 | 238 | ||
249 | a->priv = police; | ||
250 | return ret; | 239 | return ret; |
251 | 240 | ||
252 | failure_unlock: | 241 | failure_unlock: |
@@ -255,7 +244,7 @@ failure: | |||
255 | qdisc_put_rtab(P_tab); | 244 | qdisc_put_rtab(P_tab); |
256 | qdisc_put_rtab(R_tab); | 245 | qdisc_put_rtab(R_tab); |
257 | if (ret == ACT_P_CREATED) | 246 | if (ret == ACT_P_CREATED) |
258 | kfree(police); | 247 | tcf_hash_cleanup(a, est); |
259 | return err; | 248 | return err; |
260 | } | 249 | } |
261 | 250 | ||