Subject: [alpine-aports] [PATCH v3.2] main/libevent: security fixes #6802

From: Sergei Lukin <[email-masked]>
Date: Thu, 2 Feb 2017 15:11:44 +0000

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             |  44 ++++++++++++---
 main/libevent/CVE-2016-10195.patch | 112 +++++++++++++++++++++++++++++++++++++
 main/libevent/CVE-2016-10196.patch |  85 ++++++++++++++++++++++++++++
 main/libevent/CVE-2016-10197.patch |  62 ++++++++++++++++++++
 4 files changed, 294 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 19b051b..68c17b4 100644
--- a/main/libevent/APKBUILD
+++ b/main/libevent/APKBUILD
@@ -1,7 +1,8 @@
+# Contributor: Sergei Lukin <[email-masked]>
 # Maintainer: Natanael Copa <[email-masked]>
 pkgname=libevent
 pkgver=2.0.22
-pkgrel=0
+pkgrel=1
 pkgdesc="An event notification library"
 url="http://libevent.org/"
 arch="all"
@@ -10,16 +11,32 @@ depends=""
 depends_dev="python"
 makedepends="$depends_dev openssl-dev"
 subpackages="$pkgname-dev"
-source="https://sourceforge.net/projects/levent/files/libevent/libevent-${pkgver%.*}/libevent-$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-r1:
+#   - CVE-2016-10195
+#   - CVE-2016-10196
+#   - CVE-2016-10197
+
+builddir="$srcdir"/$pkgname-$pkgver-stable
 
 prepare() {
-	cd "$_builddir"
+	cd "$builddir"
 	update_config_sub || return 1
+	for i in $source; do
+		case $i in
+		*.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
+		esac
+	done
 }
 
 build() {
-	cd "$_builddir"
+	cd "$builddir"
 	./configure \
 		--build=$CBUILD \
 		--host=$CHOST \
@@ -31,7 +48,7 @@ build() {
 }
 
 package() {
-	cd "$_builddir"
+	cd "$builddir"
 	make -j1 DESTDIR=$pkgdir install || return 1
 	rm "$pkgdir"/usr/lib/*.la || return 1
 }
@@ -42,6 +59,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 0000000..c7b45cd
--- /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 <[email-masked]>
+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 0000000..02116a1
--- /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 <[email-masked]>
+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 0000000..ca8de2a
--- /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 <[email-masked]>
+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.4.11

---
Unsubscribe:  [email-masked]
Help:         [email-masked]
---