[RFC/PATCH net-next v2 5/5] flow_offload: validate flags of filter and actions
From: Simon Horman <hidden>
Date: 2021-10-01 11:33:32
Subsystem:
networking [general], tc subsystem, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jamal Hadi Salim, Jiri Pirko, Linus Torvalds
From: Baowen Zheng <redacted> Add process to validate flags of filter and actions when adding a tc filter. We need to prevent adding filter with flags conflicts with its actions. Signed-off-by: Baowen Zheng <redacted> Signed-off-by: Louis Peens <redacted> Signed-off-by: Simon Horman <redacted> --- include/net/pkt_cls.h | 32 ++++++++++++++++++++++++++++++++ net/sched/cls_flower.c | 5 +++++ net/sched/cls_matchall.c | 6 ++++++ net/sched/cls_u32.c | 11 +++++++++++ 4 files changed, 54 insertions(+)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 5c394f04feb5..2d51bed434d2 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h@@ -735,6 +735,38 @@ static inline bool tc_in_hw(u32 flags) return (flags & TCA_CLS_FLAGS_IN_HW) ? true : false; } +/** + * tcf_exts_validate_actions - check if exts actions flags are compatible with + * tc filter flags + * @exts: tc filter extensions handle + * @flags: tc filter flags + * + * Returns true if exts actions flags are compatible with tc filter flags + */ +static inline bool +tcf_exts_validate_actions(const struct tcf_exts *exts, u32 flags) +{ +#ifdef CONFIG_NET_CLS_ACT + bool skip_sw = tc_skip_sw(flags); + bool skip_hw = tc_skip_hw(flags); + int i; + + if (!(skip_sw | skip_hw)) + return true; + + for (i = 0; i < exts->nr_actions; i++) { + struct tc_action *a = exts->actions[i]; + + if ((skip_sw && tc_act_skip_hw(a->tcfa_flags)) || + (skip_hw && tc_act_skip_sw(a->tcfa_flags))) + return false; + } + return true; +#else + return true; +#endif +} + static inline void tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common, const struct tcf_proto *tp, u32 flags,
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index eb6345a027e1..15e439349124 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c@@ -2039,6 +2039,11 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, if (err) goto errout; + if (!tcf_exts_validate_actions(&fnew->exts, fnew->flags)) { + err = -EINVAL; + goto errout; + } + err = fl_check_assign_mask(head, fnew, fold, mask); if (err) goto errout;
diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c
index 24f0046ce0b3..89dbbb9f31e8 100644
--- a/net/sched/cls_matchall.c
+++ b/net/sched/cls_matchall.c@@ -231,6 +231,11 @@ static int mall_change(struct net *net, struct sk_buff *in_skb, if (err) goto err_set_parms; + if (!tcf_exts_validate_actions(&new->exts, new->flags)) { + err = -EINVAL; + goto err_validate; + } + if (!tc_skip_hw(new->flags)) { err = mall_replace_hw_filter(tp, new, (unsigned long)new, extack);
@@ -246,6 +251,7 @@ static int mall_change(struct net *net, struct sk_buff *in_skb, return 0; err_replace_hw_filter: +err_validate: err_set_parms: free_percpu(new->pf); err_alloc_percpu:
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 4272814487f0..8bc19af18e4a 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c@@ -902,6 +902,11 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return err; } + if (!tcf_exts_validate_actions(&new->exts, flags)) { + u32_destroy_key(new, false); + return -EINVAL; + } + err = u32_replace_hw_knode(tp, new, flags, extack); if (err) { u32_destroy_key(new, false);
@@ -1066,6 +1071,11 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, struct tc_u_knode __rcu **ins; struct tc_u_knode *pins; + if (!tcf_exts_validate_actions(&n->exts, n->flags)) { + err = -EINVAL; + goto err_validate; + } + err = u32_replace_hw_knode(tp, n, flags, extack); if (err) goto errhw;
@@ -1086,6 +1096,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return 0; } +err_validate: errhw: #ifdef CONFIG_CLS_U32_MARK free_percpu(n->pcpu_success);
--
2.20.1