From: Adrian Bunk Date: Mon, 30 Apr 2007 23:31:47 +0000 (+0200) Subject: [IPV6]: Disallow RH0 by default (CVE-2007-2242) X-Git-Tag: v2.6.16.50-rc1~1 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.16.y.git;a=commitdiff_plain;h=5225791117b564cd8b5683cf82d9eea45b0f0d59 [IPV6]: Disallow RH0 by default (CVE-2007-2242) 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 Signed-off-by: Adrian Bunk --- Documentation/networking/ip-sysctl.txt | 9 ++++++++ include/linux/ipv6.h | 4 +++ include/linux/sysctl.h | 1 net/ipv6/addrconf.c | 11 ++++++++++ net/ipv6/exthdrs.c | 36 +++++++++++++++++++++++++++------ 5 files changed, 55 insertions(+), 6 deletions(-) Index: linux-2.6.18/Documentation/networking/ip-sysctl.txt =================================================================== --- linux-2.6.18.orig/Documentation/networking/ip-sysctl.txt +++ linux-2.6.18/Documentation/networking/ip-sysctl.txt @@ -775,6 +775,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: linux-2.6.18/include/linux/ipv6.h =================================================================== --- linux-2.6.18.orig/include/linux/ipv6.h +++ linux-2.6.18/include/linux/ipv6.h @@ -153,6 +153,7 @@ struct ipv6_devconf { __s32 accept_ra_rt_info_max_plen; #endif #endif + __s32 accept_source_route; void *sysctl; }; @@ -180,6 +181,9 @@ enum { 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: linux-2.6.18/include/linux/sysctl.h =================================================================== --- linux-2.6.18.orig/include/linux/sysctl.h +++ linux-2.6.18/include/linux/sysctl.h @@ -555,6 +555,7 @@ enum { NET_IPV6_ACCEPT_RA_RTR_PREF=20, NET_IPV6_RTR_PROBE_INTERVAL=21, NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22, + NET_IPV6_ACCEPT_SOURCE_ROUTE=25, __NET_IPV6_MAX }; Index: linux-2.6.18/net/ipv6/addrconf.c =================================================================== --- linux-2.6.18.orig/net/ipv6/addrconf.c +++ linux-2.6.18/net/ipv6/addrconf.c @@ -164,6 +164,7 @@ struct ipv6_devconf ipv6_devconf = { .max_desync_factor = MAX_DESYNC_FACTOR, #endif .max_addresses = IPV6_MAX_ADDRESSES, + .accept_source_route= 0, .accept_ra_defrtr = 1, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF @@ -194,6 +195,7 @@ static struct ipv6_devconf ipv6_devconf_ .max_desync_factor = MAX_DESYNC_FACTOR, #endif .max_addresses = IPV6_MAX_ADDRESSES, + .accept_source_route= 0, .accept_ra_defrtr = 1, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF @@ -3320,6 +3322,7 @@ static void inline ipv6_store_devconf(st 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; array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; #ifdef CONFIG_IPV6_ROUTER_PREF @@ -3798,6 +3801,14 @@ static struct addrconf_sysctl_table .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 = NET_IPV6_ACCEPT_RA_DEFRTR, .procname = "accept_ra_defrtr", .data = &ipv6_devconf.accept_ra_defrtr, Index: linux-2.6.18/net/ipv6/exthdrs.c =================================================================== --- linux-2.6.18.orig/net/ipv6/exthdrs.c +++ linux-2.6.18/net/ipv6/exthdrs.c @@ -221,10 +221,28 @@ static int ipv6_rthdr_rcv(struct sk_buff 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 +253,18 @@ static int ipv6_rthdr_rcv(struct sk_buff 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 +283,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);