aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2007-07-11 01:47:58 -0400
committerDavid S. Miller <davem@davemloft.net>2007-07-11 01:47:58 -0400
commitc382bb9d32a55029fb13b118858e25908fab4617 (patch)
tree0a7466b0e27ec88d27af579393d26df80c38a35e /net/ipv6
parentc9726d6890f7f3a892c879e067c3ed839f61e745 (diff)
[IPV6]: Restore semantics of Routing Header processing.
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>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/exthdrs.c47
1 files changed, 16 insertions, 31 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 173a4bb52255..fc3a961fc5ba 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -372,22 +372,13 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
372 struct rt0_hdr *rthdr; 372 struct rt0_hdr *rthdr;
373 int accept_source_route = ipv6_devconf.accept_source_route; 373 int accept_source_route = ipv6_devconf.accept_source_route;
374 374
375 if (accept_source_route < 0 || 375 idev = in6_dev_get(skb->dev);
376 ((idev = in6_dev_get(skb->dev)) == NULL)) { 376 if (idev) {
377 kfree_skb(skb); 377 if (accept_source_route > idev->cnf.accept_source_route)
378 return -1; 378 accept_source_route = idev->cnf.accept_source_route;
379 }
380 if (idev->cnf.accept_source_route < 0) {
381 in6_dev_put(idev); 379 in6_dev_put(idev);
382 kfree_skb(skb);
383 return -1;
384 } 380 }
385 381
386 if (accept_source_route > idev->cnf.accept_source_route)
387 accept_source_route = idev->cnf.accept_source_route;
388
389 in6_dev_put(idev);
390
391 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || 382 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
392 !pskb_may_pull(skb, (skb_transport_offset(skb) + 383 !pskb_may_pull(skb, (skb_transport_offset(skb) +
393 ((skb_transport_header(skb)[1] + 1) << 3)))) { 384 ((skb_transport_header(skb)[1] + 1) << 3)))) {
@@ -399,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
399 390
400 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); 391 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
401 392
402 switch (hdr->type) {
403#ifdef CONFIG_IPV6_MIP6
404 case IPV6_SRCRT_TYPE_2:
405 break;
406#endif
407 case IPV6_SRCRT_TYPE_0:
408 if (accept_source_route > 0)
409 break;
410 kfree_skb(skb);
411 return -1;
412 default:
413 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
414 IPSTATS_MIB_INHDRERRORS);
415 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
416 (&hdr->type) - skb_network_header(skb));
417 return -1;
418 }
419
420 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || 393 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
421 skb->pkt_type != PACKET_HOST) { 394 skb->pkt_type != PACKET_HOST) {
422 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 395 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -455,6 +428,8 @@ looped_back:
455 428
456 switch (hdr->type) { 429 switch (hdr->type) {
457 case IPV6_SRCRT_TYPE_0: 430 case IPV6_SRCRT_TYPE_0:
431 if (accept_source_route <= 0)
432 goto unknown_rh;
458 if (hdr->hdrlen & 0x01) { 433 if (hdr->hdrlen & 0x01) {
459 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 434 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
460 IPSTATS_MIB_INHDRERRORS); 435 IPSTATS_MIB_INHDRERRORS);
@@ -466,6 +441,8 @@ looped_back:
466 break; 441 break;
467#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 442#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
468 case IPV6_SRCRT_TYPE_2: 443 case IPV6_SRCRT_TYPE_2:
444 if (accept_source_route < 0)
445 goto unknown_rh;
469 /* Silently discard invalid RTH type 2 */ 446 /* Silently discard invalid RTH type 2 */
470 if (hdr->hdrlen != 2 || hdr->segments_left != 1) { 447 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
471 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 448 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -475,6 +452,8 @@ looped_back:
475 } 452 }
476 break; 453 break;
477#endif 454#endif
455 default:
456 goto unknown_rh;
478 } 457 }
479 458
480 /* 459 /*
@@ -578,6 +557,12 @@ looped_back:
578 skb_push(skb, skb->data - skb_network_header(skb)); 557 skb_push(skb, skb->data - skb_network_header(skb));
579 dst_input(skb); 558 dst_input(skb);
580 return -1; 559 return -1;
560
561unknown_rh:
562 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
563 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
564 (&hdr->type) - skb_network_header(skb));
565 return -1;
581} 566}
582 567
583static struct inet6_protocol rthdr_protocol = { 568static struct inet6_protocol rthdr_protocol = {