Flow dissector does not limit the number of encapsulated packets or IPv6 header extensions that will be processed. This could easily be suceptible to DOS attack-- for instance a 1500 byte packet could contain 75 IPIP headers.
This patch places limits on the number of encapsulations and IPv6 extension headers that are processed in flow dissector Signed-off-by: Tom Herbert <t...@herbertland.com> --- net/core/flow_dissector.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 1a7b80f..919bd02 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -91,6 +91,22 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, } EXPORT_SYMBOL(__skb_flow_get_ports); +#define MAX_DISSECT_DEPTH 10 +#define MAX_DISSECT_EXT 10 + +#define __DISSECT_AGAIN(_target, _depth, _limit) do { \ + (_depth)++; \ + if ((_depth) > (_limit)) \ + goto out_good; \ + else \ + goto _target; \ +} while (0) + +#define DISSECT_AGAIN(target) \ + __DISSECT_AGAIN(target, depth, MAX_DISSECT_DEPTH) +#define DISSECT_AGAIN_EXT(target) \ + __DISSECT_AGAIN(target, ext_cnt, MAX_DISSECT_EXT) + /** * __skb_flow_dissect - extract the flow_keys struct and return it * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified @@ -123,6 +139,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, bool skip_vlan = false; u8 ip_proto = 0; bool ret = false; + int depth = 0, ext_cnt = 0; if (!data) { data = skb->data; @@ -262,7 +279,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, proto = vlan->h_vlan_encapsulated_proto; nhoff += sizeof(*vlan); if (skip_vlan) - goto again; + DISSECT_AGAIN(again); } skip_vlan = true; @@ -285,7 +302,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, } } - goto again; + DISSECT_AGAIN(again); } case htons(ETH_P_PPP_SES): { struct { @@ -299,9 +316,9 @@ bool __skb_flow_dissect(const struct sk_buff *skb, nhoff += PPPOE_SES_HLEN; switch (proto) { case htons(PPP_IP): - goto ip; + DISSECT_AGAIN(ip); case htons(PPP_IPV6): - goto ipv6; + DISSECT_AGAIN(ipv6); default: goto out_bad; } @@ -472,7 +489,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; - goto again; + DISSECT_AGAIN(again); } case NEXTHDR_HOP: case NEXTHDR_ROUTING: @@ -490,7 +507,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, ip_proto = opthdr[0]; nhoff += (opthdr[1] + 1) << 3; - goto ip_proto_again; + DISSECT_AGAIN_EXT(ip_proto_again); } case NEXTHDR_FRAGMENT: { struct frag_hdr _fh, *fh; @@ -512,7 +529,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, if (!(fh->frag_off & htons(IP6_OFFSET))) { key_control->flags |= FLOW_DIS_FIRST_FRAG; if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) - goto ip_proto_again; + DISSECT_AGAIN_EXT(ip_proto_again); } goto out_good; } @@ -523,7 +540,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; - goto ip; + DISSECT_AGAIN(ip); case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); @@ -531,10 +548,10 @@ bool __skb_flow_dissect(const struct sk_buff *skb, if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; - goto ipv6; + DISSECT_AGAIN(ipv6); case IPPROTO_MPLS: proto = htons(ETH_P_MPLS_UC); - goto mpls; + DISSECT_AGAIN(mpls); default: break; } -- 2.9.3