Wed Jan 24 13:30:47 2018 UTC ()
Fix a vulnerability in IPsec-IPv6-AH, that allows an attacker to remotely
crash the kernel with a single packet.

In this loop we need to increment 'ad' by two, because the length field
of the option header does not count the size of the option header itself.

If the length is zero, then 'count' is incremented by zero, and there's
an infinite loop. Beyond that, this code was written with the assumption
that since the IPv6 packet already went through the generic IPv6 option
parser, several fields are guaranteed to be valid; but this assumption
does not hold because of the missing '+2', and there's as a result a
triggerable buffer overflow (write zeros after the end of the mbuf,
potentially to the next mbuf in memory since it's a pool).

Add the missing '+2', this place will be reinforced in separate commits.


(maxv)
diff -r1.75 -r1.76 src/sys/netipsec/xform_ah.c

cvs diff -r1.75 -r1.76 src/sys/netipsec/xform_ah.c (expand / switch to unified diff)

--- src/sys/netipsec/xform_ah.c 2018/01/24 13:13:11 1.75
+++ src/sys/netipsec/xform_ah.c 2018/01/24 13:30:47 1.76
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: xform_ah.c,v 1.75 2018/01/24 13:13:11 maxv Exp $ */ 1/* $NetBSD: xform_ah.c,v 1.76 2018/01/24 13:30:47 maxv Exp $ */
2/* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ 2/* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
3/* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ 3/* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */
4/* 4/*
5 * The authors of this code are John Ioannidis (ji@tla.org), 5 * The authors of this code are John Ioannidis (ji@tla.org),
6 * Angelos D. Keromytis (kermit@csd.uch.gr) and 6 * Angelos D. Keromytis (kermit@csd.uch.gr) and
7 * Niels Provos (provos@physnet.uni-hamburg.de). 7 * Niels Provos (provos@physnet.uni-hamburg.de).
8 * 8 *
9 * The original version of this code was written by John Ioannidis 9 * The original version of this code was written by John Ioannidis
10 * for BSD/OS in Athens, Greece, in November 1995. 10 * for BSD/OS in Athens, Greece, in November 1995.
11 * 11 *
12 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
13 * by Angelos D. Keromytis. 13 * by Angelos D. Keromytis.
14 * 14 *
@@ -29,27 +29,27 @@ @@ -29,27 +29,27 @@
29 * You may use this code under the GNU public license if you so wish. Please 29 * You may use this code under the GNU public license if you so wish. Please
30 * contribute changes back to the authors under this freer than GPL license 30 * contribute changes back to the authors under this freer than GPL license
31 * so that we may further the use of strong encryption without limitations to 31 * so that we may further the use of strong encryption without limitations to
32 * all. 32 * all.
33 * 33 *
34 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 34 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
35 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 35 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
36 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 36 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
37 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 37 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
38 * PURPOSE. 38 * PURPOSE.
39 */ 39 */
40 40
41#include <sys/cdefs.h> 41#include <sys/cdefs.h>
42__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.75 2018/01/24 13:13:11 maxv Exp $"); 42__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.76 2018/01/24 13:30:47 maxv Exp $");
43 43
44#if defined(_KERNEL_OPT) 44#if defined(_KERNEL_OPT)
45#include "opt_inet.h" 45#include "opt_inet.h"
46#include "opt_ipsec.h" 46#include "opt_ipsec.h"
47#endif 47#endif
48 48
49#include <sys/param.h> 49#include <sys/param.h>
50#include <sys/systm.h> 50#include <sys/systm.h>
51#include <sys/mbuf.h> 51#include <sys/mbuf.h>
52#include <sys/socket.h> 52#include <sys/socket.h>
53#include <sys/syslog.h> 53#include <sys/syslog.h>
54#include <sys/kernel.h> 54#include <sys/kernel.h>
55#include <sys/sysctl.h> 55#include <sys/sysctl.h>
@@ -513,32 +513,32 @@ ah_massage_headers(struct mbuf **m0, int @@ -513,32 +513,32 @@ ah_massage_headers(struct mbuf **m0, int
513 } 513 }
514 514
515 /* Sanity check. */ 515 /* Sanity check. */
516 if (count > off + 516 if (count > off +
517 ((ip6e->ip6e_len + 1) << 3)) { 517 ((ip6e->ip6e_len + 1) << 3)) {
518 m_freem(m); 518 m_freem(m);
519 519
520 /* Free, if we allocated. */ 520 /* Free, if we allocated. */
521 if (alloc) 521 if (alloc)
522 free(ptr, M_XDATA); 522 free(ptr, M_XDATA);
523 return EINVAL; 523 return EINVAL;
524 } 524 }
525 525
526 ad = ptr[count + 1]; 526 ad = ptr[count + 1] + 2;
527 527
528 /* If mutable option, zeroize. */ 528 /* If mutable option, zeroize. */
529 if (ptr[count] & IP6OPT_MUTABLE) 529 if (ptr[count] & IP6OPT_MUTABLE)
530 memcpy(ptr + count, ipseczeroes, 530 memcpy(ptr + count, ipseczeroes,
531 ptr[count + 1]); 531 ad);
532 532
533 count += ad; 533 count += ad;
534 534
535 /* Sanity check. */ 535 /* Sanity check. */
536 if (count > 536 if (count >
537 skip - sizeof(struct ip6_hdr)) { 537 skip - sizeof(struct ip6_hdr)) {
538 m_freem(m); 538 m_freem(m);
539 539
540 /* Free, if we allocated. */ 540 /* Free, if we allocated. */
541 if (alloc) 541 if (alloc)
542 free(ptr, M_XDATA); 542 free(ptr, M_XDATA);
543 return EINVAL; 543 return EINVAL;
544 } 544 }