mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
sys/netipsec: ensure sah stability during input callback processing
Citing ae: this fixes some rare panics, that are reported in derived projects: `panic: esp_input_cb: Unexpected address family'. Reported by: ae Tested by: ae, Daniel Dubnikov <ddaniel@nvidia.com> Reviewed by: ae, Ariel Ehrenberg <aehrenberg@nvidia.com> (previous version) Sponsored by: NVidia networking MFC after: 1 week Differential revision: https://reviews.freebsd.org/D54325
This commit is contained in:
parent
3b1126208f
commit
183513d15f
7 changed files with 68 additions and 15 deletions
|
|
@ -450,7 +450,8 @@ ipsec_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
|||
}
|
||||
|
||||
int
|
||||
ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
|
||||
ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af,
|
||||
struct rm_priotracker *sahtree_tracker)
|
||||
{
|
||||
IPSEC_RLOCK_TRACKER;
|
||||
struct secasindex *saidx;
|
||||
|
|
@ -459,13 +460,16 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
|
|||
|
||||
if (sav->state != SADB_SASTATE_MATURE &&
|
||||
sav->state != SADB_SASTATE_DYING) {
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
m_freem(m);
|
||||
return (ENETDOWN);
|
||||
}
|
||||
|
||||
if (sav->sah->saidx.mode != IPSEC_MODE_TUNNEL ||
|
||||
sav->sah->saidx.proto != IPPROTO_ESP)
|
||||
sav->sah->saidx.proto != IPPROTO_ESP) {
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
return (0);
|
||||
}
|
||||
|
||||
IPSEC_RLOCK();
|
||||
CK_LIST_FOREACH(sc, ipsec_idhash(sav->sah->saidx.reqid), idhash) {
|
||||
|
|
@ -487,6 +491,7 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
|
|||
}
|
||||
if (sc == NULL) {
|
||||
IPSEC_RUNLOCK();
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
/* Tunnel was not found. Nothing to do. */
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -494,6 +499,7 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
|
|||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
|
||||
(ifp->if_flags & IFF_UP) == 0) {
|
||||
IPSEC_RUNLOCK();
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
m_freem(m);
|
||||
return (ENETDOWN);
|
||||
}
|
||||
|
|
@ -503,6 +509,8 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af)
|
|||
*/
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
|
||||
m_clrprotoflags(m);
|
||||
M_SETFIB(m, ifp->if_fib);
|
||||
BPF_MTAP2(ifp, &af, sizeof(af), m);
|
||||
|
|
|
|||
|
|
@ -330,12 +330,14 @@ VNET_DECLARE(int, natt_cksum_policy);
|
|||
struct inpcb;
|
||||
struct ip;
|
||||
struct m_tag;
|
||||
struct rm_priotracker;
|
||||
struct secasvar;
|
||||
struct sockopt;
|
||||
struct tcphdr;
|
||||
union sockaddr_union;
|
||||
|
||||
int ipsec_if_input(struct mbuf *, struct secasvar *, uint32_t);
|
||||
int ipsec_if_input(struct mbuf *, struct secasvar *, uint32_t,
|
||||
struct rm_priotracker *);
|
||||
|
||||
struct ipsecrequest *ipsec_newisr(void);
|
||||
void ipsec_delisr(struct ipsecrequest *);
|
||||
|
|
@ -357,7 +359,8 @@ void ipsec_setspidx_inpcb(struct inpcb *, struct secpolicyindex *, u_int);
|
|||
|
||||
void ipsec4_setsockaddrs(const struct mbuf *, const struct ip *,
|
||||
union sockaddr_union *, union sockaddr_union *);
|
||||
int ipsec4_common_input_cb(struct mbuf *, struct secasvar *, int, int);
|
||||
int ipsec4_common_input_cb(struct mbuf *, struct secasvar *, int, int,
|
||||
struct rm_priotracker *sahtree_tracker);
|
||||
int ipsec4_check_pmtu(struct ifnet *, struct mbuf *, struct ip *ip1,
|
||||
struct secpolicy *, int);
|
||||
int ipsec4_process_packet(struct ifnet *, struct mbuf *, struct ip *ip1,
|
||||
|
|
|
|||
|
|
@ -60,12 +60,15 @@ VNET_DECLARE(int, ip6_ipsec_ecn);
|
|||
#define V_ip6_ipsec_ecn VNET(ip6_ipsec_ecn)
|
||||
|
||||
struct inpcb;
|
||||
struct rm_priotracker;
|
||||
|
||||
struct secpolicy *ipsec6_checkpolicy(const struct mbuf *,
|
||||
struct inpcb *, int *, int);
|
||||
|
||||
void ipsec6_setsockaddrs(const struct mbuf *, union sockaddr_union *,
|
||||
union sockaddr_union *);
|
||||
int ipsec6_common_input_cb(struct mbuf *, struct secasvar *, int, int);
|
||||
int ipsec6_common_input_cb(struct mbuf *, struct secasvar *, int, int,
|
||||
struct rm_priotracker *sahtree_tracker);
|
||||
int ipsec6_check_pmtu(struct ifnet *, struct mbuf *, struct secpolicy *, int);
|
||||
int ipsec6_process_packet(struct ifnet *, struct mbuf *, struct secpolicy *,
|
||||
struct inpcb *, u_long);
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ ipsec4_ctlinput(ipsec_ctlinput_param_t param)
|
|||
*/
|
||||
int
|
||||
ipsec4_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;
|
||||
|
|
@ -492,7 +492,9 @@ ipsec4_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);
|
||||
if (error) {
|
||||
|
|
@ -507,6 +509,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
|
|||
bad:
|
||||
NET_EPOCH_EXIT(et);
|
||||
bad_noepoch:
|
||||
ipsec_sahtree_runlock(sahtree_tracker);
|
||||
key_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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue