Module Name: src
Committed By: martin
Date: Thu May 3 14:37:25 UTC 2018
Modified Files:
src/sys/netipsec [netbsd-6-0]: ipsec_output.c
Log Message:
Pull up following revision(s) (requested by maxv in ticket #1546):
sys/netipsec/ipsec_output.c: revision 1.67,1.75 (via patch)
Strengthen this check, to make sure there is room for an ip6_ext structure.
Seems possible to crash m_copydata here (but I didn't test more than that).
Fix the checks in compute_ipsec_pos, otherwise m_copydata could crash. I
already fixed half of the problem two months ago in rev1.67, back then I
thought it was not triggerable because each packet we emit is guaranteed
to have correctly formed IPv6 options; but it is actually triggerable via
IPv6 forwarding, we emit a packet we just received, and we don't sanitize
its options before invoking IPsec.
Since it would be wrong to just stop the iteration and continue the IPsec
processing, allow compute_ipsec_pos to fail, and when it does, drop the
packet entirely.
To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.38.8.1 src/sys/netipsec/ipsec_output.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/ipsec_output.c
diff -u src/sys/netipsec/ipsec_output.c:1.38 src/sys/netipsec/ipsec_output.c:1.38.8.1
--- src/sys/netipsec/ipsec_output.c:1.38 Tue Jan 10 20:01:57 2012
+++ src/sys/netipsec/ipsec_output.c Thu May 3 14:37:25 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $ */
+/* $NetBSD: ipsec_output.c,v 1.38.8.1 2018/05/03 14:37:25 martin Exp $ */
/*-
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.38.8.1 2018/05/03 14:37:25 martin Exp $");
/*
* IPsec output processing.
@@ -632,7 +632,7 @@ bad:
#endif
#ifdef INET6
-static void
+static int
compute_ipsec_pos(struct mbuf *m, int *i, int *off)
{
int nxt;
@@ -649,7 +649,11 @@ compute_ipsec_pos(struct mbuf *m, int *i
* put AH/ESP/IPcomp header.
* IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
*/
- do {
+ while (1) {
+ if (*i + sizeof(ip6e) > m->m_pkthdr.len) {
+ return EINVAL;
+ }
+
switch (nxt) {
case IPPROTO_AH:
case IPPROTO_ESP:
@@ -658,7 +662,7 @@ compute_ipsec_pos(struct mbuf *m, int *i
* we should not skip security header added
* beforehand.
*/
- return;
+ return 0;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
@@ -668,7 +672,7 @@ compute_ipsec_pos(struct mbuf *m, int *i
* we should stop there.
*/
if (nxt == IPPROTO_DSTOPTS && dstopt)
- return;
+ return 0;
if (nxt == IPPROTO_DSTOPTS) {
/*
@@ -688,16 +692,14 @@ compute_ipsec_pos(struct mbuf *m, int *i
m_copydata(m, *i, sizeof(ip6e), &ip6e);
nxt = ip6e.ip6e_nxt;
*off = *i + offsetof(struct ip6_ext, ip6e_nxt);
- /*
- * we will never see nxt == IPPROTO_AH
- * so it is safe to omit AH case.
- */
*i += (ip6e.ip6e_len + 1) << 3;
break;
default:
- return;
+ return 0;
}
- } while (*i < m->m_pkthdr.len);
+ }
+
+ return 0;
}
static int
@@ -799,7 +801,9 @@ ipsec6_process_packet(
i = ip->ip_hl << 2;
off = offsetof(struct ip, ip_p);
} else {
- compute_ipsec_pos(m, &i, &off);
+ error = compute_ipsec_pos(m, &i, &off);
+ if (error)
+ goto bad;
}
error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
splx(s);