ipsec: add a lock encompassing SPI allocation
SPIs get allocated and inserted in separate steps. Prior to the change there was nothing preventing 2 differnet threads from ending up with the same one. PR: 258849 Reported by: Herbie.Robinson@stratus.com Reviewed by: ae Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D32826
This commit is contained in:
parent
626bd0970a
commit
10ea195fa2
@ -216,6 +216,13 @@ VNET_DEFINE_STATIC(struct mtx *, spdcache_lock);
|
|||||||
#define SPDCACHE_LOCK(a) mtx_lock(&V_spdcache_lock[a]);
|
#define SPDCACHE_LOCK(a) mtx_lock(&V_spdcache_lock[a]);
|
||||||
#define SPDCACHE_UNLOCK(a) mtx_unlock(&V_spdcache_lock[a]);
|
#define SPDCACHE_UNLOCK(a) mtx_unlock(&V_spdcache_lock[a]);
|
||||||
|
|
||||||
|
static struct sx spi_alloc_lock;
|
||||||
|
#define SPI_ALLOC_LOCK_INIT() sx_init(&spi_alloc_lock, "spialloc")
|
||||||
|
#define SPI_ALLOC_LOCK_DESTROY() sx_destroy(&spi_alloc_lock)
|
||||||
|
#define SPI_ALLOC_LOCK() sx_xlock(&spi_alloc_lock)
|
||||||
|
#define SPI_ALLOC_UNLOCK() sx_unlock(&spi_alloc_lock)
|
||||||
|
#define SPI_ALLOC_LOCK_ASSERT() sx_assert(&spi_alloc_lock, SA_XLOCKED)
|
||||||
|
|
||||||
/* SAD */
|
/* SAD */
|
||||||
TAILQ_HEAD(secashead_queue, secashead);
|
TAILQ_HEAD(secashead_queue, secashead);
|
||||||
LIST_HEAD(secashead_list, secashead);
|
LIST_HEAD(secashead_list, secashead);
|
||||||
@ -4902,6 +4909,7 @@ key_getspi(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
|
KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx);
|
||||||
|
|
||||||
/* SPI allocation */
|
/* SPI allocation */
|
||||||
|
SPI_ALLOC_LOCK();
|
||||||
spi = key_do_getnewspi(
|
spi = key_do_getnewspi(
|
||||||
(struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], &saidx);
|
(struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], &saidx);
|
||||||
if (spi == 0) {
|
if (spi == 0) {
|
||||||
@ -4909,10 +4917,12 @@ key_getspi(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
* Requested SPI or SPI range is not available or
|
* Requested SPI or SPI range is not available or
|
||||||
* already used.
|
* already used.
|
||||||
*/
|
*/
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
error = EEXIST;
|
error = EEXIST;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
sav = key_newsav(mhp, &saidx, spi, &error);
|
sav = key_newsav(mhp, &saidx, spi, &error);
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
if (sav == NULL)
|
if (sav == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@ -5021,6 +5031,8 @@ key_do_getnewspi(struct sadb_spirange *spirange, struct secasindex *saidx)
|
|||||||
uint32_t min, max, newspi, t;
|
uint32_t min, max, newspi, t;
|
||||||
int tries, limit;
|
int tries, limit;
|
||||||
|
|
||||||
|
SPI_ALLOC_LOCK_ASSERT();
|
||||||
|
|
||||||
/* set spi range to allocate */
|
/* set spi range to allocate */
|
||||||
if (spirange != NULL) {
|
if (spirange != NULL) {
|
||||||
min = spirange->sadb_spirange_min;
|
min = spirange->sadb_spirange_min;
|
||||||
@ -5629,9 +5641,11 @@ key_add(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
* secasindex.
|
* secasindex.
|
||||||
* XXXAE: IPComp seems also doesn't use SPI.
|
* XXXAE: IPComp seems also doesn't use SPI.
|
||||||
*/
|
*/
|
||||||
|
SPI_ALLOC_LOCK();
|
||||||
if (proto == IPPROTO_TCP) {
|
if (proto == IPPROTO_TCP) {
|
||||||
sav = key_getsav_tcpmd5(&saidx, &spi);
|
sav = key_getsav_tcpmd5(&saidx, &spi);
|
||||||
if (sav == NULL && spi == 0) {
|
if (sav == NULL && spi == 0) {
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
/* Failed to allocate SPI */
|
/* Failed to allocate SPI */
|
||||||
ipseclog((LOG_DEBUG, "%s: SA already exists.\n",
|
ipseclog((LOG_DEBUG, "%s: SA already exists.\n",
|
||||||
__func__));
|
__func__));
|
||||||
@ -5643,12 +5657,14 @@ key_add(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
sav = key_getsavbyspi(spi);
|
sav = key_getsavbyspi(spi);
|
||||||
}
|
}
|
||||||
if (sav != NULL) {
|
if (sav != NULL) {
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
key_freesav(&sav);
|
key_freesav(&sav);
|
||||||
ipseclog((LOG_DEBUG, "%s: SA already exists.\n", __func__));
|
ipseclog((LOG_DEBUG, "%s: SA already exists.\n", __func__));
|
||||||
return key_senderror(so, m, EEXIST);
|
return key_senderror(so, m, EEXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
sav = key_newsav(mhp, &saidx, spi, &error);
|
sav = key_newsav(mhp, &saidx, spi, &error);
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
if (sav == NULL)
|
if (sav == NULL)
|
||||||
return key_senderror(so, m, error);
|
return key_senderror(so, m, error);
|
||||||
KEYDBG(KEY_STAMP,
|
KEYDBG(KEY_STAMP,
|
||||||
@ -6023,10 +6039,12 @@ key_delete(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
return (key_senderror(so, m, EINVAL));
|
return (key_senderror(so, m, EINVAL));
|
||||||
}
|
}
|
||||||
sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA];
|
sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA];
|
||||||
|
SPI_ALLOC_LOCK();
|
||||||
if (proto == IPPROTO_TCP)
|
if (proto == IPPROTO_TCP)
|
||||||
sav = key_getsav_tcpmd5(&saidx, NULL);
|
sav = key_getsav_tcpmd5(&saidx, NULL);
|
||||||
else
|
else
|
||||||
sav = key_getsavbyspi(sa0->sadb_sa_spi);
|
sav = key_getsavbyspi(sa0->sadb_sa_spi);
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
if (sav == NULL) {
|
if (sav == NULL) {
|
||||||
ipseclog((LOG_DEBUG, "%s: no SA found for SPI %u.\n",
|
ipseclog((LOG_DEBUG, "%s: no SA found for SPI %u.\n",
|
||||||
__func__, ntohl(sa0->sadb_sa_spi)));
|
__func__, ntohl(sa0->sadb_sa_spi)));
|
||||||
@ -6235,10 +6253,12 @@ key_get(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
|
|||||||
}
|
}
|
||||||
KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
|
KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx);
|
||||||
|
|
||||||
|
SPI_ALLOC_LOCK();
|
||||||
if (proto == IPPROTO_TCP)
|
if (proto == IPPROTO_TCP)
|
||||||
sav = key_getsav_tcpmd5(&saidx, NULL);
|
sav = key_getsav_tcpmd5(&saidx, NULL);
|
||||||
else
|
else
|
||||||
sav = key_getsavbyspi(sa0->sadb_sa_spi);
|
sav = key_getsavbyspi(sa0->sadb_sa_spi);
|
||||||
|
SPI_ALLOC_UNLOCK();
|
||||||
if (sav == NULL) {
|
if (sav == NULL) {
|
||||||
ipseclog((LOG_DEBUG, "%s: no SA found.\n", __func__));
|
ipseclog((LOG_DEBUG, "%s: no SA found.\n", __func__));
|
||||||
return key_senderror(so, m, ESRCH);
|
return key_senderror(so, m, ESRCH);
|
||||||
@ -8318,6 +8338,7 @@ key_init(void)
|
|||||||
SAHTREE_LOCK_INIT();
|
SAHTREE_LOCK_INIT();
|
||||||
ACQ_LOCK_INIT();
|
ACQ_LOCK_INIT();
|
||||||
SPACQ_LOCK_INIT();
|
SPACQ_LOCK_INIT();
|
||||||
|
SPI_ALLOC_LOCK_INIT();
|
||||||
|
|
||||||
#ifndef IPSEC_DEBUG2
|
#ifndef IPSEC_DEBUG2
|
||||||
callout_init(&key_timer, 1);
|
callout_init(&key_timer, 1);
|
||||||
@ -8442,6 +8463,7 @@ key_destroy(void)
|
|||||||
SAHTREE_LOCK_DESTROY();
|
SAHTREE_LOCK_DESTROY();
|
||||||
ACQ_LOCK_DESTROY();
|
ACQ_LOCK_DESTROY();
|
||||||
SPACQ_LOCK_DESTROY();
|
SPACQ_LOCK_DESTROY();
|
||||||
|
SPI_ALLOC_LOCK_DESTROY();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user