Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-8]: src/sys/netipsec Pull up following revision(s) (requested by ...
details: https://anonhg.NetBSD.org/src/rev/2f391d17ddc4
branches: netbsd-8
changeset: 434683:2f391d17ddc4
user: martin <martin%NetBSD.org@localhost>
date: Mon Feb 26 13:10:52 2018 +0000
description:
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@
diffstat:
sys/netipsec/xform_ah.c | 132 ++++++++++++++++++++++++++++---------------
sys/netipsec/xform_esp.c | 105 ++++++++++-------------------------
sys/netipsec/xform_ipcomp.c | 69 ++++++----------------
3 files changed, 136 insertions(+), 170 deletions(-)
diffs (truncated from 732 to 300 lines):
diff -r 49761a791aba -r 2f391d17ddc4 sys/netipsec/xform_ah.c
--- a/sys/netipsec/xform_ah.c Mon Feb 26 04:32:29 2018 +0000
+++ b/sys/netipsec/xform_ah.c Mon Feb 26 13:10:52 2018 +0000
@@ -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 @@
#include <sys/sysctl.h>
#include <sys/pool.h>
#include <sys/pserialize.h>
+#include <sys/kmem.h>
#include <net/if.h>
@@ -100,8 +101,8 @@
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 @@
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 @@
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 @@
if (off > skip) {
DPRINTF(("%s: malformed IPv4 options header\n",
__func__));
-
m_freem(m);
return EINVAL;
}
@@ -629,6 +626,7 @@
struct cryptodesc *crda;
struct cryptop *crp = NULL;
uint8_t nxt;
+ bool pool_used;
IPSEC_SPLASSERT_SOFTNET(__func__);
@@ -715,9 +713,14 @@
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 @@
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 @@
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 @@
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 @@
crp = NULL;
}
- /* Figure out header size. */
- rplen = HDRSIZE(sav);
- authsize = AUTHSIZE(sav);
-
if (ipsec_debug)
memset(calc, 0, sizeof(calc));
@@ -924,7 +939,10 @@
/* 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 @@
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 @@
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 @@
* 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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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;
}
Home |
Main Index |
Thread Index |
Old Index