Module Name:    src
Committed By:   martin
Date:           Thu May  3 14:37:25 UTC 2018

Modified Files:
        src/sys/netipsec [netbsd-6-0]: ipsec_output.c

Log Message:
Pull up following revision(s) (requested by maxv in ticket #1546):

        sys/netipsec/ipsec_output.c: revision 1.67,1.75 (via patch)

Strengthen this check, to make sure there is room for an ip6_ext structure.
Seems possible to crash m_copydata here (but I didn't test more than that).

Fix the checks in compute_ipsec_pos, otherwise m_copydata could crash. I
already fixed half of the problem two months ago in rev1.67, back then I
thought it was not triggerable because each packet we emit is guaranteed
to have correctly formed IPv6 options; but it is actually triggerable via
IPv6 forwarding, we emit a packet we just received, and we don't sanitize
its options before invoking IPsec.

Since it would be wrong to just stop the iteration and continue the IPsec
processing, allow compute_ipsec_pos to fail, and when it does, drop the
packet entirely.


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.38.8.1 src/sys/netipsec/ipsec_output.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netipsec/ipsec_output.c
diff -u src/sys/netipsec/ipsec_output.c:1.38 src/sys/netipsec/ipsec_output.c:1.38.8.1
--- src/sys/netipsec/ipsec_output.c:1.38	Tue Jan 10 20:01:57 2012
+++ src/sys/netipsec/ipsec_output.c	Thu May  3 14:37:25 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $	*/
+/*	$NetBSD: ipsec_output.c,v 1.38.8.1 2018/05/03 14:37:25 martin Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.38.8.1 2018/05/03 14:37:25 martin Exp $");
 
 /*
  * IPsec output processing.
@@ -632,7 +632,7 @@ bad:
 #endif
 
 #ifdef INET6
-static void
+static int
 compute_ipsec_pos(struct mbuf *m, int *i, int *off)
 {
 	int nxt;
@@ -649,7 +649,11 @@ compute_ipsec_pos(struct mbuf *m, int *i
 	 * put AH/ESP/IPcomp header.
 	 *  IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
 	 */
-	do {
+	while (1) {
+		if (*i + sizeof(ip6e) > m->m_pkthdr.len) {
+			return EINVAL;
+		}
+
 		switch (nxt) {
 		case IPPROTO_AH:
 		case IPPROTO_ESP:
@@ -658,7 +662,7 @@ compute_ipsec_pos(struct mbuf *m, int *i
 		 * we should not skip security header added
 		 * beforehand.
 		 */
-			return;
+			return 0;
 
 		case IPPROTO_HOPOPTS:
 		case IPPROTO_DSTOPTS:
@@ -668,7 +672,7 @@ compute_ipsec_pos(struct mbuf *m, int *i
 		 * we should stop there.
 		 */
 			if (nxt == IPPROTO_DSTOPTS && dstopt)
-				return;
+				return 0;
 
 			if (nxt == IPPROTO_DSTOPTS) {
 				/*
@@ -688,16 +692,14 @@ compute_ipsec_pos(struct mbuf *m, int *i
 			m_copydata(m, *i, sizeof(ip6e), &ip6e);
 			nxt = ip6e.ip6e_nxt;
 			*off = *i + offsetof(struct ip6_ext, ip6e_nxt);
-			/*
-			 * we will never see nxt == IPPROTO_AH
-			 * so it is safe to omit AH case.
-			 */
 			*i += (ip6e.ip6e_len + 1) << 3;
 			break;
 		default:
-			return;
+			return 0;
 		}
-	} while (*i < m->m_pkthdr.len);
+	}
+
+	return 0;
 }
 
 static int
@@ -799,7 +801,9 @@ ipsec6_process_packet(
 		i = ip->ip_hl << 2;
 		off = offsetof(struct ip, ip_p);
 	} else {	
-		compute_ipsec_pos(m, &i, &off);
+		error = compute_ipsec_pos(m, &i, &off);
+		if (error)
+			goto bad;
 	}
 	error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
 	splx(s);

Reply via email to