lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1559576867-4241-1-git-send-email-tom@quantonium.net>
Date:   Mon,  3 Jun 2019 08:47:47 -0700
From:   Tom Herbert <tom@...bertland.com>
To:     davem@...emloft.net, netdev@...r.kernel.org
Cc:     Tom Herbert <tom@...ntonium.net>
Subject: [PATCH v2 net-next] ipv6: Send ICMP errors for exceeding extension header limits

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@...ntonium.net>
---
 include/uapi/linux/icmpv6.h |  6 ++++++
 net/ipv6/exthdrs.c          | 50 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 48 insertions(+), 8 deletions(-)

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,
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ