[curl/f20] Resolves: #1166239 - low-speed-limit: avoid timeout flood

Kamil Dudka kdudka at fedoraproject.org
Mon Nov 24 12:55:23 UTC 2014


commit f35c74dedac0a0d0d60289bff9c2e79aec591cf0
Author: Kamil Dudka <kdudka at redhat.com>
Date:   Fri Nov 21 13:10:00 2014 +0100

    Resolves: #1166239 - low-speed-limit: avoid timeout flood

 0019-curl-7.32.0-cacdc27f.patch |  187 +++++++++++++++++++++++++++++++++++++++
 curl.spec                       |    5 +
 2 files changed, 192 insertions(+), 0 deletions(-)
---
diff --git a/0019-curl-7.32.0-cacdc27f.patch b/0019-curl-7.32.0-cacdc27f.patch
new file mode 100644
index 0000000..e5ca418
--- /dev/null
+++ b/0019-curl-7.32.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
+@@ -502,7 +502,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
+@@ -1016,7 +1016,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
+@@ -1454,7 +1454,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;
+       }
+ 
+@@ -1470,7 +1470,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;
+       }
+ 
+@@ -1532,7 +1532,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(data->easy_conn->recv_pipe->head->ptr, 1);
+ 
+         /* Check if we can move pending requests to send pipe */
+         Curl_multi_process_pending_handles(multi);
+@@ -2644,6 +2644,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
+@@ -28,6 +28,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_pipeline_enabled(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 d689328..2d8780d 100644
--- a/curl.spec
+++ b/curl.spec
@@ -61,6 +61,9 @@ Patch17: 0017-curl-7.32.0-tls12.patch
 # disable libcurl-level downgrade to SSLv3 (#1166567)
 Patch18: 0018-curl-7.32.0-3f430c9c.patch
 
+# low-speed-limit: avoid timeout flood (#1166239)
+Patch19: 0019-curl-7.32.0-cacdc27f.patch
+
 # patch making libcurl multilib ready
 Patch101: 0101-curl-7.32.0-multilib.patch
 
@@ -191,6 +194,7 @@ documentation of the library, too.
 %patch16 -p1
 %patch17 -p1
 %patch18 -p1
+%patch19 -p1
 
 # Fedora patches
 %patch101 -p1
@@ -315,6 +319,7 @@ rm -rf $RPM_BUILD_ROOT
 * Mon Nov 24 2014 Kamil Dudka <kdudka at redhat.com> 7.32.0-16
 - 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.32.0-15
 - fix handling of CURLOPT_COPYPOSTFIELDS in curl_easy_duphandle (CVE-2014-3707)


More information about the scm-commits mailing list