Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

WANG Cong and committed by
David S. Miller
a03e6fe5 aafddbf0

+11 -22
+11 -22
net/sched/act_police.c
··· 38 38 bool peak_present; 39 39 }; 40 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 43 #define POL_TAB_MASK 15 44 44 ··· 119 119 struct nlattr *est, struct tc_action *a, 120 120 int ovr, int bind) 121 121 { 122 - unsigned int h; 123 122 int ret = 0, err; 124 123 struct nlattr *tb[TCA_POLICE_MAX + 1]; 125 124 struct tc_police *parm; 126 125 struct tcf_police *police; 127 126 struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; 128 127 struct tc_action_net *tn = net_generic(net, police_net_id); 129 - struct tcf_hashinfo *hinfo = tn->hinfo; 130 128 int size; 131 129 132 130 if (nla == NULL) ··· 143 145 144 146 if (parm->index) { 145 147 if (tcf_hash_search(tn, a, parm->index)) { 146 - police = to_police(a->priv); 148 + police = to_police(a); 147 149 if (bind) { 148 150 police->tcf_bindcnt += 1; 149 151 police->tcf_refcnt += 1; ··· 154 156 /* not replacing */ 155 157 return -EEXIST; 156 158 } 159 + } else { 160 + ret = tcf_hash_create(tn, parm->index, NULL, a, 161 + sizeof(*police), bind, false); 162 + if (ret) 163 + return ret; 164 + ret = ACT_P_CREATED; 157 165 } 158 166 159 - police = kzalloc(sizeof(*police), GFP_KERNEL); 160 - if (police == NULL) 161 - return -ENOMEM; 162 - ret = ACT_P_CREATED; 163 - police->tcf_refcnt = 1; 164 - spin_lock_init(&police->tcf_lock); 165 - if (bind) 166 - police->tcf_bindcnt = 1; 167 + police = to_police(a); 167 168 override: 168 169 if (parm->rate.rate) { 169 170 err = -ENOMEM; ··· 234 237 return ret; 235 238 236 239 police->tcfp_t_c = ktime_get_ns(); 237 - police->tcf_index = parm->index ? parm->index : 238 - tcf_hash_new_index(tn); 239 - police->tcf_tm.install = jiffies; 240 - police->tcf_tm.lastuse = jiffies; 241 - h = tcf_hash(police->tcf_index, POL_TAB_MASK); 242 - spin_lock_bh(&hinfo->lock); 243 - hlist_add_head(&police->tcf_head, &hinfo->htab[h]); 244 - spin_unlock_bh(&hinfo->lock); 240 + tcf_hash_insert(tn, a); 245 241 246 - a->priv = police; 247 242 return ret; 248 243 249 244 failure_unlock: ··· 244 255 qdisc_put_rtab(P_tab); 245 256 qdisc_put_rtab(R_tab); 246 257 if (ret == ACT_P_CREATED) 247 - kfree(police); 258 + tcf_hash_cleanup(a, est); 248 259 return err; 249 260 } 250 261