Vulnerability: Stack-based buffer overflow in the evutil_parse_sockaddr_port function in evutil.c in libevent before 2.1.6-beta allows attackers to cause a denial of service (segmentation fault) via vectors involving a long string in brackets in the ip_as_string argument.
Vulnerability ID: CVE-2016-10196
CWE: CWE-787
Severity score: 2.9
Project: https://github.com/libevent/libevent
Published: 2017-03-15
File: evutil.c
Commit message: 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
Commit author: Azat Khuzhin

Vulnerable version (before fix):
 evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *  	cp = strchr(ip_as_string, ':'); 	if (*ip_as_string == '[') { 		int len; 		if (!(cp = strchr(ip_as_string, ']'))) { 			return -1; 		} 		len = (int) ( cp-(ip_as_string + 1) ); 		if (len > (int)sizeof(buf)-1) { 			return -1; 		} 		memcpy(buf, ip_as_string+1, len);

Fixed version (after fix):
 evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *  	cp = strchr(ip_as_string, ':'); 	if (*ip_as_string == '[') { 		size_t len; 		if (!(cp = strchr(ip_as_string, ']'))) { 			return -1; 		} 		len = ( cp-(ip_as_string + 1) ); 		if (len > sizeof(buf)-1) { 			return -1; 		} 		memcpy(buf, ip_as_string+1, len);

Patch:
patch: @@ -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);
path: evutil.c