Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c382bb9d authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller
Browse files

[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: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c9726d68
Loading
Loading
Loading
Loading
+16 −31
Original line number Diff line number Diff line
@@ -372,21 +372,12 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
	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;
	}

	idev = in6_dev_get(skb->dev);
	if (idev) {
		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_transport_offset(skb) + 8) ||
	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -399,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)

	hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);

	switch (hdr->type) {
#ifdef CONFIG_IPV6_MIP6
	case IPV6_SRCRT_TYPE_2:
		break;
#endif
	case IPV6_SRCRT_TYPE_0:
		if (accept_source_route > 0)
			break;
		kfree_skb(skb);
		return -1;
	default:
		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
				 IPSTATS_MIB_INHDRERRORS);
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
				  (&hdr->type) - skb_network_header(skb));
		return -1;
	}

	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
	    skb->pkt_type != PACKET_HOST) {
		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -455,6 +428,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)

	switch (hdr->type) {
	case IPV6_SRCRT_TYPE_0:
		if (accept_source_route <= 0)
			goto unknown_rh;
		if (hdr->hdrlen & 0x01) {
			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
					 IPSTATS_MIB_INHDRERRORS);
@@ -466,6 +441,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
		break;
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
	case IPV6_SRCRT_TYPE_2:
		if (accept_source_route < 0)
			goto unknown_rh;
		/* Silently discard invalid RTH type 2 */
		if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -475,6 +452,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
		}
		break;
#endif
	default:
		goto unknown_rh;
	}

	/*
@@ -578,6 +557,12 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
	skb_push(skb, skb->data - skb_network_header(skb));
	dst_input(skb);
	return -1;

unknown_rh:
	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
			  (&hdr->type) - skb_network_header(skb));
	return -1;
}

static struct inet6_protocol rthdr_protocol = {