]> granicus.if.org Git - libevent/commitdiff
be_sock: bufferevent_socket_connect_hostname(): make it thread-safe
authorAzat Khuzhin <a3at.mail@gmail.com>
Mon, 23 Nov 2015 10:52:31 +0000 (13:52 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Fri, 27 Nov 2015 19:45:09 +0000 (22:45 +0300)
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

index eb7314849b606275817d676003c3c37804c4d116..a2b381ac4df67f5ee5d8d567b995523cfca00764 100644 (file)
@@ -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;