| From foo@baz Sat Jan 26 10:22:50 CET 2019 |
| From: Cong Wang <xiyou.wangcong@gmail.com> |
| Date: Fri, 11 Jan 2019 18:55:42 -0800 |
| Subject: net_sched: refetch skb protocol for each filter |
| |
| From: Cong Wang <xiyou.wangcong@gmail.com> |
| |
| [ Upstream commit cd0c4e70fc0ccfa705cdf55efb27519ce9337a26 ] |
| |
| Martin reported a set of filters don't work after changing |
| from reclassify to continue. Looking into the code, it |
| looks like skb protocol is not always fetched for each |
| iteration of the filters. But, as demonstrated by Martin, |
| TC actions could modify skb->protocol, for example act_vlan, |
| this means we have to refetch skb protocol in each iteration, |
| rather than using the one we fetch in the beginning of the loop. |
| |
| This bug is _not_ introduced by commit 3b3ae880266d |
| ("net: sched: consolidate tc_classify{,_compat}"), technically, |
| if act_vlan is the only action that modifies skb protocol, then |
| it is commit c7e2b9689ef8 ("sched: introduce vlan action") which |
| introduced this bug. |
| |
| Reported-by: Martin Olsson <martin.olsson+netdev@sentorsecurity.com> |
| Cc: Jamal Hadi Salim <jhs@mojatatu.com> |
| Cc: Jiri Pirko <jiri@resnulli.us> |
| Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> |
| Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/sched/cls_api.c | 3 +-- |
| 1 file changed, 1 insertion(+), 2 deletions(-) |
| |
| --- a/net/sched/cls_api.c |
| +++ b/net/sched/cls_api.c |
| @@ -1053,7 +1053,6 @@ static int tcf_block_cb_call(struct tcf_ |
| int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, |
| struct tcf_result *res, bool compat_mode) |
| { |
| - __be16 protocol = tc_skb_protocol(skb); |
| #ifdef CONFIG_NET_CLS_ACT |
| const int max_reclassify_loop = 4; |
| const struct tcf_proto *orig_tp = tp; |
| @@ -1063,6 +1062,7 @@ int tcf_classify(struct sk_buff *skb, co |
| reclassify: |
| #endif |
| for (; tp; tp = rcu_dereference_bh(tp->next)) { |
| + __be16 protocol = tc_skb_protocol(skb); |
| int err; |
| |
| if (tp->protocol != protocol && |
| @@ -1095,7 +1095,6 @@ reset: |
| } |
| |
| tp = first_tp; |
| - protocol = tc_skb_protocol(skb); |
| goto reclassify; |
| #endif |
| } |