~alpine/aports

[alpine-aports] [PATCH v3.5] main/libevent: security fixes #6799

Details
Message ID
<20170202145038.24931-1-sergej.lukin@gmail.com>
Sender timestamp
1486047038
DKIM signature
missing
Download raw message
Patch: +290 -9
CVE-2016-10195: dns remote stack overread vulnerability
CVE-2016-10196: (stack) buffer overflow in evutil_parse_sockaddr_port()
CVE-2016-10197: out-of-bounds read in search_make_new()
---
 main/libevent/APKBUILD             |  40 ++++++++++---
 main/libevent/CVE-2016-10195.patch | 112 +++++++++++++++++++++++++++++++++++++
 main/libevent/CVE-2016-10196.patch |  85 ++++++++++++++++++++++++++++
 main/libevent/CVE-2016-10197.patch |  62 ++++++++++++++++++++
 4 files changed, 290 insertions(+), 9 deletions(-)
 create mode 100644 main/libevent/CVE-2016-10195.patch
 create mode 100644 main/libevent/CVE-2016-10196.patch
 create mode 100644 main/libevent/CVE-2016-10197.patch

diff --git a/main/libevent/APKBUILD b/main/libevent/APKBUILD
index 13ec0052c2..863bb0da23 100644
--- a/main/libevent/APKBUILD
+++ b/main/libevent/APKBUILD
@@ -1,7 +1,8 @@
# Contributor: Sergei Lukin <sergej.lukin@gmail.com>
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=libevent
pkgver=2.0.22
pkgrel=1
pkgrel=2
pkgdesc="An event notification library"
url="http://libevent.org/"
arch="all"
@@ -10,16 +11,28 @@ depends=""
depends_dev="python2"
makedepends="$depends_dev libressl-dev"
subpackages="$pkgname-dev"
source="https://github.com/$pkgname/$pkgname/releases/download/release-${pkgver}-stable/$pkgname-${pkgver}-stable.tar.gz"
_builddir="$srcdir"/$pkgname-$pkgver-stable
source="https://github.com/$pkgname/$pkgname/releases/download/release-${pkgver}-stable/$pkgname-${pkgver}-stable.tar.gz
	CVE-2016-10195.patch
	CVE-2016-10196.patch
	CVE-2016-10197.patch
	"

# secfixes:
#   2.0.22-r2:
#   - CVE-2016-10195
#   - CVE-2016-10196
#   - CVE-2016-10197

builddir="$srcdir"/$pkgname-$pkgver-stable

prepare() {
	cd "$_builddir"
	cd "$builddir"
	default_prepare || return 1
	update_config_sub || return 1
}

build() {
	cd "$_builddir"
	cd "$builddir"
	./configure \
		--build=$CBUILD \
		--host=$CHOST \
@@ -31,7 +44,7 @@ build() {
}

package() {
	cd "$_builddir"
	cd "$builddir"
	make -j1 DESTDIR=$pkgdir install || return 1
}

@@ -41,6 +54,15 @@ dev() {
	mv "$pkgdir"/usr/bin "$subpkgdir"/usr/
}

md5sums="c4c56f986aa985677ca1db89630a2e11  libevent-2.0.22-stable.tar.gz"
sha256sums="71c2c49f0adadacfdbe6332a372c38cf9c8b7895bb73dabeaa53cdcc1d4e1fa3  libevent-2.0.22-stable.tar.gz"
sha512sums="990637f12e890bfa7f86c194c8b112701436e92b60afb829194879efb85d558b986261e6508fe29bde73981feada874438e2d442cec8ea5730c889954f9bc907  libevent-2.0.22-stable.tar.gz"
md5sums="c4c56f986aa985677ca1db89630a2e11  libevent-2.0.22-stable.tar.gz
5973445706814d61d573ac1baa747029  CVE-2016-10195.patch
095d09dafa215939d065e20ca13e3cb1  CVE-2016-10196.patch
52e2e3eae3b5219542a564ca57cbf14d  CVE-2016-10197.patch"
sha256sums="71c2c49f0adadacfdbe6332a372c38cf9c8b7895bb73dabeaa53cdcc1d4e1fa3  libevent-2.0.22-stable.tar.gz
1acc1ace88a157ed53c99bd52853cc4f8473da2ae183881619190a41bd92f6c7  CVE-2016-10195.patch
f3d535cece4c2b437bc276c3f7833b4ea762baf82ef99c5e15eb893dba713429  CVE-2016-10196.patch
4e1dace28e11ffc8b69635d1dd0ed5efab34a950f4b7198cf08bccaba1106bc0  CVE-2016-10197.patch"
sha512sums="990637f12e890bfa7f86c194c8b112701436e92b60afb829194879efb85d558b986261e6508fe29bde73981feada874438e2d442cec8ea5730c889954f9bc907  libevent-2.0.22-stable.tar.gz
ecc76b4ebdcee4567ff53bbb710a39475e56a8298f14c9967e76aeb09b7b701b088c5c6771251fdbf2d67a3bb6524cffa3efb38b078cc486fe4648280f6d2b10  CVE-2016-10195.patch
7999677bd17ca1457ef3fe4ccc7a031c36f42ec6bf6059cc53cc999ba73ecce87ba5813445e1f63ea1b120dc5a4b5b77206fe4753ac3268d5e3ad5b5e64209a4  CVE-2016-10196.patch
b366247b478a691165ca7288e5924988d04031136411f0133149a455b5d0dc9553ef629c2282251537d6dde2b507ab116829807d0322f2dace30e93d2bab5f53  CVE-2016-10197.patch"
diff --git a/main/libevent/CVE-2016-10195.patch b/main/libevent/CVE-2016-10195.patch
new file mode 100644
index 0000000000..c7b45cdb23
--- /dev/null
+++ b/main/libevent/CVE-2016-10195.patch
@@ -0,0 +1,112 @@
Source: https://github.com/libevent/libevent/commit/96f64a022014a208105ead6c8a7066018449d86d

commit 96f64a022014a208105ead6c8a7066018449d86d
Author: Azat Khuzhin <a3at.mail@gmail.com>
Date:   Mon Feb 1 17:32:09 2016 +0300

    evdns: name_parse(): fix remote stack overread
    
    @asn-the-goblin-slayer:
      "the name_parse() function in libevent's DNS code is vulnerable to a buffer overread.
    
       971         if (cp != name_out) {
       972             if (cp + 1 >= end) return -1;
       973             *cp++ = '.';
       974         }
       975         if (cp + label_len >= end) return -1;
       976         memcpy(cp, packet + j, label_len);
       977         cp += label_len;
       978         j += label_len;
       No check is made against length before the memcpy occurs.
    
       This was found through the Tor bug bounty program and the discovery should be credited to 'Guido Vranken'."
    
    Reproducer for gdb (https://gist.github.com/azat/e4fcf540e9b89ab86d02):
      set $PROT_NONE=0x0
      set $PROT_READ=0x1
      set $PROT_WRITE=0x2
      set $MAP_ANONYMOUS=0x20
      set $MAP_SHARED=0x01
      set $MAP_FIXED=0x10
      set $MAP_32BIT=0x40
    
      start
    
      set $length=202
      # overread
      set $length=2
      # allocate with mmap to have a seg fault on page boundary
      set $l=(1<<20)*2
      p mmap(0, $l, $PROT_READ|$PROT_WRITE, $MAP_ANONYMOUS|$MAP_SHARED|$MAP_32BIT, -1, 0)
      set $packet=(char *)$1+$l-$length
      # hack the packet
      set $packet[0]=63
      set $packet[1]='/'
    
      p malloc(sizeof(int))
      set $idx=(int *)$2
      set $idx[0]=0
      set $name_out_len=202
    
      p malloc($name_out_len)
      set $name_out=$3
    
      # have WRITE only mapping to fail on read
      set $end=$1+$l
      p (void *)mmap($end, 1<<12, $PROT_NONE, $MAP_ANONYMOUS|$MAP_SHARED|$MAP_FIXED|$MAP_32BIT, -1, 0)
      set $m=$4
    
      p name_parse($packet, $length, $idx, $name_out, $name_out_len)
      x/2s (char *)$name_out
    
    Before this patch:
    $ gdb -ex 'source gdb' dns-example
    $1 = 1073741824
    $2 = (void *) 0x633010
    $3 = (void *) 0x633030
    $4 = (void *) 0x40200000
    
    Program received signal SIGSEGV, Segmentation fault.
    __memcpy_sse2_unaligned () at memcpy-sse2-unaligned.S:33
    
    After this patch:
    $ gdb -ex 'source gdb' dns-example
    $1 = 1073741824
    $2 = (void *) 0x633010
    $3 = (void *) 0x633030
    $4 = (void *) 0x40200000
    $5 = -1
    0x633030:       "/"
    0x633032:       ""
    (gdb) p $m
    $6 = (void *) 0x40200000
    (gdb) p $1
    $7 = 1073741824
    (gdb) p/x $1
    $8 = 0x40000000
    (gdb) quit
    
    P.S. plus drop one condition duplicate.
    
    Fixes: #317

diff --git a/evdns.c b/evdns.c
index 0955a289..c4112330 100644
--- a/evdns.c
+++ b/evdns.c
@@ -976,7 +976,6 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
 
 	for (;;) {
 		u8 label_len;
-		if (j >= length) return -1;
 		GET8(label_len);
 		if (!label_len) break;
 		if (label_len & 0xc0) {
@@ -997,6 +996,7 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
 			*cp++ = '.';
 		}
 		if (cp + label_len >= end) return -1;
+		if (j + label_len > length) return -1;
 		memcpy(cp, packet + j, label_len);
 		cp += label_len;
 		j += label_len;
diff --git a/main/libevent/CVE-2016-10196.patch b/main/libevent/CVE-2016-10196.patch
new file mode 100644
index 0000000000..02116a1504
--- /dev/null
+++ b/main/libevent/CVE-2016-10196.patch
@@ -0,0 +1,85 @@
Source: https://github.com/libevent/libevent/commit/329acc18a0768c21ba22522f01a5c7f46cacc4d5

commit 329acc18a0768c21ba22522f01a5c7f46cacc4d5
Author: Azat Khuzhin <a3at.mail@gmail.com>
Date:   Sun Jan 31 00:57:16 2016 +0300

    evutil_parse_sockaddr_port(): fix buffer overflow
    
    @asn-the-goblin-slayer:
      "Length between '[' and ']' is cast to signed 32 bit integer on line 1815. Is
       the length is more than 2<<31 (INT_MAX), len will hold a negative value.
       Consequently, it will pass the check at line 1816. Segfault happens at line
       1819.
    
       Generate a resolv.conf with generate-resolv.conf, then compile and run
       poc.c. See entry-functions.txt for functions in tor that might be
       vulnerable.
    
       Please credit 'Guido Vranken' for this discovery through the Tor bug bounty
       program."
    
    Reproducer for gdb (https://gist.github.com/azat/be2b0d5e9417ba0dfe2c):
      start
      p (1ULL<<31)+1ULL
      # $1 = 2147483649
      p malloc(sizeof(struct sockaddr))
      # $2 = (void *) 0x646010
      p malloc(sizeof(int))
      # $3 = (void *) 0x646030
      p malloc($1)
      # $4 = (void *) 0x7fff76a2a010
      p memset($4, 1, $1)
      # $5 = 1990369296
      p (char *)$4
      # $6 = 0x7fff76a2a010 '\001' <repeats 200 times>...
      set $6[0]='['
      set $6[$1]=']'
      p evutil_parse_sockaddr_port($4, $2, $3)
      # $7 = -1
    
    Before:
      $ gdb bin/http-connect < gdb
      (gdb) $1 = 2147483649
      (gdb) (gdb) $2 = (void *) 0x646010
      (gdb) (gdb) $3 = (void *) 0x646030
      (gdb) (gdb) $4 = (void *) 0x7fff76a2a010
      (gdb) (gdb) $5 = 1990369296
      (gdb) (gdb) $6 = 0x7fff76a2a010 '\001' <repeats 200 times>...
      (gdb) (gdb) (gdb) (gdb)
      Program received signal SIGSEGV, Segmentation fault.
      __memcpy_sse2_unaligned () at memcpy-sse2-unaligned.S:36
    
    After:
      $ gdb bin/http-connect < gdb
      (gdb) $1 = 2147483649
      (gdb) (gdb) $2 = (void *) 0x646010
      (gdb) (gdb) $3 = (void *) 0x646030
      (gdb) (gdb) $4 = (void *) 0x7fff76a2a010
      (gdb) (gdb) $5 = 1990369296
      (gdb) (gdb) $6 = 0x7fff76a2a010 '\001' <repeats 200 times>...
      (gdb) (gdb) (gdb) (gdb) $7 = -1
      (gdb) (gdb) quit
    
    Fixes: #318

diff --git a/evutil.c b/evutil.c
index 79d825d9..495bfcc0 100644
--- a/evutil.c
+++ b/evutil.c
@@ -2058,12 +2058,12 @@ evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *
 
 	cp = strchr(ip_as_string, ':');
 	if (*ip_as_string == '[') {
-		int len;
+		size_t len;
 		if (!(cp = strchr(ip_as_string, ']'))) {
 			return -1;
 		}
-		len = (int) ( cp-(ip_as_string + 1) );
-		if (len > (int)sizeof(buf)-1) {
+		len = ( cp-(ip_as_string + 1) );
+		if (len > sizeof(buf)-1) {
 			return -1;
 		}
 		memcpy(buf, ip_as_string+1, len);
diff --git a/main/libevent/CVE-2016-10197.patch b/main/libevent/CVE-2016-10197.patch
new file mode 100644
index 0000000000..ca8de2aadb
--- /dev/null
+++ b/main/libevent/CVE-2016-10197.patch
@@ -0,0 +1,62 @@
Source: https://github.com/libevent/libevent/commit/ec65c42052d95d2c23d1d837136d1cf1d9ecef9e

commit ec65c42052d95d2c23d1d837136d1cf1d9ecef9e
Author: Azat Khuzhin <a3at.mail@gmail.com>
Date:   Fri Mar 25 00:33:47 2016 +0300

    evdns: fix searching empty hostnames
    
    From #332:
      Here follows a bug report by **Guido Vranken** via the _Tor bug bounty program_. Please credit Guido accordingly.
    
      ## Bug report
    
      The DNS code of Libevent contains this rather obvious OOB read:
    
      ```c
      static char *
      search_make_new(const struct search_state *const state, int n, const char *const base_name) {
          const size_t base_len = strlen(base_name);
          const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
      ```
    
      If the length of ```base_name``` is 0, then line 3125 reads 1 byte before the buffer. This will trigger a crash on ASAN-protected builds.
    
      To reproduce:
    
      Build libevent with ASAN:
      ```
      $ CFLAGS='-fomit-frame-pointer -fsanitize=address' ./configure && make -j4
      ```
      Put the attached ```resolv.conf``` and ```poc.c``` in the source directory and then do:
    
      ```
      $ gcc -fsanitize=address -fomit-frame-pointer poc.c .libs/libevent.a
      $ ./a.out
      =================================================================
      ==22201== ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60060000efdf at pc 0x4429da bp 0x7ffe1ed47300 sp 0x7ffe1ed472f8
      READ of size 1 at 0x60060000efdf thread T0
      ```
    
    P.S. we can add a check earlier, but since this is very uncommon, I didn't add it.
    
    Fixes: #332

diff --git a/evdns.c b/evdns.c
index 905ff6b5..e9dbc35c 100644
--- a/evdns.c
+++ b/evdns.c
@@ -3175,9 +3175,12 @@ search_set_from_hostname(struct evdns_base *base) {
 static char *
 search_make_new(const struct search_state *const state, int n, const char *const base_name) {
 	const size_t base_len = strlen(base_name);
-	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+	char need_to_append_dot;
 	struct search_domain *dom;
 
+	if (!base_len) return NULL;
+	need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+
 	for (dom = state->head; dom; dom = dom->next) {
 		if (!n--) {
 			/* this is the postfix we want */
-- 
2.11.0



---
Unsubscribe:  alpine-aports+unsubscribe@lists.alpinelinux.org
Help:         alpine-aports+help@lists.alpinelinux.org
---
Reply to thread Export thread (mbox)