[curl/f19] Resolves: #1166239 - low-speed-limit: avoid timeout flood
Kamil Dudka
kdudka at fedoraproject.org
Mon Nov 24 13:59:19 UTC 2014
commit 5495ee4cfc7367fba94416bd12a2c5b3b827df5c
Author: Kamil Dudka <kdudka at redhat.com>
Date: Fri Nov 21 13:10:00 2014 +0100
Resolves: #1166239 - low-speed-limit: avoid timeout flood
0031-curl-7.29.0-cacdc27f.patch | 187 +++++++++++++++++++++++++++++++++++++++
curl.spec | 5 +
2 files changed, 192 insertions(+), 0 deletions(-)
---
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 <daniel at haxx.se>
+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 <kdudka at redhat.com>
+---
+ 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 <kdudka at redhat.com> 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 <kdudka at redhat.com> 7.29.0-25
- fix handling of CURLOPT_COPYPOSTFIELDS in curl_easy_duphandle (CVE-2014-3707)
More information about the scm-commits
mailing list