Module Name:    src
Committed By:   martin
Date:           Mon Feb 26 13:10:52 UTC 2018

Modified Files:
        src/sys/netipsec [netbsd-8]: xform_ah.c xform_esp.c xform_ipcomp.c

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #587):
        sys/netipsec/xform_ipcomp.c: revision 1.54-1.56
        sys/netipsec/xform_ah.c: revision 1.78,1.79(patch),1.82-1.84
        sys/netipsec/xform_esp.c: revision 1.74-1.76

Fix mbuf leaks on error paths

Dedup common codes in error paths (NFCI)

Don't relook up an SP/SA in opencrpyto callbacks
We don't need to do so because we have a reference to it. And also
relooking-up one there may return an sp/sav that has different
parameters from an original one.

Fix kernel panic (assertion failure) on receiving an IPv6 packet with large 
options
If an IPv6 packet has large options, a necessary space for evacuation can
exceed the expected size (ah_pool_item_size). Give up using the pool_cache
if it happens.

Style.

Commonalize error paths (NFC)

Fix buffer overflow on sending an IPv6 packet with large options
If an IPv6 packet has large options, a necessary space for evacuation can
exceed the expected size (ah_pool_item_size). Give up using the pool_cache
if it happens.
Pointed out by maxv@


To generate a diff of this commit:
cvs rdiff -u -r1.54.2.3 -r1.54.2.4 src/sys/netipsec/xform_ah.c
cvs rdiff -u -r1.55.2.1 -r1.55.2.2 src/sys/netipsec/xform_esp.c
cvs rdiff -u -r1.38.2.1 -r1.38.2.2 src/sys/netipsec/xform_ipcomp.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/xform_ah.c
diff -u src/sys/netipsec/xform_ah.c:1.54.2.3 src/sys/netipsec/xform_ah.c:1.54.2.4
--- src/sys/netipsec/xform_ah.c:1.54.2.3	Thu Feb 15 07:58:04 2018
+++ src/sys/netipsec/xform_ah.c	Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ah.c,v 1.54.2.3 2018/02/15 07:58:04 martin Exp $	*/
+/*	$NetBSD: xform_ah.c,v 1.54.2.4 2018/02/26 13:10:52 martin 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.54.2.3 2018/02/15 07:58:04 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.54.2.4 2018/02/26 13:10:52 martin Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v
 #include <sys/sysctl.h>
 #include <sys/pool.h>
 #include <sys/pserialize.h>
+#include <sys/kmem.h>
 
 #include <net/if.h>
 
@@ -100,8 +101,8 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v
 
 percpu_t *ahstat_percpu;
 
-int	ah_enable = 1;			/* control flow of packets with AH */
-int	ip4_ah_cleartos = 1;		/* clear ip_tos when doing AH calc */
+int ah_enable = 1;			/* control flow of packets with AH */
+int ip4_ah_cleartos = 1;		/* clear ip_tos when doing AH calc */
 
 #ifdef __FreeBSD__
 SYSCTL_DECL(_net_inet_ah);
@@ -111,7 +112,6 @@ SYSCTL_INT(_net_inet_ah, OID_AUTO,
 	ah_cleartos,	CTLFLAG_RW,	&ip4_ah_cleartos,	0, "");
 SYSCTL_STRUCT(_net_inet_ah, IPSECCTL_STATS,
 	stats,		CTLFLAG_RD,	&ahstat,	ahstat, "");
-
 #endif /* __FreeBSD__ */
 
 static unsigned char ipseczeroes[256];	/* larger than an ip6 extension hdr */
@@ -277,17 +277,15 @@ ah_massage_headers(struct mbuf **m0, int
 	struct mbuf *m = *m0;
 	unsigned char *ptr;
 	int off, count;
-
 #ifdef INET
 	struct ip *ip;
-#endif /* INET */
-
+#endif
 #ifdef INET6
 	struct ip6_ext *ip6e;
 	struct ip6_hdr ip6;
 	struct ip6_rthdr *rh;
 	int alloc, ad, nxt;
-#endif /* INET6 */
+#endif
 
 	switch (proto) {
 #ifdef INET
@@ -428,7 +426,6 @@ ah_massage_headers(struct mbuf **m0, int
 			if (off > skip)	{
 				DPRINTF(("%s: malformed IPv4 options header\n",
 					__func__));
-
 				m_freem(m);
 				return EINVAL;
 			}
@@ -629,6 +626,7 @@ ah_input(struct mbuf *m, struct secasvar
 	struct cryptodesc *crda;
 	struct cryptop *crp = NULL;
 	uint8_t nxt;
+	bool pool_used;
 
 	IPSEC_SPLASSERT_SOFTNET(__func__);
 
@@ -715,9 +713,14 @@ ah_input(struct mbuf *m, struct secasvar
 	size_t extra = skip + rplen + authsize;
 	size += extra;
 
-	KASSERTMSG(size <= ah_pool_item_size,
-	    "size=%zu > ah_pool_item_size=%zu\n", size, ah_pool_item_size);
-	tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+	if (__predict_true(size <= ah_pool_item_size)) {
+		tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+		pool_used = true;
+	} else {
+		/* size can exceed on IPv6 packets with large options.  */
+		tc = kmem_intr_zalloc(size, KM_NOSLEEP);
+		pool_used = false;
+	}
 	if (tc == NULL) {
 		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
 		stat = AH_STAT_CRYPTO;
@@ -789,8 +792,12 @@ ah_input(struct mbuf *m, struct secasvar
 	return crypto_dispatch(crp);
 
 bad:
-	if (tc != NULL)
-		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	if (tc != NULL) {
+		if (__predict_true(pool_used))
+			pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+		else
+			kmem_intr_free(tc, size);
+	}
 	if (crp != NULL)
 		crypto_freereq(crp);
 	if (m != NULL)
@@ -830,6 +837,8 @@ ah_input_cb(struct cryptop *crp)
 	int authsize;
 	uint16_t dport;
 	uint16_t sport;
+	bool pool_used;
+	size_t size;
 	IPSEC_DECLARE_LOCK_VARIABLE;
 
 	KASSERT(crp->crp_opaque != NULL);
@@ -863,6 +872,16 @@ ah_input_cb(struct cryptop *crp)
 	    saidx->dst.sa.sa_family == AF_INET6,
 	    "unexpected protocol family %u", saidx->dst.sa.sa_family);
 
+	/* Figure out header size. */
+	rplen = HDRSIZE(sav);
+	authsize = AUTHSIZE(sav);
+
+	size = sizeof(*tc) + skip + rplen + authsize;
+	if (__predict_true(size <= ah_pool_item_size))
+		pool_used = true;
+	else
+		pool_used = false;
+
 	/* Check for crypto errors. */
 	if (crp->crp_etype) {
 		if (sav->tdb_cryptoid != 0)
@@ -883,10 +902,6 @@ ah_input_cb(struct cryptop *crp)
 		crp = NULL;
 	}
 
-	/* Figure out header size. */
-	rplen = HDRSIZE(sav);
-	authsize = AUTHSIZE(sav);
-
 	if (ipsec_debug)
 		memset(calc, 0, sizeof(calc));
 
@@ -924,7 +939,10 @@ ah_input_cb(struct cryptop *crp)
 	/* Copyback the saved (uncooked) network headers. */
 	m_copyback(m, 0, skip, ptr);
 
-	pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	if (__predict_true(pool_used))
+		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	else
+		kmem_intr_free(tc, size);
 	tc = NULL;
 
 	/*
@@ -942,7 +960,7 @@ ah_input_cb(struct cryptop *crp)
 		    sizeof(seq), &seq);
 		if (ipsec_updatereplay(ntohl(seq), sav)) {
 			AH_STATINC(AH_STAT_REPLAY);
-			error = ENOBUFS;			/*XXX as above*/
+			error = ENOBUFS; /* XXX as above */
 			goto bad;
 		}
 	}
@@ -965,14 +983,19 @@ ah_input_cb(struct cryptop *crp)
 	KEY_SA_UNREF(&sav);
 	IPSEC_RELEASE_GLOBAL_LOCKS();
 	return error;
+
 bad:
 	if (sav)
 		KEY_SA_UNREF(&sav);
 	IPSEC_RELEASE_GLOBAL_LOCKS();
 	if (m != NULL)
 		m_freem(m);
-	if (tc != NULL)
-		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	if (tc != NULL) {
+		if (pool_used)
+			pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+		else
+			kmem_intr_free(tc, size);
+	}
 	if (crp != NULL)
 		crypto_freereq(crp);
 	return error;
@@ -982,14 +1005,8 @@ bad:
  * AH output routine, called by ipsec[46]_process_packet().
  */
 static int
-ah_output(
-    struct mbuf *m,
-    const struct ipsecrequest *isr,
-    struct secasvar *sav,
-    struct mbuf **mp,
-    int skip,
-    int protoff
-)
+ah_output(struct mbuf *m, const struct ipsecrequest *isr, struct secasvar *sav,
+    struct mbuf **mp, int skip, int protoff)
 {
 	char buf[IPSEC_ADDRSTRLEN];
 	const struct auth_hash *ahx;
@@ -1001,6 +1018,8 @@ ah_output(
 	int error, rplen, authsize, maxpacketsize, roff;
 	uint8_t prot;
 	struct newah *ah;
+	size_t ipoffs;
+	bool pool_used;
 
 	IPSEC_SPLASSERT_SOFTNET(__func__);
 
@@ -1013,7 +1032,6 @@ ah_output(
 	/* Figure out header size. */
 	rplen = HDRSIZE(sav);
 
-	size_t ipoffs;
 	/* Check for maximum packet size violations. */
 	switch (sav->sah->saidx.dst.sa.sa_family) {
 #ifdef INET
@@ -1021,13 +1039,13 @@ ah_output(
 		maxpacketsize = IP_MAXPACKET;
 		ipoffs = offsetof(struct ip, ip_len);
 		break;
-#endif /* INET */
+#endif
 #ifdef INET6
 	case AF_INET6:
 		maxpacketsize = IPV6_MAXPACKET;
 		ipoffs = offsetof(struct ip6_hdr, ip6_plen);
 		break;
-#endif /* INET6 */
+#endif
 	default:
 		DPRINTF(("%s: unknown/unsupported protocol "
 		    "family %u, SA %s/%08lx\n", __func__,
@@ -1071,7 +1089,7 @@ ah_output(
 		    rplen + authsize,
 		    ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
 		    (u_long) ntohl(sav->spi)));
-		AH_STATINC(AH_STAT_HDROPS);	/*XXX differs from openbsd */
+		AH_STATINC(AH_STAT_HDROPS);
 		error = ENOBUFS;
 		goto bad;
 	}
@@ -1132,13 +1150,21 @@ ah_output(
 	crda->crd_klen = _KEYBITS(sav->key_auth);
 
 	/* Allocate IPsec-specific opaque crypto info. */
-	tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+	size_t size = sizeof(*tc) + skip;
+
+	if (__predict_true(size <= ah_pool_item_size)) {
+		tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+		pool_used = true;
+	} else {
+		/* size can exceed on IPv6 packets with large options.  */
+		tc = kmem_intr_zalloc(size, KM_NOSLEEP);
+		pool_used = false;
+	}
 	if (tc == NULL) {
-		crypto_freereq(crp);
 		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
 		AH_STATINC(AH_STAT_CRYPTO);
 		error = ENOBUFS;
-		goto bad;
+		goto bad_crp;
 	}
 
 	uint8_t *pext = (char *)(tc + 1);
@@ -1166,9 +1192,7 @@ ah_output(
 	    skip, ahx->type, 1);
 	if (error != 0) {
 		m = NULL;	/* mbuf was free'd by ah_massage_headers. */
-		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
-		crypto_freereq(crp);
-		goto bad;
+		goto bad_tc;
 	}
 
     {
@@ -1180,11 +1204,9 @@ ah_output(
 	if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD ||
 	    sav->state == SADB_SASTATE_DEAD)) {
 		pserialize_read_exit(s);
-		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
-		crypto_freereq(crp);
 		AH_STATINC(AH_STAT_NOTDB);
 		error = ENOENT;
-		goto bad;
+		goto bad_tc;
 	}
 	KEY_SP_REF(isr->sp);
 	KEY_SA_REF(sav);
@@ -1209,6 +1231,14 @@ ah_output(
 	tc->tc_sav = sav;
 
 	return crypto_dispatch(crp);
+
+bad_tc:
+	if (__predict_true(pool_used))
+		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	else
+		kmem_intr_free(tc, size);
+bad_crp:
+	crypto_freereq(crp);
 bad:
 	if (m)
 		m_freem(m);
@@ -1228,6 +1258,8 @@ ah_output_cb(struct cryptop *crp)
 	struct mbuf *m;
 	void *ptr;
 	int err;
+	size_t size;
+	bool pool_used;
 	IPSEC_DECLARE_LOCK_VARIABLE;
 
 	KASSERT(crp->crp_opaque != NULL);
@@ -1235,6 +1267,8 @@ ah_output_cb(struct cryptop *crp)
 	skip = tc->tc_skip;
 	ptr = (tc + 1);
 	m = crp->crp_buf;
+	size = sizeof(*tc) + skip;
+	pool_used = size <= ah_pool_item_size;
 
 	IPSEC_ACQUIRE_GLOBAL_LOCKS();
 
@@ -1284,7 +1318,10 @@ ah_output_cb(struct cryptop *crp)
 	m_copyback(m, 0, skip, ptr);
 
 	/* No longer needed. */
-	pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	if (__predict_true(pool_used))
+		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	else
+		kmem_intr_free(tc, size);
 	crypto_freereq(crp);
 
 #ifdef IPSEC_DEBUG
@@ -1314,7 +1351,10 @@ bad:
 	IPSEC_RELEASE_GLOBAL_LOCKS();
 	if (m)
 		m_freem(m);
-	pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	if (__predict_true(pool_used))
+		pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+	else
+		kmem_intr_free(tc, size);
 	crypto_freereq(crp);
 	return error;
 }

Index: src/sys/netipsec/xform_esp.c
diff -u src/sys/netipsec/xform_esp.c:1.55.2.1 src/sys/netipsec/xform_esp.c:1.55.2.2
--- src/sys/netipsec/xform_esp.c:1.55.2.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/xform_esp.c	Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_esp.c,v 1.55.2.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: xform_esp.c,v 1.55.2.2 2018/02/26 13:10:52 martin 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.55.2.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.55.2.2 2018/02/26 13:10:52 martin Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -87,17 +87,15 @@ __KERNEL_RCSID(0, "$NetBSD: xform_esp.c,
 
 percpu_t *espstat_percpu;
 
-int	esp_enable = 1;
+int esp_enable = 1;
 
 #ifdef __FreeBSD__
 SYSCTL_DECL(_net_inet_esp);
 SYSCTL_INT(_net_inet_esp, OID_AUTO,
 	esp_enable,	CTLFLAG_RW,	&esp_enable,	0, "");
-SYSCTL_STRUCT(_net_inet_esp, IPSECCTL_STATS,
-	stats,		CTLFLAG_RD,	&espstat,	espstat, "");
 #endif /* __FreeBSD__ */
 
-static	int esp_max_ivlen;		/* max iv length over all algorithms */
+static int esp_max_ivlen;		/* max iv length over all algorithms */
 
 static int esp_input_cb(struct cryptop *op);
 static int esp_output_cb(struct cryptop *crp);
@@ -306,9 +304,8 @@ esp_input(struct mbuf *m, struct secasva
 	const struct auth_hash *esph;
 	const struct enc_xform *espx;
 	struct tdb_crypto *tc;
-	int plen, alen, hlen, error;
+	int plen, alen, hlen, error, stat = ESP_STAT_CRYPTO;
 	struct newesp *esp;
-
 	struct cryptodesc *crde;
 	struct cryptop *crp;
 
@@ -349,9 +346,9 @@ esp_input(struct mbuf *m, struct secasva
 		    "  SA %s/%08lx\n", __func__, plen, espx->blocksize,
 		    ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
 		    (u_long) ntohl(sav->spi)));
-		ESP_STATINC(ESP_STAT_BADILEN);
-		m_freem(m);
-		return EINVAL;
+		stat = ESP_STAT_BADILEN;
+		error = EINVAL;
+		goto out;
 	}
 
 	/*
@@ -361,9 +358,9 @@ esp_input(struct mbuf *m, struct secasva
 		char logbuf[IPSEC_LOGSASTRLEN];
 		DPRINTF(("%s: packet replay check for %s\n", __func__,
 		    ipsec_logsastr(sav, logbuf, sizeof(logbuf))));	/*XXX*/
-		ESP_STATINC(ESP_STAT_REPLAY);
-		m_freem(m);
-		return ENOBUFS;		/*XXX*/
+		stat = ESP_STAT_REPLAY;
+		error = ENOBUFS;		/*XXX*/
+		goto out;
 	}
 
 	/* Update the counters */
@@ -437,10 +434,9 @@ esp_input(struct mbuf *m, struct secasva
 	 */
 	if (__predict_false(sav->state == SADB_SASTATE_DEAD)) {
 		pserialize_read_exit(s);
-		pool_cache_put(esp_tdb_crypto_pool_cache, tc);
-		crypto_freereq(crp);
-		ESP_STATINC(ESP_STAT_NOTDB);
-		return ENOENT;
+		stat = ESP_STAT_NOTDB;
+		error = ENOENT;
+		goto out2;
 	}
 	KEY_SA_REF(sav);
 	pserialize_read_exit(s);
@@ -485,7 +481,7 @@ out2:
 out1:
 	crypto_freereq(crp);
 out:
-	ESP_STATINC(ESP_STAT_CRYPTO);
+	ESP_STATINC(stat);
 	m_freem(m);
 	return error;
 }
@@ -536,21 +532,6 @@ esp_input_cb(struct cryptop *crp)
 	IPSEC_ACQUIRE_GLOBAL_LOCKS();
 
 	sav = tc->tc_sav;
-	if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
-		KEY_SA_UNREF(&sav);
-		sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi,
-		    sport, dport);
-		if (sav == NULL) {
-			ESP_STATINC(ESP_STAT_NOTDB);
-			DPRINTF(("%s: SA expired while in crypto "
-			    "(SA %s/%08lx proto %u)\n", __func__,
-			    ipsec_address(&tc->tc_dst, buf, sizeof(buf)),
-			    (u_long) ntohl(tc->tc_spi), tc->tc_proto));
-			error = ENOBUFS;		/*XXX*/
-			goto bad;
-		}
-	}
-
 	saidx = &sav->sah->saidx;
 	KASSERTMSG(saidx->dst.sa.sa_family == AF_INET ||
 	    saidx->dst.sa.sa_family == AF_INET6,
@@ -709,14 +690,8 @@ bad:
  * ESP output routine, called by ipsec[46]_process_packet().
  */
 static int
-esp_output(
-    struct mbuf *m,
-    const struct ipsecrequest *isr,
-    struct secasvar *sav,
-    struct mbuf **mp,
-    int skip,
-    int protoff
-)
+esp_output(struct mbuf *m, const struct ipsecrequest *isr, struct secasvar *sav,
+    struct mbuf **mp, int skip, int protoff)
 {
 	char buf[IPSEC_ADDRSTRLEN];
 	const struct enc_xform *espx;
@@ -767,12 +742,12 @@ esp_output(
 	case AF_INET:
 		maxpacketsize = IP_MAXPACKET;
 		break;
-#endif /* INET */
+#endif
 #ifdef INET6
 	case AF_INET6:
 		maxpacketsize = IPV6_MAXPACKET;
 		break;
-#endif /* INET6 */
+#endif
 	default:
 		DPRINTF(("%s: unknown/unsupported protocol family %d, "
 		    "SA %s/%08lx\n", __func__, saidx->dst.sa.sa_family,
@@ -813,7 +788,7 @@ esp_output(
 		    "%s/%08lx\n", __func__, hlen,
 		    ipsec_address(&saidx->dst, buf, sizeof(buf)),
 		    (u_long) ntohl(sav->spi)));
-		ESP_STATINC(ESP_STAT_HDROPS);	/* XXX diffs from openbsd */
+		ESP_STATINC(ESP_STAT_HDROPS);
 		error = ENOBUFS;
 		goto bad;
 	}
@@ -850,19 +825,19 @@ esp_output(
 
 	/*
 	 * Add padding: random, zero, or self-describing.
-	 * XXX catch unexpected setting
 	 */
 	switch (sav->flags & SADB_X_EXT_PMASK) {
+	case SADB_X_EXT_PSEQ:
+		for (i = 0; i < padding - 2; i++)
+			pad[i] = i+1;
+		break;
 	case SADB_X_EXT_PRAND:
-		(void) cprng_fast(pad, padding - 2);
+		(void)cprng_fast(pad, padding - 2);
 		break;
 	case SADB_X_EXT_PZERO:
+	default:
 		memset(pad, 0, padding - 2);
 		break;
-	case SADB_X_EXT_PSEQ:
-		for (i = 0; i < padding - 2; i++)
-			pad[i] = i+1;
-		break;
 	}
 
 	/* Fix padding length and Next Protocol in padding itself. */
@@ -971,10 +946,11 @@ esp_output(
 	}
 
 	return crypto_dispatch(crp);
+
 bad:
 	if (m)
 		m_freem(m);
-	return (error);
+	return error;
 }
 
 /*
@@ -998,28 +974,6 @@ esp_output_cb(struct cryptop *crp)
 
 	isr = tc->tc_isr;
 	sav = tc->tc_sav;
-	if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
-		ESP_STATINC(ESP_STAT_NOTDB);
-		IPSECLOG(LOG_DEBUG,
-		    "SP is being destroyed while in crypto (id=%u)\n",
-		    isr->sp->id);
-		error = ENOENT;
-		goto bad;
-	}
-	if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
-		KEY_SA_UNREF(&sav);
-		sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
-		if (sav == NULL) {
-			char buf[IPSEC_ADDRSTRLEN];
-			ESP_STATINC(ESP_STAT_NOTDB);
-			DPRINTF(("%s: SA expired while in crypto (SA %s/%08lx "
-			    "proto %u)\n", __func__,
-			    ipsec_address(&tc->tc_dst, buf, sizeof(buf)),
-			    (u_long) ntohl(tc->tc_spi), tc->tc_proto));
-			error = ENOBUFS;		/*XXX*/
-			goto bad;
-		}
-	}
 
 	/* Check for crypto errors. */
 	if (crp->crp_etype) {
@@ -1070,6 +1024,7 @@ esp_output_cb(struct cryptop *crp)
 	KEY_SP_UNREF(&isr->sp);
 	IPSEC_RELEASE_GLOBAL_LOCKS();
 	return err;
+
 bad:
 	if (sav)
 		KEY_SA_UNREF(&sav);

Index: src/sys/netipsec/xform_ipcomp.c
diff -u src/sys/netipsec/xform_ipcomp.c:1.38.2.1 src/sys/netipsec/xform_ipcomp.c:1.38.2.2
--- src/sys/netipsec/xform_ipcomp.c:1.38.2.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/xform_ipcomp.c	Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: xform_ipcomp.c,v 1.38.2.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: xform_ipcomp.c,v 1.38.2.2 2018/02/26 13:10:52 martin Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/xform_ipcomp.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $	*/
 /* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
 
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.38.2.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.38.2.2 2018/02/26 13:10:52 martin Exp $");
 
 /* IP payload compression protocol (IPComp), see RFC 2393 */
 #if defined(_KERNEL_OPT)
@@ -152,36 +152,29 @@ ipcomp_input(struct mbuf *m, struct seca
 	struct tdb_crypto *tc;
 	struct cryptodesc *crdc;
 	struct cryptop *crp;
-	int error, hlen = IPCOMP_HLENGTH;
+	int error, hlen = IPCOMP_HLENGTH, stat = IPCOMP_STAT_CRYPTO;
 
 	IPSEC_SPLASSERT_SOFTNET(__func__);
 
 	/* Get crypto descriptors */
 	crp = crypto_getreq(1);
 	if (crp == NULL) {
-		m_freem(m);
 		DPRINTF(("%s: no crypto descriptors\n", __func__));
-		IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
-		return ENOBUFS;
+		error = ENOBUFS;
+		goto error_m;
 	}
 	/* Get IPsec-specific opaque pointer */
 	tc = pool_cache_get(ipcomp_tdb_crypto_pool_cache, PR_NOWAIT);
 	if (tc == NULL) {
-		m_freem(m);
-		crypto_freereq(crp);
 		DPRINTF(("%s: cannot allocate tdb_crypto\n", __func__));
-		IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
-		return ENOBUFS;
+		error = ENOBUFS;
+		goto error_crp;
 	}
 
 	error = m_makewritable(&m, 0, m->m_pkthdr.len, M_NOWAIT);
 	if (error) {
 		DPRINTF(("%s: m_makewritable failed\n", __func__));
-		m_freem(m);
-		pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
-		crypto_freereq(crp);
-		IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
-		return error;
+		goto error_tc;
 	}
 
     {
@@ -192,10 +185,9 @@ ipcomp_input(struct mbuf *m, struct seca
 	 */
 	if (__predict_false(sav->state == SADB_SASTATE_DEAD)) {
 		pserialize_read_exit(s);
-		pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
-		crypto_freereq(crp);
-		IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
-		return ENOENT;
+		stat = IPCOMP_STAT_NOTDB;
+		error = ENOENT;
+		goto error_tc;
 	}
 	KEY_SA_REF(sav);
 	pserialize_read_exit(s);
@@ -228,6 +220,15 @@ ipcomp_input(struct mbuf *m, struct seca
 	tc->tc_sav = sav;
 
 	return crypto_dispatch(crp);
+
+error_tc:
+	pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
+error_crp:
+	crypto_freereq(crp);
+error_m:
+	m_freem(m);
+	IPCOMP_STATINC(stat);
+	return error;
 }
 
 #ifdef INET6
@@ -274,18 +275,6 @@ ipcomp_input_cb(struct cryptop *crp)
 	IPSEC_ACQUIRE_GLOBAL_LOCKS();
 
 	sav = tc->tc_sav;
-	if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
-		KEY_SA_UNREF(&sav);
-		sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi,
-		    sport, dport);
-		if (sav == NULL) {
-			IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
-			DPRINTF(("%s: SA expired while in crypto\n", __func__));
-			error = ENOBUFS;		/*XXX*/
-			goto bad;
-		}
-	}
-
 	saidx = &sav->sah->saidx;
 	KASSERTMSG(saidx->dst.sa.sa_family == AF_INET ||
 	    saidx->dst.sa.sa_family == AF_INET6,
@@ -566,24 +555,6 @@ ipcomp_output_cb(struct cryptop *crp)
 
 	isr = tc->tc_isr;
 	sav = tc->tc_sav;
-	if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
-		IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
-		IPSECLOG(LOG_DEBUG,
-		    "SP is being destroyed while in crypto (id=%u)\n",
-		    isr->sp->id);
-		error = ENOENT;
-		goto bad;
-	}
-	if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
-		KEY_SA_UNREF(&sav);
-		sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
-		if (sav == NULL) {
-			IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
-			DPRINTF(("%s: SA expired while in crypto\n", __func__));
-			error = ENOBUFS;		/*XXX*/
-			goto bad;
-		}
-	}
 
 	/* Check for crypto errors */
 	if (crp->crp_etype) {

Reply via email to