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-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 31 May 2019 09:48:37 -0700
From:   Tom Herbert <tom@...bertland.com>
To:     davem@...emloft.net, netdev@...r.kernel.org, dlebrun@...gle.com,
        ahabdels.dev@...il.com
Cc:     Tom Herbert <tom@...ntonium.net>
Subject: [RFC PATCH 3/6] seg6: Obsolete unused SRH flags

Currently no flags are defined for segment routing in
draft-ietf-6man-segment-routing-header-19. Mark them as being
obsolete.

The HMAC flag is the only one used by the stack. This needs
additional consideration.

Rewrite sr_has_hmac in uapi/linux/seg6.h to properly parse a
segment routing header as opposed to relying on the now obsolete
code.

Implement seg6_find_hmac_tlv for internal stack use. That function
parses (via __seg6_parse_srh) a TLV list and returns the pointer to
an HMAC TLV if one exists. The parsing function also eliminates the
assumption in seg6_get_tlv_hmac that the HMAC TLV must be the first TLV.

Signed-off-by: Tom Herbert <tom@...ntonium.net>
---
 include/net/seg6.h        | 12 +++++++++++-
 include/uapi/linux/seg6.h | 49 ++++++++++++++++++++++++++++++++++++++++-------
 net/ipv6/exthdrs.c        |  2 +-
 net/ipv6/seg6.c           | 12 ++++++++++--
 net/ipv6/seg6_hmac.c      |  8 +++-----
 net/ipv6/seg6_iptunnel.c  |  4 ++--
 6 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/include/net/seg6.h b/include/net/seg6.h
index 563d4a6..47e7c90 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -17,6 +17,7 @@
 #include <linux/net.h>
 #include <linux/ipv6.h>
 #include <linux/seg6.h>
+#include <linux/seg6_hmac.h>
 #include <linux/rhashtable-types.h>
 
 static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
@@ -67,11 +68,20 @@ extern void seg6_iptunnel_exit(void);
 extern int seg6_local_init(void);
 extern void seg6_local_exit(void);
 
-extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh);
+extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh,
+			     struct sr6_tlv_hmac **hmacp);
 extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len);
 extern int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
 			     int proto);
 extern int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh);
 extern int seg6_lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
 			       u32 tbl_id);
+
+static inline struct sr6_tlv_hmac *seg6_find_hmac_tlv(struct ipv6_sr_hdr *srh)
+{
+	struct sr6_tlv_hmac *hmacp = NULL;
+
+	return __seg6_parse_srh(srh, &hmacp) ? hmacp : NULL;
+}
+
 #endif
diff --git a/include/uapi/linux/seg6.h b/include/uapi/linux/seg6.h
index 9117113..890420b0 100644
--- a/include/uapi/linux/seg6.h
+++ b/include/uapi/linux/seg6.h
@@ -33,11 +33,10 @@ struct ipv6_sr_hdr {
 	struct in6_addr segments[0];
 };
 
-#define SR6_FLAG1_PROTECTED	(1 << 6)
-#define SR6_FLAG1_OAM		(1 << 5)
-#define SR6_FLAG1_ALERT		(1 << 4)
-#define SR6_FLAG1_HMAC		(1 << 3)
-
+#define SR6_FLAG1_PROTECTED	(1 << 6)	/* obsoleted */
+#define SR6_FLAG1_OAM		(1 << 5)	/* obsoleted */
+#define SR6_FLAG1_ALERT		(1 << 4)	/* obsoleted */
+#define SR6_FLAG1_HMAC		(1 << 3)	/* obsoleted */
 
 #define SR6_TLV_INGRESS		1	/* obsoleted */
 #define SR6_TLV_EGRESS		2	/* obsoleted */
@@ -47,12 +46,48 @@ struct ipv6_sr_hdr {
 #define SR6_TLV_PADDING		1
 #define SR6_TLV_HMAC		5
 
-#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
-
 struct sr6_tlv {
 	__u8 type;
 	__u8 len;
 	__u8 data[0];
 };
 
+static inline bool __sr_has_hmac(struct ipv6_sr_hdr *srh)
+{
+	unsigned char *opt = (unsigned char *)srh;
+	int len = (srh->hdrlen + 1) << 8;
+	unsigned int off;
+
+	off = sizeof(*srh) + ((srh->first_segment + 1) << 4);
+	len -= off;
+
+	while (len > 0) {
+		struct sr6_tlv *tlv;
+		unsigned int optlen;
+
+		switch (opt[off]) {
+		case SR6_TLV_PAD1:
+			optlen = 1;
+			break;
+		case SR6_TLV_HMAC:
+			return true;
+		default:
+			if (len < sizeof(*tlv))
+				return false;
+
+			tlv = (struct sr6_tlv *)&opt[off];
+			optlen = sizeof(*tlv) + tlv->len;
+
+			break;
+		}
+
+		off += optlen;
+		len -= optlen;
+	}
+
+	return false;
+}
+
+#define sr_has_hmac(srh) __sr_has_hmac(srh)
+
 #endif
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 20291c2..112e2fd 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -922,7 +922,7 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
 	}
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (sr_has_hmac(sr_phdr)) {
+	if (seg6_find_hmac_tlv(sr_phdr)) {
 		struct net *net = NULL;
 
 		if (skb->dev)
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index e461357..1e782a6 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -30,7 +30,7 @@
 #include <net/seg6_hmac.h>
 #endif
 
-bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
+bool __seg6_parse_srh(struct ipv6_sr_hdr *srh, struct sr6_tlv_hmac **hmacp)
 {
 	int len = ipv6_optlen((struct ipv6_opt_hdr *)srh);
 	unsigned char *opt = (unsigned char *)srh;
@@ -39,6 +39,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
 	off = seg6_tlv_offset(srh);
 	len -= off;
 
+	*hmacp = NULL;
+
 	while (len > 0) {
 		struct sr6_tlv *tlv;
 		unsigned int optlen;
@@ -47,6 +49,10 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
 		case SR6_TLV_PAD1:
 			optlen = 1;
 			break;
+		case SR6_TLV_HMAC:
+			if (!*hmacp)
+				*hmacp = (struct sr6_tlv_hmac *)&opt[off];
+			/* Fall through */
 		default:
 			if (len < sizeof(*tlv))
 				return false;
@@ -66,6 +72,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
 
 bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
 {
+	struct sr6_tlv_hmac *hmacp;
+
 	if (srh->type != IPV6_SRCRT_TYPE_4)
 		return false;
 
@@ -75,7 +83,7 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
 	if (srh->segments_left > srh->first_segment)
 		return false;
 
-	return __seg6_parse_srh(srh);
+	return __seg6_parse_srh(srh, &hmacp);
 }
 
 static struct genl_family seg6_genl_family;
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 8546f94..92b398c 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -95,13 +95,11 @@ static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh)
 	if (srh->hdrlen < (srh->first_segment + 1) * 2 + 5)
 		return NULL;
 
-	if (!sr_has_hmac(srh))
+	tlv = seg6_find_hmac_tlv(srh);
+	if (!tlv)
 		return NULL;
 
-	tlv = (struct sr6_tlv_hmac *)
-	      ((char *)srh + ((srh->hdrlen + 1) << 3) - 40);
-
-	if (tlv->tlvhdr.type != SR6_TLV_HMAC || tlv->tlvhdr.len != 38)
+	if (tlv->tlvhdr.len != sizeof(*tlv) - 2)
 		return NULL;
 
 	return tlv;
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 7a525fd..5344bee 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -161,7 +161,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
 	set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (sr_has_hmac(isrh)) {
+	if (seg6_find_hmac_tlv(isrh)) {
 		err = seg6_push_hmac(net, &hdr->saddr, isrh);
 		if (unlikely(err))
 			return err;
@@ -211,7 +211,7 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 	hdr->daddr = isrh->segments[isrh->first_segment];
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (sr_has_hmac(isrh)) {
+	if (seg6_find_hmac_tlv(isrh)) {
 		struct net *net = dev_net(skb_dst(skb)->dev);
 
 		err = seg6_push_hmac(net, &hdr->saddr, isrh);
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ