Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Nov 2016 13:20:23 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r309103 - projects/ipsec/sys/netipsec
Message-ID:  <201611241320.uAODKNjY042063@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Thu Nov 24 13:20:23 2016
New Revision: 309103
URL: https://svnweb.freebsd.org/changeset/base/309103

Log:
  Update outbound ESP processing.
  
  Use xform_data structure to pass needed information to xform callback.
  Use SA lock to protect access to replay window structure, cryptoid and
  CTR counter. Use new rules how we hold references to SP and SA.

Modified:
  projects/ipsec/sys/netipsec/xform_esp.c

Modified: projects/ipsec/sys/netipsec/xform_esp.c
==============================================================================
--- projects/ipsec/sys/netipsec/xform_esp.c	Thu Nov 24 13:04:41 2016	(r309102)
+++ projects/ipsec/sys/netipsec/xform_esp.c	Thu Nov 24 13:20:23 2016	(r309103)
@@ -647,30 +647,27 @@ bad:
 	return error;
 }
 /*
- * ESP output routine, called by ipsec[46]_process_packet().
+ * ESP output routine, called by ipsec[46]_perform_request().
  */
 static int
-esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp,
-    int skip, int protoff)
+esp_output(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
+    u_int idx, int skip, int protoff)
 {
-	char buf[INET6_ADDRSTRLEN];
+	char buf[IPSEC_ADDRSTRLEN];
+	struct cryptodesc *crde = NULL, *crda = NULL;
+	struct cryptop *crp;
 	struct enc_xform *espx;
 	struct auth_hash *esph;
-	uint8_t *ivp;
-	uint64_t cntr;
-	int hlen, rlen, padding, blks, alen, i, roff;
-	struct mbuf *mo = (struct mbuf *) NULL;
-	struct tdb_crypto *tc;
-	struct secasvar *sav;
+	struct mbuf *mo = NULL;
+	struct xform_data *xd;
 	struct secasindex *saidx;
 	unsigned char *pad;
-	u_int8_t prot;
+	uint8_t *ivp;
+	uint64_t cntr, cryptoid;
+	int hlen, rlen, padding, blks, alen, i, roff;
 	int error, maxpacketsize;
+	uint8_t prot;
 
-	struct cryptodesc *crde = NULL, *crda = NULL;
-	struct cryptop *crp;
-
-	sav = isr->sav;
 	IPSEC_ASSERT(sav != NULL, ("null SA"));
 	esph = sav->tdb_authalgxform;
 	espx = sav->tdb_encalgxform;
@@ -716,8 +713,9 @@ esp_output(struct mbuf *m, struct ipsecr
 		error = EPFNOSUPPORT;
 		goto bad;
 	}
+	/*
 	DPRINTF(("%s: skip %d hlen %d rlen %d padding %d alen %d blksd %d\n",
-		__func__, skip, hlen, rlen, padding, alen, blks));
+		__func__, skip, hlen, rlen, padding, alen, blks)); */
 	if (skip + hlen + rlen + padding + alen > maxpacketsize) {
 		DPRINTF(("%s: packet in SA %s/%08lx got too big "
 		    "(len %u, max len %u)\n", __func__,
@@ -748,15 +746,17 @@ esp_output(struct mbuf *m, struct ipsecr
 		DPRINTF(("%s: %u byte ESP hdr inject failed for SA %s/%08lx\n",
 		    __func__, hlen, ipsec_address(&saidx->dst, buf,
 		    sizeof(buf)), (u_long) ntohl(sav->spi)));
-		ESPSTAT_INC(esps_hdrops);		/* XXX diffs from openbsd */
+		ESPSTAT_INC(esps_hdrops);	/* XXX diffs from openbsd */
 		error = ENOBUFS;
 		goto bad;
 	}
 
 	/* Initialize ESP header. */
-	bcopy((caddr_t) &sav->spi, mtod(mo, caddr_t) + roff, sizeof(u_int32_t));
+	bcopy((caddr_t) &sav->spi, mtod(mo, caddr_t) + roff,
+	    sizeof(uint32_t));
+	SECASVAR_LOCK(sav);
 	if (sav->replay) {
-		u_int32_t replay;
+		uint32_t replay;
 
 #ifdef REGRESSION
 		/* Emulate replay attack when ipsec_replay is TRUE. */
@@ -764,10 +764,14 @@ esp_output(struct mbuf *m, struct ipsecr
 #endif
 			sav->replay->count++;
 		replay = htonl(sav->replay->count);
-		bcopy((caddr_t) &replay,
-		    mtod(mo, caddr_t) + roff + sizeof(u_int32_t),
-		    sizeof(u_int32_t));
+
+		bcopy((caddr_t) &replay, mtod(mo, caddr_t) + roff +
+		    sizeof(uint32_t), sizeof(uint32_t));
 	}
+	cryptoid = sav->tdb_cryptoid;
+	if (SAV_ISCTRORGCM(sav))
+		cntr = sav->cntr++;
+	SECASVAR_UNLOCK(sav);
 
 	/*
 	 * Add padding -- better to do it ourselves than use the crypto engine,
@@ -819,11 +823,10 @@ esp_output(struct mbuf *m, struct ipsecr
 	}
 
 	/* IPsec-specific opaque crypto info. */
-	tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
-	    M_XDATA, M_NOWAIT|M_ZERO);
-	if (tc == NULL) {
+	xd =  malloc(sizeof(struct xform_data), M_XDATA, M_NOWAIT | M_ZERO);
+	if (xd == NULL) {
 		crypto_freereq(crp);
-		DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
+		DPRINTF(("%s: failed to allocate xform_data\n", __func__));
 		ESPSTAT_INC(esps_crypto);
 		error = ENOBUFS;
 		goto bad;
@@ -849,13 +852,10 @@ esp_output(struct mbuf *m, struct ipsecr
 		/* Nonce is last four bytes of key, RFC3686 5.1 */
 		memcpy(ivp, sav->key_enc->key_data +
 		    _KEYLEN(sav->key_enc) - 4, 4);
-		SECASVAR_LOCK(sav);
-		cntr = sav->cntr++;
-		SECASVAR_UNLOCK(sav);
 		be64enc(&ivp[4], cntr);
-
 		if (SAV_ISCTR(sav)) {
 			/* Initial block counter is 1, RFC3686 4 */
+			/* XXXAE: should we use this only for first packet? */
 			be32enc(&ivp[sav->ivlen + 4], 1);
 		}
 
@@ -864,21 +864,18 @@ esp_output(struct mbuf *m, struct ipsecr
 	}
 
 	/* Callback parameters */
-	key_addref(isr->sp);
-	tc->tc_isr = isr;
-	KEY_ADDREFSA(sav);
-	tc->tc_sav = sav;
-	tc->tc_spi = sav->spi;
-	tc->tc_dst = saidx->dst;
-	tc->tc_proto = saidx->proto;
+	xd->sp = sp;
+	xd->sav = sav;
+	xd->idx = idx;
+	xd->cryptoid = cryptoid;
 
 	/* Crypto operation descriptor. */
 	crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
 	crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
 	crp->crp_buf = (caddr_t) m;
 	crp->crp_callback = esp_output_cb;
-	crp->crp_opaque = (caddr_t) tc;
-	crp->crp_sid = sav->tdb_cryptoid;
+	crp->crp_opaque = (caddr_t) xd;
+	crp->crp_sid = cryptoid;
 
 	if (esph) {
 		/* Authentication descriptor. */
@@ -897,53 +894,40 @@ bad:
 		m_freem(m);
 	return (error);
 }
-
 /*
  * ESP output callback from the crypto driver.
  */
 static int
 esp_output_cb(struct cryptop *crp)
 {
-	char buf[INET6_ADDRSTRLEN];
-	struct tdb_crypto *tc;
-	struct ipsecrequest *isr;
+	struct xform_data *xd;
+	struct secpolicy *sp;
 	struct secasvar *sav;
 	struct mbuf *m;
+	uint64_t cryptoid;
+	u_int idx;
 	int error;
 
-	tc = (struct tdb_crypto *) crp->crp_opaque;
-	IPSEC_ASSERT(tc != NULL, ("null opaque data area!"));
+	xd = (struct xform_data *) crp->crp_opaque;
 	m = (struct mbuf *) crp->crp_buf;
-
-	isr = tc->tc_isr;
-	IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp"));
-	IPSECREQUEST_LOCK(isr);
-	sav = tc->tc_sav;
-
-	/* With the isr lock released, SA pointer may have changed. */
-	if (sav != isr->sav) {
-		ESPSTAT_INC(esps_notdb);
-		DPRINTF(("%s: SA gone during 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;
-	}
+	sp = xd->sp;
+	sav = xd->sav;
+	idx = xd->idx;
+	cryptoid = xd->cryptoid;
 
 	/* Check for crypto errors. */
 	if (crp->crp_etype) {
-		/* Reset session ID. */
-		if (sav->tdb_cryptoid != 0)
-			sav->tdb_cryptoid = crp->crp_sid;
-
 		if (crp->crp_etype == EAGAIN) {
-			IPSECREQUEST_UNLOCK(isr);
+			/* Reset the session ID */
+			if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0)
+				crypto_freesession(cryptoid);
+			xd->cryptoid = crp->crp_sid;
 			return (crypto_dispatch(crp));
 		}
-
 		ESPSTAT_INC(esps_noxform);
 		DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
 		error = crp->crp_etype;
+		m_freem(m);
 		goto bad;
 	}
 
@@ -954,14 +938,12 @@ esp_output_cb(struct cryptop *crp)
 		error = EINVAL;
 		goto bad;
 	}
+	free(xd, M_XDATA);
+	crypto_freereq(crp);
 	ESPSTAT_INC(esps_hist[sav->alg_enc]);
 	if (sav->tdb_authalgxform != NULL)
 		AHSTAT_INC(ahs_hist[sav->alg_auth]);
 
-	/* Release crypto descriptors. */
-	free(tc, M_XDATA);
-	crypto_freereq(crp);
-
 #ifdef REGRESSION
 	/* Emulate man-in-the-middle attack when ipsec_integrity is TRUE. */
 	if (V_ipsec_integrity) {
@@ -984,23 +966,15 @@ esp_output_cb(struct cryptop *crp)
 #endif
 
 	/* NB: m is reclaimed by ipsec_process_done. */
-	error = ipsec_process_done(m, isr);
-	KEY_FREESAV(&sav);
-	IPSECREQUEST_UNLOCK(isr);
-	KEY_FREESP(&isr->sp);
+	error = ipsec_process_done(m, sp, sav, idx);
 	return (error);
 bad:
-	if (sav)
-		KEY_FREESAV(&sav);
-	IPSECREQUEST_UNLOCK(isr);
-	KEY_FREESP(&isr->sp);
-	if (m)
-		m_freem(m);
-	free(tc, M_XDATA);
+	free(xd, M_XDATA);
 	crypto_freereq(crp);
+	key_freesav(&sav);
+	key_freesp(&sp);
 	return (error);
 }
-
 static struct xformsw esp_xformsw = {
 	XF_ESP,		XFT_CONF|XFT_AUTH,	"IPsec ESP",
 	esp_init,	esp_zeroize,		esp_input,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611241320.uAODKNjY042063>