aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2017-11-06 16:47:23 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-08 20:03:09 -0500
commit22f7cec93f0af86c4b66bf34a977da9d7cef076e (patch)
tree7ef156054146fce727443685455fb4f90f67b305
parented1481681414e4d4264ad46864d5c1da5ff6ccb1 (diff)
cls_flow: use tcf_exts_get_net() before call_rcu()
Hold netns refcnt before call_rcu() and release it after the tcf_exts_destroy() is done. Note, on ->destroy() path we have to respect the return value of tcf_exts_get_net(), on other paths it should always return true, so we don't need to care. Cc: Lucas Bates <lucasb@mojatatu.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Jiri Pirko <jiri@resnulli.us> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/cls_flow.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 67f3a2af6aab..85f765cff697 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -372,15 +372,21 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
372 [TCA_FLOW_PERTURB] = { .type = NLA_U32 }, 372 [TCA_FLOW_PERTURB] = { .type = NLA_U32 },
373}; 373};
374 374
375static void flow_destroy_filter_work(struct work_struct *work) 375static void __flow_destroy_filter(struct flow_filter *f)
376{ 376{
377 struct flow_filter *f = container_of(work, struct flow_filter, work);
378
379 rtnl_lock();
380 del_timer_sync(&f->perturb_timer); 377 del_timer_sync(&f->perturb_timer);
381 tcf_exts_destroy(&f->exts); 378 tcf_exts_destroy(&f->exts);
382 tcf_em_tree_destroy(&f->ematches); 379 tcf_em_tree_destroy(&f->ematches);
380 tcf_exts_put_net(&f->exts);
383 kfree(f); 381 kfree(f);
382}
383
384static void flow_destroy_filter_work(struct work_struct *work)
385{
386 struct flow_filter *f = container_of(work, struct flow_filter, work);
387
388 rtnl_lock();
389 __flow_destroy_filter(f);
384 rtnl_unlock(); 390 rtnl_unlock();
385} 391}
386 392
@@ -552,8 +558,10 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
552 558
553 *arg = fnew; 559 *arg = fnew;
554 560
555 if (fold) 561 if (fold) {
562 tcf_exts_get_net(&fold->exts);
556 call_rcu(&fold->rcu, flow_destroy_filter); 563 call_rcu(&fold->rcu, flow_destroy_filter);
564 }
557 return 0; 565 return 0;
558 566
559err2: 567err2:
@@ -570,6 +578,7 @@ static int flow_delete(struct tcf_proto *tp, void *arg, bool *last)
570 struct flow_filter *f = arg; 578 struct flow_filter *f = arg;
571 579
572 list_del_rcu(&f->list); 580 list_del_rcu(&f->list);
581 tcf_exts_get_net(&f->exts);
573 call_rcu(&f->rcu, flow_destroy_filter); 582 call_rcu(&f->rcu, flow_destroy_filter);
574 *last = list_empty(&head->filters); 583 *last = list_empty(&head->filters);
575 return 0; 584 return 0;
@@ -594,7 +603,10 @@ static void flow_destroy(struct tcf_proto *tp)
594 603
595 list_for_each_entry_safe(f, next, &head->filters, list) { 604 list_for_each_entry_safe(f, next, &head->filters, list) {
596 list_del_rcu(&f->list); 605 list_del_rcu(&f->list);
597 call_rcu(&f->rcu, flow_destroy_filter); 606 if (tcf_exts_get_net(&f->exts))
607 call_rcu(&f->rcu, flow_destroy_filter);
608 else
609 __flow_destroy_filter(f);
598 } 610 }
599 kfree_rcu(head, rcu); 611 kfree_rcu(head, rcu);
600} 612}