datapath: Allow jumbograms through IPv6 parsing.
authorJesse Gross <jesse@nicira.com>
Wed, 2 Mar 2011 22:51:31 +0000 (14:51 -0800)
committerJesse Gross <jesse@nicira.com>
Thu, 3 Mar 2011 20:13:13 +0000 (12:13 -0800)
Currently we stop parsing packets that are IPv6 jumbograms.  While
it isn't possible to send such large packets to userspace, it's better
to drop them at that point rather than prematurely in the IPv6 code.
IPv6 does make some use of the payload length field but we can just as
easily use skb->len, which is what all other parsing uses.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
datapath/flow.c
lib/flow.c

index fe05df3..9cba723 100644 (file)
@@ -106,7 +106,6 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
        unsigned int nh_ofs = skb_network_offset(skb);
        unsigned int nh_len;
        int payload_ofs;
-       int payload_len;
        struct ipv6hdr *nh;
        uint8_t nexthdr;
 
@@ -116,31 +115,18 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
        nh = ipv6_hdr(skb);
        nexthdr = nh->nexthdr;
        payload_ofs = (u8 *)(nh + 1) - skb->data;
-       payload_len = ntohs(nh->payload_len);
 
        memcpy(key->ipv6_src, nh->saddr.in6_u.u6_addr8, sizeof(key->ipv6_src));
        memcpy(key->ipv6_dst, nh->daddr.in6_u.u6_addr8, sizeof(key->ipv6_dst));
        key->nw_tos = ipv6_get_dsfield(nh) & ~INET_ECN_MASK;
        key->nw_proto = NEXTHDR_NONE;
 
-       /* We don't process jumbograms. */
-       if (!payload_len)
-               return -EINVAL;
-
-       if (unlikely(skb->len < nh_ofs + sizeof(*nh) + payload_len))
-               return -EINVAL;
-
        payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr);
        if (payload_ofs < 0) {
                return -EINVAL;
        }
        nh_len = payload_ofs - nh_ofs;
 
-       /* Ensure that the payload length claimed is at least large enough
-        * for the headers we've already processed. */
-       if (payload_len < nh_len - sizeof(*nh))
-               return -EINVAL;
-
        /* Pull enough header bytes to account for the IP header plus the
         * longest transport header that we parse, currently 20 bytes for TCP.
         * To dig deeper than the transport header, transport parsers may need
@@ -320,8 +306,6 @@ static __be16 parse_ethertype(struct sk_buff *skb)
 static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
                int nh_len)
 {
-       struct ipv6hdr *nh = ipv6_hdr(skb);
-       int icmp_len = ntohs(nh->payload_len) + sizeof(*nh) - nh_len;
        struct icmp6hdr *icmp = icmp6_hdr(skb);
 
        /* The ICMPv6 type and code fields use the 16-bit transport port
@@ -332,6 +316,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
        if (!icmp->icmp6_code
                        && ((icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
                          || (icmp->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT))) {
+               int icmp_len = skb->len - skb_transport_offset(skb);
                struct nd_msg *nd;
                int offset;
 
@@ -339,7 +324,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
                 * entire packet. */
                if (icmp_len < sizeof(*nd))
                        goto invalid;
-               if (!pskb_may_pull(skb, skb_transport_offset(skb) + icmp_len))
+               if (unlikely(!pskb_may_pull(skb, skb->len)))
                        return -ENOMEM;
 
                nd = (struct nd_msg *)skb_transport_header(skb);
index 6928f74..e0566bb 100644 (file)
@@ -136,7 +136,6 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
 {
     struct ip6_hdr *nh;
     int nh_len = sizeof(struct ip6_hdr);
-    int payload_len;
     ovs_be32 tc_flow;
     int nexthdr;
 
@@ -146,7 +145,6 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
 
     nh = packet->data;
     nexthdr = nh->ip6_nxt;
-    payload_len = ntohs(nh->ip6_plen);
 
     flow->ipv6_src = nh->ip6_src;
     flow->ipv6_dst = nh->ip6_dst;
@@ -155,15 +153,6 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
     flow->nw_tos = (ntohl(tc_flow) >> 4) & IP_DSCP_MASK;
     flow->nw_proto = IPPROTO_NONE;
 
-    /* We don't process jumbograms. */
-    if (!payload_len) {
-        return -EINVAL;
-    }
-
-    if (packet->size < sizeof *nh + payload_len) {
-        return -EINVAL;
-    }
-
     while (1) {
         if ((nexthdr != IPPROTO_HOPOPTS)
                 && (nexthdr != IPPROTO_ROUTING)
@@ -220,12 +209,6 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
         }
     }
 
-    /* The payload length claims to be smaller than the size of the
-     * headers we've already processed. */
-    if (payload_len < nh_len - sizeof *nh) {
-        return -EINVAL;
-    }
-
     flow->nw_proto = nexthdr;
     return nh_len;
 }
@@ -432,8 +415,7 @@ flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t in_port,
                     packet->l7 = b.data;
                 }
             } else if (flow->nw_proto == IPPROTO_ICMPV6) {
-                int icmp_len = ntohs(nh->ip6_plen) + sizeof *nh - nh_len;
-                if (parse_icmpv6(&b, flow, icmp_len)) {
+                if (parse_icmpv6(&b, flow, b.size)) {
                     packet->l7 = b.data;
                 }
             }