y_freesav(&sav); if (m != NULL) m_freem(m); @@ -590,7 +593,7 @@ extern ipproto_input_t *ip6_protox[]; */ int ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, - int protoff) + int protoff, struct rm_priotracker *sahtree_tracker) { IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); struct epoch_tracker et; @@ -734,7 +737,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, } /* Handle virtual tunneling interfaces */ if (saidx->mode == IPSEC_MODE_TUNNEL) - error = ipsec_if_input(m, sav, af); + error = ipsec_if_input(m, sav, af, sahtree_tracker); + else + ipsec_sahtree_runlock(sahtree_tracker); if (error == 0) { error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m); @@ -748,6 +753,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, key_freesav(&sav); return (error); } + + ipsec_sahtree_runlock(sahtree_tracker); + /* * See the end of ip6_input for this logic. * IPPROTO_IPV[46] case will be processed just like other ones @@ -787,6 +795,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, return (0); bad: NET_EPOCH_EXIT(et); + ipsec_sahtree_runlock(sahtree_tracker); key_freesav(&sav); if (m) m_freem(m); diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index 8f08872eb38a..65c67db983d6 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -692,6 +692,7 @@ ah_input_cb(struct cryptop *crp) { IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); unsigned char calc[AH_ALEN_MAX]; + struct rm_priotracker sahtree_tracker; struct mbuf *m; struct xform_data *xd; struct secasvar *sav; @@ -711,6 +712,14 @@ ah_input_cb(struct cryptop *crp) nxt = xd->nxt; protoff = xd->protoff; cryptoid = xd->cryptoid; + ipsec_sahtree_rlock(&sahtree_tracker); + if (sav->state >= SADB_SASTATE_DEAD) { + /* saidx is freed */ + DPRINTF(("%s: dead SA %p spi %#x\n", __func__, sav, sav->spi)); + AHSTAT_INC(ahs_notdb); + error = ESRCH; + goto bad; + } saidx = &sav->sah->saidx; IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || saidx->dst.sa.sa_family == AF_INET6, @@ -808,12 +817,14 @@ ah_input_cb(struct cryptop *crp) switch (saidx->dst.sa.sa_family) { #ifdef INET6 case AF_INET6: - error = ipsec6_common_input_cb(m, sav, skip, protoff); + error = ipsec6_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif #ifdef INET case AF_INET: - error = ipsec4_common_input_cb(m, sav, skip, protoff); + error = ipsec4_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif default: @@ -823,6 +834,7 @@ ah_input_cb(struct cryptop *crp) CURVNET_RESTORE(); return error; bad: + ipsec_sahtree_runlock(&sahtree_tracker); CURVNET_RESTORE(); if (sav) key_freesav(&sav); diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c index 7aec10549e6c..be8c18da60b3 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -492,6 +492,7 @@ static int esp_input_cb(struct cryptop *crp) { IPSEC_DEBUG_DECLARE(char buf[128]); + struct rm_priotracker sahtree_tracker; uint8_t lastthree[3]; const struct auth_hash *esph; struct mbuf *m; @@ -507,6 +508,7 @@ esp_input_cb(struct cryptop *crp) xd = crp->crp_opaque; CURVNET_SET(xd->vnet); sav = xd->sav; + ipsec_sahtree_rlock(&sahtree_tracker); if (sav->state >= SADB_SASTATE_DEAD) { /* saidx is freed */ DPRINTF(("%s: dead SA %p spi %#x\n", __func__, sav, sav->spi)); @@ -527,6 +529,7 @@ esp_input_cb(struct cryptop *crp) if (ipsec_updateid(sav, &crp->crp_session, &cryptoid) != 0) crypto_freesession(cryptoid); xd->cryptoid = crp->crp_session; + ipsec_sahtree_runlock(&sahtree_tracker); CURVNET_RESTORE(); return (crypto_dispatch(crp)); } @@ -658,12 +661,14 @@ esp_input_cb(struct cryptop *crp) switch (saidx->dst.sa.sa_family) { #ifdef INET6 case AF_INET6: - error = ipsec6_common_input_cb(m, sav, skip, protoff); + error = ipsec6_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif #ifdef INET case AF_INET: - error = ipsec4_common_input_cb(m, sav, skip, protoff); + error = ipsec4_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif default: @@ -673,6 +678,7 @@ esp_input_cb(struct cryptop *crp) CURVNET_RESTORE(); return error; bad: + ipsec_sahtree_runlock(&sahtree_tracker); if (sav != NULL) key_freesav(&sav); if (m != NULL) diff --git a/sys/netipsec/xform_ipcomp.c b/sys/netipsec/xform_ipcomp.c index 05a01b75e0bb..61fb9413a01a 100644 --- a/sys/netipsec/xform_ipcomp.c +++ b/sys/netipsec/xform_ipcomp.c @@ -283,6 +283,7 @@ static int ipcomp_input_cb(struct cryptop *crp) { IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]); + struct rm_priotracker sahtree_tracker; struct xform_data *xd; struct mbuf *m; struct secasvar *sav; @@ -300,6 +301,14 @@ ipcomp_input_cb(struct cryptop *crp) skip = xd->skip; protoff = xd->protoff; cryptoid = xd->cryptoid; + ipsec_sahtree_rlock(&sahtree_tracker); + if (sav->state >= SADB_SASTATE_DEAD) { + /* saidx is freed */ + DPRINTF(("%s: dead SA %p spi %#x\n", __func__, sav, sav->spi)); + IPCOMPSTAT_INC(ipcomps_notdb); + error = ESRCH; + goto bad; + } saidx = &sav->sah->saidx; IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || saidx->dst.sa.sa_family == AF_INET6, @@ -365,12 +374,14 @@ ipcomp_input_cb(struct cryptop *crp) switch (saidx->dst.sa.sa_family) { #ifdef INET6 case AF_INET6: - error = ipsec6_common_input_cb(m, sav, skip, protoff); + error = ipsec6_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif #ifdef INET case AF_INET: - error = ipsec4_common_input_cb(m, sav, skip, protoff); + error = ipsec4_common_input_cb(m, sav, skip, protoff, + &sahtree_tracker); break; #endif default: @@ -380,6 +391,7 @@ ipcomp_input_cb(struct cryptop *crp) CURVNET_RESTORE(); return error; bad: + ipsec_sahtree_runlock(&sahtree_tracker); CURVNET_RESTORE(); if (sav != NULL) key_freesav(&sav);