svn commit: r309086 - projects/ipsec/sys/netipsec
Andrey V. Elsukov
ae at FreeBSD.org
Thu Nov 24 08:08:43 UTC 2016
Author: ae
Date: Thu Nov 24 08:08:42 2016
New Revision: 309086
URL: https://svnweb.freebsd.org/changeset/base/309086
Log:
Modify inbound AH processing.
Use struct xform_data to pass needed information from ah_input()
to ah_input_cb(). Protect access to SA replay window structure and
cryptoid by acquiring SA lock.
Add ipsec_updateid() function to handle EAGAIN error from cryptoid
subsystem.
Modified:
projects/ipsec/sys/netipsec/ipsec.c
projects/ipsec/sys/netipsec/xform_ah.c
Modified: projects/ipsec/sys/netipsec/ipsec.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.c Thu Nov 24 07:35:16 2016 (r309085)
+++ projects/ipsec/sys/netipsec/ipsec.c Thu Nov 24 08:08:42 2016 (r309086)
@@ -1612,6 +1612,52 @@ ok:
return (0);
}
+int
+ipsec_updateid(struct secasvar *sav, uint64_t *new, uint64_t *old)
+{
+ uint64_t tmp;
+
+ /*
+ * tdb_cryptoid is initialized by xform_init().
+ * Then it can be changed only when some crypto error occurred or
+ * when SA is deleted. We stored used cryptoid in the xform_data
+ * structure. In case when crypto error occurred and crypto
+ * subsystem has reinited the session, it returns new cryptoid
+ * and EAGAIN error code.
+ *
+ * This function will be called when we got EAGAIN from crypto
+ * subsystem.
+ * *new is cryptoid that was returned by crypto subsystem in
+ * the crp_sid.
+ * *old is the original cryptoid that we stored in xform_data.
+ *
+ * For first failed request *old == sav->tdb_cryptoid, then
+ * we update sav->tdb_cryptoid and redo crypto_dispatch().
+ * For next failed request *old != sav->tdb_cryptoid, then
+ * we store cryptoid from first request into the *new variable
+ * and crp_sid from this second session will be returned via
+ * *old pointer, so caller can release second session.
+ *
+ * XXXAE: check this more carefully.
+ */
+ KEYDBG(IPSEC_STAMP,
+ printf("%s: SA(%p) moves cryptoid %jd -> %jd\n",
+ __func__, sav, (uintmax_t)(*old), (uintmax_t)(*new)));
+ KEYDBG(IPSEC_DATA, kdebug_secasv(sav));
+ SECASVAR_LOCK(sav);
+ if (sav->tdb_cryptoid != *old) {
+ /* cryptoid was already updated */
+ tmp = *new;
+ *new = sav->tdb_cryptoid;
+ *old = tmp;
+ SECASVAR_UNLOCK(sav);
+ return (1);
+ }
+ sav->tdb_cryptoid = *new;
+ SECASVAR_UNLOCK(sav);
+ return (0);
+}
+
/*
* Shift variable length buffer to left.
* IN: bitmap: pointer to the buffer
Modified: projects/ipsec/sys/netipsec/xform_ah.c
==============================================================================
--- projects/ipsec/sys/netipsec/xform_ah.c Thu Nov 24 07:35:16 2016 (r309085)
+++ projects/ipsec/sys/netipsec/xform_ah.c Thu Nov 24 08:08:42 2016 (r309086)
@@ -582,14 +582,14 @@ static int
ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
{
char buf[128];
+ struct cryptodesc *crda;
+ struct cryptop *crp;
struct auth_hash *ahx;
- struct tdb_crypto *tc;
+ struct xform_data *xd;
struct newah *ah;
+ uint64_t cryptoid;
int hl, rplen, authsize, error;
- struct cryptodesc *crda;
- struct cryptop *crp;
-
IPSEC_ASSERT(sav != NULL, ("null SA"));
IPSEC_ASSERT(sav->key_auth != NULL, ("null authentication key"));
IPSEC_ASSERT(sav->tdb_authalgxform != NULL,
@@ -608,13 +608,18 @@ ah_input(struct mbuf *m, struct secasvar
}
/* Check replay window, if applicable. */
- if (sav->replay && !ipsec_chkreplay(ntohl(ah->ah_seq), sav)) {
+ SECASVAR_LOCK(sav);
+ if (sav->replay != NULL && sav->replay->wsize != 0 &&
+ ipsec_chkreplay(ntohl(ah->ah_seq), sav) == 0) {
+ SECASVAR_UNLOCK(sav);
AHSTAT_INC(ahs_replay);
DPRINTF(("%s: packet replay failure: %s\n", __func__,
ipsec_logsastr(sav, buf, sizeof(buf))));
m_freem(m);
- return ENOBUFS;
+ return (EACCES);
}
+ cryptoid = sav->tdb_cryptoid;
+ SECASVAR_UNLOCK(sav);
/* Verify AH header length. */
hl = ah->ah_len * sizeof (u_int32_t);
@@ -635,7 +640,8 @@ ah_input(struct mbuf *m, struct secasvar
/* Get crypto descriptors. */
crp = crypto_getreq(1);
if (crp == NULL) {
- DPRINTF(("%s: failed to acquire crypto descriptor\n",__func__));
+ DPRINTF(("%s: failed to acquire crypto descriptor\n",
+ __func__));
AHSTAT_INC(ahs_crypto);
m_freem(m);
return ENOBUFS;
@@ -654,10 +660,10 @@ ah_input(struct mbuf *m, struct secasvar
crda->crd_key = sav->key_auth->key_data;
/* Allocate IPsec-specific opaque crypto info. */
- tc = (struct tdb_crypto *) malloc(sizeof (struct tdb_crypto) +
- skip + rplen + authsize, M_XDATA, M_NOWAIT | M_ZERO);
- if (tc == NULL) {
- DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
+ xd = malloc(sizeof(*xd) + skip + rplen + authsize, M_XDATA,
+ M_NOWAIT | M_ZERO);
+ if (xd == NULL) {
+ DPRINTF(("%s: failed to allocate xform_data\n", __func__));
AHSTAT_INC(ahs_crypto);
crypto_freereq(crp);
m_freem(m);
@@ -668,7 +674,7 @@ ah_input(struct mbuf *m, struct secasvar
* Save the authenticator, the skipped portion of the packet,
* and the AH header.
*/
- m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(tc+1));
+ m_copydata(m, 0, skip + rplen + authsize, (caddr_t)(xd + 1));
/* Zeroize the authenticator on the packet. */
m_copyback(m, skip + rplen, authsize, ipseczeroes);
@@ -679,7 +685,7 @@ ah_input(struct mbuf *m, struct secasvar
if (error != 0) {
/* NB: mbuf is free'd by ah_massage_headers */
AHSTAT_INC(ahs_hdrops);
- free(tc, M_XDATA);
+ free(xd, M_XDATA);
crypto_freereq(crp);
return (error);
}
@@ -689,18 +695,15 @@ ah_input(struct mbuf *m, struct secasvar
crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_CBIFSYNC;
crp->crp_buf = (caddr_t) m;
crp->crp_callback = ah_input_cb;
- crp->crp_sid = sav->tdb_cryptoid;
- crp->crp_opaque = (caddr_t) tc;
+ crp->crp_sid = cryptoid;
+ crp->crp_opaque = (caddr_t) xd;
/* These are passed as-is to the callback. */
- tc->tc_spi = sav->spi;
- tc->tc_dst = sav->sah->saidx.dst;
- tc->tc_proto = sav->sah->saidx.proto;
- tc->tc_nxt = ah->ah_nxt;
- tc->tc_protoff = protoff;
- tc->tc_skip = skip;
- KEY_ADDREFSA(sav);
- tc->tc_sav = sav;
+ xd->sav = sav;
+ xd->nxt = ah->ah_nxt;
+ xd->protoff = protoff;
+ xd->skip = skip;
+ xd->cryptoid = cryptoid;
return (crypto_dispatch(crp));
}
@@ -710,31 +713,27 @@ ah_input(struct mbuf *m, struct secasvar
static int
ah_input_cb(struct cryptop *crp)
{
- char buf[INET6_ADDRSTRLEN];
- int rplen, error, skip, protoff;
+ char buf[IPSEC_ADDRSTRLEN];
unsigned char calc[AH_ALEN_MAX];
struct mbuf *m;
struct cryptodesc *crd;
struct auth_hash *ahx;
- struct tdb_crypto *tc;
+ struct xform_data *xd;
struct secasvar *sav;
struct secasindex *saidx;
- u_int8_t nxt;
caddr_t ptr;
- int authsize;
+ uint64_t cryptoid;
+ int authsize, rplen, error, skip, protoff;
+ uint8_t nxt;
crd = crp->crp_desc;
-
- tc = (struct tdb_crypto *) crp->crp_opaque;
- IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!"));
- skip = tc->tc_skip;
- nxt = tc->tc_nxt;
- protoff = tc->tc_protoff;
m = (struct mbuf *) crp->crp_buf;
-
- sav = tc->tc_sav;
- IPSEC_ASSERT(sav != NULL, ("null SA!"));
-
+ xd = (struct xform_data *) crp->crp_opaque;
+ sav = xd->sav;
+ skip = xd->skip;
+ nxt = xd->nxt;
+ protoff = xd->protoff;
+ cryptoid = xd->cryptoid;
saidx = &sav->sah->saidx;
IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
saidx->dst.sa.sa_family == AF_INET6,
@@ -744,12 +743,13 @@ ah_input_cb(struct cryptop *crp)
/* Check for crypto errors. */
if (crp->crp_etype) {
- if (sav->tdb_cryptoid != 0)
- sav->tdb_cryptoid = crp->crp_sid;
-
- if (crp->crp_etype == EAGAIN)
+ if (crp->crp_etype == EAGAIN) {
+ /* 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));
-
+ }
AHSTAT_INC(ahs_noxform);
DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype));
error = crp->crp_etype;
@@ -776,7 +776,7 @@ ah_input_cb(struct cryptop *crp)
m_copydata(m, skip + rplen, authsize, calc);
/* Verify authenticator. */
- ptr = (caddr_t) (tc + 1);
+ ptr = (caddr_t) (xd + 1);
if (timingsafe_bcmp(ptr + skip + rplen, calc, authsize)) {
DPRINTF(("%s: authentication hash mismatch for packet "
"in SA %s/%08lx\n", __func__,
@@ -787,11 +787,11 @@ ah_input_cb(struct cryptop *crp)
goto bad;
}
/* Fix the Next Protocol field. */
- ((u_int8_t *) ptr)[protoff] = nxt;
+ ((uint8_t *) ptr)[protoff] = nxt;
/* Copyback the saved (uncooked) network headers. */
m_copyback(m, 0, skip, ptr);
- free(tc, M_XDATA), tc = NULL; /* No longer needed */
+ free(xd, M_XDATA), xd = NULL; /* No longer needed */
/*
* Header is now authenticated.
@@ -806,11 +806,14 @@ ah_input_cb(struct cryptop *crp)
m_copydata(m, skip + offsetof(struct newah, ah_seq),
sizeof (seq), (caddr_t) &seq);
+ SECASVAR_LOCK(sav);
if (ipsec_updatereplay(ntohl(seq), sav)) {
+ SECASVAR_UNLOCK(sav);
AHSTAT_INC(ahs_replay);
- error = ENOBUFS; /*XXX as above*/
+ error = EACCES;
goto bad;
}
+ SECASVAR_UNLOCK(sav);
}
/*
@@ -840,16 +843,14 @@ ah_input_cb(struct cryptop *crp)
panic("%s: Unexpected address family: %d saidx=%p", __func__,
saidx->dst.sa.sa_family, saidx);
}
-
- KEY_FREESAV(&sav);
return error;
bad:
if (sav)
- KEY_FREESAV(&sav);
+ key_freesav(&sav);
if (m != NULL)
m_freem(m);
- if (tc != NULL)
- free(tc, M_XDATA);
+ if (xd != NULL)
+ free(xd, M_XDATA);
if (crp != NULL)
crypto_freereq(crp);
return error;
More information about the svn-src-projects
mailing list