summaryrefslogtreecommitdiff
blob: 9d5977962bb697ce8aad541e2d4878eaa912810d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
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 <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---

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);