Module Name: src
Committed By: martin
Date: Mon Feb 26 13:10:52 UTC 2018
Modified Files:
src/sys/netipsec [netbsd-8]: xform_ah.c xform_esp.c xform_ipcomp.c
Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #587):
sys/netipsec/xform_ipcomp.c: revision 1.54-1.56
sys/netipsec/xform_ah.c: revision 1.78,1.79(patch),1.82-1.84
sys/netipsec/xform_esp.c: revision 1.74-1.76
Fix mbuf leaks on error paths
Dedup common codes in error paths (NFCI)
Don't relook up an SP/SA in opencrpyto callbacks
We don't need to do so because we have a reference to it. And also
relooking-up one there may return an sp/sav that has different
parameters from an original one.
Fix kernel panic (assertion failure) on receiving an IPv6 packet with large
options
If an IPv6 packet has large options, a necessary space for evacuation can
exceed the expected size (ah_pool_item_size). Give up using the pool_cache
if it happens.
Style.
Commonalize error paths (NFC)
Fix buffer overflow on sending an IPv6 packet with large options
If an IPv6 packet has large options, a necessary space for evacuation can
exceed the expected size (ah_pool_item_size). Give up using the pool_cache
if it happens.
Pointed out by maxv@
To generate a diff of this commit:
cvs rdiff -u -r1.54.2.3 -r1.54.2.4 src/sys/netipsec/xform_ah.c
cvs rdiff -u -r1.55.2.1 -r1.55.2.2 src/sys/netipsec/xform_esp.c
cvs rdiff -u -r1.38.2.1 -r1.38.2.2 src/sys/netipsec/xform_ipcomp.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netipsec/xform_ah.c
diff -u src/sys/netipsec/xform_ah.c:1.54.2.3 src/sys/netipsec/xform_ah.c:1.54.2.4
--- src/sys/netipsec/xform_ah.c:1.54.2.3 Thu Feb 15 07:58:04 2018
+++ src/sys/netipsec/xform_ah.c Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: xform_ah.c,v 1.54.2.3 2018/02/15 07:58:04 martin Exp $ */
+/* $NetBSD: xform_ah.c,v 1.54.2.4 2018/02/26 13:10:52 martin 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.54.2.3 2018/02/15 07:58:04 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.54.2.4 2018/02/26 13:10:52 martin Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v
#include <sys/sysctl.h>
#include <sys/pool.h>
#include <sys/pserialize.h>
+#include <sys/kmem.h>
#include <net/if.h>
@@ -100,8 +101,8 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v
percpu_t *ahstat_percpu;
-int ah_enable = 1; /* control flow of packets with AH */
-int ip4_ah_cleartos = 1; /* clear ip_tos when doing AH calc */
+int ah_enable = 1; /* control flow of packets with AH */
+int ip4_ah_cleartos = 1; /* clear ip_tos when doing AH calc */
#ifdef __FreeBSD__
SYSCTL_DECL(_net_inet_ah);
@@ -111,7 +112,6 @@ SYSCTL_INT(_net_inet_ah, OID_AUTO,
ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, "");
SYSCTL_STRUCT(_net_inet_ah, IPSECCTL_STATS,
stats, CTLFLAG_RD, &ahstat, ahstat, "");
-
#endif /* __FreeBSD__ */
static unsigned char ipseczeroes[256]; /* larger than an ip6 extension hdr */
@@ -277,17 +277,15 @@ ah_massage_headers(struct mbuf **m0, int
struct mbuf *m = *m0;
unsigned char *ptr;
int off, count;
-
#ifdef INET
struct ip *ip;
-#endif /* INET */
-
+#endif
#ifdef INET6
struct ip6_ext *ip6e;
struct ip6_hdr ip6;
struct ip6_rthdr *rh;
int alloc, ad, nxt;
-#endif /* INET6 */
+#endif
switch (proto) {
#ifdef INET
@@ -428,7 +426,6 @@ ah_massage_headers(struct mbuf **m0, int
if (off > skip) {
DPRINTF(("%s: malformed IPv4 options header\n",
__func__));
-
m_freem(m);
return EINVAL;
}
@@ -629,6 +626,7 @@ ah_input(struct mbuf *m, struct secasvar
struct cryptodesc *crda;
struct cryptop *crp = NULL;
uint8_t nxt;
+ bool pool_used;
IPSEC_SPLASSERT_SOFTNET(__func__);
@@ -715,9 +713,14 @@ ah_input(struct mbuf *m, struct secasvar
size_t extra = skip + rplen + authsize;
size += extra;
- KASSERTMSG(size <= ah_pool_item_size,
- "size=%zu > ah_pool_item_size=%zu\n", size, ah_pool_item_size);
- tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+ if (__predict_true(size <= ah_pool_item_size)) {
+ tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+ pool_used = true;
+ } else {
+ /* size can exceed on IPv6 packets with large options. */
+ tc = kmem_intr_zalloc(size, KM_NOSLEEP);
+ pool_used = false;
+ }
if (tc == NULL) {
DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
stat = AH_STAT_CRYPTO;
@@ -789,8 +792,12 @@ ah_input(struct mbuf *m, struct secasvar
return crypto_dispatch(crp);
bad:
- if (tc != NULL)
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ if (tc != NULL) {
+ if (__predict_true(pool_used))
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
+ }
if (crp != NULL)
crypto_freereq(crp);
if (m != NULL)
@@ -830,6 +837,8 @@ ah_input_cb(struct cryptop *crp)
int authsize;
uint16_t dport;
uint16_t sport;
+ bool pool_used;
+ size_t size;
IPSEC_DECLARE_LOCK_VARIABLE;
KASSERT(crp->crp_opaque != NULL);
@@ -863,6 +872,16 @@ ah_input_cb(struct cryptop *crp)
saidx->dst.sa.sa_family == AF_INET6,
"unexpected protocol family %u", saidx->dst.sa.sa_family);
+ /* Figure out header size. */
+ rplen = HDRSIZE(sav);
+ authsize = AUTHSIZE(sav);
+
+ size = sizeof(*tc) + skip + rplen + authsize;
+ if (__predict_true(size <= ah_pool_item_size))
+ pool_used = true;
+ else
+ pool_used = false;
+
/* Check for crypto errors. */
if (crp->crp_etype) {
if (sav->tdb_cryptoid != 0)
@@ -883,10 +902,6 @@ ah_input_cb(struct cryptop *crp)
crp = NULL;
}
- /* Figure out header size. */
- rplen = HDRSIZE(sav);
- authsize = AUTHSIZE(sav);
-
if (ipsec_debug)
memset(calc, 0, sizeof(calc));
@@ -924,7 +939,10 @@ ah_input_cb(struct cryptop *crp)
/* Copyback the saved (uncooked) network headers. */
m_copyback(m, 0, skip, ptr);
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ if (__predict_true(pool_used))
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
tc = NULL;
/*
@@ -942,7 +960,7 @@ ah_input_cb(struct cryptop *crp)
sizeof(seq), &seq);
if (ipsec_updatereplay(ntohl(seq), sav)) {
AH_STATINC(AH_STAT_REPLAY);
- error = ENOBUFS; /*XXX as above*/
+ error = ENOBUFS; /* XXX as above */
goto bad;
}
}
@@ -965,14 +983,19 @@ ah_input_cb(struct cryptop *crp)
KEY_SA_UNREF(&sav);
IPSEC_RELEASE_GLOBAL_LOCKS();
return error;
+
bad:
if (sav)
KEY_SA_UNREF(&sav);
IPSEC_RELEASE_GLOBAL_LOCKS();
if (m != NULL)
m_freem(m);
- if (tc != NULL)
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ if (tc != NULL) {
+ if (pool_used)
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
+ }
if (crp != NULL)
crypto_freereq(crp);
return error;
@@ -982,14 +1005,8 @@ bad:
* AH output routine, called by ipsec[46]_process_packet().
*/
static int
-ah_output(
- struct mbuf *m,
- const struct ipsecrequest *isr,
- struct secasvar *sav,
- struct mbuf **mp,
- int skip,
- int protoff
-)
+ah_output(struct mbuf *m, const struct ipsecrequest *isr, struct secasvar *sav,
+ struct mbuf **mp, int skip, int protoff)
{
char buf[IPSEC_ADDRSTRLEN];
const struct auth_hash *ahx;
@@ -1001,6 +1018,8 @@ ah_output(
int error, rplen, authsize, maxpacketsize, roff;
uint8_t prot;
struct newah *ah;
+ size_t ipoffs;
+ bool pool_used;
IPSEC_SPLASSERT_SOFTNET(__func__);
@@ -1013,7 +1032,6 @@ ah_output(
/* Figure out header size. */
rplen = HDRSIZE(sav);
- size_t ipoffs;
/* Check for maximum packet size violations. */
switch (sav->sah->saidx.dst.sa.sa_family) {
#ifdef INET
@@ -1021,13 +1039,13 @@ ah_output(
maxpacketsize = IP_MAXPACKET;
ipoffs = offsetof(struct ip, ip_len);
break;
-#endif /* INET */
+#endif
#ifdef INET6
case AF_INET6:
maxpacketsize = IPV6_MAXPACKET;
ipoffs = offsetof(struct ip6_hdr, ip6_plen);
break;
-#endif /* INET6 */
+#endif
default:
DPRINTF(("%s: unknown/unsupported protocol "
"family %u, SA %s/%08lx\n", __func__,
@@ -1071,7 +1089,7 @@ ah_output(
rplen + authsize,
ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
- AH_STATINC(AH_STAT_HDROPS); /*XXX differs from openbsd */
+ AH_STATINC(AH_STAT_HDROPS);
error = ENOBUFS;
goto bad;
}
@@ -1132,13 +1150,21 @@ ah_output(
crda->crd_klen = _KEYBITS(sav->key_auth);
/* Allocate IPsec-specific opaque crypto info. */
- tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+ size_t size = sizeof(*tc) + skip;
+
+ if (__predict_true(size <= ah_pool_item_size)) {
+ tc = pool_cache_get(ah_tdb_crypto_pool_cache, PR_NOWAIT);
+ pool_used = true;
+ } else {
+ /* size can exceed on IPv6 packets with large options. */
+ tc = kmem_intr_zalloc(size, KM_NOSLEEP);
+ pool_used = false;
+ }
if (tc == NULL) {
- crypto_freereq(crp);
DPRINTF(("%s: failed to allocate tdb_crypto\n", __func__));
AH_STATINC(AH_STAT_CRYPTO);
error = ENOBUFS;
- goto bad;
+ goto bad_crp;
}
uint8_t *pext = (char *)(tc + 1);
@@ -1166,9 +1192,7 @@ ah_output(
skip, ahx->type, 1);
if (error != 0) {
m = NULL; /* mbuf was free'd by ah_massage_headers. */
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
- crypto_freereq(crp);
- goto bad;
+ goto bad_tc;
}
{
@@ -1180,11 +1204,9 @@ ah_output(
if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD ||
sav->state == SADB_SASTATE_DEAD)) {
pserialize_read_exit(s);
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
- crypto_freereq(crp);
AH_STATINC(AH_STAT_NOTDB);
error = ENOENT;
- goto bad;
+ goto bad_tc;
}
KEY_SP_REF(isr->sp);
KEY_SA_REF(sav);
@@ -1209,6 +1231,14 @@ ah_output(
tc->tc_sav = sav;
return crypto_dispatch(crp);
+
+bad_tc:
+ if (__predict_true(pool_used))
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
+bad_crp:
+ crypto_freereq(crp);
bad:
if (m)
m_freem(m);
@@ -1228,6 +1258,8 @@ ah_output_cb(struct cryptop *crp)
struct mbuf *m;
void *ptr;
int err;
+ size_t size;
+ bool pool_used;
IPSEC_DECLARE_LOCK_VARIABLE;
KASSERT(crp->crp_opaque != NULL);
@@ -1235,6 +1267,8 @@ ah_output_cb(struct cryptop *crp)
skip = tc->tc_skip;
ptr = (tc + 1);
m = crp->crp_buf;
+ size = sizeof(*tc) + skip;
+ pool_used = size <= ah_pool_item_size;
IPSEC_ACQUIRE_GLOBAL_LOCKS();
@@ -1284,7 +1318,10 @@ ah_output_cb(struct cryptop *crp)
m_copyback(m, 0, skip, ptr);
/* No longer needed. */
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ if (__predict_true(pool_used))
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
crypto_freereq(crp);
#ifdef IPSEC_DEBUG
@@ -1314,7 +1351,10 @@ bad:
IPSEC_RELEASE_GLOBAL_LOCKS();
if (m)
m_freem(m);
- pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ if (__predict_true(pool_used))
+ pool_cache_put(ah_tdb_crypto_pool_cache, tc);
+ else
+ kmem_intr_free(tc, size);
crypto_freereq(crp);
return error;
}
Index: src/sys/netipsec/xform_esp.c
diff -u src/sys/netipsec/xform_esp.c:1.55.2.1 src/sys/netipsec/xform_esp.c:1.55.2.2
--- src/sys/netipsec/xform_esp.c:1.55.2.1 Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/xform_esp.c Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: xform_esp.c,v 1.55.2.1 2017/10/21 19:43:54 snj Exp $ */
+/* $NetBSD: xform_esp.c,v 1.55.2.2 2018/02/26 13:10:52 martin 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.55.2.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.55.2.2 2018/02/26 13:10:52 martin Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -87,17 +87,15 @@ __KERNEL_RCSID(0, "$NetBSD: xform_esp.c,
percpu_t *espstat_percpu;
-int esp_enable = 1;
+int esp_enable = 1;
#ifdef __FreeBSD__
SYSCTL_DECL(_net_inet_esp);
SYSCTL_INT(_net_inet_esp, OID_AUTO,
esp_enable, CTLFLAG_RW, &esp_enable, 0, "");
-SYSCTL_STRUCT(_net_inet_esp, IPSECCTL_STATS,
- stats, CTLFLAG_RD, &espstat, espstat, "");
#endif /* __FreeBSD__ */
-static int esp_max_ivlen; /* max iv length over all algorithms */
+static int esp_max_ivlen; /* max iv length over all algorithms */
static int esp_input_cb(struct cryptop *op);
static int esp_output_cb(struct cryptop *crp);
@@ -306,9 +304,8 @@ esp_input(struct mbuf *m, struct secasva
const struct auth_hash *esph;
const struct enc_xform *espx;
struct tdb_crypto *tc;
- int plen, alen, hlen, error;
+ int plen, alen, hlen, error, stat = ESP_STAT_CRYPTO;
struct newesp *esp;
-
struct cryptodesc *crde;
struct cryptop *crp;
@@ -349,9 +346,9 @@ esp_input(struct mbuf *m, struct secasva
" SA %s/%08lx\n", __func__, plen, espx->blocksize,
ipsec_address(&sav->sah->saidx.dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
- ESP_STATINC(ESP_STAT_BADILEN);
- m_freem(m);
- return EINVAL;
+ stat = ESP_STAT_BADILEN;
+ error = EINVAL;
+ goto out;
}
/*
@@ -361,9 +358,9 @@ esp_input(struct mbuf *m, struct secasva
char logbuf[IPSEC_LOGSASTRLEN];
DPRINTF(("%s: packet replay check for %s\n", __func__,
ipsec_logsastr(sav, logbuf, sizeof(logbuf)))); /*XXX*/
- ESP_STATINC(ESP_STAT_REPLAY);
- m_freem(m);
- return ENOBUFS; /*XXX*/
+ stat = ESP_STAT_REPLAY;
+ error = ENOBUFS; /*XXX*/
+ goto out;
}
/* Update the counters */
@@ -437,10 +434,9 @@ esp_input(struct mbuf *m, struct secasva
*/
if (__predict_false(sav->state == SADB_SASTATE_DEAD)) {
pserialize_read_exit(s);
- pool_cache_put(esp_tdb_crypto_pool_cache, tc);
- crypto_freereq(crp);
- ESP_STATINC(ESP_STAT_NOTDB);
- return ENOENT;
+ stat = ESP_STAT_NOTDB;
+ error = ENOENT;
+ goto out2;
}
KEY_SA_REF(sav);
pserialize_read_exit(s);
@@ -485,7 +481,7 @@ out2:
out1:
crypto_freereq(crp);
out:
- ESP_STATINC(ESP_STAT_CRYPTO);
+ ESP_STATINC(stat);
m_freem(m);
return error;
}
@@ -536,21 +532,6 @@ esp_input_cb(struct cryptop *crp)
IPSEC_ACQUIRE_GLOBAL_LOCKS();
sav = tc->tc_sav;
- if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
- KEY_SA_UNREF(&sav);
- sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi,
- sport, dport);
- if (sav == NULL) {
- ESP_STATINC(ESP_STAT_NOTDB);
- DPRINTF(("%s: SA expired while in crypto "
- "(SA %s/%08lx proto %u)\n", __func__,
- ipsec_address(&tc->tc_dst, buf, sizeof(buf)),
- (u_long) ntohl(tc->tc_spi), tc->tc_proto));
- error = ENOBUFS; /*XXX*/
- goto bad;
- }
- }
-
saidx = &sav->sah->saidx;
KASSERTMSG(saidx->dst.sa.sa_family == AF_INET ||
saidx->dst.sa.sa_family == AF_INET6,
@@ -709,14 +690,8 @@ bad:
* ESP output routine, called by ipsec[46]_process_packet().
*/
static int
-esp_output(
- struct mbuf *m,
- const struct ipsecrequest *isr,
- struct secasvar *sav,
- struct mbuf **mp,
- int skip,
- int protoff
-)
+esp_output(struct mbuf *m, const struct ipsecrequest *isr, struct secasvar *sav,
+ struct mbuf **mp, int skip, int protoff)
{
char buf[IPSEC_ADDRSTRLEN];
const struct enc_xform *espx;
@@ -767,12 +742,12 @@ esp_output(
case AF_INET:
maxpacketsize = IP_MAXPACKET;
break;
-#endif /* INET */
+#endif
#ifdef INET6
case AF_INET6:
maxpacketsize = IPV6_MAXPACKET;
break;
-#endif /* INET6 */
+#endif
default:
DPRINTF(("%s: unknown/unsupported protocol family %d, "
"SA %s/%08lx\n", __func__, saidx->dst.sa.sa_family,
@@ -813,7 +788,7 @@ esp_output(
"%s/%08lx\n", __func__, hlen,
ipsec_address(&saidx->dst, buf, sizeof(buf)),
(u_long) ntohl(sav->spi)));
- ESP_STATINC(ESP_STAT_HDROPS); /* XXX diffs from openbsd */
+ ESP_STATINC(ESP_STAT_HDROPS);
error = ENOBUFS;
goto bad;
}
@@ -850,19 +825,19 @@ esp_output(
/*
* Add padding: random, zero, or self-describing.
- * XXX catch unexpected setting
*/
switch (sav->flags & SADB_X_EXT_PMASK) {
+ case SADB_X_EXT_PSEQ:
+ for (i = 0; i < padding - 2; i++)
+ pad[i] = i+1;
+ break;
case SADB_X_EXT_PRAND:
- (void) cprng_fast(pad, padding - 2);
+ (void)cprng_fast(pad, padding - 2);
break;
case SADB_X_EXT_PZERO:
+ default:
memset(pad, 0, padding - 2);
break;
- case SADB_X_EXT_PSEQ:
- for (i = 0; i < padding - 2; i++)
- pad[i] = i+1;
- break;
}
/* Fix padding length and Next Protocol in padding itself. */
@@ -971,10 +946,11 @@ esp_output(
}
return crypto_dispatch(crp);
+
bad:
if (m)
m_freem(m);
- return (error);
+ return error;
}
/*
@@ -998,28 +974,6 @@ esp_output_cb(struct cryptop *crp)
isr = tc->tc_isr;
sav = tc->tc_sav;
- if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
- ESP_STATINC(ESP_STAT_NOTDB);
- IPSECLOG(LOG_DEBUG,
- "SP is being destroyed while in crypto (id=%u)\n",
- isr->sp->id);
- error = ENOENT;
- goto bad;
- }
- if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
- KEY_SA_UNREF(&sav);
- sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
- if (sav == NULL) {
- char buf[IPSEC_ADDRSTRLEN];
- ESP_STATINC(ESP_STAT_NOTDB);
- DPRINTF(("%s: SA expired while in crypto (SA %s/%08lx "
- "proto %u)\n", __func__,
- ipsec_address(&tc->tc_dst, buf, sizeof(buf)),
- (u_long) ntohl(tc->tc_spi), tc->tc_proto));
- error = ENOBUFS; /*XXX*/
- goto bad;
- }
- }
/* Check for crypto errors. */
if (crp->crp_etype) {
@@ -1070,6 +1024,7 @@ esp_output_cb(struct cryptop *crp)
KEY_SP_UNREF(&isr->sp);
IPSEC_RELEASE_GLOBAL_LOCKS();
return err;
+
bad:
if (sav)
KEY_SA_UNREF(&sav);
Index: src/sys/netipsec/xform_ipcomp.c
diff -u src/sys/netipsec/xform_ipcomp.c:1.38.2.1 src/sys/netipsec/xform_ipcomp.c:1.38.2.2
--- src/sys/netipsec/xform_ipcomp.c:1.38.2.1 Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/xform_ipcomp.c Mon Feb 26 13:10:52 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: xform_ipcomp.c,v 1.38.2.1 2017/10/21 19:43:54 snj Exp $ */
+/* $NetBSD: xform_ipcomp.c,v 1.38.2.2 2018/02/26 13:10:52 martin 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.38.2.1 2017/10/21 19:43:54 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.38.2.2 2018/02/26 13:10:52 martin Exp $");
/* IP payload compression protocol (IPComp), see RFC 2393 */
#if defined(_KERNEL_OPT)
@@ -152,36 +152,29 @@ ipcomp_input(struct mbuf *m, struct seca
struct tdb_crypto *tc;
struct cryptodesc *crdc;
struct cryptop *crp;
- int error, hlen = IPCOMP_HLENGTH;
+ int error, hlen = IPCOMP_HLENGTH, stat = IPCOMP_STAT_CRYPTO;
IPSEC_SPLASSERT_SOFTNET(__func__);
/* Get crypto descriptors */
crp = crypto_getreq(1);
if (crp == NULL) {
- m_freem(m);
DPRINTF(("%s: no crypto descriptors\n", __func__));
- IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
- return ENOBUFS;
+ error = ENOBUFS;
+ goto error_m;
}
/* Get IPsec-specific opaque pointer */
tc = pool_cache_get(ipcomp_tdb_crypto_pool_cache, PR_NOWAIT);
if (tc == NULL) {
- m_freem(m);
- crypto_freereq(crp);
DPRINTF(("%s: cannot allocate tdb_crypto\n", __func__));
- IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
- return ENOBUFS;
+ error = ENOBUFS;
+ goto error_crp;
}
error = m_makewritable(&m, 0, m->m_pkthdr.len, M_NOWAIT);
if (error) {
DPRINTF(("%s: m_makewritable failed\n", __func__));
- m_freem(m);
- pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
- crypto_freereq(crp);
- IPCOMP_STATINC(IPCOMP_STAT_CRYPTO);
- return error;
+ goto error_tc;
}
{
@@ -192,10 +185,9 @@ ipcomp_input(struct mbuf *m, struct seca
*/
if (__predict_false(sav->state == SADB_SASTATE_DEAD)) {
pserialize_read_exit(s);
- pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
- crypto_freereq(crp);
- IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
- return ENOENT;
+ stat = IPCOMP_STAT_NOTDB;
+ error = ENOENT;
+ goto error_tc;
}
KEY_SA_REF(sav);
pserialize_read_exit(s);
@@ -228,6 +220,15 @@ ipcomp_input(struct mbuf *m, struct seca
tc->tc_sav = sav;
return crypto_dispatch(crp);
+
+error_tc:
+ pool_cache_put(ipcomp_tdb_crypto_pool_cache, tc);
+error_crp:
+ crypto_freereq(crp);
+error_m:
+ m_freem(m);
+ IPCOMP_STATINC(stat);
+ return error;
}
#ifdef INET6
@@ -274,18 +275,6 @@ ipcomp_input_cb(struct cryptop *crp)
IPSEC_ACQUIRE_GLOBAL_LOCKS();
sav = tc->tc_sav;
- if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
- KEY_SA_UNREF(&sav);
- sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi,
- sport, dport);
- if (sav == NULL) {
- IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
- DPRINTF(("%s: SA expired while in crypto\n", __func__));
- error = ENOBUFS; /*XXX*/
- goto bad;
- }
- }
-
saidx = &sav->sah->saidx;
KASSERTMSG(saidx->dst.sa.sa_family == AF_INET ||
saidx->dst.sa.sa_family == AF_INET6,
@@ -566,24 +555,6 @@ ipcomp_output_cb(struct cryptop *crp)
isr = tc->tc_isr;
sav = tc->tc_sav;
- if (__predict_false(isr->sp->state == IPSEC_SPSTATE_DEAD)) {
- IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
- IPSECLOG(LOG_DEBUG,
- "SP is being destroyed while in crypto (id=%u)\n",
- isr->sp->id);
- error = ENOENT;
- goto bad;
- }
- if (__predict_false(!SADB_SASTATE_USABLE_P(sav))) {
- KEY_SA_UNREF(&sav);
- sav = KEY_LOOKUP_SA(&tc->tc_dst, tc->tc_proto, tc->tc_spi, 0, 0);
- if (sav == NULL) {
- IPCOMP_STATINC(IPCOMP_STAT_NOTDB);
- DPRINTF(("%s: SA expired while in crypto\n", __func__));
- error = ENOBUFS; /*XXX*/
- goto bad;
- }
- }
/* Check for crypto errors */
if (crp->crp_etype) {