From: Davide Caratti <dcaratti@redhat.com>
To: Cong Wang <xiyou.wangcong@gmail.com>,
Vlad Buslov <vladbu@mellanox.com>,
Jamal Hadi Salim <jhs@mojatatu.com>,
Jiri Pirko <jiri@resnulli.us>,
"David S . Miller" <davem@davemloft.net>,
netdev <netdev@vger.kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Subject: [PATCH net v2 18/18] net/sched: let actions use RCU to access 'goto_chain'
Date: Wed, 20 Mar 2019 15:00:16 +0100 [thread overview]
Message-ID: <65be1e806111c804989863d2a7d1f00304b921b7.1553085664.git.dcaratti@redhat.com> (raw)
In-Reply-To: <cover.1553085663.git.dcaratti@redhat.com>
use RCU when accessing the action chain, to avoid use after free in the
traffic path when 'goto chain' is replaced on existing TC actions (see
script below). Since the control action is read in the traffic path
without holding the action spinlock, we need to explicitly ensure that
a->goto_chain is not NULL before dereferencing (i.e it's not sufficient
to rely on the value of TC_ACT_GOTO_CHAIN bits). Not doing so caused NULL
dereferences in tcf_action_goto_chain_exec() when the following script:
# tc chain add dev dd0 chain 42 ingress protocol ip flower \
> ip_proto udp action pass index 4
# tc filter add dev dd0 ingress protocol ip flower \
> ip_proto udp action csum udp goto chain 42 index 66
# tc chain del dev dd0 chain 42 ingress
(start UDP traffic towards dd0)
# tc action replace action csum udp pass index 66
was run repeatedly for several hours.
Suggested-by: Cong Wang <xiyou.wangcong@gmail.com>
Suggested-by: Vlad Buslov <vladbu@mellanox.com>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
---
include/net/act_api.h | 2 +-
include/net/sch_generic.h | 1 +
net/sched/act_api.c | 18 ++++++++++--------
net/sched/cls_api.c | 2 +-
4 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 54fbb49bd08a..c61a1bf4e3de 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -39,7 +39,7 @@ struct tc_action {
struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw;
struct gnet_stats_queue __percpu *cpu_qstats;
struct tc_cookie __rcu *act_cookie;
- struct tcf_chain *goto_chain;
+ struct tcf_chain __rcu *goto_chain;
};
#define tcf_index common.tcfa_index
#define tcf_refcnt common.tcfa_refcnt
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 31284c078d06..7d1a0483a17b 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -378,6 +378,7 @@ struct tcf_chain {
bool flushing;
const struct tcf_proto_ops *tmplt_ops;
void *tmplt_priv;
+ struct rcu_head rcu;
};
struct tcf_block {
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index fe67b98ac641..5a87e271d35a 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -31,7 +31,7 @@
static void tcf_action_goto_chain_exec(const struct tc_action *a,
struct tcf_result *res)
{
- const struct tcf_chain *chain = a->goto_chain;
+ const struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
res->goto_tp = rcu_dereference_bh(chain->filter_chain);
}
@@ -91,13 +91,11 @@ int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
EXPORT_SYMBOL(tcf_action_check_ctrlact);
struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action,
- struct tcf_chain *newchain)
+ struct tcf_chain *goto_chain)
{
- struct tcf_chain *oldchain = a->goto_chain;
-
a->tcfa_action = action;
- a->goto_chain = newchain;
- return oldchain;
+ rcu_swap_protected(a->goto_chain, goto_chain, 1);
+ return goto_chain;
}
EXPORT_SYMBOL(tcf_action_set_ctrlact);
@@ -108,7 +106,7 @@ EXPORT_SYMBOL(tcf_action_set_ctrlact);
*/
static void free_tcf(struct tc_action *p)
{
- struct tcf_chain *chain = p->goto_chain;
+ struct tcf_chain *chain = rcu_dereference_protected(p->goto_chain, 1);
free_percpu(p->cpu_bstats);
free_percpu(p->cpu_bstats_hw);
@@ -686,6 +684,10 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
return TC_ACT_OK;
}
} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
+ if (unlikely(!rcu_access_pointer(a->goto_chain))) {
+ net_warn_ratelimited("can't go to NULL chain!\n");
+ return TC_ACT_SHOT;
+ }
tcf_action_goto_chain_exec(a, res);
}
@@ -931,7 +933,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
module_put(a_o->owner);
if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN) &&
- !a->goto_chain) {
+ !rcu_access_pointer(a->goto_chain)) {
tcf_action_destroy_1(a, bind);
NL_SET_ERR_MSG(extack, "can't use goto chain with NULL chain");
return ERR_PTR(-EINVAL);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 2c2aac4ac721..acd4f4e11ece 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -367,7 +367,7 @@ static void tcf_chain_destroy(struct tcf_chain *chain, bool free_block)
struct tcf_block *block = chain->block;
mutex_destroy(&chain->filter_chain_lock);
- kfree(chain);
+ kfree_rcu(chain, rcu);
if (free_block)
tcf_block_destroy(block);
}
--
2.20.1
next prev parent reply other threads:[~2019-03-20 14:01 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-03-20 13:59 [PATCH net v2 00/18] net/sched: validate the control action with all the other parameters Davide Caratti
2019-03-20 13:59 ` [PATCH net v2 01/18] net/sched: prepare TC actions to properly validate the control action Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 02/18] net/sched: act_bpf: validate the control action inside init() Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 03/18] net/sched: act_csum: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 04/18] net/sched: act_gact: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 05/18] net/sched: act_ife: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 06/18] net/sched: act_mirred: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 07/18] net/sched: act_connmark: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 08/18] net/sched: act_nat: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 09/18] net/sched: act_pedit: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 10/18] net/sched: act_police: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 11/18] net/sched: act_sample: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 12/18] net/sched: act_simple: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 13/18] net/sched: act_skbedit: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 14/18] net/sched: act_skbmod: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 15/18] net/sched: act_tunnel_key: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 16/18] net/sched: act_vlan: " Davide Caratti
2019-03-20 14:00 ` [PATCH net v2 17/18] net/sched: don't dereference a->goto_chain to read the chain index Davide Caratti
2019-03-20 14:00 ` Davide Caratti [this message]
2019-03-20 19:36 ` [PATCH net v2 00/18] net/sched: validate the control action with all the other parameters David Miller
2019-03-21 20:27 ` David Miller
2019-03-22 2:17 ` Cong Wang
2019-03-22 3:03 ` Cong Wang
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=65be1e806111c804989863d2a7d1f00304b921b7.1553085664.git.dcaratti@redhat.com \
--to=dcaratti@redhat.com \
--cc=davem@davemloft.net \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=vladbu@mellanox.com \
--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).