From: John Fastabend <john.fastabend@gmail.com>
To: xiyou.wangcong@gmail.com, davem@davemloft.net
Cc: netdev@vger.kernel.org, jhs@mojatatu.com, eric.dumazet@gmail.com
Subject: [PATCH v1 1/2] net: sched: do not use tcf_proto 'tp' argument from call_rcu
Date: Thu, 02 Oct 2014 22:45:59 -0700 [thread overview]
Message-ID: <20141003054558.20925.67091.stgit@nitbit.x32> (raw)
Using the tcf_proto pointer 'tp' from inside the classifiers callback
is not valid because it may have been cleaned up by another call_rcu
occuring on another CPU.
'tp' is currently being used by tcf_unbind_filter() in this patch we
move instances of tcf_unbind_filter outside of the call_rcu() context.
This is safe to do because any running schedulers will either read the
valid class field or it will be zeroed.
And all schedulers today when the class is 0 do a lookup using the
same call used by the tcf_exts_bind(). So even if we have a running
classifier hit the null class pointer it will do a lookup and get
to the same result. This is particularly fragile at the moment because
the only way to verify this is to audit the schedulers call sites.
Reported-by: Cong Wang <xiyou.wangconf@gmail.com>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
net/sched/cls_basic.c | 4 +++-
net/sched/cls_bpf.c | 4 +++-
net/sched/cls_fw.c | 5 +++--
net/sched/cls_route.c | 8 +++++---
4 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index fe20826..81ddfa6 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -93,7 +93,6 @@ static void basic_delete_filter(struct rcu_head *head)
struct basic_filter *f = container_of(head, struct basic_filter, rcu);
struct tcf_proto *tp = f->tp;
- tcf_unbind_filter(tp, &f->res);
tcf_exts_destroy(&f->exts);
tcf_em_tree_destroy(tp, &f->ematches);
kfree(f);
@@ -106,6 +105,7 @@ static void basic_destroy(struct tcf_proto *tp)
list_for_each_entry_safe(f, n, &head->flist, link) {
list_del_rcu(&f->link);
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, basic_delete_filter);
}
RCU_INIT_POINTER(tp->root, NULL);
@@ -120,6 +120,7 @@ static int basic_delete(struct tcf_proto *tp, unsigned long arg)
list_for_each_entry(t, &head->flist, link)
if (t == f) {
list_del_rcu(&t->link);
+ tcf_unbind_filter(tp, &t->res);
call_rcu(&t->rcu, basic_delete_filter);
return 0;
}
@@ -222,6 +223,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
if (fold) {
list_replace_rcu(&fold->link, &fnew->link);
+ tcf_unbind_filter(tp, &fold->res);
call_rcu(&fold->rcu, basic_delete_filter);
} else {
list_add_rcu(&fnew->link, &head->flist);
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 4318d06..eed49d1 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -92,7 +92,6 @@ static int cls_bpf_init(struct tcf_proto *tp)
static void cls_bpf_delete_prog(struct tcf_proto *tp, struct cls_bpf_prog *prog)
{
- tcf_unbind_filter(tp, &prog->res);
tcf_exts_destroy(&prog->exts);
bpf_prog_destroy(prog->filter);
@@ -116,6 +115,7 @@ static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg)
list_for_each_entry(prog, &head->plist, link) {
if (prog == todel) {
list_del_rcu(&prog->link);
+ tcf_unbind_filter(tp, &prog->res);
call_rcu(&prog->rcu, __cls_bpf_delete_prog);
return 0;
}
@@ -131,6 +131,7 @@ static void cls_bpf_destroy(struct tcf_proto *tp)
list_for_each_entry_safe(prog, tmp, &head->plist, link) {
list_del_rcu(&prog->link);
+ tcf_unbind_filter(tp, &prog->res);
call_rcu(&prog->rcu, __cls_bpf_delete_prog);
}
@@ -282,6 +283,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
if (oldprog) {
list_replace_rcu(&prog->link, &oldprog->link);
+ tcf_unbind_filter(tp, &oldprog->res);
call_rcu(&oldprog->rcu, __cls_bpf_delete_prog);
} else {
list_add_rcu(&prog->link, &head->plist);
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index da805ae..dbfdfd1 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -123,9 +123,7 @@ static int fw_init(struct tcf_proto *tp)
static void fw_delete_filter(struct rcu_head *head)
{
struct fw_filter *f = container_of(head, struct fw_filter, rcu);
- struct tcf_proto *tp = f->tp;
- tcf_unbind_filter(tp, &f->res);
tcf_exts_destroy(&f->exts);
kfree(f);
}
@@ -143,6 +141,7 @@ static void fw_destroy(struct tcf_proto *tp)
while ((f = rtnl_dereference(head->ht[h])) != NULL) {
RCU_INIT_POINTER(head->ht[h],
rtnl_dereference(f->next));
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, fw_delete_filter);
}
}
@@ -166,6 +165,7 @@ static int fw_delete(struct tcf_proto *tp, unsigned long arg)
fp = &pfp->next, pfp = rtnl_dereference(*fp)) {
if (pfp == f) {
RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, fw_delete_filter);
return 0;
}
@@ -280,6 +280,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
RCU_INIT_POINTER(fnew->next, rtnl_dereference(pfp->next));
rcu_assign_pointer(*fp, fnew);
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, fw_delete_filter);
*arg = (unsigned long)fnew;
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index b665aee..6f22baa 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -269,9 +269,7 @@ static void
route4_delete_filter(struct rcu_head *head)
{
struct route4_filter *f = container_of(head, struct route4_filter, rcu);
- struct tcf_proto *tp = f->tp;
- tcf_unbind_filter(tp, &f->res);
tcf_exts_destroy(&f->exts);
kfree(f);
}
@@ -297,6 +295,7 @@ static void route4_destroy(struct tcf_proto *tp)
next = rtnl_dereference(f->next);
RCU_INIT_POINTER(b->ht[h2], next);
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, route4_delete_filter);
}
}
@@ -338,6 +337,7 @@ static int route4_delete(struct tcf_proto *tp, unsigned long arg)
route4_reset_fastmap(head);
/* Delete it */
+ tcf_unbind_filter(tp, &f->res);
call_rcu(&f->rcu, route4_delete_filter);
/* Strip RTNL protected tree */
@@ -545,8 +545,10 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
route4_reset_fastmap(head);
*arg = (unsigned long)f;
- if (fold)
+ if (fold) {
+ tcf_unbind_filter(tp, &fold->res);
call_rcu(&fold->rcu, route4_delete_filter);
+ }
return 0;
errout:
next reply other threads:[~2014-10-03 5:46 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-10-03 5:45 John Fastabend [this message]
2014-10-03 5:46 ` [PATCH v1 2/2] net: sched: replace ematch calls to use struct net John Fastabend
2014-10-03 22:40 ` Cong Wang
2014-10-04 0:19 ` John Fastabend
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20141003054558.20925.67091.stgit@nitbit.x32 \
--to=john.fastabend@gmail.com \
--cc=davem@davemloft.net \
--cc=eric.dumazet@gmail.com \
--cc=jhs@mojatatu.com \
--cc=netdev@vger.kernel.org \
--cc=xiyou.wangcong@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).