aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinoru Usui <usui@mxm.nes.nec.co.jp>2009-06-02 05:17:34 -0400
committerDavid S. Miller <davem@davemloft.net>2009-06-02 05:17:34 -0400
commit12186be7d2e1106cede1cc728526e3d7998cbe94 (patch)
treea27e9c1cf720fbd31d67c27ea1426a0ae891733b
parentea30e11970a96cfe5e32c03a29332554573b4a10 (diff)
net_cls: fix unconfigured struct tcf_proto keeps chaining and avoid kernel panic when we use cls_cgroup
This patch fixes a bug which unconfigured struct tcf_proto keeps chaining in tc_ctl_tfilter(), and avoids kernel panic in cls_cgroup_classify() when we use cls_cgroup. When we execute 'tc filter add', tcf_proto is allocated, initialized by classifier's init(), and chained. After it's chained, tc_ctl_tfilter() calls classifier's change(). When classifier's change() fails, tc_ctl_tfilter() does not free and keeps tcf_proto. In addition, cls_cgroup is initialized in change() not in init(). It accesses unconfigured struct tcf_proto which is chained before change(), then hits Oops. Signed-off-by: Minoru Usui <usui@mxm.nes.nec.co.jp> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com> Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca> Tested-by: Minoru Usui <usui@mxm.nes.nec.co.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/cls_api.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 0759f32e9dca..09cdcdfe7e91 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -135,6 +135,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
135 unsigned long cl; 135 unsigned long cl;
136 unsigned long fh; 136 unsigned long fh;
137 int err; 137 int err;
138 int tp_created = 0;
138 139
139 if (net != &init_net) 140 if (net != &init_net)
140 return -EINVAL; 141 return -EINVAL;
@@ -266,10 +267,7 @@ replay:
266 goto errout; 267 goto errout;
267 } 268 }
268 269
269 spin_lock_bh(root_lock); 270 tp_created = 1;
270 tp->next = *back;
271 *back = tp;
272 spin_unlock_bh(root_lock);
273 271
274 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) 272 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
275 goto errout; 273 goto errout;
@@ -296,8 +294,11 @@ replay:
296 switch (n->nlmsg_type) { 294 switch (n->nlmsg_type) {
297 case RTM_NEWTFILTER: 295 case RTM_NEWTFILTER:
298 err = -EEXIST; 296 err = -EEXIST;
299 if (n->nlmsg_flags & NLM_F_EXCL) 297 if (n->nlmsg_flags & NLM_F_EXCL) {
298 if (tp_created)
299 tcf_destroy(tp);
300 goto errout; 300 goto errout;
301 }
301 break; 302 break;
302 case RTM_DELTFILTER: 303 case RTM_DELTFILTER:
303 err = tp->ops->delete(tp, fh); 304 err = tp->ops->delete(tp, fh);
@@ -314,8 +315,18 @@ replay:
314 } 315 }
315 316
316 err = tp->ops->change(tp, cl, t->tcm_handle, tca, &fh); 317 err = tp->ops->change(tp, cl, t->tcm_handle, tca, &fh);
317 if (err == 0) 318 if (err == 0) {
319 if (tp_created) {
320 spin_lock_bh(root_lock);
321 tp->next = *back;
322 *back = tp;
323 spin_unlock_bh(root_lock);
324 }
318 tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER); 325 tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER);
326 } else {
327 if (tp_created)
328 tcf_destroy(tp);
329 }
319 330
320errout: 331errout:
321 if (cl) 332 if (cl)