From 329acc18a0768c21ba22522f01a5c7f46cacc4d5 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Sun, 31 Jan 2016 00:57:16 +0300 Subject: 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' ... 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' ... (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' ... (gdb) (gdb) (gdb) (gdb) $7 = -1 (gdb) (gdb) quit Fixes: #318 --- evutil.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'evutil.c') 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); -- cgit v1.2.1