Code: evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
{
	int port;
	char buf[128];
	const char *cp, *addr_part, *port_part;
	int is_ipv6;
	/* recognized formats are:
	 * [ipv6]:port
	 * ipv6
	 * [ipv6]
	 * ipv4:port
	 * ipv4
	 */
 
 	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);
		buf[len] = '\0';
		addr_part = buf;
		if (cp[1] == ':')
			port_part = cp+2;
		else
			port_part = NULL;
		is_ipv6 = 1;
	} else if (cp && strchr(cp+1, ':')) {
		is_ipv6 = 1;
		addr_part = ip_as_string;
		port_part = NULL;
	} else if (cp) {
		is_ipv6 = 0;
		if (cp - ip_as_string > (int)sizeof(buf)-1) {
			return -1;
		}
		memcpy(buf, ip_as_string, cp-ip_as_string);
		buf[cp-ip_as_string] = '\0';
		addr_part = buf;
		port_part = cp+1;
	} else {
		addr_part = ip_as_string;
		port_part = NULL;
		is_ipv6 = 0;
	}

	if (port_part == NULL) {
		port = 0;
	} else {
		port = atoi(port_part);
		if (port <= 0 || port > 65535) {
			return -1;
		}
	}

	if (!addr_part)
		return -1; /* Should be impossible. */
#ifdef AF_INET6
	if (is_ipv6)
	{
		struct sockaddr_in6 sin6;
		memset(&sin6, 0, sizeof(sin6));
#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
		sin6.sin6_len = sizeof(sin6);
#endif
		sin6.sin6_family = AF_INET6;
		sin6.sin6_port = htons(port);
		if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
			return -1;
		if ((int)sizeof(sin6) > *outlen)
			return -1;
		memset(out, 0, *outlen);
		memcpy(out, &sin6, sizeof(sin6));
		*outlen = sizeof(sin6);
		return 0;
	}
	else
#endif
	{
		struct sockaddr_in sin;
		memset(&sin, 0, sizeof(sin));
#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
		sin.sin_len = sizeof(sin);
#endif
		sin.sin_family = AF_INET;
		sin.sin_port = htons(port);
		if (1 != evutil_inet_pton(AF_INET, addr_part, &sin.sin_addr))
			return -1;
		if ((int)sizeof(sin) > *outlen)
			return -1;
		memset(out, 0, *outlen);
		memcpy(out, &sin, sizeof(sin));
		*outlen = sizeof(sin);
		return 0;
	}
}

Vulnerability Type: DoS Overflow 
CWE ID: CWE-119
Summary: 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.
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