From 5495ee4cfc7367fba94416bd12a2c5b3b827df5c Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Nov 24 2014 13:56:05 +0000 Subject: Resolves: #1166239 - low-speed-limit: avoid timeout flood --- diff --git a/0031-curl-7.29.0-cacdc27f.patch b/0031-curl-7.29.0-cacdc27f.patch new file mode 100644 index 0000000..85b6977 --- /dev/null +++ b/0031-curl-7.29.0-cacdc27f.patch @@ -0,0 +1,187 @@ +From 7383e925273fd54850f2a7d6365e5e4e7600ddb2 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 25 Aug 2014 11:34:14 +0200 +Subject: [PATCH] low-speed-limit: avoid timeout flood + +Introducing Curl_expire_latest(). To be used when we the code flow only +wants to get called at a later time that is "no later than X" so that +something can be checked (and another timeout be added). + +The low-speed logic for example could easily be made to set very many +expire timeouts if it would be called faster or sooner than what it had +set its own timer and this goes for a few other timers too that aren't +explictiy checked for timer expiration in the code. + +If there's no condition the code that says if(time-passed >= TIME), then +Curl_expire_latest() is preferred to Curl_expire(). + +If there exists such a condition, it is on the other hand important that +Curl_expire() is used and not the other. + +Bug: http://curl.haxx.se/mail/lib-2014-06/0235.html +Reported-by: Florian Weimer +Upstream-commit: cacdc27f52ba7b0bf08aa57886bfbd18bc82ebfb +Signed-off-by: Kamil Dudka +--- + lib/asyn-ares.c | 2 +- + lib/asyn-thread.c | 2 +- + lib/connect.c | 2 +- + lib/multi.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- + lib/multiif.h | 1 + + lib/speedcheck.c | 4 ++-- + 6 files changed, 49 insertions(+), 8 deletions(-) + +diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c +index 081667d..f14e3e1 100644 +--- a/lib/asyn-ares.c ++++ b/lib/asyn-ares.c +@@ -235,7 +235,7 @@ int Curl_resolver_getsock(struct connectdata *conn, + milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000); + if(milli == 0) + milli += 10; +- Curl_expire(conn->data, milli); ++ Curl_expire_latest(conn->data, milli); + + return max; + } +diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c +index 66fb510..bc94c5d 100644 +--- a/lib/asyn-thread.c ++++ b/lib/asyn-thread.c +@@ -548,7 +548,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, + td->poll_interval = 250; + + td->interval_end = elapsed + td->poll_interval; +- Curl_expire(conn->data, td->poll_interval); ++ Curl_expire_latest(conn->data, td->poll_interval); + } + + return CURLE_OK; +diff --git a/lib/connect.c b/lib/connect.c +index 413c66e..0fea766 100644 +--- a/lib/connect.c ++++ b/lib/connect.c +@@ -926,7 +926,7 @@ singleipconnect(struct connectdata *conn, + + conn->connecttime = Curl_tvnow(); + if(conn->num_addr > 1) +- Curl_expire(data, conn->timeoutms_per_addr); ++ Curl_expire_latest(data, conn->timeoutms_per_addr); + + /* Connect TCP sockets, bind UDP */ + if(!isconnected && (conn->socktype == SOCK_STREAM)) { +diff --git a/lib/multi.c b/lib/multi.c +index 476f058..6fc5bb1 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -1411,7 +1411,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, + data->set.buffer_size : BUFSIZE); + timeout_ms = Curl_sleep_time(data->set.max_send_speed, + data->progress.ulspeed, buffersize); +- Curl_expire(data, timeout_ms); ++ Curl_expire_latest(data, timeout_ms); + break; + } + +@@ -1427,7 +1427,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, + data->set.buffer_size : BUFSIZE); + timeout_ms = Curl_sleep_time(data->set.max_recv_speed, + data->progress.dlspeed, buffersize); +- Curl_expire(data, timeout_ms); ++ Curl_expire_latest(data, timeout_ms); + break; + } + +@@ -1490,7 +1490,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, + + /* expire the new receiving pipeline head */ + if(easy->easy_conn->recv_pipe->head) +- Curl_expire(easy->easy_conn->recv_pipe->head->ptr, 1); ++ Curl_expire_latest(easy->easy_conn->recv_pipe->head->ptr, 1); + + /* Check if we can move pending requests to send pipe */ + checkPendPipeline(easy->easy_conn); +@@ -2647,6 +2647,46 @@ void Curl_expire(struct SessionHandle *data, long milli) + #endif + } + ++/* ++ * Curl_expire_latest() ++ * ++ * This is like Curl_expire() but will only add a timeout node to the list of ++ * timers if there is no timeout that will expire before the given time. ++ * ++ * Use this function if the code logic risks calling this function many times ++ * or if there's no particular conditional wait in the code for this specific ++ * time-out period to expire. ++ * ++ */ ++void Curl_expire_latest(struct SessionHandle *data, long milli) ++{ ++ struct timeval *exp = &data->state.expiretime; ++ ++ struct timeval set; ++ ++ set = Curl_tvnow(); ++ set.tv_sec += milli/1000; ++ set.tv_usec += (milli%1000)*1000; ++ ++ if(set.tv_usec >= 1000000) { ++ set.tv_sec++; ++ set.tv_usec -= 1000000; ++ } ++ ++ if(exp->tv_sec || exp->tv_usec) { ++ /* This means that the struct is added as a node in the splay tree. ++ Compare if the new time is earlier, and only remove-old/add-new if it ++ is. */ ++ long diff = curlx_tvdiff(set, *exp); ++ if(diff > 0) ++ /* the new expire time was later than the top time, so just skip this */ ++ return; ++ } ++ ++ /* Just add the timeout like normal */ ++ Curl_expire(data, milli); ++} ++ + CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t s, void *hashp) + { +diff --git a/lib/multiif.h b/lib/multiif.h +index d1b0e2f..9c00cc8 100644 +--- a/lib/multiif.h ++++ b/lib/multiif.h +@@ -26,6 +26,7 @@ + * Prototypes for library-wide functions provided by multi.c + */ + void Curl_expire(struct SessionHandle *data, long milli); ++void Curl_expire_latest(struct SessionHandle *data, long milli); + + bool Curl_multi_canPipeline(const struct Curl_multi* multi); + void Curl_multi_handlePipeBreak(struct SessionHandle *data); +diff --git a/lib/speedcheck.c b/lib/speedcheck.c +index ea17a59..a9b421d 100644 +--- a/lib/speedcheck.c ++++ b/lib/speedcheck.c +@@ -57,7 +57,7 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, + } + else { + /* wait complete low_speed_time */ +- Curl_expire(data, nextcheck); ++ Curl_expire_latest(data, nextcheck); + } + } + else { +@@ -68,7 +68,7 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, + /* if there is a low speed limit enabled, we set the expire timer to + make this connection's speed get checked again no later than when + this time is up */ +- Curl_expire(data, data->set.low_speed_time*1000); ++ Curl_expire_latest(data, data->set.low_speed_time*1000); + } + return CURLE_OK; + } +-- +2.1.0 + diff --git a/curl.spec b/curl.spec index 336eb69..efb9b2a 100644 --- a/curl.spec +++ b/curl.spec @@ -94,6 +94,9 @@ Patch29: 0029-curl-7.29.0-tls12.patch # disable libcurl-level downgrade to SSLv3 (#1166567) Patch30: 0030-curl-7.29.0-3f430c9c.patch +# low-speed-limit: avoid timeout flood (#1166239) +Patch31: 0031-curl-7.29.0-cacdc27f.patch + # patch making libcurl multilib ready Patch101: 0101-curl-7.29.0-multilib.patch @@ -231,6 +234,7 @@ documentation of the library, too. %patch28 -p1 %patch29 -p1 %patch30 -p1 +%patch31 -p1 # Fedora patches %patch101 -p1 @@ -354,6 +358,7 @@ rm -rf $RPM_BUILD_ROOT * Mon Nov 24 2014 Kamil Dudka 7.29.0-26 - allow to use TLS 1.1 and TLS 1.2 (#1153814) - disable libcurl-level downgrade to SSLv3 (#1166567) +- low-speed-limit: avoid timeout flood (#1166239) * Wed Nov 05 2014 Kamil Dudka 7.29.0-25 - fix handling of CURLOPT_COPYPOSTFIELDS in curl_easy_duphandle (CVE-2014-3707)