From: YOSHIFUJI Hideaki Date: Thu, 26 Apr 2007 04:56:57 +0000 (-0700) Subject: [PATCH] IPV6: Disallow RH0 by default. X-Git-Tag: v2.6.20.9~1 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.20.y.git;a=commitdiff_plain;h=010831ab8436dfd9304b203467566fb6b135c24f [PATCH] IPV6: Disallow RH0 by default. [IPV6]: Disallow RH0 by default. A security issue is emerging. Disallow Routing Header Type 0 by default as we have been doing for IPv4. Note: We allow RH2 by default because it is harmless. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- Backported to Debian's 2.6.18 by dann frazier and Vlad Yasevich diff -urpN linux-source-2.6.18.orig/Documentation/networking/ip-sysctl.txt linux-source-2.6.18/Documentation/networking/ip-sysctl.txt --- linux-source-2.6.18.orig/Documentation/networking/ip-sysctl.txt 2007-05-11 15:09:21.000000000 -0600 +++ linux-source-2.6.18/Documentation/networking/ip-sysctl.txt 2007-05-11 15:10:03.000000000 -0600 @@ -775,6 +775,14 @@ 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: Do not accept routing header. + + Default: 0 + autoconf - BOOLEAN Autoconfigure addresses using Prefix Information in Router Advertisements. diff -urpN linux-source-2.6.18.orig/include/linux/ipv6.h linux-source-2.6.18/include/linux/ipv6.h --- linux-source-2.6.18.orig/include/linux/ipv6.h 2007-05-11 15:09:21.000000000 -0600 +++ linux-source-2.6.18/include/linux/ipv6.h 2007-05-11 15:10:03.000000000 -0600 @@ -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,7 @@ enum { DEVCONF_ACCEPT_RA_RTR_PREF, DEVCONF_RTR_PROBE_INTERVAL, DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, + DEVCONF_ACCEPT_SOURCE_ROUTE, DEVCONF_MAX }; diff -urpN linux-source-2.6.18.orig/include/linux/sysctl.h linux-source-2.6.18/include/linux/sysctl.h --- linux-source-2.6.18.orig/include/linux/sysctl.h 2007-05-11 15:09:21.000000000 -0600 +++ linux-source-2.6.18/include/linux/sysctl.h 2007-05-11 15:10:03.000000000 -0600 @@ -553,6 +553,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=23, __NET_IPV6_MAX }; diff -urpN linux-source-2.6.18.orig/net/ipv6/addrconf.c linux-source-2.6.18/net/ipv6/addrconf.c --- linux-source-2.6.18.orig/net/ipv6/addrconf.c 2007-05-11 15:09:21.000000000 -0600 +++ linux-source-2.6.18/net/ipv6/addrconf.c 2007-05-11 15:10:07.000000000 -0600 @@ -173,6 +173,7 @@ struct ipv6_devconf ipv6_devconf = { .accept_ra_rt_info_max_plen = 0, #endif #endif + .accept_source_route = 0, /* we do not accept RH0 by default. */ }; static struct ipv6_devconf ipv6_devconf_dflt = { @@ -203,6 +204,7 @@ static struct ipv6_devconf ipv6_devconf_ .accept_ra_rt_info_max_plen = 0, #endif #endif + .accept_source_route = 0, /* we do not accept RH0 by default. */ }; /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ @@ -3333,6 +3335,7 @@ static void inline ipv6_store_devconf(st array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; #endif #endif + array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; } /* Maximum length of ifinfomsg attributes */ @@ -3847,6 +3850,14 @@ static struct addrconf_sysctl_table #endif #endif { + .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 */ } }, diff -urpN linux-source-2.6.18.orig/net/ipv6/exthdrs.c linux-source-2.6.18/net/ipv6/exthdrs.c --- linux-source-2.6.18.orig/net/ipv6/exthdrs.c 2007-05-11 15:09:21.000000000 -0600 +++ linux-source-2.6.18/net/ipv6/exthdrs.c 2007-05-11 15:10:03.000000000 -0600 @@ -221,10 +221,24 @@ 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; + } + + 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 +249,12 @@ static int ipv6_rthdr_rcv(struct sk_buff hdr = (struct ipv6_rt_hdr *) skb->h.raw; + 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 (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) || skb->pkt_type != PACKET_HOST) { IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); @@ -253,12 +273,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);