Fix witness warning in xform_init().

Do not call crypto_newsession() while holding xforms_lock mutex.
Release mutex before invoking crypto_newsession(), and use
ipsec_kmod_enter()/ipsec_kmod_exit() functions to protect from doing
access to unloaded kernel module memory.

Move xform-releated functions into subr_ipsec.c to be able use
ipsec_kmod_* functions. Also unconditionally build ipsec_kmod_*
functions, since now they are always used by IPSec code.

Add xf_cntr field to struct xformsw, it is used by ipsec_kmod_*
functions. Also constify xf_name field, since it is not expected to be
modified.

Approved by:	re (kib)
Differential Revision:	https://reviews.freebsd.org/D17302
This commit is contained in:
Andrey V. Elsukov 2018-09-26 14:47:51 +00:00
parent 6f282e722e
commit 0ddfd867ed
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=338945
4 changed files with 87 additions and 90 deletions

View File

@ -534,14 +534,6 @@ MALLOC_DEFINE(M_IPSEC_SPDCACHE, "ipsec-spdcache", "ipsec SPD cache");
VNET_DEFINE_STATIC(uma_zone_t, key_lft_zone);
#define V_key_lft_zone VNET(key_lft_zone)
static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
static struct mtx xforms_lock;
#define XFORMS_LOCK_INIT() \
mtx_init(&xforms_lock, "xforms_list", "IPsec transforms list", MTX_DEF)
#define XFORMS_LOCK_DESTROY() mtx_destroy(&xforms_lock)
#define XFORMS_LOCK() mtx_lock(&xforms_lock)
#define XFORMS_UNLOCK() mtx_unlock(&xforms_lock)
/*
* set parameters into secpolicyindex buffer.
* Must allocate secpolicyindex buffer passed to this function.
@ -717,7 +709,6 @@ static int key_delete(struct socket *, struct mbuf *,
const struct sadb_msghdr *);
static int key_delete_all(struct socket *, struct mbuf *,
const struct sadb_msghdr *, struct secasindex *);
static void key_delete_xform(const struct xformsw *);
static int key_get(struct socket *, struct mbuf *,
const struct sadb_msghdr *);
@ -750,7 +741,6 @@ static int key_validate_ext(const struct sadb_ext *, int);
static int key_align(struct mbuf *, struct sadb_msghdr *);
static struct mbuf *key_setlifetime(struct seclifetime *, uint16_t);
static struct mbuf *key_setkey(struct seckey *, uint16_t);
static int xform_init(struct secasvar *, u_short);
static void spdcache_init(void);
static void spdcache_clear(void);
@ -6167,7 +6157,7 @@ key_delete_all(struct socket *so, struct mbuf *m,
* Larval SAs have not initialized tdb_xform, so it is safe to leave them
* here when xform disappears.
*/
static void
void
key_delete_xform(const struct xformsw *xsp)
{
struct secasvar_queue drainq;
@ -8335,7 +8325,6 @@ key_init(void)
if (!IS_DEFAULT_VNET(curvnet))
return;
XFORMS_LOCK_INIT();
SPTREE_LOCK_INIT();
REGTREE_LOCK_INIT();
SAHTREE_LOCK_INIT();
@ -8458,7 +8447,6 @@ key_destroy(void)
#ifndef IPSEC_DEBUG2
callout_drain(&key_timer);
#endif
XFORMS_LOCK_DESTROY();
SPTREE_LOCK_DESTROY();
REGTREE_LOCK_DESTROY();
SAHTREE_LOCK_DESTROY();
@ -8617,70 +8605,3 @@ comp_algorithm_lookup(int alg)
return (NULL);
}
/*
* Register a transform.
*/
static int
xform_register(struct xformsw* xsp)
{
struct xformsw *entry;
XFORMS_LOCK();
LIST_FOREACH(entry, &xforms, chain) {
if (entry->xf_type == xsp->xf_type) {
XFORMS_UNLOCK();
return (EEXIST);
}
}
LIST_INSERT_HEAD(&xforms, xsp, chain);
XFORMS_UNLOCK();
return (0);
}
void
xform_attach(void *data)
{
struct xformsw *xsp = (struct xformsw *)data;
if (xform_register(xsp) != 0)
printf("%s: failed to register %s xform\n", __func__,
xsp->xf_name);
}
void
xform_detach(void *data)
{
struct xformsw *xsp = (struct xformsw *)data;
XFORMS_LOCK();
LIST_REMOVE(xsp, chain);
XFORMS_UNLOCK();
/* Delete all SAs related to this xform. */
key_delete_xform(xsp);
}
/*
* Initialize transform support in an sav.
*/
static int
xform_init(struct secasvar *sav, u_short xftype)
{
struct xformsw *entry;
int ret;
IPSEC_ASSERT(sav->tdb_xform == NULL,
("tdb_xform is already initialized"));
ret = EINVAL;
XFORMS_LOCK();
LIST_FOREACH(entry, &xforms, chain) {
if (entry->xf_type == xftype) {
ret = (*entry->xf_init)(sav, entry);
break;
}
}
XFORMS_UNLOCK();
return (ret);
}

View File

@ -46,6 +46,7 @@ struct sadb_msg;
struct sadb_x_policy;
struct secasindex;
union sockaddr_union;
struct xformsw;
struct secpolicy *key_newsp(void);
struct secpolicy *key_allocsp(struct secpolicyindex *, u_int);
@ -74,6 +75,8 @@ int key_sockaddrcmp_withmask(const struct sockaddr *, const struct sockaddr *,
int key_register_ifnet(struct secpolicy **, u_int);
void key_unregister_ifnet(struct secpolicy **, u_int);
void key_delete_xform(const struct xformsw *);
extern u_long key_random(void);
extern void key_randomfill(void *, size_t);
extern void key_freereg(struct socket *);

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <netipsec/ipsec6.h>
#include <netipsec/key.h>
#include <netipsec/key_debug.h>
#include <netipsec/xform.h>
#include <machine/atomic.h>
/*
@ -124,14 +125,6 @@ ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
}
#endif
#ifdef IPSEC_SUPPORT
/*
* IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
* IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
* IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
* IPSEC_SUPPORT.
*/
#if !defined(IPSEC) || !defined(TCP_SIGNATURE)
#define IPSEC_MODULE_INCR 2
static int
ipsec_kmod_enter(volatile u_int *cntr)
@ -171,6 +164,83 @@ ipsec_kmod_drain(volatile u_int *cntr)
pause("ipsecd", hz/2);
}
static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
static struct mtx xforms_lock;
MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
#define XFORMS_LOCK() mtx_lock(&xforms_lock)
#define XFORMS_UNLOCK() mtx_unlock(&xforms_lock)
void
xform_attach(void *data)
{
struct xformsw *xsp, *entry;
xsp = (struct xformsw *)data;
XFORMS_LOCK();
LIST_FOREACH(entry, &xforms, chain) {
if (entry->xf_type == xsp->xf_type) {
XFORMS_UNLOCK();
printf("%s: failed to register %s xform\n",
__func__, xsp->xf_name);
return;
}
}
LIST_INSERT_HEAD(&xforms, xsp, chain);
xsp->xf_cntr = IPSEC_MODULE_ENABLED;
XFORMS_UNLOCK();
}
void
xform_detach(void *data)
{
struct xformsw *xsp = (struct xformsw *)data;
XFORMS_LOCK();
LIST_REMOVE(xsp, chain);
XFORMS_UNLOCK();
/* Delete all SAs related to this xform. */
key_delete_xform(xsp);
if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
ipsec_kmod_drain(&xsp->xf_cntr);
}
/*
* Initialize transform support in an sav.
*/
int
xform_init(struct secasvar *sav, u_short xftype)
{
struct xformsw *entry;
int ret;
IPSEC_ASSERT(sav->tdb_xform == NULL,
("tdb_xform is already initialized"));
XFORMS_LOCK();
LIST_FOREACH(entry, &xforms, chain) {
if (entry->xf_type == xftype) {
ret = ipsec_kmod_enter(&entry->xf_cntr);
XFORMS_UNLOCK();
if (ret != 0)
return (ret);
ret = (*entry->xf_init)(sav, entry);
ipsec_kmod_exit(&entry->xf_cntr);
return (ret);
}
}
XFORMS_UNLOCK();
return (EINVAL);
}
#ifdef IPSEC_SUPPORT
/*
* IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
* IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
* IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
* IPSEC_SUPPORT.
*/
#if !defined(IPSEC) || !defined(TCP_SIGNATURE)
#define METHOD_DECL(...) __VA_ARGS__
#define METHOD_ARGS(...) __VA_ARGS__
#define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args) \

View File

@ -86,14 +86,16 @@ struct xform_data {
#define XF_IPCOMP 6 /* IPCOMP */
struct xformsw {
u_short xf_type; /* xform ID */
char *xf_name; /* human-readable name */
u_short xf_type; /* xform ID */
const char *xf_name; /* human-readable name */
int (*xf_init)(struct secasvar*, struct xformsw*); /* setup */
int (*xf_zeroize)(struct secasvar*); /* cleanup */
int (*xf_input)(struct mbuf*, struct secasvar*, /* input */
int, int);
int (*xf_output)(struct mbuf*, /* output */
struct secpolicy *, struct secasvar *, u_int, int, int);
volatile u_int xf_cntr;
LIST_ENTRY(xformsw) chain;
};
@ -103,6 +105,7 @@ const struct comp_algo * comp_algorithm_lookup(int);
void xform_attach(void *);
void xform_detach(void *);
int xform_init(struct secasvar *, u_short);
struct cryptoini;
/* XF_AH */