svn commit: r331985 - in releng: 10.3/sys/netipsec 10.4/sys/netipsec 11.1/sys/netipsec

Gordon Tetlow gordon at FreeBSD.org
Wed Apr 4 05:37:53 UTC 2018


Author: gordon
Date: Wed Apr  4 05:37:52 2018
New Revision: 331985
URL: https://svnweb.freebsd.org/changeset/base/331985

Log:
  Fix ipsec crash or denial of service. [SA-18:05.ipsec]
  
  Reported by:	Maxime Villard
  Approved by:	so
  Security:	CVE-2018-6918
  Security:	FreeBSD-SA-18:05.ipsec

Modified:
  releng/10.3/sys/netipsec/xform_ah.c
  releng/10.4/sys/netipsec/xform_ah.c
  releng/11.1/sys/netipsec/xform_ah.c

Modified: releng/10.3/sys/netipsec/xform_ah.c
==============================================================================
--- releng/10.3/sys/netipsec/xform_ah.c	Wed Apr  4 05:33:56 2018	(r331984)
+++ releng/10.3/sys/netipsec/xform_ah.c	Wed Apr  4 05:37:52 2018	(r331985)
@@ -285,7 +285,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #ifdef INET6
 	struct ip6_ext *ip6e;
 	struct ip6_hdr ip6;
-	int alloc, len, ad;
+	int ad, alloc, nxt, noff;
 #endif /* INET6 */
 
 	switch (proto) {
@@ -314,7 +314,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		else
 			ip->ip_off = htons(0);
 
-		ptr = mtod(m, unsigned char *) + sizeof(struct ip);
+		ptr = mtod(m, unsigned char *);
 
 		/* IPv4 option processing */
 		for (off = sizeof(struct ip); off < skip;) {
@@ -395,7 +395,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 
 				/* Zeroize all other options. */
 				count = ptr[off + 1];
-				bcopy(ipseczeroes, ptr, count);
+				bcopy(ipseczeroes, ptr + off, count);
 				off += count;
 				break;
 			}
@@ -468,61 +468,44 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		} else
 			break;
 
-		off = ip6.ip6_nxt & 0xff; /* Next header type. */
+		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
 
-		for (len = 0; len < skip - sizeof(struct ip6_hdr);)
-			switch (off) {
+		for (off = 0; off < skip - sizeof(struct ip6_hdr);)
+			switch (nxt) {
 			case IPPROTO_HOPOPTS:
 			case IPPROTO_DSTOPTS:
-				ip6e = (struct ip6_ext *) (ptr + len);
+				ip6e = (struct ip6_ext *)(ptr + off);
+				noff = off + ((ip6e->ip6e_len + 1) << 3);
 
+				/* Sanity check. */
+				if (noff > skip - sizeof(struct ip6_hdr))
+					goto error6;
+
 				/*
-				 * Process the mutable/immutable
-				 * options -- borrows heavily from the
-				 * KAME code.
+				 * Zero out mutable options.
 				 */
-				for (count = len + sizeof(struct ip6_ext);
-				     count < len + ((ip6e->ip6e_len + 1) << 3);) {
+				for (count = off + sizeof(struct ip6_ext);
+				     count < noff;) {
 					if (ptr[count] == IP6OPT_PAD1) {
 						count++;
 						continue; /* Skip padding. */
 					}
 
-					/* Sanity check. */
-					if (count > len +
-					    ((ip6e->ip6e_len + 1) << 3)) {
-						m_freem(m);
+					ad = ptr[count + 1] + 2;
+					if (count + ad > noff)
+						goto error6;
 
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
-
-					ad = ptr[count + 1];
-
-					/* If mutable option, zeroize. */
 					if (ptr[count] & IP6OPT_MUTABLE)
-						bcopy(ipseczeroes, ptr + count,
-						    ptr[count + 1]);
-
+						memset(ptr + count, 0, ad);
 					count += ad;
-
-					/* Sanity check. */
-					if (count >
-					    skip - sizeof(struct ip6_hdr)) {
-						m_freem(m);
-
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
 				}
 
+				if (count != noff)
+					goto error6;
+
 				/* Advance. */
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			case IPPROTO_ROUTING:
@@ -530,14 +513,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 				 * Always include routing headers in
 				 * computation.
 				 */
-				ip6e = (struct ip6_ext *) (ptr + len);
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				ip6e = (struct ip6_ext *) (ptr + off);
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			default:
 				DPRINTF(("%s: unexpected IPv6 header type %d",
 					__func__, off));
+error6:
 				if (alloc)
 					free(ptr, M_XDATA);
 				m_freem(m);

Modified: releng/10.4/sys/netipsec/xform_ah.c
==============================================================================
--- releng/10.4/sys/netipsec/xform_ah.c	Wed Apr  4 05:33:56 2018	(r331984)
+++ releng/10.4/sys/netipsec/xform_ah.c	Wed Apr  4 05:37:52 2018	(r331985)
@@ -285,7 +285,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #ifdef INET6
 	struct ip6_ext *ip6e;
 	struct ip6_hdr ip6;
-	int alloc, len, ad;
+	int ad, alloc, nxt, noff;
 #endif /* INET6 */
 
 	switch (proto) {
@@ -314,7 +314,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		else
 			ip->ip_off = htons(0);
 
-		ptr = mtod(m, unsigned char *) + sizeof(struct ip);
+		ptr = mtod(m, unsigned char *);
 
 		/* IPv4 option processing */
 		for (off = sizeof(struct ip); off < skip;) {
@@ -395,7 +395,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 
 				/* Zeroize all other options. */
 				count = ptr[off + 1];
-				bcopy(ipseczeroes, ptr, count);
+				bcopy(ipseczeroes, ptr + off, count);
 				off += count;
 				break;
 			}
@@ -468,61 +468,44 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		} else
 			break;
 
-		off = ip6.ip6_nxt & 0xff; /* Next header type. */
+		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
 
-		for (len = 0; len < skip - sizeof(struct ip6_hdr);)
-			switch (off) {
+		for (off = 0; off < skip - sizeof(struct ip6_hdr);)
+			switch (nxt) {
 			case IPPROTO_HOPOPTS:
 			case IPPROTO_DSTOPTS:
-				ip6e = (struct ip6_ext *) (ptr + len);
+				ip6e = (struct ip6_ext *)(ptr + off);
+				noff = off + ((ip6e->ip6e_len + 1) << 3);
 
+				/* Sanity check. */
+				if (noff > skip - sizeof(struct ip6_hdr))
+					goto error6;
+
 				/*
-				 * Process the mutable/immutable
-				 * options -- borrows heavily from the
-				 * KAME code.
+				 * Zero out mutable options.
 				 */
-				for (count = len + sizeof(struct ip6_ext);
-				     count < len + ((ip6e->ip6e_len + 1) << 3);) {
+				for (count = off + sizeof(struct ip6_ext);
+				     count < noff;) {
 					if (ptr[count] == IP6OPT_PAD1) {
 						count++;
 						continue; /* Skip padding. */
 					}
 
-					/* Sanity check. */
-					if (count > len +
-					    ((ip6e->ip6e_len + 1) << 3)) {
-						m_freem(m);
+					ad = ptr[count + 1] + 2;
+					if (count + ad > noff)
+						goto error6;
 
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
-
-					ad = ptr[count + 1];
-
-					/* If mutable option, zeroize. */
 					if (ptr[count] & IP6OPT_MUTABLE)
-						bcopy(ipseczeroes, ptr + count,
-						    ptr[count + 1]);
-
+						memset(ptr + count, 0, ad);
 					count += ad;
-
-					/* Sanity check. */
-					if (count >
-					    skip - sizeof(struct ip6_hdr)) {
-						m_freem(m);
-
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
 				}
 
+				if (count != noff)
+					goto error6;
+
 				/* Advance. */
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			case IPPROTO_ROUTING:
@@ -530,14 +513,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 				 * Always include routing headers in
 				 * computation.
 				 */
-				ip6e = (struct ip6_ext *) (ptr + len);
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				ip6e = (struct ip6_ext *) (ptr + off);
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			default:
 				DPRINTF(("%s: unexpected IPv6 header type %d",
 					__func__, off));
+error6:
 				if (alloc)
 					free(ptr, M_XDATA);
 				m_freem(m);

Modified: releng/11.1/sys/netipsec/xform_ah.c
==============================================================================
--- releng/11.1/sys/netipsec/xform_ah.c	Wed Apr  4 05:33:56 2018	(r331984)
+++ releng/11.1/sys/netipsec/xform_ah.c	Wed Apr  4 05:37:52 2018	(r331985)
@@ -264,7 +264,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 #ifdef INET6
 	struct ip6_ext *ip6e;
 	struct ip6_hdr ip6;
-	int alloc, len, ad;
+	int ad, alloc, nxt, noff;
 #endif /* INET6 */
 
 	switch (proto) {
@@ -293,7 +293,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		else
 			ip->ip_off = htons(0);
 
-		ptr = mtod(m, unsigned char *) + sizeof(struct ip);
+		ptr = mtod(m, unsigned char *);
 
 		/* IPv4 option processing */
 		for (off = sizeof(struct ip); off < skip;) {
@@ -374,7 +374,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 
 				/* Zeroize all other options. */
 				count = ptr[off + 1];
-				bcopy(ipseczeroes, ptr, count);
+				bcopy(ipseczeroes, ptr + off, count);
 				off += count;
 				break;
 			}
@@ -447,61 +447,44 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 		} else
 			break;
 
-		off = ip6.ip6_nxt & 0xff; /* Next header type. */
+		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
 
-		for (len = 0; len < skip - sizeof(struct ip6_hdr);)
-			switch (off) {
+		for (off = 0; off < skip - sizeof(struct ip6_hdr);)
+			switch (nxt) {
 			case IPPROTO_HOPOPTS:
 			case IPPROTO_DSTOPTS:
-				ip6e = (struct ip6_ext *) (ptr + len);
+				ip6e = (struct ip6_ext *)(ptr + off);
+				noff = off + ((ip6e->ip6e_len + 1) << 3);
 
+				/* Sanity check. */
+				if (noff > skip - sizeof(struct ip6_hdr))
+					goto error6;
+
 				/*
-				 * Process the mutable/immutable
-				 * options -- borrows heavily from the
-				 * KAME code.
+				 * Zero out mutable options.
 				 */
-				for (count = len + sizeof(struct ip6_ext);
-				     count < len + ((ip6e->ip6e_len + 1) << 3);) {
+				for (count = off + sizeof(struct ip6_ext);
+				     count < noff;) {
 					if (ptr[count] == IP6OPT_PAD1) {
 						count++;
 						continue; /* Skip padding. */
 					}
 
-					/* Sanity check. */
-					if (count > len +
-					    ((ip6e->ip6e_len + 1) << 3)) {
-						m_freem(m);
+					ad = ptr[count + 1] + 2;
+					if (count + ad > noff)
+						goto error6;
 
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
-
-					ad = ptr[count + 1];
-
-					/* If mutable option, zeroize. */
 					if (ptr[count] & IP6OPT_MUTABLE)
-						bcopy(ipseczeroes, ptr + count,
-						    ptr[count + 1]);
-
+						memset(ptr + count, 0, ad);
 					count += ad;
-
-					/* Sanity check. */
-					if (count >
-					    skip - sizeof(struct ip6_hdr)) {
-						m_freem(m);
-
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
-					}
 				}
 
+				if (count != noff)
+					goto error6;
+
 				/* Advance. */
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			case IPPROTO_ROUTING:
@@ -509,14 +492,15 @@ ah_massage_headers(struct mbuf **m0, int proto, int sk
 				 * Always include routing headers in
 				 * computation.
 				 */
-				ip6e = (struct ip6_ext *) (ptr + len);
-				len += ((ip6e->ip6e_len + 1) << 3);
-				off = ip6e->ip6e_nxt;
+				ip6e = (struct ip6_ext *) (ptr + off);
+				off += ((ip6e->ip6e_len + 1) << 3);
+				nxt = ip6e->ip6e_nxt;
 				break;
 
 			default:
 				DPRINTF(("%s: unexpected IPv6 header type %d",
 					__func__, off));
+error6:
 				if (alloc)
 					free(ptr, M_XDATA);
 				m_freem(m);


More information about the svn-src-releng mailing list