]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
[IPV6]: Disallow RH0 by default (CVE-2007-2242)
authorAdrian Bunk <bunk@stusta.de>
Mon, 30 Apr 2007 23:31:47 +0000 (01:31 +0200)
committerAdrian Bunk <bunk@stusta.de>
Mon, 30 Apr 2007 23:31:47 +0000 (01:31 +0200)
A security issue is emerging.  Disallow Routing Header Type 0 by default
as we have been doing for IPv4.

This version already includes a fix for the original patch.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Documentation/networking/ip-sysctl.txt
include/linux/ipv6.h
include/linux/sysctl.h
net/ipv6/addrconf.c
net/ipv6/exthdrs.c

index 26364d06ae927f0262e4cbccda03d1ad2cca35ba..d512f227dda66dd637af7009276ceb08d4080f49 100644 (file)
@@ -723,6 +723,15 @@ accept_redirects - BOOLEAN
        Functional default: enabled if local forwarding is disabled.
                            disabled if local forwarding is enabled.
 
+accept_source_route - INTEGER
+       Accept source routing (routing extension header).
+
+       > 0: Accept routing header.
+       = 0: Accept only routing header type 2.
+       < 0: Do not accept routing header.
+
+       Default: 0
+
 autoconf - BOOLEAN
        Autoconfigure addresses using Prefix Information in Router 
        Advertisements.
index 9c8f4c9ed4298d35d90e08f00ec9274370acf50d..501ddc9ae2b37f98d442605530d9372547f434d1 100644 (file)
@@ -145,6 +145,7 @@ struct ipv6_devconf {
        __s32           max_desync_factor;
 #endif
        __s32           max_addresses;
+       __s32           accept_source_route;
        void            *sysctl;
 };
 
@@ -167,6 +168,14 @@ enum {
        DEVCONF_MAX_DESYNC_FACTOR,
        DEVCONF_MAX_ADDRESSES,
        DEVCONF_FORCE_MLD_VERSION,
+       __DEVCONF_ACCEPT_RA_DEFRTR,
+       __DEVCONF_ACCEPT_RA_PINFO,
+       __DEVCONF_ACCEPT_RA_RTR_PREF,
+       __DEVCONF_RTR_PROBE_INTERVAL,
+       __DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
+       __DEVCONF_PROXY_NDP,
+       __DEVCONF_OPTIMISTIC_DAD,
+       DEVCONF_ACCEPT_SOURCE_ROUTE,
        DEVCONF_MAX
 };
 
index bac61db264566539679b21a4edc59adfa945d95f..d84d8cb691ad30c8e25ba82cc4ca5a3882b7da7e 100644 (file)
@@ -531,6 +531,7 @@ enum {
        NET_IPV6_MAX_DESYNC_FACTOR=15,
        NET_IPV6_MAX_ADDRESSES=16,
        NET_IPV6_FORCE_MLD_VERSION=17,
+       NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
        __NET_IPV6_MAX
 };
 
index e9e9894d2cab71ea62077da2ad3d92dcbfa4e664..eef33b83a406b60a658bd4b8c78bf30047299a20 100644 (file)
@@ -169,6 +169,7 @@ struct ipv6_devconf ipv6_devconf = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
+       .accept_source_route    = 0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -190,6 +191,7 @@ static struct ipv6_devconf ipv6_devconf_dflt = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
+       .accept_source_route    = 0,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -3153,6 +3155,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
 #endif
        array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
+       array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
 }
 
 /* Maximum length of ifinfomsg attributes */
@@ -3620,6 +3623,14 @@ static struct addrconf_sysctl_table
                        .mode           =       0644,
                        .proc_handler   =       &proc_dointvec,
                },
+               {
+                       .ctl_name       =       NET_IPV6_ACCEPT_SOURCE_ROUTE,
+                       .procname       =       "accept_source_route",
+                       .data           =       &ipv6_devconf.accept_source_route,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
                {
                        .ctl_name       =       0,      /* sentinel */
                }
index af78fe8bb8e514ba5dd19d857dc45b871d5868dc..a7cac228f5b51ebcc1cc095a1d839a99c8a907d3 100644 (file)
@@ -221,10 +221,27 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
        struct inet6_skb_parm *opt = IP6CB(skb);
        struct in6_addr *addr;
        struct in6_addr daddr;
+       struct inet6_dev *idev;
        int n, i;
-
        struct ipv6_rt_hdr *hdr;
        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) {
+               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->h.raw-skb->data)+8) ||
            !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
@@ -235,6 +252,18 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
 
        hdr = (struct ipv6_rt_hdr *) skb->h.raw;
 
+       switch (hdr->type) {
+       case IPV6_SRCRT_TYPE_0:
+               if (accept_source_route > 0)
+                       break;
+               kfree_skb(skb);
+               return -1;
+       default:
+               IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+               icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+               return -1;
+       }
+
        if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
            skb->pkt_type != PACKET_HOST) {
                IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
@@ -253,12 +282,6 @@ looped_back:
                return 1;
        }
 
-       if (hdr->type != IPV6_SRCRT_TYPE_0) {
-               IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
-               icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
-               return -1;
-       }
-       
        if (hdr->hdrlen & 0x01) {
                IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);