From 809bb39b2b7b632c86337877b483520d997cd5db Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Mon, 23 Nov 2015 13:52:31 +0300 Subject: [PATCH] be_sock: bufferevent_socket_connect_hostname(): make it thread-safe If you use bufferevent_socket_connect_hostname() to resolve, then ipv4 answer can be returned before ipv6 scheduled and if you will destroy bufferevent after ipv4 answer will come (in a separate thread of course) then ipv6 will trigger UAF: $ a.out ================================================================= ==29733==ERROR: AddressSanitizer: heap-use-after-free on address 0x60200000ef50 at pc 0x0000004b7aef bp 0x7fffffffd940 sp 0x7fffffffd0f8 READ of size 2 at 0x60200000ef50 thread T0 #0 0x4b7aee in __interceptor_index (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x4b7aee) #1 0x5060eb in string_num_dots /src/oss/libevent/libevent-github/.cmake-debug/../evdns.c:2739 #2 0x5078df in search_request_new /src/oss/libevent/libevent-github/.cmake-debug/../evdns.c:3214 #3 0x506afd in evdns_base_resolve_ipv6 /src/oss/libevent/libevent-github/.cmake-debug/../evdns.c:2935 #4 0x50aa94 in evdns_getaddrinfo /src/oss/libevent/libevent-github/.cmake-debug/../evdns.c:4719 #5 0x51de4f in evutil_getaddrinfo_async_ /src/oss/libevent/libevent-github/.cmake-debug/../evutil.c:1567 #6 0x4fe023 in bufferevent_socket_connect_hostname /src/oss/libevent/libevent-github/.cmake-debug/../bufferevent_sock.c:519 #7 0x524f54 in evhttp_connection_connect_ /src/oss/libevent/libevent-github/.cmake-debug/../http.c:2493 #8 0x525156 in evhttp_make_request /src/oss/libevent/libevent-github/.cmake-debug/../http.c:2548 #9 0x52d373 in main (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x52d373) #10 0x7ffff6849b44 in __libc_start_main /tmp/buildd/glibc-2.19/csu/libc-start.c:287 #11 0x445806 in _start (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x445806) 0x60200000ef50 is located 0 bytes inside of 15-byte region [0x60200000ef50,0x60200000ef5f) freed by thread T1 here: #0 0x4cc4f2 in __interceptor_free (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x4cc4f2) #1 0x5141c1 in event_mm_free_ /src/oss/libevent/libevent-github/.cmake-debug/../event.c:3512 #2 0x522402 in evhttp_connection_free /src/oss/libevent/libevent-github/.cmake-debug/../http.c:1206 #3 0x52cc5f in connection_closer (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x52cc5f) #4 0x50e80e in event_process_active_single_queue /src/oss/libevent/libevent-github/.cmake-debug/../event.c:1642 #5 0x50ed57 in event_process_active /src/oss/libevent/libevent-github/.cmake-debug/../event.c:1734 #6 0x50f458 in event_base_loop /src/oss/libevent/libevent-github/.cmake-debug/../event.c:1957 #7 0x50eddf in event_base_dispatch /src/oss/libevent/libevent-github/.cmake-debug/../event.c:1768 #8 0x52d075 in event_dispatch_thread (/src/oss/libevent/libevent-github/.invest/217-evhttp-threaded/a.out+0x52d075) #9 0x7ffff74fc0a3 in start_thread /tmp/buildd/glibc-2.19/nptl/pthread_create.c:309 Fixes: #217 Closes: #222 Closes: #219 Gist: https://gist.github.com/azat/92cbb34232ac02d7972b (from #217 but thread-safe) --- bufferevent_sock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bufferevent_sock.c b/bufferevent_sock.c index eb731484..a2b381ac 100644 --- a/bufferevent_sock.c +++ b/bufferevent_sock.c @@ -501,23 +501,23 @@ bufferevent_socket_connect_hostname(struct bufferevent *bev, if (port < 1 || port > 65535) return -1; - BEV_LOCK(bev); - bev_p->dns_error = 0; - BEV_UNLOCK(bev); - - evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); - memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_protocol = IPPROTO_TCP; hint.ai_socktype = SOCK_STREAM; + evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); + + BEV_LOCK(bev); + bev_p->dns_error = 0; + bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP); bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP); bufferevent_incref_(bev); err = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev); + BEV_UNLOCK(bev); if (err == 0) { return 0; -- 2.40.0