aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2016-06-06 12:54:30 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-07 19:38:59 -0400
commita03e6fe569713fb3ff0714f8fd7c8785c0ca9e22 (patch)
tree2503e58b9720cb4ee120033ab4df1bc97ba93c4c /net
parentaafddbf0cffeb790f919436285328c762279b5d4 (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.c33
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;
169override: 166override:
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
252failure_unlock: 241failure_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