From 6830828c9eecd9ab14404f2f49f19b56dec62130 Mon Sep 17 00:00:00 2001 From: Marc Aldorasi <marc@groundctl.com> Date: Thu, 30 Jul 2020 14:16:17 -0400 Subject: [PATCH 1/2] multi_remove_handle: close unused connect-only connections Previously any connect-only connections in a multi handle would be kept alive until the multi handle was closed. Since these connections cannot be re-used, they can be marked for closure when the associated easy handle is removed from the multi handle. Closes #5749 Upstream-commit: d5bb459ccf1fc5980ae4b95c05b4ecf6454a7599 Signed-off-by: Kamil Dudka <kdudka@redhat.com> --- lib/multi.c | 34 ++++++++++++++++++++++++++++++---- tests/data/test1554 | 6 ++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/multi.c b/lib/multi.c index 249e360..f1371bd 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -689,6 +689,26 @@ static CURLcode multi_done(struct Curl_easy *data, return result; } +static int close_connect_only(struct connectdata *conn, void *param) +{ + struct Curl_easy *data = param; + + if(data->state.lastconnect != conn) + return 0; + + if(conn->data != data) + return 1; + conn->data = NULL; + + if(!conn->bits.connect_only) + return 1; + + connclose(conn, "Removing connect-only easy handle"); + conn->bits.connect_only = FALSE; + + return 1; +} + CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, struct Curl_easy *data) { @@ -776,10 +796,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, multi_done() as that may actually call Curl_expire that uses this */ Curl_llist_destroy(&data->state.timeoutlist, NULL); - /* as this was using a shared connection cache we clear the pointer to that - since we're not part of that multi handle anymore */ - data->state.conn_cache = NULL; - /* change state without using multistate(), only to make singlesocket() do what we want */ data->mstate = CURLM_STATE_COMPLETED; @@ -789,12 +805,22 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* Remove the association between the connection and the handle */ Curl_detach_connnection(data); + if(data->state.lastconnect) { + /* Mark any connect-only connection for closure */ + Curl_conncache_foreach(data, data->state.conn_cache, + data, &close_connect_only); + } + #ifdef USE_LIBPSL /* Remove the PSL association. */ if(data->psl == &multi->psl) data->psl = NULL; #endif + /* as this was using a shared connection cache we clear the pointer to that + since we're not part of that multi handle anymore */ + data->state.conn_cache = NULL; + data->multi = NULL; /* clear the association to this multi handle */ /* make sure there's no pending message in the queue sent from this easy diff --git a/tests/data/test1554 b/tests/data/test1554 index d3926d9..fffa6ad 100644 --- a/tests/data/test1554 +++ b/tests/data/test1554 @@ -50,6 +50,8 @@ run 1: foobar and so on fun! <- Mutex unlock -> Mutex lock <- Mutex unlock +-> Mutex lock +<- Mutex unlock run 1: foobar and so on fun! -> Mutex lock <- Mutex unlock @@ -65,6 +67,8 @@ run 1: foobar and so on fun! <- Mutex unlock -> Mutex lock <- Mutex unlock +-> Mutex lock +<- Mutex unlock run 1: foobar and so on fun! -> Mutex lock <- Mutex unlock @@ -74,6 +78,8 @@ run 1: foobar and so on fun! <- Mutex unlock -> Mutex lock <- Mutex unlock +-> Mutex lock +<- Mutex unlock </datacheck> </reply> -- 2.25.4 From 01148ee40dd913a169435b0f9ea90e6393821e70 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg <daniel@haxx.se> Date: Sun, 16 Aug 2020 11:34:35 +0200 Subject: [PATCH 2/2] Curl_easy: remember last connection by id, not by pointer CVE-2020-8231 Bug: https://curl.haxx.se/docs/CVE-2020-8231.html Reported-by: Marc Aldorasi Closes #5824 Upstream-commit: 3c9e021f86872baae412a427e807fbfa2f3e8a22 Signed-off-by: Kamil Dudka <kdudka@redhat.com> --- lib/connect.c | 19 ++++++++++--------- lib/easy.c | 3 +-- lib/multi.c | 9 +++++---- lib/url.c | 2 +- lib/urldata.h | 2 +- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/connect.c b/lib/connect.c index 29293f0..e1c5662 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -1363,15 +1363,15 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ } struct connfind { - struct connectdata *tofind; - bool found; + long id_tofind; + struct connectdata *found; }; static int conn_is_conn(struct connectdata *conn, void *param) { struct connfind *f = (struct connfind *)param; - if(conn == f->tofind) { - f->found = TRUE; + if(conn->connection_id == f->id_tofind) { + f->found = conn; return 1; } return 0; @@ -1393,21 +1393,22 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, * - that is associated with a multi handle, and whose connection * was detached with CURLOPT_CONNECT_ONLY */ - if(data->state.lastconnect && (data->multi_easy || data->multi)) { - struct connectdata *c = data->state.lastconnect; + if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) { + struct connectdata *c; struct connfind find; - find.tofind = data->state.lastconnect; - find.found = FALSE; + find.id_tofind = data->state.lastconnect_id; + find.found = NULL; Curl_conncache_foreach(data, data->multi_easy? &data->multi_easy->conn_cache: &data->multi->conn_cache, &find, conn_is_conn); if(!find.found) { - data->state.lastconnect = NULL; + data->state.lastconnect_id = -1; return CURL_SOCKET_BAD; } + c = find.found; if(connp) { /* only store this if the caller cares for it */ *connp = c; diff --git a/lib/easy.c b/lib/easy.c index 292cca7..a69eb9e 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -838,8 +838,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) /* the connection cache is setup on demand */ outcurl->state.conn_cache = NULL; - - outcurl->state.lastconnect = NULL; + outcurl->state.lastconnect_id = -1; outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; diff --git a/lib/multi.c b/lib/multi.c index f1371bd..778c537 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -455,6 +455,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->state.conn_cache = &data->share->conn_cache; else data->state.conn_cache = &multi->conn_cache; + data->state.lastconnect_id = -1; #ifdef USE_LIBPSL /* Do the same for PSL. */ @@ -677,11 +678,11 @@ static CURLcode multi_done(struct Curl_easy *data, CONNCACHE_UNLOCK(data); if(Curl_conncache_return_conn(data, conn)) { /* remember the most recently used connection */ - data->state.lastconnect = conn; + data->state.lastconnect_id = conn->connection_id; infof(data, "%s\n", buffer); } else - data->state.lastconnect = NULL; + data->state.lastconnect_id = -1; } Curl_safefree(data->state.buffer); @@ -693,7 +694,7 @@ static int close_connect_only(struct connectdata *conn, void *param) { struct Curl_easy *data = param; - if(data->state.lastconnect != conn) + if(data->state.lastconnect_id != conn->connection_id) return 0; if(conn->data != data) @@ -805,7 +806,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* Remove the association between the connection and the handle */ Curl_detach_connnection(data); - if(data->state.lastconnect) { + if(data->state.lastconnect_id != -1) { /* Mark any connect-only connection for closure */ Curl_conncache_foreach(data, data->state.conn_cache, data, &close_connect_only); diff --git a/lib/url.c b/lib/url.c index a1a6b69..2919a3d 100644 --- a/lib/url.c +++ b/lib/url.c @@ -630,7 +630,7 @@ CURLcode Curl_open(struct Curl_easy **curl) Curl_initinfo(data); /* most recent connection is not yet defined */ - data->state.lastconnect = NULL; + data->state.lastconnect_id = -1; data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ diff --git a/lib/urldata.h b/lib/urldata.h index f80a02d..6d8eb69 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1300,7 +1300,7 @@ struct UrlState { /* buffers to store authentication data in, as parsed from input options */ struct curltime keeps_speed; /* for the progress meter really */ - struct connectdata *lastconnect; /* The last connection, NULL if undefined */ + long lastconnect_id; /* The last connection, -1 if undefined */ struct dynbuf headerb; /* buffer to store headers in */ char *buffer; /* download buffer */ -- 2.25.4