diff mbox series

[v2,net-next] ipv6: Send ICMP errors for exceeding extension header limits

Message ID 1559576867-4241-1-git-send-email-tom@quantonium.net
State Rejected
Delegated to: David Miller
Headers show
Series [v2,net-next] ipv6: Send ICMP errors for exceeding extension header limits | expand

Commit Message

Tom Herbert June 3, 2019, 3:47 p.m. UTC
Define constants and add support to send ICMPv6 Parameter Problem
errors as specified in draft-ietf-6man-icmp-limits-02.

The following parameter problem errors are sent when processing
Hop-by-Hop or Destination Options:

   * ICMPV6_TOOBIG_OPTION
      - Sent if the length of an option exceeds the extent of the
        extension header.
      - Sent if a packet exceeding the padding limit is received
        (more than seven consecutive bytes of padding).

   * ICMPV6_TOOMANY_OPTIONS
      - Sent if a packet is received and HBH option count exceeds
        ipv6.sysctl.max_hbh_opts_cnt or DO option count exceeds
        ipv6.sysctl.max_dst_opts_cnt.

   * ICMPV6_EXTHDR_TOOBIG
      - Sent if length of HBH EH exceeds ipv6.sysctl.max_hbh_opts_len
        or length of DO EH exceeds ipv6.sysctl.max_dst_opts_len.
      - Sent if the length of an extension header exceeds the
        extent of the packet.

   * ICMPV6_HDR_FIELD
      - Sent if a data byte in PADN is non-zero

Signed-off-by: Tom Herbert <tom@quantonium.net>
---
 include/uapi/linux/icmpv6.h |  6 ++++++
 net/ipv6/exthdrs.c          | 50 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 48 insertions(+), 8 deletions(-)

Comments

David Miller June 6, 2019, 12:11 a.m. UTC | #1
From: Tom Herbert <tom@herbertland.com>
Date: Mon,  3 Jun 2019 08:47:47 -0700

> Define constants and add support to send ICMPv6 Parameter Problem
> errors as specified in draft-ietf-6man-icmp-limits-02.

Tom, I've kinda had enough of this pushing your agenda by trying to
add support for ipv6 features that are in draft state with the IETF
and you are the author of said drafts.

I'm not applying this stuff, sorry.
Tom Herbert June 6, 2019, 1:03 a.m. UTC | #2
On Wed, Jun 5, 2019 at 5:11 PM David Miller <davem@davemloft.net> wrote:
>
> From: Tom Herbert <tom@herbertland.com>
> Date: Mon,  3 Jun 2019 08:47:47 -0700
>
> > Define constants and add support to send ICMPv6 Parameter Problem
> > errors as specified in draft-ietf-6man-icmp-limits-02.
>
> Tom, I've kinda had enough of this pushing your agenda by trying to
> add support for ipv6 features that are in draft state with the IETF
> and you are the author of said drafts.
>
I'm sorry, I had no idea that there were criteria that we had to
follow with respect to patches and IETF. Please specify the criteria,
which I will assume that apply to everyone and not to just me, so that
we can avoid further instances of wasted time.

Thanks,
Tom

> I'm not applying this stuff, sorry.
diff mbox series

Patch

diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h
index 2622b5a..966279b 100644
--- a/include/uapi/linux/icmpv6.h
+++ b/include/uapi/linux/icmpv6.h
@@ -124,6 +124,7 @@  struct icmp6hdr {
 #define ICMPV6_PORT_UNREACH		4
 #define ICMPV6_POLICY_FAIL		5
 #define ICMPV6_REJECT_ROUTE		6
+#define ICMPV6_SRCRT_ERR		7
 
 /*
  *	Codes for Time Exceeded
@@ -137,6 +138,11 @@  struct icmp6hdr {
 #define ICMPV6_HDR_FIELD		0
 #define ICMPV6_UNK_NEXTHDR		1
 #define ICMPV6_UNK_OPTION		2
+#define ICMPV6_FIRST_FRAG_INCOMP	3
+#define ICMPV6_EXTHDR_TOOBIG		4
+#define ICMPV6_EXTHDR_CHAINLONG		5
+#define ICMPV6_TOOMANY_OPTIONS		6
+#define ICMPV6_TOOBIG_OPTION		7
 
 /*
  *	constants for (set|get)sockopt
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 20291c2..05061f4 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -131,8 +131,11 @@  static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
 		max_count = -max_count;
 	}
 
-	if (skb_transport_offset(skb) + len > skb_headlen(skb))
+	if (skb_transport_offset(skb) + len > skb_headlen(skb)) {
+		icmpv6_send(skb, ICMPV6_PARAMPROB,
+			    ICMPV6_EXTHDR_TOOBIG, skb_transport_offset(skb));
 		goto bad;
+	}
 
 	off += 2;
 	len -= 2;
@@ -145,8 +148,11 @@  static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
 		case IPV6_TLV_PAD1:
 			optlen = 1;
 			padlen++;
-			if (padlen > 7)
+			if (padlen > 7) {
+				icmpv6_send(skb, ICMPV6_PARAMPROB,
+					    ICMPV6_TOOBIG_OPTION, off);
 				goto bad;
+			}
 			break;
 
 		case IPV6_TLV_PADN:
@@ -156,25 +162,37 @@  static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
 			 * See also RFC 4942, Section 2.1.9.5.
 			 */
 			padlen += optlen;
-			if (padlen > 7)
+			if (padlen > 7) {
+				icmpv6_send(skb, ICMPV6_PARAMPROB,
+					    ICMPV6_TOOBIG_OPTION, off);
 				goto bad;
+			}
 			/* RFC 4942 recommends receiving hosts to
 			 * actively check PadN payload to contain
 			 * only zeroes.
 			 */
 			for (i = 2; i < optlen; i++) {
-				if (nh[off + i] != 0)
+				if (nh[off + i] != 0) {
+					icmpv6_send(skb, ICMPV6_PARAMPROB,
+						    ICMPV6_HDR_FIELD, off + i);
 					goto bad;
+				}
 			}
 			break;
 
 		default: /* Other TLV code so scan list */
-			if (optlen > len)
+			if (optlen > len) {
+				icmpv6_send(skb, ICMPV6_PARAMPROB,
+					    ICMPV6_TOOBIG_OPTION, off);
 				goto bad;
+			}
 
 			tlv_count++;
-			if (tlv_count > max_count)
+			if (tlv_count > max_count) {
+				icmpv6_send(skb, ICMPV6_PARAMPROB,
+					    ICMPV6_TOOMANY_OPTIONS, off);
 				goto bad;
+			}
 
 			for (curr = procs; curr->type >= 0; curr++) {
 				if (curr->type == nh[off]) {
@@ -200,6 +218,8 @@  static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
 	if (len == 0)
 		return true;
 bad:
+	__IP6_INC_STATS(dev_net(skb->dev), __in6_dev_get(skb->dev),
+			IPSTATS_MIB_INHDRERRORS);
 	kfree_skb(skb);
 	return false;
 }
@@ -300,8 +320,15 @@  static int ipv6_destopt_rcv(struct sk_buff *skb)
 	}
 
 	extlen = (skb_transport_header(skb)[1] + 1) << 3;
-	if (extlen > net->ipv6.sysctl.max_dst_opts_len)
+	if (extlen > net->ipv6.sysctl.max_dst_opts_len) {
+		icmpv6_send(skb, ICMPV6_PARAMPROB,
+			    ICMPV6_EXTHDR_TOOBIG,
+			    skb_network_header_len(skb) +
+				net->ipv6.sysctl.max_dst_opts_len);
+		__IP6_INC_STATS(dev_net(dst->dev), idev,
+				IPSTATS_MIB_INHDRERRORS);
 		goto fail_and_free;
+	}
 
 	opt->lastopt = opt->dst1 = skb_network_header_len(skb);
 #if IS_ENABLED(CONFIG_IPV6_MIP6)
@@ -843,8 +870,15 @@  int ipv6_parse_hopopts(struct sk_buff *skb)
 	}
 
 	extlen = (skb_transport_header(skb)[1] + 1) << 3;
-	if (extlen > net->ipv6.sysctl.max_hbh_opts_len)
+	if (extlen > net->ipv6.sysctl.max_hbh_opts_len) {
+		__IP6_INC_STATS(net, __in6_dev_get(skb->dev),
+				IPSTATS_MIB_INHDRERRORS);
+		icmpv6_send(skb, ICMPV6_PARAMPROB,
+			    ICMPV6_EXTHDR_TOOBIG,
+			skb_network_header_len(skb) +
+				net->ipv6.sysctl.max_hbh_opts_len);
 		goto fail_and_free;
+	}
 
 	opt->flags |= IP6SKB_HOPBYHOP;
 	if (ip6_parse_tlv(tlvprochopopt_lst, skb,