]> granicus.if.org Git - libevent/commitdiff
Fix conceivable UAF of the bufferevent in evhttp_connection_free()
authorAzat Khuzhin <a3at.mail@gmail.com>
Tue, 13 Nov 2018 18:26:12 +0000 (21:26 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Tue, 13 Nov 2018 19:26:12 +0000 (22:26 +0300)
Although this is not a problem, since bufferevent uses finalizers and
will free itself only from the loop (well this is not a problem if you
do not play games with various event_base in different threads) it
generates questions, so rewrite it in more reliable way.

Fixes: #712
http.c

diff --git a/http.c b/http.c
index cd3f2f050ddf9fc4c9b14bee786402a5a67178a7..27d3bd9e6957cb97091c43a257d561cd679e5308 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1203,6 +1203,7 @@ void
 evhttp_connection_free(struct evhttp_connection *evcon)
 {
        struct evhttp_request *req;
+       int need_close = 0;
 
        /* notify interested parties that this connection is going down */
        if (evcon->fd != -1) {
@@ -1229,21 +1230,22 @@ evhttp_connection_free(struct evhttp_connection *evcon)
                event_debug_unassign(&evcon->retry_ev);
        }
 
-       if (evcon->bufev != NULL)
-               bufferevent_free(evcon->bufev);
-
        event_deferred_cb_cancel_(get_deferred_queue(evcon),
            &evcon->read_more_deferred_cb);
 
-       if (evcon->fd == -1)
-               evcon->fd = bufferevent_getfd(evcon->bufev);
+       if (evcon->bufev != NULL) {
+               need_close =
+                       !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE);
+               if (evcon->fd == -1)
+                       evcon->fd = bufferevent_getfd(evcon->bufev);
+
+               bufferevent_free(evcon->bufev);
+       }
 
        if (evcon->fd != -1) {
-               bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
                shutdown(evcon->fd, EVUTIL_SHUT_WR);
-               if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
+               if (need_close)
                        evutil_closesocket(evcon->fd);
-               }
        }
 
        if (evcon->bind_address != NULL)