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
CVE: CVE-2016-10196
CWE: CWE-119
Vulnerability description: 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.

Project: libevent
File: evutil.c

apply_socktype_protocol_hack(struct evutil_addrinfo *ai)
{
	struct evutil_addrinfo *ai_new;
	for (; ai; ai = ai->ai_next) {
		evutil_getaddrinfo_infer_protocols(ai);
		if (ai->ai_socktype || ai->ai_protocol)
			continue;
		ai_new = mm_malloc(sizeof(*ai_new));
		if (!ai_new)
			return -1;
		memcpy(ai_new, ai, sizeof(*ai_new));
		ai->ai_socktype = SOCK_STREAM;
		ai->ai_protocol = IPPROTO_TCP;
		ai_new->ai_socktype = SOCK_DGRAM;
		ai_new->ai_protocol = IPPROTO_UDP;

		ai_new->ai_next = ai->ai_next;
		ai->ai_next = ai_new;
	}
	return 0;
}

Project: libevent
File: evutil.c

evutil_check_ifaddrs(void)
{
#if defined(EVENT__HAVE_GETIFADDRS)
	/* Most free Unixy systems provide getifaddrs, which gives us a linked list
	 * of struct ifaddrs. */
	struct ifaddrs *ifa = NULL;
	const struct ifaddrs *i;
	if (getifaddrs(&ifa) < 0) {
		event_warn("Unable to call getifaddrs()");
		return -1;
	}

	for (i = ifa; i; i = i->ifa_next) {
		if (!i->ifa_addr)
			continue;
		evutil_found_ifaddr(i->ifa_addr);
	}

	freeifaddrs(ifa);
	return 0;
#elif defined(_WIN32)
	/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
	   "GetAdaptersInfo", but that's deprecated; let's just try
	   GetAdaptersAddresses and fall back to connect+getsockname.
	*/
	HMODULE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
	GetAdaptersAddresses_fn_t fn;
	ULONG size, res;
	IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
	int result = -1;

#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
               GAA_FLAG_SKIP_MULTICAST | \
               GAA_FLAG_SKIP_DNS_SERVER)

	if (!lib)
		goto done;

	if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses")))
		goto done;

	/* Guess how much space we need. */
	size = 15*1024;
	addresses = mm_malloc(size);
	if (!addresses)
		goto done;
	res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
	if (res == ERROR_BUFFER_OVERFLOW) {
		/* we didn't guess that we needed enough space; try again */
		mm_free(addresses);
		addresses = mm_malloc(size);
		if (!addresses)
			goto done;
		res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
	}
	if (res != NO_ERROR)
		goto done;

	for (address = addresses; address; address = address->Next) {
		IP_ADAPTER_UNICAST_ADDRESS *a;
		for (a = address->FirstUnicastAddress; a; a = a->Next) {
			/* Yes, it's a linked list inside a linked list */
			struct sockaddr *sa = a->Address.lpSockaddr;
			evutil_found_ifaddr(sa);
		}
	}

	result = 0;
done:
	if (lib)
		FreeLibrary(lib);
	if (addresses)
		mm_free(addresses);
	return result;
#else
	return -1;
#endif
}

Project: libevent
File: evutil.c

evutil_check_interfaces(int force_recheck)
{
	evutil_socket_t fd = -1;
	struct sockaddr_in sin, sin_out;
	struct sockaddr_in6 sin6, sin6_out;
	ev_socklen_t sin_out_len = sizeof(sin_out);
	ev_socklen_t sin6_out_len = sizeof(sin6_out);
	int r;
	if (have_checked_interfaces && !force_recheck)
		return 0;

	if (evutil_check_ifaddrs() == 0) {
		/* Use a nice sane interface, if this system has one. */
		return 0;
	}

	/* Ugh. There was no nice sane interface.  So to check whether we have
	 * an interface open for a given protocol, will try to make a UDP
	 * 'connection' to a remote host on the internet.  We don't actually
	 * use it, so the address doesn't matter, but we want to pick one that
	 * keep us from using a host- or link-local interface. */
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(53);
	r = evutil_inet_pton(AF_INET, "18.244.0.188", &sin.sin_addr);
	EVUTIL_ASSERT(r);

	memset(&sin6, 0, sizeof(sin6));
	sin6.sin6_family = AF_INET6;
	sin6.sin6_port = htons(53);
	r = evutil_inet_pton(AF_INET6, "2001:4860:b002::68", &sin6.sin6_addr);
	EVUTIL_ASSERT(r);

	memset(&sin_out, 0, sizeof(sin_out));
	memset(&sin6_out, 0, sizeof(sin6_out));

	/* XXX some errnos mean 'no address'; some mean 'not enough sockets'. */
	if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
	    connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
	    getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
		/* We might have an IPv4 interface. */
		evutil_found_ifaddr((struct sockaddr*) &sin_out);
	}
	if (fd >= 0)
		evutil_closesocket(fd);

	if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
	    connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
	    getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
		/* We might have an IPv6 interface. */
		evutil_found_ifaddr((struct sockaddr*) &sin6_out);
	}

	if (fd >= 0)
		evutil_closesocket(fd);

	return 0;
}

Project: libevent
File: evutil.c

evutil_getaddrinfo_async_(struct evdns_base *dns_base,
    const char *nodename, const char *servname,
    const struct evutil_addrinfo *hints_in,
    void (*cb)(int, struct evutil_addrinfo *, void *), void *arg)
{
	if (dns_base && evdns_getaddrinfo_impl) {
		evdns_getaddrinfo_impl(
			dns_base, nodename, servname, hints_in, cb, arg);
	} else {
		struct evutil_addrinfo *ai=NULL;
		int err;
		err = evutil_getaddrinfo(nodename, servname, hints_in, &ai);
		cb(err, ai, arg);
	}
	return 0;
}

Project: libevent
File: evutil.c

evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen,
    const struct evutil_addrinfo *hints)
{
	struct evutil_addrinfo *res;
	EVUTIL_ASSERT(hints);

	if (hints->ai_socktype == 0 && hints->ai_protocol == 0) {
		/* Indecisive user! Give them a UDP and a TCP. */
		struct evutil_addrinfo *r1, *r2;
		struct evutil_addrinfo tmp;
		memcpy(&tmp, hints, sizeof(tmp));
		tmp.ai_socktype = SOCK_STREAM; tmp.ai_protocol = IPPROTO_TCP;
		r1 = evutil_new_addrinfo_(sa, socklen, &tmp);
		if (!r1)
			return NULL;
		tmp.ai_socktype = SOCK_DGRAM; tmp.ai_protocol = IPPROTO_UDP;
		r2 = evutil_new_addrinfo_(sa, socklen, &tmp);
		if (!r2) {
			evutil_freeaddrinfo(r1);
			return NULL;
		}
		r1->ai_next = r2;
		return r1;
	}

	/* We're going to allocate extra space to hold the sockaddr. */
	res = mm_calloc(1,sizeof(struct evutil_addrinfo)+socklen);
	if (!res)
		return NULL;
	res->ai_addr = (struct sockaddr*)
	    (((char*)res) + sizeof(struct evutil_addrinfo));
	memcpy(res->ai_addr, sa, socklen);
	res->ai_addrlen = socklen;
	res->ai_family = sa->sa_family; /* Same or not? XXX */
	res->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED;
	res->ai_socktype = hints->ai_socktype;
	res->ai_protocol = hints->ai_protocol;

	return res;
}

Project: libevent
File: evutil.c

evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
    int include_port)
{
	int r;
	if (0 != (r = (sa1->sa_family - sa2->sa_family)))
		return r;

	if (sa1->sa_family == AF_INET) {
		const struct sockaddr_in *sin1, *sin2;
		sin1 = (const struct sockaddr_in *)sa1;
		sin2 = (const struct sockaddr_in *)sa2;
		if (sin1->sin_addr.s_addr < sin2->sin_addr.s_addr)
			return -1;
		else if (sin1->sin_addr.s_addr > sin2->sin_addr.s_addr)
			return 1;
		else if (include_port &&
		    (r = ((int)sin1->sin_port - (int)sin2->sin_port)))
			return r;
		else
			return 0;
	}
#ifdef AF_INET6
	else if (sa1->sa_family == AF_INET6) {
		const struct sockaddr_in6 *sin1, *sin2;
		sin1 = (const struct sockaddr_in6 *)sa1;
		sin2 = (const struct sockaddr_in6 *)sa2;
		if ((r = memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)))
			return r;
		else if (include_port &&
		    (r = ((int)sin1->sin6_port - (int)sin2->sin6_port)))
			return r;
		else
			return 0;
	}
#endif
	return 1;
}

Project: libevent
File: evutil.c

evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
{
	if (seed == 0) {
		struct timeval tv;
		evutil_gettimeofday(&tv, NULL);
		seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec;
#ifdef _WIN32
		seed += (ev_uint32_t) _getpid();
#else
		seed += (ev_uint32_t) getpid();
#endif
	}
	state->seed = seed;
	return seed;
}