Module Name: src Committed By: ozaki-r Date: Wed Aug 9 09:48:11 UTC 2017
Modified Files: src/sys/netipsec: key.c key.h keydb.h xform_ah.c xform_esp.c xform_ipcomp.c Log Message: MP-ify SAD (savlist) localcount(9) is used to protect savlist of sah. The basic design is similar to MP-ifications of SPD and SAD sahlist. Please read the locking notes of SAD for more details. To generate a diff of this commit: cvs rdiff -u -r1.222 -r1.223 src/sys/netipsec/key.c cvs rdiff -u -r1.28 -r1.29 src/sys/netipsec/key.h cvs rdiff -u -r1.19 -r1.20 src/sys/netipsec/keydb.h cvs rdiff -u -r1.71 -r1.72 src/sys/netipsec/xform_ah.c cvs rdiff -u -r1.69 -r1.70 src/sys/netipsec/xform_esp.c cvs rdiff -u -r1.50 -r1.51 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/key.c diff -u src/sys/netipsec/key.c:1.222 src/sys/netipsec/key.c:1.223 --- src/sys/netipsec/key.c:1.222 Wed Aug 9 08:30:54 2017 +++ src/sys/netipsec/key.c Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.222 2017/08/09 08:30:54 ozaki-r Exp $ */ +/* $NetBSD: key.c,v 1.223 2017/08/09 09:48:11 ozaki-r Exp $ */ /* $FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $ */ /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.222 2017/08/09 08:30:54 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.223 2017/08/09 09:48:11 ozaki-r Exp $"); /* * This code is referd to RFC 2367 @@ -202,13 +202,15 @@ static u_int32_t acq_seq = 0; * - Data structures * - SAs are managed by the list called key_sad.sahlist and sav lists of sah * entries + * - An sav is supposed to be an SA from a viewpoint of users * - A sah has sav lists for each SA state * - Multiple sahs with the same saidx can exist * - Only one entry has MATURE state and others should be DEAD * - DEAD entries are just ignored from searching - * - Modifications to the key_sad.sahlist must be done with holding key_sad.lock - * which is a adaptive mutex - * - Read accesses to the key_sad.sahlist must be in pserialize(9) read sections + * - Modifications to the key_sad.sahlist and sah.savlist must be done with + * holding key_sad.lock which is a adaptive mutex + * - Read accesses to the key_sad.sahlist and sah.savlist must be in + * pserialize(9) read sections * - sah's lifetime is managed by localcount(9) * - Getting an sah entry * - We get an sah from the key_sad.sahlist @@ -218,6 +220,16 @@ static u_int32_t acq_seq = 0; * - An sah is destroyed when its state become DEAD and no sav is * listed to the sah * - The destruction is done only in the timer (see key_timehandler_sad) + * - sav's lifetime is managed by localcount(9) + * - Getting an sav entry + * - First get an sah by saidx and get an sav from either of sah's savlists + * - Must iterate the list and increment the reference count of a found sav + * (by key_sa_ref) in a pserialize read section + * - We can gain another reference from a held SA only if we check its state + * and take its reference in a pserialize read section + * (see esp_output for example) + * - A gotten sav must be released after use by key_sa_unref + * - An sav is destroyed when its state become DEAD */ /* * Locking notes on misc data: @@ -643,6 +655,9 @@ static void key_destroy_sah(struct secas static bool key_sah_has_sav(struct secashead *); static void key_sah_ref(struct secashead *); static void key_sah_unref(struct secashead *); +static void key_init_sav(struct secasvar *); +static void key_destroy_sav(struct secasvar *); +static void key_destroy_sav_with_ref(struct secasvar *); static struct secasvar *key_newsav(struct mbuf *, const struct sadb_msghdr *, int *, const char*, int); #define KEY_NEWSAV(m, sadb, e) \ @@ -776,35 +791,6 @@ static struct callout key_timehandler_ch static struct workqueue *key_timehandler_wq; static struct work key_timehandler_wk; -#ifdef IPSEC_REF_DEBUG -#define REFLOG(label, p, where, tag) \ - log(LOG_DEBUG, "%s:%d: " label " : refcnt=%d (%p)\n.", \ - (where), (tag), (p)->refcnt, (p)) -#else -#define REFLOG(label, p, where, tag) do {} while (0) -#endif - -#define SA_ADDREF(p) do { \ - atomic_inc_uint(&(p)->refcnt); \ - REFLOG("SA_ADDREF", (p), __func__, __LINE__); \ - KASSERTMSG((p)->refcnt != 0, "SA refcnt overflow"); \ -} while (0) -#define SA_ADDREF2(p, where, tag) do { \ - atomic_inc_uint(&(p)->refcnt); \ - REFLOG("SA_ADDREF", (p), (where), (tag)); \ - KASSERTMSG((p)->refcnt != 0, "SA refcnt overflow"); \ -} while (0) -#define SA_DELREF(p) do { \ - KASSERTMSG((p)->refcnt > 0, "SA refcnt underflow"); \ - atomic_dec_uint(&(p)->refcnt); \ - REFLOG("SA_DELREF", (p), __func__, __LINE__); \ -} while (0) -#define SA_DELREF2(p, nv, where, tag) do { \ - KASSERTMSG((p)->refcnt > 0, "SA refcnt underflow"); \ - nv = atomic_dec_uint_nv(&(p)->refcnt); \ - REFLOG("SA_DELREF", (p), (where), (tag)); \ -} while (0) - u_int key_sp_refcnt(const struct secpolicy *sp) { @@ -1085,7 +1071,7 @@ key_lookup_sa_bysaidx(const struct secas sav = last; } if (sav != NULL) { - SA_ADDREF(sav); + KEY_SA_REF(sav); KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, "DP cause refcnt++:%d SA:%p\n", key_sa_refcnt(sav), sav); @@ -1284,7 +1270,7 @@ key_lookup_sa( /* check dst address */ if (!key_sockaddr_match(&dst->sa, &sav->sah->saidx.dst.sa, chkport)) continue; - SA_ADDREF2(sav, where, tag); + key_sa_ref(sav, where, tag); goto done; } } @@ -1371,25 +1357,46 @@ key_sp_unref(struct secpolicy *sp, const localcount_release(&sp->localcount, &key_spd.cv, &key_spd.lock); } +static void +key_init_sav(struct secasvar *sav) +{ + + ASSERT_SLEEPABLE(); + + localcount_init(&sav->localcount); + SAVLIST_ENTRY_INIT(sav); +} + u_int key_sa_refcnt(const struct secasvar *sav) { - if (sav == NULL) - return 0; - - return sav->refcnt; + /* FIXME */ + return 0; } void key_sa_ref(struct secasvar *sav, const char* where, int tag) { - SA_ADDREF2(sav, where, tag); + localcount_acquire(&sav->localcount); KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, - "DP cause refcnt++:%d SA:%p from %s:%u\n", - sav->refcnt, sav, where, tag); + "DP cause refcnt++: SA:%p from %s:%u\n", + sav, where, tag); +} + +void +key_sa_unref(struct secasvar *sav, const char* where, int tag) +{ + + KDASSERT(mutex_ownable(&key_sad.lock)); + + KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, + "DP cause refcnt--: SA:%p from %s:%u\n", + sav, where, tag); + + localcount_release(&sav->localcount, &key_sad.cv, &key_sad.lock); } #if 0 @@ -1468,32 +1475,67 @@ key_freesp_so(struct secpolicy **sp) #endif /* - * Must be called after calling key_lookup_sa(). - * This function is called by key_freesp() to free some SA allocated - * for a policy. + * Remove the sav from the savlist of its sah and wait for references to the sav + * to be released. key_sad.lock must be held. */ -void -key_freesav(struct secasvar **psav, const char* where, int tag) +static void +key_unlink_sav(struct secasvar *sav) { - struct secasvar *sav = *psav; - unsigned int nv; - KASSERT(sav != NULL); + KASSERT(mutex_owned(&key_sad.lock)); - SA_DELREF2(sav, nv, where, tag); + SAVLIST_WRITER_REMOVE(sav); - KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, - "DP SA:%p (SPI %lu) from %s:%u; refcnt now %u\n", - sav, (u_long)ntohl(sav->spi), where, tag, nv); +#ifdef NET_MPSAFE + KASSERT(mutex_ownable(softnet_lock)); + pserialize_perform(key_sad_psz); +#endif - if (nv == 0) { - *psav = NULL; + localcount_drain(&sav->localcount, &key_sad.cv, &key_sad.lock); +} - /* remove from SA header */ - SAVLIST_WRITER_REMOVE(sav); +/* + * Destroy an sav where the sav must be unlinked from an sah + * by say key_unlink_sav. + */ +static void +key_destroy_sav(struct secasvar *sav) +{ - key_delsav(sav); - } + ASSERT_SLEEPABLE(); + + localcount_fini(&sav->localcount); + SAVLIST_ENTRY_DESTROY(sav); + + key_delsav(sav); +} + +/* + * Destroy sav with holding its reference. + */ +static void +key_destroy_sav_with_ref(struct secasvar *sav) +{ + + ASSERT_SLEEPABLE(); + + mutex_enter(&key_sad.lock); + sav->state = SADB_SASTATE_DEAD; + SAVLIST_WRITER_REMOVE(sav); + mutex_exit(&key_sad.lock); + + /* We cannot unref with holding key_sad.lock */ + KEY_SA_UNREF(&sav); + + mutex_enter(&key_sad.lock); +#ifdef NET_MPSAFE + KASSERT(mutex_ownable(softnet_lock)); + pserialize_perform(key_sad_psz); +#endif + localcount_drain(&sav->localcount, &key_sad.cv, &key_sad.lock); + mutex_exit(&key_sad.lock); + + key_destroy_sav(sav); } /* %%% SPD management */ @@ -3173,15 +3215,9 @@ static void key_delsav(struct secasvar *sav) { - KASSERT(sav != NULL); - KASSERTMSG(sav->refcnt == 0, "reference count %u > 0", sav->refcnt); - key_clear_xform(sav); key_freesaval(sav); - SAVLIST_ENTRY_DESTROY(sav); - kmem_intr_free(sav, sizeof(*sav)); - - return; + kmem_free(sav, sizeof(*sav)); } /* @@ -3315,7 +3351,7 @@ key_getsavbyspi(struct secashead *sah, u } if (sav->spi == spi) { - SA_ADDREF(sav); + KEY_SA_REF(sav); goto out; } } @@ -4718,20 +4754,23 @@ restart: pserialize_read_exit(s); /* if LARVAL entry doesn't become MATURE, delete it. */ + mutex_enter(&key_sad.lock); restart_sav_LARVAL: - SAVLIST_READER_FOREACH(sav, sah, SADB_SASTATE_LARVAL) { + SAVLIST_WRITER_FOREACH(sav, sah, SADB_SASTATE_LARVAL) { if (now - sav->created > key_larval_lifetime) { key_sa_chgstate(sav, SADB_SASTATE_DEAD); goto restart_sav_LARVAL; } } + mutex_exit(&key_sad.lock); /* * check MATURE entry to start to send expire message * whether or not. */ restart_sav_MATURE: - SAVLIST_READER_FOREACH(sav, sah, SADB_SASTATE_MATURE) { + mutex_enter(&key_sad.lock); + SAVLIST_WRITER_FOREACH(sav, sah, SADB_SASTATE_MATURE) { /* we don't need to check. */ if (sav->lft_s == NULL) continue; @@ -4748,8 +4787,10 @@ restart: */ if (sav->lft_c->sadb_lifetime_usetime == 0) { key_sa_chgstate(sav, SADB_SASTATE_DEAD); + mutex_exit(&key_sad.lock); } else { key_sa_chgstate(sav, SADB_SASTATE_DYING); + mutex_exit(&key_sad.lock); /* * XXX If we keep to send expire * message in the status of @@ -4770,6 +4811,7 @@ restart: sav->lft_c->sadb_lifetime_bytes) { key_sa_chgstate(sav, SADB_SASTATE_DYING); + mutex_exit(&key_sad.lock); /* * XXX If we keep to send expire * message in the status of @@ -4779,10 +4821,12 @@ restart: goto restart_sav_MATURE; } } + mutex_exit(&key_sad.lock); /* check DYING entry to change status to DEAD. */ + mutex_enter(&key_sad.lock); restart_sav_DYING: - SAVLIST_READER_FOREACH(sav, sah, SADB_SASTATE_DYING) { + SAVLIST_WRITER_FOREACH(sav, sah, SADB_SASTATE_DYING) { /* we don't need to check. */ if (sav->lft_h == NULL) continue; @@ -4819,13 +4863,18 @@ restart: goto restart_sav_DYING; } } + mutex_exit(&key_sad.lock); /* delete entry in DEAD */ restart_sav_DEAD: - SAVLIST_READER_FOREACH(sav, sah, SADB_SASTATE_DEAD) { - KEY_FREESAV(&sav); + mutex_enter(&key_sad.lock); + SAVLIST_WRITER_FOREACH(sav, sah, SADB_SASTATE_DEAD) { + key_unlink_sav(sav); + mutex_exit(&key_sad.lock); + key_destroy_sav(sav); goto restart_sav_DEAD; } + mutex_exit(&key_sad.lock); s = pserialize_read_enter(); key_sah_unref(sah); @@ -5120,11 +5169,10 @@ key_api_getspi(struct socket *so, struct /* set spi */ newsav->spi = htonl(spi); - /* add to satree */ - newsav->refcnt = 1; + /* Add to sah#savlist */ + key_init_sav(newsav); newsav->sah = sah; newsav->state = SADB_SASTATE_LARVAL; - SAVLIST_ENTRY_INIT(newsav); mutex_enter(&key_sad.lock); SAVLIST_WRITER_INSERT_TAIL(sah, SADB_SASTATE_LARVAL, newsav); mutex_exit(&key_sad.lock); @@ -5567,22 +5615,20 @@ key_api_update(struct socket *so, struct goto error; } - /* add to satree */ - newsav->refcnt = 1; + /* Add to sah#savlist */ + key_init_sav(newsav); newsav->state = SADB_SASTATE_MATURE; - SAVLIST_ENTRY_INIT(newsav); mutex_enter(&key_sad.lock); SAVLIST_WRITER_INSERT_TAIL(sah, SADB_SASTATE_MATURE, newsav); mutex_exit(&key_sad.lock); key_validate_savlist(sah, SADB_SASTATE_MATURE); - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - KEY_FREESAV(&sav); - KEY_FREESAV(&sav); - key_sah_unref(sah); sah = NULL; + key_destroy_sav_with_ref(sav); + sav = NULL; + { struct mbuf *n; @@ -5765,10 +5811,9 @@ key_api_add(struct socket *so, struct mb goto error; } - /* add to satree */ - newsav->refcnt = 1; + /* Add to sah#savlist */ + key_init_sav(newsav); newsav->state = SADB_SASTATE_MATURE; - SAVLIST_ENTRY_INIT(newsav); mutex_enter(&key_sad.lock); SAVLIST_WRITER_INSERT_TAIL(sah, SADB_SASTATE_MATURE, newsav); mutex_exit(&key_sad.lock); @@ -5995,9 +6040,8 @@ key_api_delete(struct socket *so, struct return key_senderror(so, m, ENOENT); } - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - KEY_FREESAV(&sav); - KEY_FREESAV(&sav); + key_destroy_sav_with_ref(sav); + sav = NULL; { struct mbuf *n; @@ -6049,20 +6093,15 @@ key_delete_all(struct socket *so, struct if (state == SADB_SASTATE_LARVAL) continue; restart: + mutex_enter(&key_sad.lock); SAVLIST_WRITER_FOREACH(sav, sah, state) { - /* sanity check */ - if (sav->state != state) { - IPSECLOG(LOG_DEBUG, - "invalid sav->state " - "(queue: %d SA: %d)\n", - state, sav->state); - continue; - } - - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - KEY_FREESAV(&sav); + sav->state = SADB_SASTATE_DEAD; + key_unlink_sav(sav); + mutex_exit(&key_sad.lock); + key_destroy_sav(sav); goto restart; } + mutex_exit(&key_sad.lock); } key_sah_unref(sah); } @@ -7292,11 +7331,15 @@ key_api_flush(struct socket *so, struct SASTATE_ALIVE_FOREACH(state) { restart: + mutex_enter(&key_sad.lock); SAVLIST_WRITER_FOREACH(sav, sah, state) { - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - KEY_FREESAV(&sav); + sav->state = SADB_SASTATE_DEAD; + key_unlink_sav(sav); + mutex_exit(&key_sad.lock); + key_destroy_sav(sav); goto restart; } + mutex_exit(&key_sad.lock); } s = pserialize_read_enter(); @@ -8241,14 +8284,15 @@ key_sa_chgstate(struct secasvar *sav, u_ { struct secasvar *_sav; - KASSERT(sav != NULL); + ASSERT_SLEEPABLE(); + KASSERT(mutex_owned(&key_sad.lock)); if (sav->state == state) return; - SAVLIST_WRITER_REMOVE(sav); + key_unlink_sav(sav); SAVLIST_ENTRY_DESTROY(sav); - SAVLIST_ENTRY_INIT(sav); + key_init_sav(sav); sav->state = state; if (!SADB_SASTATE_USABLE_P(sav)) { Index: src/sys/netipsec/key.h diff -u src/sys/netipsec/key.h:1.28 src/sys/netipsec/key.h:1.29 --- src/sys/netipsec/key.h:1.28 Tue Aug 8 08:23:10 2017 +++ src/sys/netipsec/key.h Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.28 2017/08/08 08:23:10 ozaki-r Exp $ */ +/* $NetBSD: key.h,v 1.29 2017/08/09 09:48:11 ozaki-r Exp $ */ /* $FreeBSD: src/sys/netipsec/key.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ /* $KAME: key.h,v 1.21 2001/07/27 03:51:30 itojun Exp $ */ @@ -61,6 +61,7 @@ u_int key_sp_refcnt(const struct secpoli void key_sp_ref(struct secpolicy *, const char*, int); void key_sp_unref(struct secpolicy *, const char*, int); void key_sa_ref(struct secasvar *, const char*, int); +void key_sa_unref(struct secasvar *, const char*, int); u_int key_sa_refcnt(const struct secasvar *); void key_socksplist_add(struct secpolicy *); @@ -85,7 +86,7 @@ void key_socksplist_add(struct secpolicy #define KEY_SA_REF(sav) \ key_sa_ref(sav, __func__, __LINE__) #define KEY_SA_UNREF(psav) \ - key_freesav(psav, __func__, __LINE__) + key_sa_unref(*(psav), __func__, __LINE__) struct secasvar *key_lookup_sa(const union sockaddr_union *, u_int, u_int32_t, u_int16_t, u_int16_t, const char*, int); @@ -93,8 +94,6 @@ void key_freesav(struct secasvar **, con #define KEY_LOOKUP_SA(dst, proto, spi, sport, dport) \ key_lookup_sa(dst, proto, spi, sport, dport, __func__, __LINE__) -#define KEY_FREESAV(psav) \ - key_freesav(psav, __func__, __LINE__) int key_checktunnelsanity (struct secasvar *, u_int, void *, void *); int key_checkrequest(struct ipsecrequest *, struct secasvar **); Index: src/sys/netipsec/keydb.h diff -u src/sys/netipsec/keydb.h:1.19 src/sys/netipsec/keydb.h:1.20 --- src/sys/netipsec/keydb.h:1.19 Tue Aug 8 04:17:34 2017 +++ src/sys/netipsec/keydb.h Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: keydb.h,v 1.19 2017/08/08 04:17:34 ozaki-r Exp $ */ +/* $NetBSD: keydb.h,v 1.20 2017/08/09 09:48:11 ozaki-r Exp $ */ /* $FreeBSD: src/sys/netipsec/keydb.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ /* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */ @@ -94,8 +94,8 @@ struct comp_algo; /* Security Association */ struct secasvar { struct pslist_entry pslist_entry; + struct localcount localcount; /* reference count */ - u_int refcnt; /* reference count */ u_int8_t state; /* Status of this Association */ u_int8_t alg_auth; /* Authentication Algorithm Identifier*/ Index: src/sys/netipsec/xform_ah.c diff -u src/sys/netipsec/xform_ah.c:1.71 src/sys/netipsec/xform_ah.c:1.72 --- src/sys/netipsec/xform_ah.c:1.71 Thu Aug 3 06:32:51 2017 +++ src/sys/netipsec/xform_ah.c Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: xform_ah.c,v 1.71 2017/08/03 06:32:51 ozaki-r Exp $ */ +/* $NetBSD: xform_ah.c,v 1.72 2017/08/09 09:48:11 ozaki-r 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.71 2017/08/03 06:32:51 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.72 2017/08/09 09:48:11 ozaki-r Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -733,6 +733,22 @@ ah_input(struct mbuf *m, struct secasvar goto bad; } + { + int s = pserialize_read_enter(); + + /* + * Take another reference to the SA for opencrypto callback. + */ + if (__predict_false(sav->state == SADB_SASTATE_DEAD)) { + pserialize_read_exit(s); + stat = AH_STAT_NOTDB; + error = ENOENT; + goto bad; + } + KEY_SA_REF(sav); + pserialize_read_exit(s); + } + /* Crypto operation descriptor. */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ crp->crp_flags = CRYPTO_F_IMBUF; @@ -749,7 +765,6 @@ ah_input(struct mbuf *m, struct secasvar tc->tc_protoff = protoff; tc->tc_skip = skip; tc->tc_sav = sav; - KEY_SA_REF(sav); DPRINTF(("%s: hash over %d bytes, skip %d: " "crda len %d skip %d inject %d\n", __func__, @@ -1144,7 +1159,11 @@ ah_output( { int s = pserialize_read_enter(); - if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) { + /* + * Take another reference to the SP and the SA for opencrypto callback. + */ + if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD || + sav->state == SADB_SASTATE_DEAD)) { pserialize_read_exit(s); pool_put(&ah_tdb_crypto_pool, tc); crypto_freereq(crp); @@ -1153,6 +1172,7 @@ ah_output( goto bad; } KEY_SP_REF(isr->sp); + KEY_SA_REF(sav); pserialize_read_exit(s); } @@ -1172,7 +1192,6 @@ ah_output( tc->tc_skip = skip; tc->tc_protoff = protoff; tc->tc_sav = sav; - KEY_SA_REF(sav); return crypto_dispatch(crp); bad: Index: src/sys/netipsec/xform_esp.c diff -u src/sys/netipsec/xform_esp.c:1.69 src/sys/netipsec/xform_esp.c:1.70 --- src/sys/netipsec/xform_esp.c:1.69 Thu Aug 3 06:32:51 2017 +++ src/sys/netipsec/xform_esp.c Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: xform_esp.c,v 1.69 2017/08/03 06:32:51 ozaki-r Exp $ */ +/* $NetBSD: xform_esp.c,v 1.70 2017/08/09 09:48:11 ozaki-r 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.69 2017/08/03 06:32:51 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.70 2017/08/09 09:48:11 ozaki-r Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -429,6 +429,23 @@ esp_input(struct mbuf *m, struct secasva crde = crp->crp_desc; } + { + int s = pserialize_read_enter(); + + /* + * Take another reference to the SA for opencrypto callback. + */ + if (__predict_false(sav->state == SADB_SASTATE_DEAD)) { + pserialize_read_exit(s); + pool_put(&esp_tdb_crypto_pool, tc); + crypto_freereq(crp); + ESP_STATINC(ESP_STAT_NOTDB); + return ENOENT; + } + KEY_SA_REF(sav); + pserialize_read_exit(s); + } + /* Crypto operation descriptor */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ crp->crp_flags = CRYPTO_F_IMBUF; @@ -444,7 +461,6 @@ esp_input(struct mbuf *m, struct secasva tc->tc_protoff = protoff; tc->tc_skip = skip; tc->tc_sav = sav; - KEY_SA_REF(sav); /* Decryption descriptor */ if (espx) { @@ -901,7 +917,11 @@ esp_output( { int s = pserialize_read_enter(); - if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) { + /* + * Take another reference to the SP and the SA for opencrypto callback. + */ + if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD || + sav->state == SADB_SASTATE_DEAD)) { pserialize_read_exit(s); pool_put(&esp_tdb_crypto_pool, tc); crypto_freereq(crp); @@ -910,6 +930,7 @@ esp_output( goto bad; } KEY_SP_REF(isr->sp); + KEY_SA_REF(sav); pserialize_read_exit(s); } @@ -919,7 +940,6 @@ esp_output( tc->tc_dst = saidx->dst; tc->tc_proto = saidx->proto; tc->tc_sav = sav; - KEY_SA_REF(sav); /* Crypto operation descriptor. */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */ Index: src/sys/netipsec/xform_ipcomp.c diff -u src/sys/netipsec/xform_ipcomp.c:1.50 src/sys/netipsec/xform_ipcomp.c:1.51 --- src/sys/netipsec/xform_ipcomp.c:1.50 Thu Aug 3 06:32:51 2017 +++ src/sys/netipsec/xform_ipcomp.c Wed Aug 9 09:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: xform_ipcomp.c,v 1.50 2017/08/03 06:32:51 ozaki-r Exp $ */ +/* $NetBSD: xform_ipcomp.c,v 1.51 2017/08/09 09:48:11 ozaki-r 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.50 2017/08/03 06:32:51 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.51 2017/08/09 09:48:11 ozaki-r Exp $"); /* IP payload compression protocol (IPComp), see RFC 2393 */ #if defined(_KERNEL_OPT) @@ -184,6 +184,23 @@ ipcomp_input(struct mbuf *m, struct seca return error; } + { + int s = pserialize_read_enter(); + + /* + * Take another reference to the SA for opencrypto callback. + */ + if (__predict_false(sav->state == SADB_SASTATE_DEAD)) { + pserialize_read_exit(s); + pool_put(&ipcomp_tdb_crypto_pool, tc); + crypto_freereq(crp); + IPCOMP_STATINC(IPCOMP_STAT_NOTDB); + return ENOENT; + } + KEY_SA_REF(sav); + pserialize_read_exit(s); + } + crdc = crp->crp_desc; crdc->crd_skip = skip + hlen; @@ -209,7 +226,6 @@ ipcomp_input(struct mbuf *m, struct seca tc->tc_protoff = protoff; tc->tc_skip = skip; tc->tc_sav = sav; - KEY_SA_REF(sav); return crypto_dispatch(crp); } @@ -483,7 +499,11 @@ ipcomp_output( { int s = pserialize_read_enter(); - if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) { + /* + * Take another reference to the SP and the SA for opencrypto callback. + */ + if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD || + sav->state == SADB_SASTATE_DEAD)) { pserialize_read_exit(s); pool_put(&ipcomp_tdb_crypto_pool, tc); crypto_freereq(crp); @@ -492,6 +512,7 @@ ipcomp_output( goto bad; } KEY_SP_REF(isr->sp); + KEY_SA_REF(sav); pserialize_read_exit(s); } @@ -502,7 +523,6 @@ ipcomp_output( tc->tc_skip = skip; tc->tc_protoff = protoff; tc->tc_sav = sav; - KEY_SA_REF(sav); /* Crypto operation descriptor */ crp->crp_ilen = m->m_pkthdr.len; /* Total input length */