Make IPsec SPD MP-safe
We use localcount(9), not psref(9), to make the sptree and secpolicy (SP) entries MP-safe because SPs need to be referenced over opencrypto processing that executes a callback in a different context. SPs on sockets aren't managed by the sptree and can be destroyed in softint. localcount_drain cannot be used in softint so we delay the destruction of such SPs to a thread context. To do so, a list to manage such SPs is added (key_socksplist) and key_timehandler_spd deletes dead SPs in the list. For more details please read the locking notes in key.c. Proposed on tech-kern@ and tech-net@
This commit is contained in:
parent
02e8a058e6
commit
0c084e85e9
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ip6_forward.c,v 1.87 2017/05/09 04:24:10 ozaki-r Exp $ */
|
||||
/* $NetBSD: ip6_forward.c,v 1.88 2017/08/02 01:28:03 ozaki-r Exp $ */
|
||||
/* $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $ */
|
||||
|
||||
/*
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.87 2017/05/09 04:24:10 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.88 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_gateway.h"
|
||||
@ -462,7 +462,7 @@ ip6_forward(struct mbuf *m, int srcrt)
|
||||
out:
|
||||
#ifdef IPSEC
|
||||
if (sp != NULL)
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
#endif
|
||||
rtcache_unref(rt, ro);
|
||||
if (ro != NULL)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ip6_output.c,v 1.192 2017/06/26 08:01:53 ozaki-r Exp $ */
|
||||
/* $NetBSD: ip6_output.c,v 1.193 2017/08/02 01:28:03 ozaki-r Exp $ */
|
||||
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
|
||||
|
||||
/*
|
||||
@ -62,7 +62,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.192 2017/06/26 08:01:53 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.193 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_inet.h"
|
||||
@ -1069,7 +1069,7 @@ done:
|
||||
|
||||
#ifdef IPSEC
|
||||
if (sp != NULL)
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
#endif /* IPSEC */
|
||||
|
||||
if_put(ifp, &psref);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ipsec.c,v 1.112 2017/07/26 07:39:54 ozaki-r Exp $ */
|
||||
/* $NetBSD: ipsec.c,v 1.113 2017/08/02 01:28:03 ozaki-r Exp $ */
|
||||
/* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/netipsec/ipsec.c,v 1.2.2.2 2003/07/01 01:38:13 sam Exp $ */
|
||||
/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.112 2017/07/26 07:39:54 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.113 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
/*
|
||||
* IPsec controller part.
|
||||
@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.112 2017/07/26 07:39:54 ozaki-r Exp $");
|
||||
#include <sys/kauth.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/pserialize.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
@ -201,6 +202,7 @@ static struct secpolicy *ipsec_deepcopy_policy (const struct secpolicy *);
|
||||
static int ipsec_set_policy (struct secpolicy **, int, const void *, size_t,
|
||||
kauth_cred_t);
|
||||
static int ipsec_get_policy (struct secpolicy *, struct mbuf **);
|
||||
static void ipsec_destroy_policy(struct secpolicy *);
|
||||
static void vshiftl (unsigned char *, int, int);
|
||||
static size_t ipsec_hdrsiz (const struct secpolicy *);
|
||||
|
||||
@ -211,34 +213,49 @@ static struct secpolicy *
|
||||
ipsec_checkpcbcache(struct mbuf *m, struct inpcbpolicy *pcbsp, int dir)
|
||||
{
|
||||
struct secpolicyindex spidx;
|
||||
struct secpolicy *sp = NULL;
|
||||
int s;
|
||||
|
||||
KASSERT(IPSEC_DIR_IS_VALID(dir));
|
||||
KASSERT(pcbsp != NULL);
|
||||
KASSERT(dir < __arraycount(pcbsp->sp_cache));
|
||||
KASSERT(inph_locked(pcbsp->sp_inph));
|
||||
|
||||
/*
|
||||
* Checking the generation and sp->state and taking a reference to an SP
|
||||
* must be in a critical section of pserialize. See key_unlink_sp.
|
||||
*/
|
||||
s = pserialize_read_enter();
|
||||
/* SPD table change invalidate all the caches. */
|
||||
if (ipsec_spdgen != pcbsp->sp_cache[dir].cachegen) {
|
||||
ipsec_invalpcbcache(pcbsp, dir);
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
if (!pcbsp->sp_cache[dir].cachesp)
|
||||
return NULL;
|
||||
if (pcbsp->sp_cache[dir].cachesp->state != IPSEC_SPSTATE_ALIVE) {
|
||||
sp = pcbsp->sp_cache[dir].cachesp;
|
||||
if (sp == NULL)
|
||||
goto out;
|
||||
if (sp->state != IPSEC_SPSTATE_ALIVE) {
|
||||
sp = NULL;
|
||||
ipsec_invalpcbcache(pcbsp, dir);
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
if ((pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) == 0) {
|
||||
if (ipsec_setspidx(m, &spidx, 1) != 0)
|
||||
return NULL;
|
||||
/* NB: assume ipsec_setspidx never sleep */
|
||||
if (ipsec_setspidx(m, &spidx, 1) != 0) {
|
||||
sp = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to make an exact match here since the cached rule
|
||||
* might have lower priority than a rule that would otherwise
|
||||
* have matched the packet.
|
||||
*/
|
||||
if (memcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx, sizeof(spidx)))
|
||||
return NULL;
|
||||
if (memcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx,
|
||||
sizeof(spidx))) {
|
||||
sp = NULL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The pcb is connected, and the L4 code is sure that:
|
||||
@ -252,13 +269,14 @@ ipsec_checkpcbcache(struct mbuf *m, struct inpcbpolicy *pcbsp, int dir)
|
||||
*/
|
||||
}
|
||||
|
||||
pcbsp->sp_cache[dir].cachesp->lastused = time_second;
|
||||
KEY_SP_REF(pcbsp->sp_cache[dir].cachesp);
|
||||
sp->lastused = time_second;
|
||||
KEY_SP_REF(sp);
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP cause refcnt++:%d SP:%p\n",
|
||||
key_sp_refcnt(pcbsp->sp_cache[dir].cachesp),
|
||||
pcbsp->sp_cache[dir].cachesp);
|
||||
return pcbsp->sp_cache[dir].cachesp;
|
||||
key_sp_refcnt(sp), pcbsp->sp_cache[dir].cachesp);
|
||||
out:
|
||||
pserialize_read_exit(s);
|
||||
return sp;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -270,8 +288,6 @@ ipsec_fillpcbcache(struct inpcbpolicy *pcbsp, struct mbuf *m,
|
||||
KASSERT(dir < __arraycount(pcbsp->sp_cache));
|
||||
KASSERT(inph_locked(pcbsp->sp_inph));
|
||||
|
||||
if (pcbsp->sp_cache[dir].cachesp)
|
||||
KEY_FREESP(&pcbsp->sp_cache[dir].cachesp);
|
||||
pcbsp->sp_cache[dir].cachesp = NULL;
|
||||
pcbsp->sp_cache[dir].cachehint = IPSEC_PCBHINT_UNKNOWN;
|
||||
if (ipsec_setspidx(m, &pcbsp->sp_cache[dir].cacheidx, 1) != 0) {
|
||||
@ -279,7 +295,6 @@ ipsec_fillpcbcache(struct inpcbpolicy *pcbsp, struct mbuf *m,
|
||||
}
|
||||
pcbsp->sp_cache[dir].cachesp = sp;
|
||||
if (pcbsp->sp_cache[dir].cachesp) {
|
||||
KEY_SP_REF(pcbsp->sp_cache[dir].cachesp);
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP cause refcnt++:%d SP:%p\n",
|
||||
key_sp_refcnt(pcbsp->sp_cache[dir].cachesp),
|
||||
@ -317,8 +332,6 @@ ipsec_invalpcbcache(struct inpcbpolicy *pcbsp, int dir)
|
||||
for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) {
|
||||
if (dir != IPSEC_DIR_ANY && i != dir)
|
||||
continue;
|
||||
if (pcbsp->sp_cache[i].cachesp)
|
||||
KEY_FREESP(&pcbsp->sp_cache[i].cachesp);
|
||||
pcbsp->sp_cache[i].cachesp = NULL;
|
||||
pcbsp->sp_cache[i].cachehint = IPSEC_PCBHINT_UNKNOWN;
|
||||
pcbsp->sp_cache[i].cachegen = 0;
|
||||
@ -609,7 +622,7 @@ ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error,
|
||||
break;
|
||||
case IPSEC_POLICY_BYPASS:
|
||||
case IPSEC_POLICY_NONE:
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
sp = NULL; /* NB: force NULL result */
|
||||
break;
|
||||
case IPSEC_POLICY_IPSEC:
|
||||
@ -617,7 +630,7 @@ ipsec4_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error,
|
||||
break;
|
||||
}
|
||||
if (*error != 0) {
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
sp = NULL;
|
||||
IPSECLOG(LOG_DEBUG, "done, error %d\n", *error);
|
||||
}
|
||||
@ -697,7 +710,7 @@ ipsec4_output(struct mbuf *m, struct inpcb *inp, int flags,
|
||||
*/
|
||||
*mtu = _mtu;
|
||||
*natt_frag = true;
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
splx(s);
|
||||
return 0;
|
||||
}
|
||||
@ -711,7 +724,7 @@ ipsec4_output(struct mbuf *m, struct inpcb *inp, int flags,
|
||||
*/
|
||||
if (error == ENOENT)
|
||||
error = 0;
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
splx(s);
|
||||
*done = true;
|
||||
return error;
|
||||
@ -734,7 +747,7 @@ ipsec4_input(struct mbuf *m, int flags)
|
||||
* Check security policy against packet attributes.
|
||||
*/
|
||||
error = ipsec_in_reject(sp, m);
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
splx(s);
|
||||
if (error) {
|
||||
return error;
|
||||
@ -753,7 +766,7 @@ ipsec4_input(struct mbuf *m, int flags)
|
||||
sp = ipsec4_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error, NULL);
|
||||
if (sp != NULL) {
|
||||
m->m_flags &= ~M_CANFASTFWD;
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
}
|
||||
splx(s);
|
||||
return 0;
|
||||
@ -802,7 +815,7 @@ ipsec4_forward(struct mbuf *m, int *destmtu)
|
||||
rtcache_unref(rt, ro);
|
||||
KEY_FREESAV(&sav);
|
||||
}
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -838,7 +851,7 @@ ipsec6_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error,
|
||||
break;
|
||||
case IPSEC_POLICY_BYPASS:
|
||||
case IPSEC_POLICY_NONE:
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
sp = NULL; /* NB: force NULL result */
|
||||
break;
|
||||
case IPSEC_POLICY_IPSEC:
|
||||
@ -846,7 +859,7 @@ ipsec6_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error,
|
||||
break;
|
||||
}
|
||||
if (*error != 0) {
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
sp = NULL;
|
||||
IPSECLOG(LOG_DEBUG, "done, error %d\n", *error);
|
||||
}
|
||||
@ -1236,20 +1249,26 @@ ipsec_init_policy(struct socket *so, struct inpcbpolicy **policy)
|
||||
else
|
||||
new->priv = 0;
|
||||
|
||||
/*
|
||||
* These SPs are dummy. Never be used because the policy
|
||||
* is ENTRUST. See ipsec_getpolicybysock.
|
||||
*/
|
||||
if ((new->sp_in = KEY_NEWSP()) == NULL) {
|
||||
ipsec_delpcbpolicy(new);
|
||||
return ENOBUFS;
|
||||
}
|
||||
new->sp_in->state = IPSEC_SPSTATE_ALIVE;
|
||||
new->sp_in->policy = IPSEC_POLICY_ENTRUST;
|
||||
new->sp_in->created = 0; /* Indicates dummy */
|
||||
|
||||
if ((new->sp_out = KEY_NEWSP()) == NULL) {
|
||||
KEY_FREESP(&new->sp_in);
|
||||
KEY_SP_UNREF(&new->sp_in);
|
||||
ipsec_delpcbpolicy(new);
|
||||
return ENOBUFS;
|
||||
}
|
||||
new->sp_out->state = IPSEC_SPSTATE_ALIVE;
|
||||
new->sp_out->policy = IPSEC_POLICY_ENTRUST;
|
||||
new->sp_out->created = 0; /* Indicates dummy */
|
||||
|
||||
*policy = new;
|
||||
|
||||
@ -1264,14 +1283,14 @@ ipsec_copy_policy(const struct inpcbpolicy *old, struct inpcbpolicy *new)
|
||||
|
||||
sp = ipsec_deepcopy_policy(old->sp_in);
|
||||
if (sp) {
|
||||
KEY_FREESP(&new->sp_in);
|
||||
KEY_SP_UNREF(&new->sp_in);
|
||||
new->sp_in = sp;
|
||||
} else
|
||||
return ENOBUFS;
|
||||
|
||||
sp = ipsec_deepcopy_policy(old->sp_out);
|
||||
if (sp) {
|
||||
KEY_FREESP(&new->sp_out);
|
||||
KEY_SP_UNREF(&new->sp_out);
|
||||
new->sp_out = sp;
|
||||
} else
|
||||
return ENOBUFS;
|
||||
@ -1326,6 +1345,23 @@ ipsec_deepcopy_policy(const struct secpolicy *src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void
|
||||
ipsec_destroy_policy(struct secpolicy *sp)
|
||||
{
|
||||
|
||||
if (sp->created == 0)
|
||||
/* It's dummy. We can simply free it */
|
||||
key_free_sp(sp);
|
||||
else {
|
||||
/*
|
||||
* We cannot destroy here because it can be called in
|
||||
* softint. So mark the SP as DEAD and let the timer
|
||||
* destroy it. See key_timehandler_spd.
|
||||
*/
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
}
|
||||
}
|
||||
|
||||
/* set policy and ipsec request if present. */
|
||||
static int
|
||||
ipsec_set_policy(
|
||||
@ -1337,7 +1373,7 @@ ipsec_set_policy(
|
||||
)
|
||||
{
|
||||
const struct sadb_x_policy *xpl;
|
||||
struct secpolicy *newsp = NULL;
|
||||
struct secpolicy *newsp = NULL, *oldsp;
|
||||
int error;
|
||||
|
||||
KASSERT(!cpu_softintr_p());
|
||||
@ -1372,11 +1408,16 @@ ipsec_set_policy(
|
||||
if ((newsp = key_msg2sp(xpl, len, &error)) == NULL)
|
||||
return error;
|
||||
|
||||
newsp->state = IPSEC_SPSTATE_ALIVE;
|
||||
key_init_sp(newsp);
|
||||
newsp->created = time_uptime;
|
||||
/* Insert the global list for SPs for sockets */
|
||||
key_socksplist_add(newsp);
|
||||
|
||||
/* clear old SP and set new SP */
|
||||
KEY_FREESP(policy);
|
||||
oldsp = *policy;
|
||||
*policy = newsp;
|
||||
ipsec_destroy_policy(oldsp);
|
||||
|
||||
if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DUMP)) {
|
||||
printf("%s: new policy\n", __func__);
|
||||
kdebug_secpolicy(newsp);
|
||||
@ -1416,6 +1457,7 @@ ipsec4_set_policy(struct inpcb *inp, int optname, const void *request,
|
||||
struct secpolicy **policy;
|
||||
|
||||
KASSERT(!cpu_softintr_p());
|
||||
KASSERT(inp_locked(inp));
|
||||
|
||||
/* sanity check. */
|
||||
if (inp == NULL || request == NULL)
|
||||
@ -1486,10 +1528,10 @@ ipsec4_delete_pcbpolicy(struct inpcb *inp)
|
||||
return 0;
|
||||
|
||||
if (inp->inp_sp->sp_in != NULL)
|
||||
KEY_FREESP(&inp->inp_sp->sp_in);
|
||||
ipsec_destroy_policy(inp->inp_sp->sp_in);
|
||||
|
||||
if (inp->inp_sp->sp_out != NULL)
|
||||
KEY_FREESP(&inp->inp_sp->sp_out);
|
||||
ipsec_destroy_policy(inp->inp_sp->sp_out);
|
||||
|
||||
ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
|
||||
|
||||
@ -1508,6 +1550,7 @@ ipsec6_set_policy(struct in6pcb *in6p, int optname, const void *request,
|
||||
struct secpolicy **policy;
|
||||
|
||||
KASSERT(!cpu_softintr_p());
|
||||
KASSERT(in6p_locked(in6p));
|
||||
|
||||
/* sanity check. */
|
||||
if (in6p == NULL || request == NULL)
|
||||
@ -1575,10 +1618,10 @@ ipsec6_delete_pcbpolicy(struct in6pcb *in6p)
|
||||
return 0;
|
||||
|
||||
if (in6p->in6p_sp->sp_in != NULL)
|
||||
KEY_FREESP(&in6p->in6p_sp->sp_in);
|
||||
ipsec_destroy_policy(in6p->in6p_sp->sp_in);
|
||||
|
||||
if (in6p->in6p_sp->sp_out != NULL)
|
||||
KEY_FREESP(&in6p->in6p_sp->sp_out);
|
||||
ipsec_destroy_policy(in6p->in6p_sp->sp_out);
|
||||
|
||||
ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY);
|
||||
|
||||
@ -1778,7 +1821,7 @@ ipsec4_in_reject(struct mbuf *m, struct inpcb *inp)
|
||||
result = ipsec_in_reject(sp, m);
|
||||
if (result)
|
||||
IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
} else {
|
||||
result = 0; /* XXX should be panic ?
|
||||
* -> No, there may be error. */
|
||||
@ -1817,7 +1860,7 @@ ipsec6_in_reject(struct mbuf *m, struct in6pcb *in6p)
|
||||
result = ipsec_in_reject(sp, m);
|
||||
if (result)
|
||||
IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
@ -1929,7 +1972,7 @@ ipsec4_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp)
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DATA, "size:%lu.\n",
|
||||
(unsigned long)size);
|
||||
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
} else {
|
||||
size = 0; /* XXX should be panic ? */
|
||||
}
|
||||
@ -1964,7 +2007,7 @@ ipsec6_hdrsiz(struct mbuf *m, u_int dir, struct in6pcb *in6p)
|
||||
return 0;
|
||||
size = ipsec_hdrsiz(sp);
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DATA, "size:%zu.\n", size);
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -2279,7 +2322,7 @@ ipsec6_input(struct mbuf *m)
|
||||
* attributes.
|
||||
*/
|
||||
error = ipsec_in_reject(sp, m);
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
} else {
|
||||
/* XXX error stat??? */
|
||||
error = EINVAL;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ipsec.h,v 1.57 2017/07/26 09:18:15 ozaki-r Exp $ */
|
||||
/* $NetBSD: ipsec.h,v 1.58 2017/08/02 01:28:03 ozaki-r Exp $ */
|
||||
/* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/netipsec/ipsec.h,v 1.2.4.2 2004/02/14 22:23:23 bms Exp $ */
|
||||
/* $KAME: ipsec.h,v 1.53 2001/11/20 08:32:38 itojun Exp $ */
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/localcount.h>
|
||||
|
||||
#include <netinet/in_pcb_hdr.h>
|
||||
#include <netipsec/keydb.h>
|
||||
@ -76,7 +77,7 @@ struct secpolicyindex {
|
||||
struct secpolicy {
|
||||
struct pslist_entry pslist_entry;
|
||||
|
||||
u_int refcnt; /* reference count */
|
||||
struct localcount localcount; /* reference count */
|
||||
struct secpolicyindex spidx; /* selector */
|
||||
u_int32_t id; /* It's unique number on the system. */
|
||||
u_int state; /* 0: dead, others: alive */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: key.c,v 1.196 2017/07/27 09:53:57 ozaki-r Exp $ */
|
||||
/* $NetBSD: key.c,v 1.197 2017/08/02 01:28:03 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.196 2017/07/27 09:53:57 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.197 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
/*
|
||||
* This code is referd to RFC 2367
|
||||
@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: key.c,v 1.196 2017/07/27 09:53:57 ozaki-r Exp $");
|
||||
#include "opt_inet.h"
|
||||
#include "opt_ipsec.h"
|
||||
#include "opt_gateway.h"
|
||||
#include "opt_net_mpsafe.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -67,6 +68,10 @@ __KERNEL_RCSID(0, "$NetBSD: key.c,v 1.196 2017/07/27 09:53:57 ozaki-r Exp $");
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/pslist.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/localcount.h>
|
||||
#include <sys/pserialize.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
@ -130,6 +135,50 @@ percpu_t *pfkeystat_percpu;
|
||||
* field hits 0 (= no external reference other than from SA header.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Locking notes on SPD:
|
||||
* - Modifications to the sptree must be done with holding key_sp_mtx
|
||||
* which is a adaptive mutex
|
||||
* - Read accesses to the sptree must be in critical sections of pserialize(9)
|
||||
* - SP's lifetime is managed by localcount(9)
|
||||
* - An SP that has been inserted to the sptree is initially referenced by none,
|
||||
* i.e., a reference from the pstree isn't counted
|
||||
* - When an SP is being destroyed, we change its state as DEAD, wait for
|
||||
* references to the SP to be released, and then deallocate the SP
|
||||
* (see key_unlink_sp)
|
||||
* - Getting an SP
|
||||
* - Normally we get an SP from the sptree by incrementing the reference count
|
||||
* of the SP
|
||||
* - We can gain another reference from a held SP only if we check its state
|
||||
* and take its reference in a critical section of pserialize
|
||||
* (see esp_output for example)
|
||||
* - We may get an SP from an SP cache. See below
|
||||
* - Updating member variables of an SP
|
||||
* - Most member variables of an SP are immutable
|
||||
* - Only sp->state and sp->lastused can be changed
|
||||
* - sp->state of an SP is updated only when destroying it under key_sp_mtx
|
||||
* - SP caches
|
||||
* - SPs can be cached in PCBs
|
||||
* - The lifetime of the caches is controlled by the global generation counter
|
||||
* (ipsec_spdgen)
|
||||
* - The global counter value is stored when an SP is cached
|
||||
* - If the stored value is different from the global counter then the cache
|
||||
* is considered invalidated
|
||||
* - The counter is incremented when an SP is being destroyed
|
||||
* - So checking the generation and taking a reference to an SP should be
|
||||
* in a critical section of pserialize
|
||||
* - Note that caching doesn't increment the reference counter of an SP
|
||||
* - SPs in sockets
|
||||
* - Userland programs can set a policy to a socket by
|
||||
* setsockopt(IP_IPSEC_POLICY)
|
||||
* - Such policies (SPs) are set to a socket (PCB) and also inserted to
|
||||
* the key_socksplist list (not the sptree)
|
||||
* - Such a policy is destroyed when a corresponding socket is destroed,
|
||||
* however, a socket can be destroyed in softint so we cannot destroy
|
||||
* it directly instead we just mark it DEAD and delay the destruction
|
||||
* until GC by the timer
|
||||
*/
|
||||
|
||||
u_int32_t key_debug_level = 0;
|
||||
static u_int key_spi_trycnt = 1000;
|
||||
static u_int32_t key_spi_minval = 0x100;
|
||||
@ -194,10 +243,23 @@ static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The list has SPs that are set to a socket via setsockopt(IP_IPSEC_POLICY)
|
||||
* from userland. See ipsec_set_policy.
|
||||
*/
|
||||
static struct pslist_head key_socksplist;
|
||||
|
||||
#define SOCKSPLIST_WRITER_FOREACH(sp) \
|
||||
PSLIST_WRITER_FOREACH((sp), &key_socksplist, struct secpolicy, \
|
||||
pslist_entry)
|
||||
|
||||
/*
|
||||
* Protect regtree, acqtree and items stored in the lists.
|
||||
*/
|
||||
static kmutex_t key_mtx __cacheline_aligned;
|
||||
static pserialize_t key_psz;
|
||||
static kmutex_t key_sp_mtx __cacheline_aligned;
|
||||
static kcondvar_t key_sp_cv __cacheline_aligned;
|
||||
|
||||
/* search order for SAs */
|
||||
/*
|
||||
@ -432,9 +494,11 @@ static struct secasvar *key_lookup_sa_bysaidx(const struct secasindex *);
|
||||
static void key_freeso(struct socket *);
|
||||
static void key_freesp_so(struct secpolicy **);
|
||||
#endif
|
||||
static void key_delsp (struct secpolicy *);
|
||||
static struct secpolicy *key_getsp (const struct secpolicyindex *);
|
||||
static struct secpolicy *key_getspbyid (u_int32_t);
|
||||
static struct secpolicy *key_lookup_and_remove_sp(const struct secpolicyindex *);
|
||||
static struct secpolicy *key_lookupbyid_and_remove_sp(u_int32_t);
|
||||
static void key_destroy_sp(struct secpolicy *);
|
||||
static u_int16_t key_newreqid (void);
|
||||
static struct mbuf *key_gather_mbuf (struct mbuf *,
|
||||
const struct sadb_msghdr *, int, int, ...);
|
||||
@ -582,8 +646,6 @@ static const char *key_getfqdn (void);
|
||||
static const char *key_getuserfqdn (void);
|
||||
#endif
|
||||
static void key_sa_chgstate (struct secasvar *, u_int8_t);
|
||||
static inline void key_sp_dead (struct secpolicy *);
|
||||
static void key_sp_unlink (struct secpolicy *sp);
|
||||
|
||||
static struct mbuf *key_alloc_mbuf (int);
|
||||
|
||||
@ -622,55 +684,37 @@ static struct work key_timehandler_wk;
|
||||
REFLOG("SA_DELREF", (p), (where), (tag)); \
|
||||
} while (0)
|
||||
|
||||
#define SP_ADDREF(p) do { \
|
||||
atomic_inc_uint(&(p)->refcnt); \
|
||||
REFLOG("SP_ADDREF", (p), __func__, __LINE__); \
|
||||
KASSERTMSG((p)->refcnt != 0, "SP refcnt overflow"); \
|
||||
} while (0)
|
||||
#define SP_ADDREF2(p, where, tag) do { \
|
||||
atomic_inc_uint(&(p)->refcnt); \
|
||||
REFLOG("SP_ADDREF", (p), (where), (tag)); \
|
||||
KASSERTMSG((p)->refcnt != 0, "SP refcnt overflow"); \
|
||||
} while (0)
|
||||
#define SP_DELREF(p) do { \
|
||||
KASSERTMSG((p)->refcnt > 0, "SP refcnt underflow"); \
|
||||
atomic_dec_uint(&(p)->refcnt); \
|
||||
REFLOG("SP_DELREF", (p), __func__, __LINE__); \
|
||||
} while (0)
|
||||
#define SP_DELREF2(p, nv, where, tag) do { \
|
||||
KASSERTMSG((p)->refcnt > 0, "SP refcnt underflow"); \
|
||||
nv = atomic_dec_uint_nv(&(p)->refcnt); \
|
||||
REFLOG("SP_DELREF", (p), (where), (tag)); \
|
||||
} while (0)
|
||||
|
||||
u_int
|
||||
key_sp_refcnt(const struct secpolicy *sp)
|
||||
{
|
||||
|
||||
if (sp == NULL)
|
||||
/* FIXME */
|
||||
return 0;
|
||||
|
||||
return sp->refcnt;
|
||||
}
|
||||
|
||||
static inline void
|
||||
key_sp_dead(struct secpolicy *sp)
|
||||
{
|
||||
|
||||
/* mark the SP dead */
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the sp from the sptree and wait for references to the sp
|
||||
* to be released. key_sp_mtx must be held.
|
||||
*/
|
||||
static void
|
||||
key_sp_unlink(struct secpolicy *sp)
|
||||
key_unlink_sp(struct secpolicy *sp)
|
||||
{
|
||||
|
||||
/* remove from SP index */
|
||||
SPLIST_WRITER_REMOVE(sp);
|
||||
/* Release refcount held just for being on chain */
|
||||
KEY_FREESP(&sp);
|
||||
}
|
||||
KASSERT(mutex_owned(&key_sp_mtx));
|
||||
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
SPLIST_WRITER_REMOVE(sp);
|
||||
|
||||
/* Invalidate all cached SPD pointers in the PCBs. */
|
||||
ipsec_invalpcbcacheall();
|
||||
|
||||
#ifdef NET_MPSAFE
|
||||
KASSERT(mutex_ownable(softnet_lock));
|
||||
pserialize_perform(key_psz);
|
||||
#endif
|
||||
|
||||
localcount_drain(&sp->localcount, &key_sp_cv, &key_sp_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 when there are known to be no SP's for the specified
|
||||
@ -704,12 +748,12 @@ key_lookup_sp_byspidx(const struct secpolicyindex *spidx,
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, "DP from %s:%u\n", where, tag);
|
||||
|
||||
/* get a SP entry */
|
||||
s = splsoftnet(); /*called from softclock()*/
|
||||
if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DATA)) {
|
||||
printf("*** objects\n");
|
||||
kdebug_secpolicyindex(spidx);
|
||||
}
|
||||
|
||||
s = pserialize_read_enter();
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DATA)) {
|
||||
printf("*** in SPD\n");
|
||||
@ -729,9 +773,9 @@ found:
|
||||
|
||||
/* found a SPD entry */
|
||||
sp->lastused = time_uptime;
|
||||
SP_ADDREF2(sp, where, tag);
|
||||
key_sp_ref(sp, where, tag);
|
||||
}
|
||||
splx(s);
|
||||
pserialize_read_exit(s);
|
||||
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP return SP:%p (ID=%u) refcnt %u\n",
|
||||
@ -765,7 +809,7 @@ key_gettunnel(const struct sockaddr *osrc,
|
||||
goto done;
|
||||
}
|
||||
|
||||
s = splsoftnet(); /*called from softclock()*/
|
||||
s = pserialize_read_enter();
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
@ -805,9 +849,9 @@ key_gettunnel(const struct sockaddr *osrc,
|
||||
found:
|
||||
if (sp) {
|
||||
sp->lastused = time_uptime;
|
||||
SP_ADDREF2(sp, where, tag);
|
||||
key_sp_ref(sp, where, tag);
|
||||
}
|
||||
splx(s);
|
||||
pserialize_read_exit(s);
|
||||
done:
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP return SP:%p (ID=%u) refcnt %u\n",
|
||||
@ -1153,17 +1197,43 @@ key_validate_savlist(const struct secashead *sah, const u_int state)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
key_init_sp(struct secpolicy *sp)
|
||||
{
|
||||
|
||||
ASSERT_SLEEPABLE();
|
||||
|
||||
sp->state = IPSEC_SPSTATE_ALIVE;
|
||||
if (sp->policy == IPSEC_POLICY_IPSEC)
|
||||
KASSERT(sp->req != NULL);
|
||||
localcount_init(&sp->localcount);
|
||||
SPLIST_ENTRY_INIT(sp);
|
||||
}
|
||||
|
||||
void
|
||||
key_sp_ref(struct secpolicy *sp, const char* where, int tag)
|
||||
{
|
||||
|
||||
SP_ADDREF2(sp, where, tag);
|
||||
localcount_acquire(&sp->localcount);
|
||||
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP SP:%p (ID=%u) from %s:%u; refcnt now %u\n",
|
||||
"DP SP:%p (ID=%u) from %s:%u; refcnt++ now %u\n",
|
||||
sp, sp->id, where, tag, key_sp_refcnt(sp));
|
||||
}
|
||||
|
||||
void
|
||||
key_sp_unref(struct secpolicy *sp, const char* where, int tag)
|
||||
{
|
||||
|
||||
KASSERT(mutex_ownable(&key_sp_mtx));
|
||||
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP SP:%p (ID=%u) from %s:%u; refcnt-- now %u\n",
|
||||
sp, sp->id, where, tag, key_sp_refcnt(sp));
|
||||
|
||||
localcount_release(&sp->localcount, &key_sp_cv, &key_sp_mtx);
|
||||
}
|
||||
|
||||
void
|
||||
key_sa_ref(struct secasvar *sav, const char* where, int tag)
|
||||
{
|
||||
@ -1175,30 +1245,6 @@ key_sa_ref(struct secasvar *sav, const char* where, int tag)
|
||||
sav->refcnt, sav, where, tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called after calling key_lookup_sp*().
|
||||
* For both the packet without socket and key_freeso().
|
||||
*/
|
||||
void
|
||||
_key_freesp(struct secpolicy **spp, const char* where, int tag)
|
||||
{
|
||||
struct secpolicy *sp = *spp;
|
||||
unsigned int nv;
|
||||
|
||||
KASSERT(sp != NULL);
|
||||
|
||||
SP_DELREF2(sp, nv, where, tag);
|
||||
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP SP:%p (ID=%u) from %s:%u; refcnt now %u\n",
|
||||
sp, sp->id, where, tag, nv);
|
||||
|
||||
if (nv == 0) {
|
||||
*spp = NULL;
|
||||
key_delsp(sp);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Must be called after calling key_lookup_sp*().
|
||||
@ -1270,7 +1316,7 @@ key_freesp_so(struct secpolicy **sp)
|
||||
|
||||
KASSERTMSG((*sp)->policy == IPSEC_POLICY_IPSEC,
|
||||
"invalid policy %u", (*sp)->policy);
|
||||
KEY_FREESP(sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1309,19 +1355,17 @@ key_freesav(struct secasvar **psav, const char* where, int tag)
|
||||
* free security policy entry.
|
||||
*/
|
||||
static void
|
||||
key_delsp(struct secpolicy *sp)
|
||||
key_destroy_sp(struct secpolicy *sp)
|
||||
{
|
||||
int s;
|
||||
|
||||
KASSERT(sp != NULL);
|
||||
SPLIST_ENTRY_DESTROY(sp);
|
||||
localcount_fini(&sp->localcount);
|
||||
|
||||
key_sp_dead(sp);
|
||||
|
||||
KASSERTMSG(sp->refcnt == 0,
|
||||
"SP with references deleted (refcnt %u)", sp->refcnt);
|
||||
|
||||
s = splsoftnet(); /*called from softclock()*/
|
||||
key_free_sp(sp);
|
||||
}
|
||||
|
||||
void
|
||||
key_free_sp(struct secpolicy *sp)
|
||||
{
|
||||
struct ipsecrequest *isr = sp->req, *nextisr;
|
||||
|
||||
@ -1330,12 +1374,17 @@ key_delsp(struct secpolicy *sp)
|
||||
kmem_intr_free(isr, sizeof(*isr));
|
||||
isr = nextisr;
|
||||
}
|
||||
|
||||
kmem_intr_free(sp, sizeof(*sp));
|
||||
}
|
||||
|
||||
SPLIST_ENTRY_DESTROY(sp);
|
||||
kmem_intr_free(sp, sizeof(*sp));
|
||||
void
|
||||
key_socksplist_add(struct secpolicy *sp)
|
||||
{
|
||||
|
||||
splx(s);
|
||||
mutex_enter(&key_sp_mtx);
|
||||
PSLIST_WRITER_INSERT_HEAD(&key_socksplist, sp, pslist_entry);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1347,21 +1396,51 @@ static struct secpolicy *
|
||||
key_getsp(const struct secpolicyindex *spidx)
|
||||
{
|
||||
struct secpolicy *sp;
|
||||
int s;
|
||||
|
||||
KASSERT(spidx != NULL);
|
||||
|
||||
s = pserialize_read_enter();
|
||||
SPLIST_READER_FOREACH(sp, spidx->dir) {
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
if (key_spidx_match_exactly(spidx, &sp->spidx)) {
|
||||
SP_ADDREF(sp);
|
||||
KEY_SP_REF(sp);
|
||||
pserialize_read_exit(s);
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
pserialize_read_exit(s);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* search SPD and remove found SP
|
||||
* OUT: NULL : not found
|
||||
* others : found, pointer to a SP.
|
||||
*/
|
||||
static struct secpolicy *
|
||||
key_lookup_and_remove_sp(const struct secpolicyindex *spidx)
|
||||
{
|
||||
struct secpolicy *sp = NULL;
|
||||
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SPLIST_WRITER_FOREACH(sp, spidx->dir) {
|
||||
KASSERT(sp->state != IPSEC_SPSTATE_DEAD);
|
||||
|
||||
if (key_spidx_match_exactly(spidx, &sp->spidx)) {
|
||||
key_unlink_sp(sp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
sp = NULL;
|
||||
out:
|
||||
mutex_exit(&key_sp_mtx);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* get SP by index.
|
||||
* OUT: NULL : not found
|
||||
@ -1371,13 +1450,15 @@ static struct secpolicy *
|
||||
key_getspbyid(u_int32_t id)
|
||||
{
|
||||
struct secpolicy *sp;
|
||||
int s;
|
||||
|
||||
s = pserialize_read_enter();
|
||||
SPLIST_READER_FOREACH(sp, IPSEC_DIR_INBOUND) {
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
if (sp->id == id) {
|
||||
SP_ADDREF(sp);
|
||||
return sp;
|
||||
KEY_SP_REF(sp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1385,12 +1466,42 @@ key_getspbyid(u_int32_t id)
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
if (sp->id == id) {
|
||||
SP_ADDREF(sp);
|
||||
KEY_SP_REF(sp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
pserialize_read_exit(s);
|
||||
return sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* get SP by index, remove and return it.
|
||||
* OUT: NULL : not found
|
||||
* others : found, pointer to a SP.
|
||||
*/
|
||||
static struct secpolicy *
|
||||
key_lookupbyid_and_remove_sp(u_int32_t id)
|
||||
{
|
||||
struct secpolicy *sp;
|
||||
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SPLIST_READER_FOREACH(sp, IPSEC_DIR_INBOUND) {
|
||||
KASSERT(sp->state != IPSEC_SPSTATE_DEAD);
|
||||
if (sp->id == id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
SPLIST_READER_FOREACH(sp, IPSEC_DIR_OUTBOUND) {
|
||||
KASSERT(sp->state != IPSEC_SPSTATE_DEAD);
|
||||
if (sp->id == id)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (sp != NULL)
|
||||
key_unlink_sp(sp);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
return sp;
|
||||
}
|
||||
|
||||
struct secpolicy *
|
||||
@ -1399,8 +1510,6 @@ key_newsp(const char* where, int tag)
|
||||
struct secpolicy *newsp = NULL;
|
||||
|
||||
newsp = kmem_intr_zalloc(sizeof(struct secpolicy), KM_NOSLEEP);
|
||||
if (newsp != NULL)
|
||||
newsp->refcnt = 1;
|
||||
|
||||
KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
|
||||
"DP from %s:%u return SP:%p\n", where, tag, newsp);
|
||||
@ -1451,7 +1560,7 @@ key_msg2sp(const struct sadb_x_policy *xpl0, size_t len, int *error)
|
||||
break;
|
||||
default:
|
||||
IPSECLOG(LOG_DEBUG, "invalid policy type.\n");
|
||||
KEY_FREESP(&newsp);
|
||||
key_free_sp(newsp);
|
||||
*error = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@ -1605,7 +1714,7 @@ key_msg2sp(const struct sadb_x_policy *xpl0, size_t len, int *error)
|
||||
return newsp;
|
||||
|
||||
free_exit:
|
||||
KEY_FREESP(&newsp);
|
||||
key_free_sp(newsp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1857,16 +1966,14 @@ key_api_spdadd(struct socket *so, struct mbuf *m,
|
||||
{
|
||||
struct secpolicy *sp;
|
||||
|
||||
sp = key_getsp(&spidx);
|
||||
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
|
||||
if (sp) {
|
||||
key_sp_dead(sp);
|
||||
key_sp_unlink(sp); /* XXX jrs ordering */
|
||||
KEY_FREESP(&sp);
|
||||
}
|
||||
sp = key_lookup_and_remove_sp(&spidx);
|
||||
if (sp != NULL)
|
||||
key_destroy_sp(sp);
|
||||
} else {
|
||||
sp = key_getsp(&spidx);
|
||||
if (sp != NULL) {
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
IPSECLOG(LOG_DEBUG, "a SP entry exists already.\n");
|
||||
return key_senderror(so, m, EEXIST);
|
||||
}
|
||||
@ -1891,12 +1998,11 @@ key_api_spdadd(struct socket *so, struct mbuf *m,
|
||||
newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0;
|
||||
newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0;
|
||||
|
||||
newsp->refcnt = 1; /* do not reclaim until I say I do */
|
||||
newsp->state = IPSEC_SPSTATE_ALIVE;
|
||||
if (newsp->policy == IPSEC_POLICY_IPSEC)
|
||||
KASSERT(newsp->req != NULL);
|
||||
SPLIST_ENTRY_INIT(newsp);
|
||||
key_init_sp(newsp);
|
||||
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SPLIST_WRITER_INSERT_TAIL(newsp->spidx.dir, newsp);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
|
||||
#ifdef notyet
|
||||
/* delete the entry in spacqtree */
|
||||
@ -1984,7 +2090,7 @@ key_getnewspid(void)
|
||||
if (sp == NULL)
|
||||
break;
|
||||
|
||||
KEY_FREESP(&sp);
|
||||
KEY_SP_UNREF(&sp);
|
||||
}
|
||||
|
||||
if (count == 0 || newid == 0) {
|
||||
@ -2044,7 +2150,7 @@ key_api_spddelete(struct socket *so, struct mbuf *m,
|
||||
key_init_spidx_bymsghdr(&spidx, mhp);
|
||||
|
||||
/* Is there SP in SPD ? */
|
||||
sp = key_getsp(&spidx);
|
||||
sp = key_lookup_and_remove_sp(&spidx);
|
||||
if (sp == NULL) {
|
||||
IPSECLOG(LOG_DEBUG, "no SP found.\n");
|
||||
return key_senderror(so, m, EINVAL);
|
||||
@ -2053,12 +2159,7 @@ key_api_spddelete(struct socket *so, struct mbuf *m,
|
||||
/* save policy id to buffer to be returned. */
|
||||
xpl0->sadb_x_policy_id = sp->id;
|
||||
|
||||
key_sp_dead(sp);
|
||||
key_sp_unlink(sp); /* XXX jrs ordering */
|
||||
KEY_FREESP(&sp); /* ref gained by key_getspbyid */
|
||||
|
||||
/* Invalidate all cached SPD pointers in the PCBs. */
|
||||
ipsec_invalpcbcacheall();
|
||||
key_destroy_sp(sp);
|
||||
|
||||
/* We're deleting policy; no need to invalidate the ipflow cache. */
|
||||
|
||||
@ -2109,19 +2210,13 @@ key_api_spddelete2(struct socket *so, struct mbuf *m,
|
||||
id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
|
||||
|
||||
/* Is there SP in SPD ? */
|
||||
sp = key_getspbyid(id);
|
||||
sp = key_lookupbyid_and_remove_sp(id);
|
||||
if (sp == NULL) {
|
||||
IPSECLOG(LOG_DEBUG, "no SP found id:%u.\n", id);
|
||||
return key_senderror(so, m, EINVAL);
|
||||
}
|
||||
|
||||
key_sp_dead(sp);
|
||||
key_sp_unlink(sp); /* XXX jrs ordering */
|
||||
KEY_FREESP(&sp); /* ref gained by key_getsp */
|
||||
sp = NULL;
|
||||
|
||||
/* Invalidate all cached SPD pointers in the PCBs. */
|
||||
ipsec_invalpcbcacheall();
|
||||
key_destroy_sp(sp);
|
||||
|
||||
/* We're deleting policy; no need to invalidate the ipflow cache. */
|
||||
|
||||
@ -2211,7 +2306,7 @@ key_api_spdget(struct socket *so, struct mbuf *m,
|
||||
|
||||
n = key_setdumpsp(sp, SADB_X_SPDGET, mhp->msg->sadb_msg_seq,
|
||||
mhp->msg->sadb_msg_pid);
|
||||
KEY_FREESP(&sp); /* ref gained by key_getspbyid */
|
||||
KEY_SP_UNREF(&sp); /* ref gained by key_getspbyid */
|
||||
if (n != NULL) {
|
||||
m_freem(m);
|
||||
return key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
|
||||
@ -2317,18 +2412,17 @@ key_api_spdflush(struct socket *so, struct mbuf *m,
|
||||
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
retry:
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
key_sp_dead(sp);
|
||||
key_sp_unlink(sp);
|
||||
KASSERT(sp->state != IPSEC_SPSTATE_DEAD);
|
||||
key_unlink_sp(sp);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
key_destroy_sp(sp);
|
||||
goto retry;
|
||||
}
|
||||
mutex_exit(&key_sp_mtx);
|
||||
}
|
||||
|
||||
/* Invalidate all cached SPD pointers in the PCBs. */
|
||||
ipsec_invalpcbcacheall();
|
||||
|
||||
/* We're deleting policy; no need to invalidate the ipflow cache. */
|
||||
|
||||
if (sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) {
|
||||
@ -2361,12 +2455,14 @@ key_setspddump_chain(int *errorp, int *lenp, pid_t pid)
|
||||
struct mbuf *m, *n, *prev;
|
||||
int totlen;
|
||||
|
||||
KASSERT(mutex_owned(&key_sp_mtx));
|
||||
|
||||
*lenp = 0;
|
||||
|
||||
/* search SPD entry and get buffer size. */
|
||||
cnt = 0;
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
@ -2380,7 +2476,7 @@ key_setspddump_chain(int *errorp, int *lenp, pid_t pid)
|
||||
prev = m;
|
||||
totlen = 0;
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
--cnt;
|
||||
n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, pid);
|
||||
|
||||
@ -2423,7 +2519,7 @@ key_api_spddump(struct socket *so, struct mbuf *m0,
|
||||
{
|
||||
struct mbuf *n;
|
||||
int error, len;
|
||||
int ok, s;
|
||||
int ok;
|
||||
pid_t pid;
|
||||
|
||||
pid = mhp->msg->sadb_msg_pid;
|
||||
@ -2438,9 +2534,9 @@ key_api_spddump(struct socket *so, struct mbuf *m0,
|
||||
return key_senderror(so, m0, ENOBUFS);
|
||||
}
|
||||
|
||||
s = splsoftnet();
|
||||
mutex_enter(&key_sp_mtx);
|
||||
n = key_setspddump_chain(&error, &len, pid);
|
||||
splx(s);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
|
||||
if (n == NULL) {
|
||||
return key_senderror(so, m0, ENOENT);
|
||||
@ -4341,24 +4437,37 @@ key_timehandler_spd(time_t now)
|
||||
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
retry:
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD) {
|
||||
key_sp_unlink(sp); /*XXX*/
|
||||
goto retry;
|
||||
}
|
||||
KASSERT(sp->state != IPSEC_SPSTATE_DEAD);
|
||||
|
||||
if (sp->lifetime == 0 && sp->validtime == 0)
|
||||
continue;
|
||||
|
||||
/* the deletion will occur next time */
|
||||
if ((sp->lifetime && now - sp->created > sp->lifetime) ||
|
||||
(sp->validtime && now - sp->lastused > sp->validtime)) {
|
||||
key_sp_dead(sp);
|
||||
key_unlink_sp(sp);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
key_spdexpire(sp);
|
||||
key_destroy_sp(sp);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
mutex_exit(&key_sp_mtx);
|
||||
}
|
||||
|
||||
retry_socksplist:
|
||||
mutex_enter(&key_sp_mtx);
|
||||
SOCKSPLIST_WRITER_FOREACH(sp) {
|
||||
if (sp->state != IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
|
||||
key_unlink_sp(sp);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
key_destroy_sp(sp);
|
||||
goto retry_socksplist;
|
||||
}
|
||||
mutex_exit(&key_sp_mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -7537,6 +7646,9 @@ key_do_init(void)
|
||||
int i, error;
|
||||
|
||||
mutex_init(&key_mtx, MUTEX_DEFAULT, IPL_NONE);
|
||||
key_psz = pserialize_create();
|
||||
mutex_init(&key_sp_mtx, MUTEX_DEFAULT, IPL_NONE);
|
||||
cv_init(&key_sp_cv, "key_sp");
|
||||
|
||||
pfkeystat_percpu = percpu_alloc(sizeof(uint64_t) * PFKEY_NSTATS);
|
||||
|
||||
@ -7550,6 +7662,8 @@ key_do_init(void)
|
||||
PSLIST_INIT(&sptree[i]);
|
||||
}
|
||||
|
||||
PSLIST_INIT(&key_socksplist);
|
||||
|
||||
LIST_INIT(&sahtree);
|
||||
|
||||
for (i = 0; i <= SADB_SATYPE_MAX; i++) {
|
||||
@ -7565,11 +7679,13 @@ key_do_init(void)
|
||||
|
||||
/* system default */
|
||||
ip4_def_policy.policy = IPSEC_POLICY_NONE;
|
||||
ip4_def_policy.refcnt++; /*never reclaim this*/
|
||||
ip4_def_policy.state = IPSEC_SPSTATE_ALIVE;
|
||||
localcount_init(&ip4_def_policy.localcount);
|
||||
|
||||
#ifdef INET6
|
||||
ip6_def_policy.policy = IPSEC_POLICY_NONE;
|
||||
ip6_def_policy.refcnt++; /*never reclaim this*/
|
||||
ip6_def_policy.state = IPSEC_SPSTATE_ALIVE;
|
||||
localcount_init(&ip6_def_policy.localcount);
|
||||
#endif
|
||||
|
||||
callout_reset(&key_timehandler_ch, hz, key_timehandler, NULL);
|
||||
@ -7909,10 +8025,12 @@ key_setspddump(int *errorp, pid_t pid)
|
||||
u_int dir;
|
||||
struct mbuf *m, *n;
|
||||
|
||||
KASSERT(mutex_owned(&key_sp_mtx));
|
||||
|
||||
/* search SPD entry and get buffer size. */
|
||||
cnt = 0;
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
@ -7924,7 +8042,7 @@ key_setspddump(int *errorp, pid_t pid)
|
||||
|
||||
m = NULL;
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
SPLIST_READER_FOREACH(sp, dir) {
|
||||
SPLIST_WRITER_FOREACH(sp, dir) {
|
||||
--cnt;
|
||||
n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, pid);
|
||||
|
||||
@ -8029,16 +8147,16 @@ sysctl_net_key_dumpsp(SYSCTLFN_ARGS)
|
||||
int err2 = 0;
|
||||
char *p, *ep;
|
||||
size_t len;
|
||||
int s, error;
|
||||
int error;
|
||||
|
||||
if (newp)
|
||||
return (EPERM);
|
||||
if (namelen != 0)
|
||||
return (EINVAL);
|
||||
|
||||
s = splsoftnet();
|
||||
mutex_enter(&key_sp_mtx);
|
||||
m = key_setspddump(&error, l->l_proc->p_pid);
|
||||
splx(s);
|
||||
mutex_exit(&key_sp_mtx);
|
||||
if (!m)
|
||||
return (error);
|
||||
if (!oldp)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: key.h,v 1.25 2017/07/26 03:59:59 ozaki-r Exp $ */
|
||||
/* $NetBSD: key.h,v 1.26 2017/08/02 01:28:03 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 $ */
|
||||
|
||||
@ -55,11 +55,15 @@ struct secpolicy *key_gettunnel(const struct sockaddr *,
|
||||
const struct sockaddr *, const struct sockaddr *,
|
||||
const struct sockaddr *, const char*, int);
|
||||
/* NB: prepend with _ for KAME IPv6 compatbility */
|
||||
void _key_freesp(struct secpolicy **, const char*, int);
|
||||
void key_init_sp(struct secpolicy *);
|
||||
void key_free_sp(struct secpolicy *);
|
||||
u_int key_sp_refcnt(const struct secpolicy *);
|
||||
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_socksplist_add(struct secpolicy *);
|
||||
|
||||
/*
|
||||
* Access to the SADB are interlocked with splsoftnet. In particular,
|
||||
* holders of SA's use this to block accesses by protocol processing
|
||||
@ -73,8 +77,8 @@ void key_sa_ref(struct secasvar *, const char*, int);
|
||||
key_newsp(__func__, __LINE__)
|
||||
#define KEY_GETTUNNEL(osrc, odst, isrc, idst) \
|
||||
key_gettunnel(osrc, odst, isrc, idst, __func__, __LINE__)
|
||||
#define KEY_FREESP(spp) \
|
||||
_key_freesp(spp, __func__, __LINE__)
|
||||
#define KEY_SP_UNREF(spp) \
|
||||
key_sp_unref(*(spp), __func__, __LINE__)
|
||||
#define KEY_SP_REF(sp) \
|
||||
key_sp_ref(sp, __func__, __LINE__)
|
||||
#define KEY_SA_REF(sav) \
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: xform_ah.c,v 1.69 2017/07/27 06:59:28 ozaki-r Exp $ */
|
||||
/* $NetBSD: xform_ah.c,v 1.70 2017/08/02 01:28:03 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.69 2017/07/27 06:59:28 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.70 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_inet.h"
|
||||
@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.69 2017/07/27 06:59:28 ozaki-r Exp $"
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/pserialize.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
@ -1140,6 +1141,21 @@ ah_output(
|
||||
goto bad;
|
||||
}
|
||||
|
||||
{
|
||||
int s = pserialize_read_enter();
|
||||
|
||||
if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
|
||||
pserialize_read_exit(s);
|
||||
pool_put(&ah_tdb_crypto_pool, tc);
|
||||
crypto_freereq(crp);
|
||||
AH_STATINC(AH_STAT_NOTDB);
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
KEY_SP_REF(isr->sp);
|
||||
pserialize_read_exit(s);
|
||||
}
|
||||
|
||||
/* Crypto operation descriptor. */
|
||||
crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
|
||||
crp->crp_flags = CRYPTO_F_IMBUF;
|
||||
@ -1150,7 +1166,6 @@ ah_output(
|
||||
|
||||
/* These are passed as-is to the callback. */
|
||||
tc->tc_isr = isr;
|
||||
KEY_SP_REF(isr->sp);
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = sav->sah->saidx.dst;
|
||||
tc->tc_proto = sav->sah->saidx.proto;
|
||||
@ -1255,13 +1270,13 @@ ah_output_cb(struct cryptop *crp)
|
||||
/* NB: m is reclaimed by ipsec_process_done. */
|
||||
err = ipsec_process_done(m, isr, sav);
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
return err;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
if (m)
|
||||
m_freem(m);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: xform_esp.c,v 1.67 2017/07/27 06:59:28 ozaki-r Exp $ */
|
||||
/* $NetBSD: xform_esp.c,v 1.68 2017/08/02 01:28:03 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.67 2017/07/27 06:59:28 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.68 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_inet.h"
|
||||
@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.67 2017/07/27 06:59:28 ozaki-r Exp $
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/cprng.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/pserialize.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
@ -897,9 +898,23 @@ esp_output(
|
||||
goto bad;
|
||||
}
|
||||
|
||||
{
|
||||
int s = pserialize_read_enter();
|
||||
|
||||
if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
|
||||
pserialize_read_exit(s);
|
||||
pool_put(&esp_tdb_crypto_pool, tc);
|
||||
crypto_freereq(crp);
|
||||
ESP_STATINC(ESP_STAT_NOTDB);
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
KEY_SP_REF(isr->sp);
|
||||
pserialize_read_exit(s);
|
||||
}
|
||||
|
||||
/* Callback parameters */
|
||||
tc->tc_isr = isr;
|
||||
KEY_SP_REF(isr->sp);
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = saidx->dst;
|
||||
tc->tc_proto = saidx->proto;
|
||||
@ -1032,13 +1047,13 @@ esp_output_cb(struct cryptop *crp)
|
||||
/* NB: m is reclaimed by ipsec_process_done. */
|
||||
err = ipsec_process_done(m, isr, sav);
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
return err;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
if (m)
|
||||
m_freem(m);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: xform_ipcomp.c,v 1.48 2017/07/27 06:59:28 ozaki-r Exp $ */
|
||||
/* $NetBSD: xform_ipcomp.c,v 1.49 2017/08/02 01:28:03 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.48 2017/07/27 06:59:28 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.49 2017/08/02 01:28:03 ozaki-r Exp $");
|
||||
|
||||
/* IP payload compression protocol (IPComp), see RFC 2393 */
|
||||
#if defined(_KERNEL_OPT)
|
||||
@ -45,6 +45,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.48 2017/07/27 06:59:28 ozaki-r Ex
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/pserialize.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
@ -479,8 +480,22 @@ ipcomp_output(
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tc->tc_isr = isr;
|
||||
{
|
||||
int s = pserialize_read_enter();
|
||||
|
||||
if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
|
||||
pserialize_read_exit(s);
|
||||
pool_put(&ipcomp_tdb_crypto_pool, tc);
|
||||
crypto_freereq(crp);
|
||||
IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
KEY_SP_REF(isr->sp);
|
||||
pserialize_read_exit(s);
|
||||
}
|
||||
|
||||
tc->tc_isr = isr;
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = sav->sah->saidx.dst;
|
||||
tc->tc_proto = sav->sah->saidx.proto;
|
||||
@ -646,13 +661,13 @@ ipcomp_output_cb(struct cryptop *crp)
|
||||
/* NB: m is reclaimed by ipsec_process_done. */
|
||||
error = ipsec_process_done(m, isr, sav);
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
return error;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
KEY_FREESP(&isr->sp);
|
||||
KEY_SP_UNREF(&isr->sp);
|
||||
IPSEC_RELEASE_GLOBAL_LOCKS();
|
||||
if (m)
|
||||
m_freem(m);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: net_stub.c,v 1.26 2017/04/14 02:43:28 ozaki-r Exp $ */
|
||||
/* $NetBSD: net_stub.c,v 1.27 2017/08/02 01:28:02 ozaki-r Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Antti Kantee. All Rights Reserved.
|
||||
@ -26,7 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: net_stub.c,v 1.26 2017/04/14 02:43:28 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: net_stub.c,v 1.27 2017/08/02 01:28:02 ozaki-r Exp $");
|
||||
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/param.h>
|
||||
@ -108,7 +108,7 @@ __weak_alias(ipsec_init_policy,rumpnet_stub);
|
||||
__weak_alias(ipsec_pcbconn,rumpnet_stub);
|
||||
__weak_alias(ipsec_pcbdisconn,rumpnet_stub);
|
||||
__weak_alias(key_sa_routechange,rumpnet_stub);
|
||||
__weak_alias(_key_freesp,rumpnet_stub);
|
||||
__weak_alias(key_sp_unref,rumpnet_stub);
|
||||
|
||||
struct ifnet_head ifnet_list;
|
||||
struct pslist_head ifnet_pslist;
|
||||
|
Loading…
Reference in New Issue
Block a user