]> code.ossystems Code Review - openembedded-core.git/commitdiff
curl: fix CVE-2020-8231/8284/8285/8286
authorLee Chee Yang <chee.yang.lee@intel.com>
Wed, 13 Jan 2021 09:29:35 +0000 (17:29 +0800)
committerSteve Sakoman <steve@sakoman.com>
Tue, 19 Jan 2021 14:22:10 +0000 (04:22 -1000)
backport CVE-2020-8284 fixes from upstream, but drop
binary file tests/data/test1465.

upstream fixes for CVE-2020-8231, CVE-2020-8285 and CVE-2020-8286
does not applies cleanly to 7.69.1, fedora have working patch
hence import patch from Fedora.
https://koji.fedoraproject.org/koji/rpminfo?rpmID=24270817

Signed-off-by: Lee Chee Yang <chee.yang.lee@intel.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
meta/recipes-support/curl/curl/CVE-2020-8231.patch [new file with mode: 0644]
meta/recipes-support/curl/curl/CVE-2020-8284.patch [new file with mode: 0644]
meta/recipes-support/curl/curl/CVE-2020-8285.patch [new file with mode: 0644]
meta/recipes-support/curl/curl/CVE-2020-8286.patch [new file with mode: 0644]
meta/recipes-support/curl/curl_7.69.1.bb

diff --git a/meta/recipes-support/curl/curl/CVE-2020-8231.patch b/meta/recipes-support/curl/curl/CVE-2020-8231.patch
new file mode 100644 (file)
index 0000000..51f4004
--- /dev/null
@@ -0,0 +1,1092 @@
+From c3359693e17fccdf2a04f0b908bc8f51cdc38133 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Mon, 27 Apr 2020 00:33:21 +0200
+Subject: [PATCH 1/3] conncache: various concept cleanups
+
+More connection cache accesses are protected by locks.
+
+CONNCACHE_* is a beter prefix for the connection cache lock macros.
+
+Curl_attach_connnection: now called as soon as there's a connection
+struct available and before the connection is added to the connection
+cache.
+
+Curl_disconnect: now assumes that the connection is already removed from
+the connection cache.
+
+Ref: #4915
+Closes #5009
+
+Upstream-commit: c06902713998d68202c5a764de910ba8d0e8f54d
+Signed-off-by: Kamil Dudka <kdudka@redhat.com>
+
+Upstream-Status: Backport [import from fedora https://koji.fedoraproject.org/koji/fileinfo?rpmID=24270817&filename=0004-curl-7.69.1-CVE-2020-8231.patch ]
+CVE: CVE-2020-8286
+Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com>
+---
+ lib/conncache.c       | 87 ++++++++++++++++++++-----------------------
+ lib/conncache.h       |  9 ++---
+ lib/hostip.c          | 12 +++---
+ lib/http_negotiate.h  |  6 ++-
+ lib/http_ntlm.h       |  6 ++-
+ lib/multi.c           | 56 ++++++++++++++--------------
+ lib/multiif.h         |  1 +
+ lib/url.c             | 69 ++++++++++++++++++----------------
+ tests/data/test1554   | 14 +++++++
+ tests/unit/unit1620.c |  6 +--
+ 10 files changed, 139 insertions(+), 127 deletions(-)
+
+diff --git a/lib/conncache.c b/lib/conncache.c
+index cbd3bb1..95fcea6 100644
+--- a/lib/conncache.c
++++ b/lib/conncache.c
+@@ -49,53 +49,51 @@ static void conn_llist_dtor(void *user, void *element)
+   conn->bundle = NULL;
+ }
+-static CURLcode bundle_create(struct Curl_easy *data,
+-                              struct connectbundle **cb_ptr)
++static CURLcode bundle_create(struct connectbundle **bundlep)
+ {
+-  (void)data;
+-  DEBUGASSERT(*cb_ptr == NULL);
+-  *cb_ptr = malloc(sizeof(struct connectbundle));
+-  if(!*cb_ptr)
++  DEBUGASSERT(*bundlep == NULL);
++  *bundlep = malloc(sizeof(struct connectbundle));
++  if(!*bundlep)
+     return CURLE_OUT_OF_MEMORY;
+-  (*cb_ptr)->num_connections = 0;
+-  (*cb_ptr)->multiuse = BUNDLE_UNKNOWN;
++  (*bundlep)->num_connections = 0;
++  (*bundlep)->multiuse = BUNDLE_UNKNOWN;
+-  Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor);
++  Curl_llist_init(&(*bundlep)->conn_list, (curl_llist_dtor) conn_llist_dtor);
+   return CURLE_OK;
+ }
+-static void bundle_destroy(struct connectbundle *cb_ptr)
++static void bundle_destroy(struct connectbundle *bundle)
+ {
+-  if(!cb_ptr)
++  if(!bundle)
+     return;
+-  Curl_llist_destroy(&cb_ptr->conn_list, NULL);
++  Curl_llist_destroy(&bundle->conn_list, NULL);
+-  free(cb_ptr);
++  free(bundle);
+ }
+ /* Add a connection to a bundle */
+-static void bundle_add_conn(struct connectbundle *cb_ptr,
++static void bundle_add_conn(struct connectbundle *bundle,
+                             struct connectdata *conn)
+ {
+-  Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn,
++  Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
+                          &conn->bundle_node);
+-  conn->bundle = cb_ptr;
+-  cb_ptr->num_connections++;
++  conn->bundle = bundle;
++  bundle->num_connections++;
+ }
+ /* Remove a connection from a bundle */
+-static int bundle_remove_conn(struct connectbundle *cb_ptr,
++static int bundle_remove_conn(struct connectbundle *bundle,
+                               struct connectdata *conn)
+ {
+   struct curl_llist_element *curr;
+-  curr = cb_ptr->conn_list.head;
++  curr = bundle->conn_list.head;
+   while(curr) {
+     if(curr->ptr == conn) {
+-      Curl_llist_remove(&cb_ptr->conn_list, curr, NULL);
+-      cb_ptr->num_connections--;
++      Curl_llist_remove(&bundle->conn_list, curr, NULL);
++      bundle->num_connections--;
+       conn->bundle = NULL;
+       return 1; /* we removed a handle */
+     }
+@@ -162,20 +160,15 @@ static void hashkey(struct connectdata *conn, char *buf,
+   msnprintf(buf, len, "%ld%s", port, hostname);
+ }
+-void Curl_conncache_unlock(struct Curl_easy *data)
+-{
+-  CONN_UNLOCK(data);
+-}
+-
+ /* Returns number of connections currently held in the connection cache.
+    Locks/unlocks the cache itself!
+ */
+ size_t Curl_conncache_size(struct Curl_easy *data)
+ {
+   size_t num;
+-  CONN_LOCK(data);
++  CONNCACHE_LOCK(data);
+   num = data->state.conn_cache->num_conn;
+-  CONN_UNLOCK(data);
++  CONNCACHE_UNLOCK(data);
+   return num;
+ }
+@@ -188,7 +181,7 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+                                                  const char **hostp)
+ {
+   struct connectbundle *bundle = NULL;
+-  CONN_LOCK(conn->data);
++  CONNCACHE_LOCK(conn->data);
+   if(connc) {
+     char key[HASHKEY_SIZE];
+     hashkey(conn, key, sizeof(key), hostp);
+@@ -235,8 +228,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
+                                  struct connectdata *conn)
+ {
+   CURLcode result = CURLE_OK;
+-  struct connectbundle *bundle;
+-  struct connectbundle *new_bundle = NULL;
++  struct connectbundle *bundle = NULL;
+   struct Curl_easy *data = conn->data;
+   /* *find_bundle() locks the connection cache */
+@@ -245,20 +237,19 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
+     int rc;
+     char key[HASHKEY_SIZE];
+-    result = bundle_create(data, &new_bundle);
++    result = bundle_create(&bundle);
+     if(result) {
+       goto unlock;
+     }
+     hashkey(conn, key, sizeof(key), NULL);
+-    rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
++    rc = conncache_add_bundle(data->state.conn_cache, key, bundle);
+     if(!rc) {
+-      bundle_destroy(new_bundle);
++      bundle_destroy(bundle);
+       result = CURLE_OUT_OF_MEMORY;
+       goto unlock;
+     }
+-    bundle = new_bundle;
+   }
+   bundle_add_conn(bundle, conn);
+@@ -270,15 +261,17 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
+                conn->connection_id, connc->num_conn));
+   unlock:
+-  CONN_UNLOCK(data);
++  CONNCACHE_UNLOCK(data);
+   return result;
+ }
+ /*
+- * Removes the connectdata object from the connection cache *and* clears the
+- * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument
+- * depending on if the parent function already holds the lock or not.
++ * Removes the connectdata object from the connection cache, but does *not*
++ * clear the conn->data association. The transfer still owns this connection.
++ *
++ * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
++ * already holds the lock or not.
+  */
+ void Curl_conncache_remove_conn(struct Curl_easy *data,
+                                 struct connectdata *conn, bool lock)
+@@ -290,7 +283,7 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
+      due to a failed connection attempt, before being added to a bundle */
+   if(bundle) {
+     if(lock) {
+-      CONN_LOCK(data);
++      CONNCACHE_LOCK(data);
+     }
+     bundle_remove_conn(bundle, conn);
+     if(bundle->num_connections == 0)
+@@ -301,9 +294,8 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
+       DEBUGF(infof(data, "The cache now contains %zu members\n",
+                    connc->num_conn));
+     }
+-    conn->data = NULL; /* clear the association */
+     if(lock) {
+-      CONN_UNLOCK(data);
++      CONNCACHE_UNLOCK(data);
+     }
+   }
+ }
+@@ -332,7 +324,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
+   if(!connc)
+     return FALSE;
+-  CONN_LOCK(data);
++  CONNCACHE_LOCK(data);
+   Curl_hash_start_iterate(&connc->hash, &iter);
+   he = Curl_hash_next_element(&iter);
+@@ -350,12 +342,12 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
+       curr = curr->next;
+       if(1 == func(conn, param)) {
+-        CONN_UNLOCK(data);
++        CONNCACHE_UNLOCK(data);
+         return TRUE;
+       }
+     }
+   }
+-  CONN_UNLOCK(data);
++  CONNCACHE_UNLOCK(data);
+   return FALSE;
+ }
+@@ -494,7 +486,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
+   now = Curl_now();
+-  CONN_LOCK(data);
++  CONNCACHE_LOCK(data);
+   Curl_hash_start_iterate(&connc->hash, &iter);
+   he = Curl_hash_next_element(&iter);
+@@ -531,7 +523,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
+                  connc->num_conn));
+     conn_candidate->data = data; /* associate! */
+   }
+-  CONN_UNLOCK(data);
++  CONNCACHE_UNLOCK(data);
+   return conn_candidate;
+ }
+@@ -548,6 +540,7 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
+     sigpipe_ignore(conn->data, &pipe_st);
+     /* This will remove the connection from the cache */
+     connclose(conn, "kill all");
++    Curl_conncache_remove_conn(conn->data, conn, TRUE);
+     (void)Curl_disconnect(connc->closure_handle, conn, FALSE);
+     sigpipe_restore(&pipe_st);
+diff --git a/lib/conncache.h b/lib/conncache.h
+index e3e4c9c..3dda21c 100644
+--- a/lib/conncache.h
++++ b/lib/conncache.h
+@@ -45,21 +45,21 @@ struct conncache {
+ #ifdef CURLDEBUG
+ /* the debug versions of these macros make extra certain that the lock is
+    never doubly locked or unlocked */
+-#define CONN_LOCK(x) if((x)->share) {                                   \
++#define CONNCACHE_LOCK(x) if((x)->share) {                              \
+     Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
+     DEBUGASSERT(!(x)->state.conncache_lock);                            \
+     (x)->state.conncache_lock = TRUE;                                   \
+   }
+-#define CONN_UNLOCK(x) if((x)->share) {                                 \
++#define CONNCACHE_UNLOCK(x) if((x)->share) {                            \
+     DEBUGASSERT((x)->state.conncache_lock);                             \
+     (x)->state.conncache_lock = FALSE;                                  \
+     Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                     \
+   }
+ #else
+-#define CONN_LOCK(x) if((x)->share)                                     \
++#define CONNCACHE_LOCK(x) if((x)->share)                                \
+     Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
+-#define CONN_UNLOCK(x) if((x)->share)                   \
++#define CONNCACHE_UNLOCK(x) if((x)->share)              \
+     Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
+ #endif
+@@ -77,7 +77,6 @@ void Curl_conncache_destroy(struct conncache *connc);
+ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+                                                  struct conncache *connc,
+                                                  const char **hostp);
+-void Curl_conncache_unlock(struct Curl_easy *data);
+ /* returns number of connections currently held in the connection cache */
+ size_t Curl_conncache_size(struct Curl_easy *data);
+diff --git a/lib/hostip.c b/lib/hostip.c
+index c0feb79..f5bb634 100644
+--- a/lib/hostip.c
++++ b/lib/hostip.c
+@@ -1085,10 +1085,12 @@ CURLcode Curl_once_resolved(struct connectdata *conn,
+   result = Curl_setup_conn(conn, protocol_done);
+-  if(result)
+-    /* We're not allowed to return failure with memory left allocated
+-       in the connectdata struct, free those here */
+-    Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
+-
++  if(result) {
++    struct Curl_easy *data = conn->data;
++    DEBUGASSERT(data);
++    Curl_detach_connnection(data);
++    Curl_conncache_remove_conn(data, conn, TRUE);
++    Curl_disconnect(data, conn, TRUE);
++  }
+   return result;
+ }
+diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h
+index 4f0ac16..a737f6f 100644
+--- a/lib/http_negotiate.h
++++ b/lib/http_negotiate.h
+@@ -7,7 +7,7 @@
+  *                            | (__| |_| |  _ <| |___
+  *                             \___|\___/|_| \_\_____|
+  *
+- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
++ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+  *
+  * This software is licensed as described in the file COPYING, which
+  * you should have received as part of this distribution. The terms
+@@ -33,6 +33,8 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+ void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
+-#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
++#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
++#define Curl_http_auth_cleanup_negotiate(x)
++#endif
+ #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
+diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h
+index 003714d..3ebdf97 100644
+--- a/lib/http_ntlm.h
++++ b/lib/http_ntlm.h
+@@ -7,7 +7,7 @@
+  *                            | (__| |_| |  _ <| |___
+  *                             \___|\___/|_| \_\_____|
+  *
+- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
++ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+  *
+  * This software is licensed as described in the file COPYING, which
+  * you should have received as part of this distribution. The terms
+@@ -35,6 +35,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+ void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
+-#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
++#else /* !CURL_DISABLE_HTTP && USE_NTLM */
++#define Curl_http_auth_cleanup_ntlm(x)
++#endif
+ #endif /* HEADER_CURL_HTTP_NTLM_H */
+diff --git a/lib/multi.c b/lib/multi.c
+index e10e752..273653d 100644
+--- a/lib/multi.c
++++ b/lib/multi.c
+@@ -79,7 +79,6 @@ static CURLMcode add_next_timeout(struct curltime now,
+ static CURLMcode multi_timeout(struct Curl_multi *multi,
+                                long *timeout_ms);
+ static void process_pending_handles(struct Curl_multi *multi);
+-static void detach_connnection(struct Curl_easy *data);
+ #ifdef DEBUGBUILD
+ static const char * const statename[]={
+@@ -112,7 +111,7 @@ static void Curl_init_completed(struct Curl_easy *data)
+   /* Important: reset the conn pointer so that we don't point to memory
+      that could be freed anytime */
+-  detach_connnection(data);
++  Curl_detach_connnection(data);
+   Curl_expire_clear(data); /* stop all timers */
+ }
+@@ -506,6 +505,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
+      easy handle is added */
+   memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
++  CONNCACHE_LOCK(data);
+   /* The closure handle only ever has default timeouts set. To improve the
+      state somewhat we clone the timeouts from each added handle so that the
+      closure handle always has the same timeouts as the most recently added
+@@ -515,6 +515,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
+     data->set.server_response_timeout;
+   data->state.conn_cache->closure_handle->set.no_signal =
+     data->set.no_signal;
++  CONNCACHE_UNLOCK(data);
+   Curl_update_timer(multi);
+   return CURLM_OK;
+@@ -589,14 +590,14 @@ static CURLcode multi_done(struct Curl_easy *data,
+   process_pending_handles(data->multi); /* connection / multiplex */
+-  CONN_LOCK(data);
+-  detach_connnection(data);
++  CONNCACHE_LOCK(data);
++  Curl_detach_connnection(data);
+   if(CONN_INUSE(conn)) {
+     /* Stop if still used. */
+     /* conn->data must not remain pointing to this transfer since it is going
+        away! Find another to own it! */
+     conn->data = conn->easyq.head->ptr;
+-    CONN_UNLOCK(data);
++    CONNCACHE_UNLOCK(data);
+     DEBUGF(infof(data, "Connection still in use %zu, "
+                  "no more multi_done now!\n",
+                  conn->easyq.size));
+@@ -647,7 +648,8 @@ static CURLcode multi_done(struct Curl_easy *data,
+        || (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
+     CURLcode res2;
+     connclose(conn, "disconnecting");
+-    CONN_UNLOCK(data);
++    Curl_conncache_remove_conn(data, conn, FALSE);
++    CONNCACHE_UNLOCK(data);
+     res2 = Curl_disconnect(data, conn, premature);
+     /* If we had an error already, make sure we return that one. But
+@@ -666,7 +668,7 @@ static CURLcode multi_done(struct Curl_easy *data,
+               conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+               conn->host.dispname);
+     /* the connection is no longer in use by this transfer */
+-    CONN_UNLOCK(data);
++    CONNCACHE_UNLOCK(data);
+     if(Curl_conncache_return_conn(data, conn)) {
+       /* remember the most recently used connection */
+       data->state.lastconnect = conn;
+@@ -774,8 +776,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
+                                 vanish with this handle */
+   /* Remove the association between the connection and the handle */
+-  if(data->conn)
+-    detach_connnection(data);
++  Curl_detach_connnection(data);
+ #ifdef USE_LIBPSL
+   /* Remove the PSL association. */
+@@ -824,9 +825,13 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi)
+   return (multi && (multi->multiplexing));
+ }
+-/* This is the only function that should clear data->conn. This will
+-   occasionally be called with the pointer already cleared. */
+-static void detach_connnection(struct Curl_easy *data)
++/*
++ * Curl_detach_connnection() removes the given transfer from the connection.
++ *
++ * This is the only function that should clear data->conn. This will
++ * occasionally be called with the data->conn pointer already cleared.
++ */
++void Curl_detach_connnection(struct Curl_easy *data)
+ {
+   struct connectdata *conn = data->conn;
+   if(conn)
+@@ -834,7 +839,11 @@ static void detach_connnection(struct Curl_easy *data)
+   data->conn = NULL;
+ }
+-/* This is the only function that should assign data->conn */
++/*
++ * Curl_attach_connnection() attaches this transfer to this connection.
++ *
++ * This is the only function that should assign data->conn
++ */
+ void Curl_attach_connnection(struct Curl_easy *data,
+                              struct connectdata *conn)
+ {
+@@ -1536,19 +1545,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+     bool stream_error = FALSE;
+     rc = CURLM_OK;
+-    DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) ||
+-                (data->mstate >= CURLM_STATE_DONE) ||
+-                data->conn);
+-    if(!data->conn &&
+-       data->mstate > CURLM_STATE_CONNECT &&
+-       data->mstate < CURLM_STATE_DONE) {
+-      /* In all these states, the code will blindly access 'data->conn'
+-         so this is precaution that it isn't NULL. And it silences static
+-         analyzers. */
+-      failf(data, "In state %d with no conn, bail out!\n", data->mstate);
+-      return CURLM_INTERNAL_ERROR;
+-    }
+-
+     if(multi_ischanged(multi, TRUE)) {
+       DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+       process_pending_handles(multi); /* multiplexed */
+@@ -2231,8 +2227,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+          * access free'd data, if the connection is free'd and the handle
+          * removed before we perform the processing in CURLM_STATE_COMPLETED
+          */
+-        if(data->conn)
+-          detach_connnection(data);
++        Curl_detach_connnection(data);
+       }
+ #ifndef CURL_DISABLE_FTP
+@@ -2284,7 +2279,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
+             /* This is where we make sure that the conn pointer is reset.
+                We don't have to do this in every case block above where a
+                failure is detected */
+-            detach_connnection(data);
++            Curl_detach_connnection(data);
++
++            /* remove connection from cache */
++            Curl_conncache_remove_conn(data, conn, TRUE);
+             /* disconnect properly */
+             Curl_disconnect(data, conn, dead_connection);
+diff --git a/lib/multiif.h b/lib/multiif.h
+index bde755e..c07587b 100644
+--- a/lib/multiif.h
++++ b/lib/multiif.h
+@@ -33,6 +33,7 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id);
+ void Curl_update_timer(struct Curl_multi *multi);
+ void Curl_attach_connnection(struct Curl_easy *data,
+                              struct connectdata *conn);
++void Curl_detach_connnection(struct Curl_easy *data);
+ bool Curl_multiplex_wanted(const struct Curl_multi *multi);
+ void Curl_set_in_callback(struct Curl_easy *data, bool value);
+ bool Curl_is_in_callback(struct Curl_easy *easy);
+diff --git a/lib/url.c b/lib/url.c
+index a826f8a..4ed0623 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -679,9 +679,7 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
+ static void conn_shutdown(struct connectdata *conn)
+ {
+-  if(!conn)
+-    return;
+-
++  DEBUGASSERT(conn);
+   infof(conn->data, "Closing connection %ld\n", conn->connection_id);
+   DEBUGASSERT(conn->data);
+@@ -702,16 +700,11 @@ static void conn_shutdown(struct connectdata *conn)
+     Curl_closesocket(conn, conn->tempsock[0]);
+   if(CURL_SOCKET_BAD != conn->tempsock[1])
+     Curl_closesocket(conn, conn->tempsock[1]);
+-
+-  /* unlink ourselves. this should be called last since other shutdown
+-     procedures need a valid conn->data and this may clear it. */
+-  Curl_conncache_remove_conn(conn->data, conn, TRUE);
+ }
+ static void conn_free(struct connectdata *conn)
+ {
+-  if(!conn)
+-    return;
++  DEBUGASSERT(conn);
+   Curl_free_idnconverted_hostname(&conn->host);
+   Curl_free_idnconverted_hostname(&conn->conn_to_host);
+@@ -778,13 +771,17 @@ static void conn_free(struct connectdata *conn)
+ CURLcode Curl_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn, bool dead_connection)
+ {
+-  if(!conn)
+-    return CURLE_OK; /* this is closed and fine already */
++  /* there must be a connection to close */
++  DEBUGASSERT(conn);
+-  if(!data) {
+-    DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
+-    return CURLE_OK;
+-  }
++  /* it must be removed from the connection cache */
++  DEBUGASSERT(!conn->bundle);
++
++  /* there must be an associated transfer */
++  DEBUGASSERT(data);
++
++  /* the transfer must be detached from the connection */
++  DEBUGASSERT(!data->conn);
+   /*
+    * If this connection isn't marked to force-close, leave it open if there
+@@ -800,16 +797,11 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
+     conn->dns_entry = NULL;
+   }
+-  Curl_hostcache_prune(data); /* kill old DNS cache entries */
+-
+-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+   /* Cleanup NTLM connection-related data */
+   Curl_http_auth_cleanup_ntlm(conn);
+-#endif
+-#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
++
+   /* Cleanup NEGOTIATE connection-related data */
+   Curl_http_auth_cleanup_negotiate(conn);
+-#endif
+   /* the protocol specific disconnect handler and conn_shutdown need a transfer
+      for the connection! */
+@@ -1006,8 +998,12 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
+ static void prune_dead_connections(struct Curl_easy *data)
+ {
+   struct curltime now = Curl_now();
+-  timediff_t elapsed =
++  timediff_t elapsed;
++
++  CONNCACHE_LOCK(data);
++  elapsed =
+     Curl_timediff(now, data->state.conn_cache->last_cleanup);
++  CONNCACHE_UNLOCK(data);
+   if(elapsed >= 1000L) {
+     struct prunedead prune;
+@@ -1015,10 +1011,17 @@ static void prune_dead_connections(struct Curl_easy *data)
+     prune.extracted = NULL;
+     while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
+                                  call_extract_if_dead)) {
++      /* unlocked */
++
++      /* remove connection from cache */
++      Curl_conncache_remove_conn(data, prune.extracted, TRUE);
++
+       /* disconnect it */
+       (void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE);
+     }
++    CONNCACHE_LOCK(data);
+     data->state.conn_cache->last_cleanup = now;
++    CONNCACHE_UNLOCK(data);
+   }
+ }
+@@ -1078,7 +1081,7 @@ ConnectionExists(struct Curl_easy *data,
+         if(data->set.pipewait) {
+           infof(data, "Server doesn't support multiplex yet, wait\n");
+           *waitpipe = TRUE;
+-          Curl_conncache_unlock(data);
++          CONNCACHE_UNLOCK(data);
+           return FALSE; /* no re-use */
+         }
+@@ -1402,11 +1405,12 @@ ConnectionExists(struct Curl_easy *data,
+   if(chosen) {
+     /* mark it as used before releasing the lock */
+     chosen->data = data; /* own it! */
+-    Curl_conncache_unlock(data);
++    Curl_attach_connnection(data, chosen);
++    CONNCACHE_UNLOCK(data);
+     *usethis = chosen;
+     return TRUE; /* yes, we found one to use! */
+   }
+-  Curl_conncache_unlock(data);
++  CONNCACHE_UNLOCK(data);
+   if(foundPendingCandidate && data->set.pipewait) {
+     infof(data,
+@@ -3519,6 +3523,7 @@ static CURLcode create_conn(struct Curl_easy *data,
+     if(!result) {
+       conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
++      Curl_attach_connnection(data, conn);
+       result = Curl_conncache_add_conn(data->state.conn_cache, conn);
+       if(result)
+         goto out;
+@@ -3533,7 +3538,6 @@ static CURLcode create_conn(struct Curl_easy *data,
+         (void)conn->handler->done(conn, result, FALSE);
+         goto out;
+       }
+-      Curl_attach_connnection(data, conn);
+       Curl_setup_transfer(data, -1, -1, FALSE, -1);
+     }
+@@ -3683,7 +3687,7 @@ static CURLcode create_conn(struct Curl_easy *data,
+         /* The bundle is full. Extract the oldest connection. */
+         conn_candidate = Curl_conncache_extract_bundle(data, bundle);
+-        Curl_conncache_unlock(data);
++        CONNCACHE_UNLOCK(data);
+         if(conn_candidate)
+           (void)Curl_disconnect(data, conn_candidate,
+@@ -3695,7 +3699,7 @@ static CURLcode create_conn(struct Curl_easy *data,
+         }
+       }
+       else
+-        Curl_conncache_unlock(data);
++        CONNCACHE_UNLOCK(data);
+     }
+@@ -3729,6 +3733,8 @@ static CURLcode create_conn(struct Curl_easy *data,
+        * This is a brand new connection, so let's store it in the connection
+        * cache of ours!
+        */
++      Curl_attach_connnection(data, conn);
++
+       result = Curl_conncache_add_conn(data->state.conn_cache, conn);
+       if(result)
+         goto out;
+@@ -3883,7 +3889,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
+   result = create_conn(data, &conn, asyncp);
+   if(!result) {
+-    if(CONN_INUSE(conn))
++    if(CONN_INUSE(conn) > 1)
+       /* multiplexed */
+       *protocol_done = TRUE;
+     else if(!*asyncp) {
+@@ -3900,11 +3906,10 @@ CURLcode Curl_connect(struct Curl_easy *data,
+   else if(result && conn) {
+     /* We're not allowed to return failure with memory left allocated in the
+        connectdata struct, free those here */
++    Curl_detach_connnection(data);
++    Curl_conncache_remove_conn(data, conn, TRUE);
+     Curl_disconnect(data, conn, TRUE);
+   }
+-  else if(!result && !data->conn)
+-    /* FILE: transfers already have the connection attached */
+-    Curl_attach_connnection(data, conn);
+   return result;
+ }
+diff --git a/tests/data/test1554 b/tests/data/test1554
+index 06f1897..d3926d9 100644
+--- a/tests/data/test1554
++++ b/tests/data/test1554
+@@ -29,6 +29,12 @@ run 1: foobar and so on fun!
+ <- Mutex unlock
+ -> Mutex lock
+ <- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
+ run 1: foobar and so on fun!
+ -> Mutex lock
+ <- Mutex unlock
+@@ -40,6 +46,10 @@ run 1: foobar and so on fun!
+ <- Mutex unlock
+ -> Mutex lock
+ <- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
+ run 1: foobar and so on fun!
+ -> Mutex lock
+ <- Mutex unlock
+@@ -51,6 +61,10 @@ run 1: foobar and so on fun!
+ <- Mutex unlock
+ -> Mutex lock
+ <- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
++-> Mutex lock
++<- Mutex unlock
+ run 1: foobar and so on fun!
+ -> Mutex lock
+ <- Mutex unlock
+diff --git a/tests/unit/unit1620.c b/tests/unit/unit1620.c
+index 6e572c6..b23e5b9 100644
+--- a/tests/unit/unit1620.c
++++ b/tests/unit/unit1620.c
+@@ -5,7 +5,7 @@
+  *                            | (__| |_| |  _ <| |___
+  *                             \___|\___/|_| \_\_____|
+  *
+- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
++ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+  *
+  * This software is licensed as described in the file COPYING, which
+  * you should have received as part of this distribution. The terms
+@@ -73,10 +73,6 @@ UNITTEST_START
+   fail_unless(rc == CURLE_OK,
+               "Curl_parse_login_details() failed");
+-  rc = Curl_disconnect(empty, empty->conn, FALSE);
+-  fail_unless(rc == CURLE_OK,
+-              "Curl_disconnect() with dead_connection set FALSE failed");
+-
+   Curl_freeset(empty);
+   for(i = (enum dupstring)0; i < STRING_LAST; i++) {
+     fail_unless(empty->set.str[i] == NULL,
+-- 
+2.25.4
+
+
+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 2/3] 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
+@@ -682,6 +682,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)
+ {
+@@ -765,10 +785,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;
+@@ -778,12 +794,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 3/3] 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
+@@ -1356,15 +1356,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;
+@@ -1386,21 +1386,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
+@@ -831,8 +831,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
+@@ -453,6 +453,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. */
+@@ -671,11 +672,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_free_request_state(data);
+@@ -686,7 +687,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)
+@@ -794,7 +795,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
+@@ -617,7 +617,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
+@@ -1332,7 +1332,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 */
+   char *headerbuff; /* allocated buffer to store headers in */
+   size_t headersize;   /* size of the allocation */
+-- 
+2.25.4
+
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8284.patch b/meta/recipes-support/curl/curl/CVE-2020-8284.patch
new file mode 100644 (file)
index 0000000..ed6e804
--- /dev/null
@@ -0,0 +1,209 @@
+From ec9cc725d598ac77de7b6df8afeec292b3c8ad46 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 24 Nov 2020 14:56:57 +0100
+Subject: [PATCH] ftp: CURLOPT_FTP_SKIP_PASV_IP by default
+
+The command line tool also independently sets --ftp-skip-pasv-ip by
+default.
+
+Ten test cases updated to adapt the modified --libcurl output.
+
+Bug: https://curl.se/docs/CVE-2020-8284.html
+CVE-2020-8284
+
+Reported-by: Varnavas Papaioannou
+
+Upstream-Status: Backport [https://github.com/curl/curl/commit/ec9cc725d598ac]
+CVE: CVE-2020-8284
+Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com>
+
+---
+ docs/cmdline-opts/ftp-skip-pasv-ip.d         |   2 ++
+ docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 |   8 +++++---
+ lib/url.c                                    |   1 +
+ src/tool_cfgable.c                           |   1 +
+ tests/data/test1400                          |   1 +
+ tests/data/test1401                          |   1 +
+ tests/data/test1402                          |   1 +
+ tests/data/test1403                          |   1 +
+ tests/data/test1404                          |   1 +
+ tests/data/test1405                          |   1 +
+ tests/data/test1406                          |   1 +
+ tests/data/test1407                          |   1 +
+ tests/data/test1420                          |   1 +
+ 14 files changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/docs/cmdline-opts/ftp-skip-pasv-ip.d b/docs/cmdline-opts/ftp-skip-pasv-ip.d
+index d6fd4589b1e..bcf4e7e62f2 100644
+--- a/docs/cmdline-opts/ftp-skip-pasv-ip.d
++++ b/docs/cmdline-opts/ftp-skip-pasv-ip.d
+@@ -10,4 +10,6 @@ to curl's PASV command when curl connects the data connection. Instead curl
+ will re-use the same IP address it already uses for the control
+ connection.
++Since curl 7.74.0 this option is enabled by default.
++
+ This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3 b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
+index d6217d0d8ca..fa87ddce769 100644
+--- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
++++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.3
+@@ -5,7 +5,7 @@
+ .\" *                            | (__| |_| |  _ <| |___
+ .\" *                             \___|\___/|_| \_\_____|
+ .\" *
+-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
++.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ .\" *
+ .\" * This software is licensed as described in the file COPYING, which
+ .\" * you should have received as part of this distribution. The terms
+@@ -35,11 +35,13 @@ address it already uses for the control connection. But it will use the port
+ number from the 227-response.
+ This option thus allows libcurl to work around broken server installations
+-that due to NATs, firewalls or incompetence report the wrong IP address back.
++that due to NATs, firewalls or incompetence report the wrong IP address
++back. Setting the option also reduces the risk for various sorts of client
++abuse by malicious servers.
+ This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+ .SH DEFAULT
+-0
++1 since 7.74.0, was 0 before then.
+ .SH PROTOCOLS
+ FTP
+ .SH EXAMPLE
+diff --git a/lib/url.c b/lib/url.c
+index f8b2a0030de..2b0ba87ba87 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -497,6 +497,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
+   set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
+   set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
+   set->ftp_filemethod = FTPFILE_MULTICWD;
++  set->ftp_skip_ip = TRUE;    /* skip PASV IP by default */
+ #endif
+   set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
+index c52d8e1c6bb..4c06d3557b7 100644
+--- a/src/tool_cfgable.c
++++ b/src/tool_cfgable.c
+@@ -44,6 +44,7 @@ void config_init(struct OperationConfig *config)
+   config->tcp_nodelay = TRUE; /* enabled by default */
+   config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
+   config->http09_allowed = FALSE;
++  config->ftp_skip_ip = TRUE;
+ }
+ static void free_config_fields(struct OperationConfig *config)
+diff --git a/tests/data/test1400 b/tests/data/test1400
+index 812ad0b88d9..b7060eca58e 100644
+--- a/tests/data/test1400
++++ b/tests/data/test1400
+@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+   curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1401 b/tests/data/test1401
+index f93b3d637de..a2629683aff 100644
+--- a/tests/data/test1401
++++ b/tests/data/test1401
+@@ -87,6 +87,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(hnd, CURLOPT_COOKIE, "chocolate=chip");
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   curl_easy_setopt(hnd, CURLOPT_PROTOCOLS, (long)CURLPROTO_FILE |
+                                            (long)CURLPROTO_FTP |
+diff --git a/tests/data/test1402 b/tests/data/test1402
+index 7593c516da1..1bd55cb4e3b 100644
+--- a/tests/data/test1402
++++ b/tests/data/test1402
+@@ -78,6 +78,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+   curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1403 b/tests/data/test1403
+index ecb4dd3dcab..a7c9fcca322 100644
+--- a/tests/data/test1403
++++ b/tests/data/test1403
+@@ -73,6 +73,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+   curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1404 b/tests/data/test1404
+index 97622b63948..1d8e8cf7779 100644
+--- a/tests/data/test1404
++++ b/tests/data/test1404
+@@ -147,6 +147,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
+   curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1405 b/tests/data/test1405
+index 2bac79eda74..b4087704f7b 100644
+--- a/tests/data/test1405
++++ b/tests/data/test1405
+@@ -89,6 +89,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
+   curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1406 b/tests/data/test1406
+index 51a166adff2..38f68d11ee1 100644
+--- a/tests/data/test1406
++++ b/tests/data/test1406
+@@ -79,6 +79,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
+   curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   curl_easy_setopt(hnd, CURLOPT_MAIL_FROM, "sender@example.com");
+   curl_easy_setopt(hnd, CURLOPT_MAIL_RCPT, slist1);
+diff --git a/tests/data/test1407 b/tests/data/test1407
+index f6879008fb2..a7e13ba7585 100644
+--- a/tests/data/test1407
++++ b/tests/data/test1407
+@@ -62,6 +62,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
+   curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+diff --git a/tests/data/test1420 b/tests/data/test1420
+index 057ecc4773a..4b8d7bbf418 100644
+--- a/tests/data/test1420
++++ b/tests/data/test1420
+@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
+   curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1");
+   curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
+   curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
++  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
+   curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
+   /* Here is a list of options the curl code used that cannot get generated
+
+
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8285.patch b/meta/recipes-support/curl/curl/CVE-2020-8285.patch
new file mode 100644 (file)
index 0000000..a66729b
--- /dev/null
@@ -0,0 +1,260 @@
+From 6fda045b19a9066701b5e09cfa657a13a3accbf3 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Sat, 28 Nov 2020 00:27:21 +0100
+Subject: [PATCH] ftp: make wc_statemach loop instead of recurse
+
+CVE-2020-8285
+
+Fixes #6255
+Bug: https://curl.se/docs/CVE-2020-8285.html
+Reported-by: xnynx on github
+
+Upstream-commit: 69a358f2186e04cf44698b5100332cbf1ee7f01d
+Signed-off-by: Kamil Dudka <kdudka@redhat.com>
+
+Upstream-Status: Backport [import from fedora https://koji.fedoraproject.org/koji/fileinfo?rpmID=24270817&filename=0006-curl-7.69.1-CVE-2020-8285.patch]
+CVE: CVE-2020-8285
+Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com>
+---
+ lib/ftp.c | 202 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 102 insertions(+), 100 deletions(-)
+
+diff --git a/lib/ftp.c b/lib/ftp.c
+index 57b22ad..3382772 100644
+--- a/lib/ftp.c
++++ b/lib/ftp.c
+@@ -3763,129 +3763,131 @@ static CURLcode init_wc_data(struct connectdata *conn)
+   return result;
+ }
+-/* This is called recursively */
+ static CURLcode wc_statemach(struct connectdata *conn)
+ {
+   struct WildcardData * const wildcard = &(conn->data->wildcard);
+   CURLcode result = CURLE_OK;
+-  switch(wildcard->state) {
+-  case CURLWC_INIT:
+-    result = init_wc_data(conn);
+-    if(wildcard->state == CURLWC_CLEAN)
+-      /* only listing! */
+-      break;
+-    wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
+-    break;
++  for(;;) {
++    switch(wildcard->state) {
++    case CURLWC_INIT:
++      result = init_wc_data(conn);
++      if(wildcard->state == CURLWC_CLEAN)
++        /* only listing! */
++        return result;
++      wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
++      return result;
+-  case CURLWC_MATCHING: {
+-    /* In this state is LIST response successfully parsed, so lets restore
+-       previous WRITEFUNCTION callback and WRITEDATA pointer */
+-    struct ftp_wc *ftpwc = wildcard->protdata;
+-    conn->data->set.fwrite_func = ftpwc->backup.write_function;
+-    conn->data->set.out = ftpwc->backup.file_descriptor;
+-    ftpwc->backup.write_function = ZERO_NULL;
+-    ftpwc->backup.file_descriptor = NULL;
+-    wildcard->state = CURLWC_DOWNLOADING;
+-
+-    if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
+-      /* error found in LIST parsing */
+-      wildcard->state = CURLWC_CLEAN;
+-      return wc_statemach(conn);
+-    }
+-    if(wildcard->filelist.size == 0) {
+-      /* no corresponding file */
+-      wildcard->state = CURLWC_CLEAN;
+-      return CURLE_REMOTE_FILE_NOT_FOUND;
++    case CURLWC_MATCHING: {
++      /* In this state is LIST response successfully parsed, so lets restore
++         previous WRITEFUNCTION callback and WRITEDATA pointer */
++      struct ftp_wc *ftpwc = wildcard->protdata;
++      conn->data->set.fwrite_func = ftpwc->backup.write_function;
++      conn->data->set.out = ftpwc->backup.file_descriptor;
++      ftpwc->backup.write_function = ZERO_NULL;
++      ftpwc->backup.file_descriptor = NULL;
++      wildcard->state = CURLWC_DOWNLOADING;
++
++      if(Curl_ftp_parselist_geterror(ftpwc->parser)) {
++        /* error found in LIST parsing */
++        wildcard->state = CURLWC_CLEAN;
++        continue;
++      }
++      if(wildcard->filelist.size == 0) {
++        /* no corresponding file */
++        wildcard->state = CURLWC_CLEAN;
++        return CURLE_REMOTE_FILE_NOT_FOUND;
++      }
++      continue;
+     }
+-    return wc_statemach(conn);
+-  }
+-  case CURLWC_DOWNLOADING: {
+-    /* filelist has at least one file, lets get first one */
+-    struct ftp_conn *ftpc = &conn->proto.ftpc;
+-    struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+-    struct FTP *ftp = conn->data->req.protop;
++    case CURLWC_DOWNLOADING: {
++      /* filelist has at least one file, lets get first one */
++      struct ftp_conn *ftpc = &conn->proto.ftpc;
++      struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
++      struct FTP *ftp = conn->data->req.protop;
+-    char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+-    if(!tmp_path)
+-      return CURLE_OUT_OF_MEMORY;
++      char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
++      if(!tmp_path)
++        return CURLE_OUT_OF_MEMORY;
+-    /* switch default ftp->path and tmp_path */
+-    free(ftp->pathalloc);
+-    ftp->pathalloc = ftp->path = tmp_path;
+-
+-    infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
+-    if(conn->data->set.chunk_bgn) {
+-      long userresponse;
+-      Curl_set_in_callback(conn->data, true);
+-      userresponse = conn->data->set.chunk_bgn(
+-        finfo, wildcard->customptr, (int)wildcard->filelist.size);
+-      Curl_set_in_callback(conn->data, false);
+-      switch(userresponse) {
+-      case CURL_CHUNK_BGN_FUNC_SKIP:
+-        infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
+-              finfo->filename);
+-        wildcard->state = CURLWC_SKIP;
+-        return wc_statemach(conn);
+-      case CURL_CHUNK_BGN_FUNC_FAIL:
+-        return CURLE_CHUNK_FAILED;
++      /* switch default ftp->path and tmp_path */
++      free(ftp->pathalloc);
++      ftp->pathalloc = ftp->path = tmp_path;
++
++      infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
++      if(conn->data->set.chunk_bgn) {
++        long userresponse;
++        Curl_set_in_callback(conn->data, true);
++        userresponse = conn->data->set.chunk_bgn(
++          finfo, wildcard->customptr, (int)wildcard->filelist.size);
++        Curl_set_in_callback(conn->data, false);
++        switch(userresponse) {
++        case CURL_CHUNK_BGN_FUNC_SKIP:
++          infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
++                finfo->filename);
++          wildcard->state = CURLWC_SKIP;
++          continue;
++        case CURL_CHUNK_BGN_FUNC_FAIL:
++          return CURLE_CHUNK_FAILED;
++        }
+       }
+-    }
+-    if(finfo->filetype != CURLFILETYPE_FILE) {
+-      wildcard->state = CURLWC_SKIP;
+-      return wc_statemach(conn);
+-    }
++      if(finfo->filetype != CURLFILETYPE_FILE) {
++        wildcard->state = CURLWC_SKIP;
++        continue;
++      }
+-    if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+-      ftpc->known_filesize = finfo->size;
++      if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
++        ftpc->known_filesize = finfo->size;
+-    result = ftp_parse_url_path(conn);
+-    if(result)
+-      return result;
++      result = ftp_parse_url_path(conn);
++      if(result)
++        return result;
+-    /* we don't need the Curl_fileinfo of first file anymore */
+-    Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
++      /* we don't need the Curl_fileinfo of first file anymore */
++      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+-    if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+-      wildcard->state = CURLWC_CLEAN;
+-      /* after that will be ftp_do called once again and no transfer
+-         will be done because of CURLWC_CLEAN state */
+-      return CURLE_OK;
++      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
++        wildcard->state = CURLWC_CLEAN;
++        /* after that will be ftp_do called once again and no transfer
++           will be done because of CURLWC_CLEAN state */
++        return CURLE_OK;
++      }
++      return result;
+     }
+-  } break;
+-  case CURLWC_SKIP: {
+-    if(conn->data->set.chunk_end) {
+-      Curl_set_in_callback(conn->data, true);
+-      conn->data->set.chunk_end(conn->data->wildcard.customptr);
+-      Curl_set_in_callback(conn->data, false);
++    case CURLWC_SKIP: {
++      if(conn->data->set.chunk_end) {
++        Curl_set_in_callback(conn->data, true);
++        conn->data->set.chunk_end(conn->data->wildcard.customptr);
++        Curl_set_in_callback(conn->data, false);
++      }
++      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
++      wildcard->state = (wildcard->filelist.size == 0) ?
++        CURLWC_CLEAN : CURLWC_DOWNLOADING;
++      continue;
+     }
+-    Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+-    wildcard->state = (wildcard->filelist.size == 0) ?
+-                      CURLWC_CLEAN : CURLWC_DOWNLOADING;
+-    return wc_statemach(conn);
+-  }
+-  case CURLWC_CLEAN: {
+-    struct ftp_wc *ftpwc = wildcard->protdata;
+-    result = CURLE_OK;
+-    if(ftpwc)
+-      result = Curl_ftp_parselist_geterror(ftpwc->parser);
++    case CURLWC_CLEAN: {
++      struct ftp_wc *ftpwc = wildcard->protdata;
++      result = CURLE_OK;
++      if(ftpwc)
++        result = Curl_ftp_parselist_geterror(ftpwc->parser);
+-    wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+-  } break;
++      wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
++      return result;
++    }
+-  case CURLWC_DONE:
+-  case CURLWC_ERROR:
+-  case CURLWC_CLEAR:
+-    if(wildcard->dtor)
+-      wildcard->dtor(wildcard->protdata);
+-    break;
++    case CURLWC_DONE:
++    case CURLWC_ERROR:
++    case CURLWC_CLEAR:
++      if(wildcard->dtor)
++        wildcard->dtor(wildcard->protdata);
++      return result;
++    }
+   }
+-
+-  return result;
++  /* UNREACHABLE */
+ }
+ /***********************************************************************
+-- 
+2.26.2
+
diff --git a/meta/recipes-support/curl/curl/CVE-2020-8286.patch b/meta/recipes-support/curl/curl/CVE-2020-8286.patch
new file mode 100644 (file)
index 0000000..093562f
--- /dev/null
@@ -0,0 +1,133 @@
+From 43d1163b3730f715704240f7f6d31af289246873 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 2 Dec 2020 23:01:11 +0100
+Subject: [PATCH] openssl: make the OCSP verification verify the certificate id
+
+CVE-2020-8286
+
+Reported by anonymous
+
+Bug: https://curl.se/docs/CVE-2020-8286.html
+
+Upstream-commit: d9d01672785b8ac04aab1abb6de95fe3072ae199
+Signed-off-by: Kamil Dudka <kdudka@redhat.com>
+
+Upstream-Status: Backport [import from fedora https://koji.fedoraproject.org/koji/fileinfo?rpmID=24270817&filename=0007-curl-7.71.1-CVE-2020-8286.patch ]
+CVE: CVE-2020-8286
+Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com>
+---
+ lib/vtls/openssl.c | 83 ++++++++++++++++++++++++++++++----------------
+ 1 file changed, 54 insertions(+), 29 deletions(-)
+
+diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
+index 1d09cad..bcfd83b 100644
+--- a/lib/vtls/openssl.c
++++ b/lib/vtls/openssl.c
+@@ -1717,6 +1717,11 @@ static CURLcode verifystatus(struct connectdata *conn,
+   OCSP_BASICRESP *br = NULL;
+   X509_STORE     *st = NULL;
+   STACK_OF(X509) *ch = NULL;
++  X509 *cert;
++  OCSP_CERTID *id = NULL;
++  int cert_status, crl_reason;
++  ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
++  int ret;
+   long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
+@@ -1785,43 +1790,63 @@ static CURLcode verifystatus(struct connectdata *conn,
+     goto end;
+   }
+-  for(i = 0; i < OCSP_resp_count(br); i++) {
+-    int cert_status, crl_reason;
+-    OCSP_SINGLERESP *single = NULL;
+-
+-    ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
++  /* Compute the certificate's ID */
++  cert = SSL_get_peer_certificate(BACKEND->handle);
++  if(!cert) {
++    failf(data, "Error getting peer certficate");
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    goto end;
++  }
+-    single = OCSP_resp_get0(br, i);
+-    if(!single)
+-      continue;
++  for(i = 0; i < sk_X509_num(ch); i++) {
++    X509 *issuer = sk_X509_value(ch, i);
++    if(X509_check_issued(issuer, cert) == X509_V_OK) {
++      id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
++      break;
++    }
++  }
++  X509_free(cert);
+-    cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
+-                                          &thisupd, &nextupd);
++  if(!id) {
++    failf(data, "Error computing OCSP ID");
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    goto end;
++  }
+-    if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+-      failf(data, "OCSP response has expired");
+-      result = CURLE_SSL_INVALIDCERTSTATUS;
+-      goto end;
+-    }
++  /* Find the single OCSP response corresponding to the certificate ID */
++  ret = OCSP_resp_find_status(br, id, &cert_status, &crl_reason, &rev,
++                              &thisupd, &nextupd);
++  OCSP_CERTID_free(id);
++  if(ret != 1) {
++    failf(data, "Could not find certificate ID in OCSP response");
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    goto end;
++  }
+-    infof(data, "SSL certificate status: %s (%d)\n",
+-          OCSP_cert_status_str(cert_status), cert_status);
++  /* Validate the corresponding single OCSP response */
++  if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
++    failf(data, "OCSP response has expired");
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    goto end;
++  }
+-    switch(cert_status) {
+-      case V_OCSP_CERTSTATUS_GOOD:
+-        break;
++  infof(data, "SSL certificate status: %s (%d)\n",
++        OCSP_cert_status_str(cert_status), cert_status);
+-      case V_OCSP_CERTSTATUS_REVOKED:
+-        result = CURLE_SSL_INVALIDCERTSTATUS;
++  switch(cert_status) {
++  case V_OCSP_CERTSTATUS_GOOD:
++    break;
+-        failf(data, "SSL certificate revocation reason: %s (%d)",
+-              OCSP_crl_reason_str(crl_reason), crl_reason);
+-        goto end;
++  case V_OCSP_CERTSTATUS_REVOKED:
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    failf(data, "SSL certificate revocation reason: %s (%d)",
++          OCSP_crl_reason_str(crl_reason), crl_reason);
++    goto end;
+-      case V_OCSP_CERTSTATUS_UNKNOWN:
+-        result = CURLE_SSL_INVALIDCERTSTATUS;
+-        goto end;
+-    }
++  case V_OCSP_CERTSTATUS_UNKNOWN:
++  default:
++    result = CURLE_SSL_INVALIDCERTSTATUS;
++    goto end;
+   }
+ end:
+-- 
+2.26.2
+
index 239852db09c1fb317863c47921d810a9193c27b1..c3d629108a49ad4927c32da59ab59bbaa3c81fff 100644 (file)
@@ -9,6 +9,10 @@ SRC_URI = "https://curl.haxx.se/download/curl-${PV}.tar.bz2 \
            file://0001-replace-krb5-config-with-pkg-config.patch \
            file://CVE-2020-8169.patch \
            file://CVE-2020-8177.patch \
+           file://CVE-2020-8231.patch \
+           file://CVE-2020-8284.patch \
+           file://CVE-2020-8285.patch \
+           file://CVE-2020-8286.patch \
 "
 
 SRC_URI[md5sum] = "ec5fc263f898a3dfef08e805f1ecca42"