Tue Mar 13 17:18:12 2018 UTC ()
Pull up following revision(s) (requested by maxv in ticket #1532):
	sys/netipsec/xform_ah.c: 1.77 via patch
	sys/netipsec/xform_esp.c: 1.73 via patch
	sys/netipsec/xform_ipip.c: 1.56-1.57 via patch
Reinforce and clarify.
--
Add missing NULL check. Normally that's not triggerable remotely, since we
are guaranteed that 8 bytes are valid at mbuf+skip.
--
Fix use-after-free. There is a path where the mbuf gets pulled up without
a proper mtod afterwards:
218     ipo = mtod(m, struct ip *);
281     m = m_pullup(m, hlen);
232     ipo->ip_src.s_addr
Found by Mootja.
Meanwhile it seems to me that 'ipo' should be set to NULL if the inner
packet is IPv6, but I'll revisit that later.
--
As I said in my last commit in this file, ipo should be set to NULL;
otherwise the 'local address spoofing' check below is always wrong on
IPv6.


(snj)
diff -r1.37.6.3 -r1.37.6.4 src/sys/netipsec/xform_ah.c
diff -r1.40 -r1.40.6.1 src/sys/netipsec/xform_esp.c
diff -r1.28.14.1 -r1.28.14.2 src/sys/netipsec/xform_ipip.c

cvs diff -r1.37.6.3 -r1.37.6.4 src/sys/netipsec/xform_ah.c (expand / switch to context diff)
--- src/sys/netipsec/xform_ah.c 2018/02/15 16:50:01 1.37.6.3
+++ src/sys/netipsec/xform_ah.c 2018/03/13 17:18:12 1.37.6.4
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ah.c,v 1.37.6.3 2018/02/15 16:50:01 martin Exp $	*/
+/*	$NetBSD: xform_ah.c,v 1.37.6.4 2018/03/13 17:18:12 snj Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */
 /*
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.37.6.3 2018/02/15 16:50:01 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.37.6.4 2018/03/13 17:18:12 snj Exp $");
 
 #include "opt_inet.h"
 #ifdef __FreeBSD__
@@ -498,54 +498,45 @@
 
 		nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
 
-		for (off = 0; off < skip - sizeof(struct ip6_hdr);)
+		for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
+			int noff;
+
 			switch (nxt) {
 			case IPPROTO_HOPOPTS:
 			case IPPROTO_DSTOPTS:
-				ip6e = (struct ip6_ext *) (ptr + off);
+				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 = off + sizeof(struct ip6_ext);
-				     count < off + ((ip6e->ip6e_len + 1) << 3);) {
+				     count < noff;) {
 					if (ptr[count] == IP6OPT_PAD1) {
 						count++;
-						continue; /* Skip padding. */
+						continue;
 					}
 
-					/* Sanity check. */
-					if (count > off +
-					    ((ip6e->ip6e_len + 1) << 3)) {
-						m_freem(m);
+					ad = ptr[count + 1] + 2;
 
-						/* Free, if we allocated. */
-						if (alloc)
-							free(ptr, M_XDATA);
-						return EINVAL;
+					if (count + ad > noff) {
+						goto error6;
 					}
 
-					ad = ptr[count + 1] + 2;
+					if (ptr[count] & IP6OPT_MUTABLE) {
+						memset(ptr + count, 0, ad);
+					}
 
-					/* If mutable option, zeroize. */
-					if (ptr[count] & IP6OPT_MUTABLE)
-						memcpy(ptr + count, ipseczeroes,
-						    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. */
@@ -603,11 +594,13 @@
 			default:
 				DPRINTF(("ah_massage_headers: unexpected "
 				    "IPv6 header type %d", off));
+error6:
 				if (alloc)
 					free(ptr, M_XDATA);
 				m_freem(m);
 				return EINVAL;
 			}
+		}
 
 		/* Copyback and free, if we allocated. */
 		if (alloc) {

cvs diff -r1.40 -r1.40.6.1 src/sys/netipsec/xform_esp.c (expand / switch to context diff)
--- src/sys/netipsec/xform_esp.c 2012/01/25 20:31:23 1.40
+++ src/sys/netipsec/xform_esp.c 2018/03/13 17:18:12 1.40.6.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_esp.c,v 1.40 2012/01/25 20:31:23 drochner Exp $	*/
+/*	$NetBSD: xform_esp.c,v 1.40.6.1 2018/03/13 17:18:12 snj Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_esp.c,v 1.2.2.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_esp.c,v 1.69 2001/06/26 06:18:59 angelos Exp $ */
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.40 2012/01/25 20:31:23 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.40.6.1 2018/03/13 17:18:12 snj Exp $");
 
 #include "opt_inet.h"
 #ifdef __FreeBSD__
@@ -315,6 +315,10 @@
 
 	/* XXX don't pullup, just copy header */
 	IP6_EXTHDR_GET(esp, struct newesp *, m, skip, sizeof (struct newesp));
+	if (esp == NULL) {
+		/* m already freed */
+		return EINVAL;
+	}
 
 	esph = sav->tdb_authalgxform;
 	espx = sav->tdb_encalgxform;

cvs diff -r1.28.14.1 -r1.28.14.2 src/sys/netipsec/xform_ipip.c (expand / switch to context diff)
--- src/sys/netipsec/xform_ipip.c 2018/02/15 14:51:44 1.28.14.1
+++ src/sys/netipsec/xform_ipip.c 2018/03/13 17:18:12 1.28.14.2
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ipip.c,v 1.28.14.1 2018/02/15 14:51:44 martin Exp $	*/
+/*	$NetBSD: xform_ipip.c,v 1.28.14.2 2018/03/13 17:18:12 snj Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
 
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.28.14.1 2018/02/15 14:51:44 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.28.14.2 2018/03/13 17:18:12 snj Exp $");
 
 /*
  * IP-inside-IP processing
@@ -324,7 +324,8 @@
 #endif /* INET */
 #ifdef INET6
     	case 6:
-                ip6 = (struct ip6_hdr *) ipo;
+		ipo = NULL;
+		ip6 = mtod(m, struct ip6_hdr *);
 		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
 		ip_ecn_egress(ip6_ipsec_ecn, &otos, &itos);
 		ip6->ip6_flow &= ~htonl(0xff << 20);