]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
[IPV6]: Restore semantics of Routing Header processing.
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Wed, 11 Jul 2007 05:47:58 +0000 (22:47 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Jul 2007 05:47:58 +0000 (22:47 -0700)
The "fix" for emerging security threat was overkill and it broke
basic semantic of IPv6 routing header processing.  We should assume
RT0 (or even RT2, depends on configuration) as "unknown" RH type so
that we
- silently ignore the routing header if segleft == 0
- send ICMPv6 Parameter Problem message back to the sender,
  otherwise.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/exthdrs.c

index 173a4bb52255d57a9e7f2b105b95a52c32f1cda2..fc3a961fc5ba7209d5a03f511dd287c4951ad3e2 100644 (file)
@@ -372,22 +372,13 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
        struct rt0_hdr *rthdr;
        int accept_source_route = ipv6_devconf.accept_source_route;
 
-       if (accept_source_route < 0 ||
-           ((idev = in6_dev_get(skb->dev)) == NULL)) {
-               kfree_skb(skb);
-               return -1;
-       }
-       if (idev->cnf.accept_source_route < 0) {
+       idev = in6_dev_get(skb->dev);
+       if (idev) {
+               if (accept_source_route > idev->cnf.accept_source_route)
+                       accept_source_route = idev->cnf.accept_source_route;
                in6_dev_put(idev);
-               kfree_skb(skb);
-               return -1;
        }
 
-       if (accept_source_route > idev->cnf.accept_source_route)
-               accept_source_route = idev->cnf.accept_source_route;
-
-       in6_dev_put(idev);
-
        if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
            !pskb_may_pull(skb, (skb_transport_offset(skb) +
                                 ((skb_transport_header(skb)[1] + 1) << 3)))) {
@@ -399,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
 
        hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
 
-       switch (hdr->type) {
-#ifdef CONFIG_IPV6_MIP6
-       case IPV6_SRCRT_TYPE_2:
-               break;
-#endif
-       case IPV6_SRCRT_TYPE_0:
-               if (accept_source_route > 0)
-                       break;
-               kfree_skb(skb);
-               return -1;
-       default:
-               IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
-                                IPSTATS_MIB_INHDRERRORS);
-               icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
-                                 (&hdr->type) - skb_network_header(skb));
-               return -1;
-       }
-
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
            skb->pkt_type != PACKET_HOST) {
                IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -455,6 +428,8 @@ looped_back:
 
        switch (hdr->type) {
        case IPV6_SRCRT_TYPE_0:
+               if (accept_source_route <= 0)
+                       goto unknown_rh;
                if (hdr->hdrlen & 0x01) {
                        IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
                                         IPSTATS_MIB_INHDRERRORS);
@@ -466,6 +441,8 @@ looped_back:
                break;
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
        case IPV6_SRCRT_TYPE_2:
+               if (accept_source_route < 0)
+                       goto unknown_rh;
                /* Silently discard invalid RTH type 2 */
                if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
                        IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -475,6 +452,8 @@ looped_back:
                }
                break;
 #endif
+       default:
+               goto unknown_rh;
        }
 
        /*
@@ -578,6 +557,12 @@ looped_back:
        skb_push(skb, skb->data - skb_network_header(skb));
        dst_input(skb);
        return -1;
+
+unknown_rh:
+       IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+       icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+                         (&hdr->type) - skb_network_header(skb));
+       return -1;
 }
 
 static struct inet6_protocol rthdr_protocol = {