From f3677984987fe59475b99a6b3f69e1ec683c8e67 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Wed, 30 Sep 2015 08:16:33 +0000 Subject: [PATCH] Take extra reference to security policy before calling crypto_dispatch(). Currently we perform crypto requests for IPSEC synchronous for most of crypto providers (software, aesni) and only VIA padlock calls crypto callback asynchronous. In synchronous mode it is possible, that security policy will be removed during the processing crypto request. And crypto callback will release the last reference to SP. Then upon return into ipsec[46]_process_packet() IPSECREQUEST_UNLOCK() will be called to already freed request. To prevent this we will take extra reference to SP. PR: 201876 Sponsored by: Yandex LLC --- sys/netinet/ip_ipsec.c | 4 +--- sys/netinet6/ip6_ipsec.c | 4 +--- sys/netipsec/ipsec_output.c | 16 ++-------------- sys/netipsec/xform_ah.c | 1 + sys/netipsec/xform_esp.c | 1 + sys/netipsec/xform_ipcomp.c | 1 + 6 files changed, 7 insertions(+), 20 deletions(-) diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c index 47f683ddd71c..546f802f9617 100644 --- a/sys/netinet/ip_ipsec.c +++ b/sys/netinet/ip_ipsec.c @@ -199,9 +199,7 @@ ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error) /* NB: callee frees mbuf */ *error = ipsec4_process_packet(*m, sp->req); - /* Release SP if an error occured */ - if (*error != 0) - KEY_FREESP(&sp); + KEY_FREESP(&sp); if (*error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We diff --git a/sys/netinet6/ip6_ipsec.c b/sys/netinet6/ip6_ipsec.c index d7f08e91537c..a99f1db14e8e 100644 --- a/sys/netinet6/ip6_ipsec.c +++ b/sys/netinet6/ip6_ipsec.c @@ -200,9 +200,7 @@ ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error) /* NB: callee frees mbuf */ *error = ipsec6_process_packet(*m, sp->req); - /* Release SP if an error occured */ - if (*error != 0) - KEY_FREESP(&sp); + KEY_FREESP(&sp); if (*error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index a6611a7e7fcb..f5cdf5a417b6 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -166,10 +166,6 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) * If this is a problem we'll need to introduce a queue * to set the packet on so we can unwind the stack before * doing further processing. - * - * If ipsec[46]_process_packet() will successfully queue - * the request, we need to take additional reference to SP, - * because xform callback will release reference. */ if (isr->next) { /* XXX-BZ currently only support same AF bundles. */ @@ -177,11 +173,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) #ifdef INET case AF_INET: IPSECSTAT_INC(ips_out_bundlesa); - key_addref(isr->sp); - error = ipsec4_process_packet(m, isr->next); - if (error != 0) - KEY_FREESP(&isr->sp); - return (error); + return (ipsec4_process_packet(m, isr->next)); /* NOTREACHED */ #endif #ifdef notyet @@ -189,11 +181,7 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) case AF_INET6: /* XXX */ IPSEC6STAT_INC(ips_out_bundlesa); - key_addref(isr->sp); - error = ipsec6_process_packet(m, isr->next); - if (error != 0) - KEY_FREESP(&isr->sp); - return (error); + return (ipsec6_process_packet(m, isr->next)); /* NOTREACHED */ #endif /* INET6 */ #endif diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index 350a735a89b3..0d39eeba49ad 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -1068,6 +1068,7 @@ ah_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, crp->crp_opaque = (caddr_t) tc; /* These are passed as-is to the callback. */ + key_addref(isr->sp); tc->tc_isr = isr; KEY_ADDREFSA(sav); tc->tc_sav = sav; diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c index a48c0386b9af..9f645c0c4f55 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -874,6 +874,7 @@ esp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, } /* Callback parameters */ + key_addref(isr->sp); tc->tc_isr = isr; KEY_ADDREFSA(sav); tc->tc_sav = sav; diff --git a/sys/netipsec/xform_ipcomp.c b/sys/netipsec/xform_ipcomp.c index ef460cdc90dc..122fc7261378 100644 --- a/sys/netipsec/xform_ipcomp.c +++ b/sys/netipsec/xform_ipcomp.c @@ -449,6 +449,7 @@ ipcomp_output(struct mbuf *m, struct ipsecrequest *isr, struct mbuf **mp, goto bad; } + key_addref(isr->sp); tc->tc_isr = isr; KEY_ADDREFSA(sav); tc->tc_sav = sav;