From 069153a396c2942f1fb6e949079355fb04de7021 Mon Sep 17 00:00:00 2001 From: xingwei Date: Thu, 8 Jun 2023 05:56:06 +0000 Subject: [PATCH] fix CVE-2023-28320 (cherry picked from commit 0fb95c607c50e71d8a422697e370854be749e471) --- backport-0001-CVE-2023-28320.patch | 327 +++++++++++++++++++++++++++++ backport-0002-CVE-2023-28320.patch | 82 ++++++++ backport-0003-CVE-2023-28320.patch | 79 +++++++ curl.spec | 11 +- 4 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 backport-0001-CVE-2023-28320.patch create mode 100644 backport-0002-CVE-2023-28320.patch create mode 100644 backport-0003-CVE-2023-28320.patch diff --git a/backport-0001-CVE-2023-28320.patch b/backport-0001-CVE-2023-28320.patch new file mode 100644 index 0000000..58dc248 --- /dev/null +++ b/backport-0001-CVE-2023-28320.patch @@ -0,0 +1,327 @@ +From 23af112f5556d6a785c17e09f2422ac931405f61 Mon Sep 17 00:00:00 2001 +From: Thomas Guillem +Date: Tue, 5 Apr 2022 15:46:03 +0200 +Subject: [PATCH 1/1] lib: make curl_global_init() threadsafe when possible + +Use a posix pthread or a Windows SRWLOCK to lock curl_global_init*() and +curl_global_cleanup(). + +Closes #8680 + +Conflict:update easy_lock.h to latest +Reference:https://github.com/curl/curl/commit/23af112f5556d6a785c17e09f2422ac931405f61 +--- + configure.ac | 2 ++ + lib/Makefile.inc | 1 + + lib/easy.c | 52 +++++++++++++++++++++++++++++---- + lib/easy_lock.h | 105 ++++++++++++++++++++++++++++++++++++++++++++ + m4/curl-functions.m4 | 23 +++++++++++++++ + 5 files changed, 178 insertions(+), 5 deletions(-) + create mode 100644 lib/easy_lock.h + +diff --git a/configure.ac b/configure.ac +index 3910ec631..009f32c32 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -118,6 +118,7 @@ AC_SUBST(libext) + dnl figure out the libcurl version + CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)".*/\1/p' ${srcdir}/include/curl/curlver.h` + XC_CHECK_PROG_CC ++CURL_ATOMIC + + dnl for --enable-code-coverage + CURL_COVERAGE +@@ -3444,6 +3445,7 @@ AC_CHECK_FUNCS([fnmatch \ + if_nametoindex \ + mach_absolute_time \ + pipe \ ++ sched_yield \ + setlocale \ + setmode \ + setrlimit \ +diff --git a/lib/Makefile.inc b/lib/Makefile.inc +index 1ab007896..f756515d6 100644 +--- a/lib/Makefile.inc ++++ b/lib/Makefile.inc +@@ -262,6 +262,7 @@ LIB_HFILES = \ + doh.h \ + dotdot.h \ + dynbuf.h \ ++ easy_lock.h \ + easyif.h \ + easyoptions.h \ + escape.h \ +diff --git a/lib/easy.c b/lib/easy.c +index 336cada87..7781c8e16 100644 +--- a/lib/easy.c ++++ b/lib/easy.c +@@ -84,11 +84,25 @@ + #include "curl_printf.h" + #include "curl_memory.h" + #include "memdebug.h" ++#include "easy_lock.h" + + /* true globals -- for curl_global_init() and curl_global_cleanup() */ + static unsigned int initialized; + static long init_flags; + ++#ifdef GLOBAL_INIT_IS_THREADSAFE ++ ++static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; ++#define global_init_lock() curl_simple_lock_lock(&s_lock) ++#define global_init_unlock() curl_simple_lock_unlock(&s_lock) ++ ++#else ++ ++#define global_init_lock() ++#define global_init_unlock() ++ ++#endif ++ + /* + * strdup (and other memory functions) is redefined in complicated + * ways, but at this point it must be defined as the system-supplied strdup +@@ -207,7 +221,14 @@ static CURLcode global_init(long flags, bool memoryfuncs) + */ + CURLcode curl_global_init(long flags) + { +- return global_init(flags, TRUE); ++ CURLcode result; ++ global_init_lock(); ++ ++ result = global_init(flags, TRUE); ++ ++ global_init_unlock(); ++ ++ return result; + } + + /* +@@ -218,15 +239,20 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, + curl_free_callback f, curl_realloc_callback r, + curl_strdup_callback s, curl_calloc_callback c) + { ++ CURLcode result; ++ + /* Invalid input, return immediately */ + if(!m || !f || !r || !s || !c) + return CURLE_FAILED_INIT; + ++ global_init_lock(); ++ + if(initialized) { + /* Already initialized, don't do it again, but bump the variable anyway to + work like curl_global_init() and require the same amount of cleanup + calls. */ + initialized++; ++ global_init_unlock(); + return CURLE_OK; + } + +@@ -239,7 +265,11 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, + Curl_ccalloc = c; + + /* Call the actual init function, but without setting */ +- return global_init(flags, FALSE); ++ result = global_init(flags, FALSE); ++ ++ global_init_unlock(); ++ ++ return result; + } + + /** +@@ -248,11 +278,17 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, + */ + void curl_global_cleanup(void) + { +- if(!initialized) ++ global_init_lock(); ++ ++ if(!initialized) { ++ global_init_unlock(); + return; ++ } + +- if(--initialized) ++ if(--initialized) { ++ global_init_unlock(); + return; ++ } + + Curl_ssl_cleanup(); + Curl_resolver_global_cleanup(); +@@ -273,6 +309,8 @@ void curl_global_cleanup(void) + #endif + + init_flags = 0; ++ ++ global_init_unlock(); + } + + /* +@@ -285,14 +323,18 @@ struct Curl_easy *curl_easy_init(void) + struct Curl_easy *data; + + /* Make sure we inited the global SSL stuff */ ++ global_init_lock(); ++ + if(!initialized) { +- result = curl_global_init(CURL_GLOBAL_DEFAULT); ++ result = global_init(CURL_GLOBAL_DEFAULT, TRUE); + if(result) { + /* something in the global init failed, return nothing */ + DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); ++ global_init_unlock(); + return NULL; + } + } ++ global_init_unlock(); + + /* We use curl_open() with undefined URL so far */ + result = Curl_open(&data); +diff --git a/lib/easy_lock.h b/lib/easy_lock.h +new file mode 100644 +index 000000000..41627c4d4 +--- /dev/null ++++ b/lib/easy_lock.h +@@ -0,0 +1,105 @@ ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) Daniel Stenberg, , et al. ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ * SPDX-License-Identifier: curl ++ * ++ ***************************************************************************/ ++ ++#include "curl_setup.h" ++ ++#define GLOBAL_INIT_IS_THREADSAFE ++ ++#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 ++ ++#ifdef __MINGW32__ ++#ifndef __MINGW64_VERSION_MAJOR ++#if (__MINGW32_MAJOR_VERSION < 5) || \ ++ (__MINGW32_MAJOR_VERSION == 5 && __MINGW32_MINOR_VERSION == 0) ++/* mingw >= 5.0.1 defines SRWLOCK, and slightly different from MS define */ ++typedef PVOID SRWLOCK, *PSRWLOCK; ++#endif ++#endif ++#ifndef SRWLOCK_INIT ++#define SRWLOCK_INIT NULL ++#endif ++#endif /* __MINGW32__ */ ++ ++#define curl_simple_lock SRWLOCK ++#define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT ++ ++#define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m) ++#define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m) ++ ++#elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H) ++#include ++#if defined(HAVE_SCHED_YIELD) ++#include ++#endif ++ ++#define curl_simple_lock atomic_int ++#define CURL_SIMPLE_LOCK_INIT 0 ++ ++/* a clang-thing */ ++#ifndef __has_builtin ++#define __has_builtin(x) 0 ++#endif ++ ++#ifndef __INTEL_COMPILER ++/* The Intel compiler tries to look like GCC *and* clang *and* lies in its ++ __has_builtin() function, so override it. */ ++ ++/* if GCC on i386/x86_64 or if the built-in is present */ ++#if ( (defined(__GNUC__) && !defined(__clang__)) && \ ++ (defined(__i386__) || defined(__x86_64__))) || \ ++ __has_builtin(__builtin_ia32_pause) ++#define HAVE_BUILTIN_IA32_PAUSE ++#endif ++ ++#endif ++ ++static inline void curl_simple_lock_lock(curl_simple_lock *lock) ++{ ++ for(;;) { ++ if(!atomic_exchange_explicit(lock, true, memory_order_acquire)) ++ break; ++ /* Reduce cache coherency traffic */ ++ while(atomic_load_explicit(lock, memory_order_relaxed)) { ++ /* Reduce load (not mandatory) */ ++#ifdef HAVE_BUILTIN_IA32_PAUSE ++ __builtin_ia32_pause(); ++#elif defined(__aarch64__) ++ __asm__ volatile("yield" ::: "memory"); ++#elif defined(HAVE_SCHED_YIELD) ++ sched_yield(); ++#endif ++ } ++ } ++} ++ ++static inline void curl_simple_lock_unlock(curl_simple_lock *lock) ++{ ++ atomic_store_explicit(lock, false, memory_order_release); ++} ++ ++#else ++ ++#undef GLOBAL_INIT_IS_THREADSAFE ++ ++#endif +diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 +index b40d42798..eb85dce4a 100644 +--- a/m4/curl-functions.m4 ++++ b/m4/curl-functions.m4 +@@ -6566,3 +6566,26 @@ AC_DEFUN([CURL_COVERAGE],[ + LIBS="$LIBS -lgcov" + fi + ]) ++ ++dnl CURL_ATOMIC ++dnl -------------------------------------------------- ++dnl Check if _Atomic works ++dnl ++AC_DEFUN([CURL_ATOMIC],[ ++ AC_MSG_CHECKING([if _Atomic is available]) ++ AC_COMPILE_IFELSE([ ++ AC_LANG_PROGRAM([[ ++ $curl_includes_unistd ++ ]],[[ ++ _Atomic int i = 0; ++ ]]) ++ ],[ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE_UNQUOTED(HAVE_ATOMIC, 1, ++ [Define to 1 if you have _Atomic support.]) ++ tst_atomic="yes" ++ ],[ ++ AC_MSG_RESULT([no]) ++ tst_atomic="no" ++ ]) ++]) +-- +2.33.0 + diff --git a/backport-0002-CVE-2023-28320.patch b/backport-0002-CVE-2023-28320.patch new file mode 100644 index 0000000..5cefb16 --- /dev/null +++ b/backport-0002-CVE-2023-28320.patch @@ -0,0 +1,82 @@ +From 13718030ad4b3209a7583b4f27f683cd3a6fa5f2 Mon Sep 17 00:00:00 2001 +From: Harry Sintonen +Date: Tue, 25 Apr 2023 09:22:26 +0200 +Subject: [PATCH] hostip: add locks around use of global buffer for alarm() + +When building with the sync name resolver and timeout ability we now +require thread-safety to be present to enable it. + +Closes #11030 + +Conflict:NA +Reference:https://github.com/curl/curl/commit/13718030ad4b3209a7583b +--- + lib/hostip.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/lib/hostip.c b/lib/hostip.c +index 2381290fdd43e..e410cda69ae6e 100644 +--- a/lib/hostip.c ++++ b/lib/hostip.c +@@ -70,12 +70,19 @@ + #include + #endif + +-#if defined(CURLRES_SYNCH) && \ +- defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP) ++#if defined(CURLRES_SYNCH) && \ ++ defined(HAVE_ALARM) && \ ++ defined(SIGALRM) && \ ++ defined(HAVE_SIGSETJMP) && \ ++ defined(GLOBAL_INIT_IS_THREADSAFE) + /* alarm-based timeouts can only be used with all the dependencies satisfied */ + #define USE_ALARM_TIMEOUT + #endif + ++#ifdef USE_ALARM_TIMEOUT ++#include "easy_lock.h" ++#endif ++ + #define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */ + + /* +@@ -254,11 +261,12 @@ void Curl_hostcache_prune(struct Curl_easy *data) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + } + +-#ifdef HAVE_SIGSETJMP ++#ifdef USE_ALARM_TIMEOUT + /* Beware this is a global and unique instance. This is used to store the + return address that we can jump back to from inside a signal handler. This + is not thread-safe stuff. */ + sigjmp_buf curl_jmpenv; ++curl_simple_lock curl_jmpenv_lock; + #endif + + /* lookup address, returns entry if found and not stale */ +@@ -832,7 +840,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, + static + void alarmfunc(int sig) + { +- /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ + (void)sig; + siglongjmp(curl_jmpenv, 1); + } +@@ -912,6 +919,8 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, + This should be the last thing we do before calling Curl_resolv(), + as otherwise we'd have to worry about variables that get modified + before we invoke Curl_resolv() (and thus use "volatile"). */ ++ curl_simple_lock_lock(&curl_jmpenv_lock); ++ + if(sigsetjmp(curl_jmpenv, 1)) { + /* this is coming from a siglongjmp() after an alarm signal */ + failf(data, "name lookup timed out"); +@@ -980,6 +989,8 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, + #endif + #endif /* HAVE_SIGACTION */ + ++ curl_simple_lock_unlock(&curl_jmpenv_lock); ++ + /* switch back the alarm() to either zero or to what it was before minus + the time we spent until now! */ + if(prev_alarm) { diff --git a/backport-0003-CVE-2023-28320.patch b/backport-0003-CVE-2023-28320.patch new file mode 100644 index 0000000..bff0c30 --- /dev/null +++ b/backport-0003-CVE-2023-28320.patch @@ -0,0 +1,79 @@ +From f446258f0269a62289cca0210157cb8558d0edc3 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 16 May 2023 23:40:42 +0200 +Subject: [PATCH 1/1] hostip: include easy_lock.h before using + GLOBAL_INIT_IS_THREADSAFE + +Since that header file is the only place that define can be defined. + +Reported-by: Marc Deslauriers + +Follow-up to 13718030ad4b3209 + +Closes #11121 + +Conflict:context adapt +Reference:https://github.com/curl/curl/commit/f446258f0269a62289cca0210157cb8558d0edc3 +--- + lib/hostip.c | 10 ++++------ + lib/hostip.h | 9 --------- + 2 files changed, 4 insertions(+), 15 deletions(-) + +diff --git a/lib/hostip.c b/lib/hostip.c +index 615f36c16..4ff348436 100644 +--- a/lib/hostip.c ++++ b/lib/hostip.c +@@ -70,6 +70,8 @@ + #include + #endif + ++#include "easy_lock.h" ++ + #if defined(CURLRES_SYNCH) && \ + defined(HAVE_ALARM) && \ + defined(SIGALRM) && \ +@@ -79,10 +81,6 @@ + #define USE_ALARM_TIMEOUT + #endif + +-#ifdef USE_ALARM_TIMEOUT +-#include "easy_lock.h" +-#endif +- + #define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */ + + /* +@@ -289,8 +287,8 @@ void Curl_hostcache_prune(struct Curl_easy *data) + /* Beware this is a global and unique instance. This is used to store the + return address that we can jump back to from inside a signal handler. This + is not thread-safe stuff. */ +-sigjmp_buf curl_jmpenv; +-curl_simple_lock curl_jmpenv_lock; ++static sigjmp_buf curl_jmpenv; ++static curl_simple_lock curl_jmpenv_lock; + #endif + + /* lookup address, returns entry if found and not stale */ +diff --git a/lib/hostip.h b/lib/hostip.h +index 4b5481f65..0dd19e87c 100644 +--- a/lib/hostip.h ++++ b/lib/hostip.h +@@ -186,15 +186,6 @@ Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, + #define CURL_INADDR_NONE INADDR_NONE + #endif + +-#ifdef HAVE_SIGSETJMP +-/* Forward-declaration of variable defined in hostip.c. Beware this +- * is a global and unique instance. This is used to store the return +- * address that we can jump back to from inside a signal handler. +- * This is not thread-safe stuff. +- */ +-extern sigjmp_buf curl_jmpenv; +-#endif +- + /* + * Function provided by the resolver backend to set DNS servers to use. + */ +-- +2.33.0 + diff --git a/curl.spec b/curl.spec index d777448..0241f3d 100644 --- a/curl.spec +++ b/curl.spec @@ -6,7 +6,7 @@ Name: curl Version: 7.79.1 -Release: 17 +Release: 18 Summary: Curl is used in command lines or scripts to transfer data License: MIT URL: https://curl.haxx.se/ @@ -50,6 +50,9 @@ Patch35: backport-CVE-2023-27535.patch Patch36: backport-after-CVE-2022-32207-to-fix-build-error-when-user-don-t-use-glibc.patch Patch37: backport-CVE-2023-28321.patch Patch38: backport-CVE-2023-28322.patch +Patch39: backport-0001-CVE-2023-28320.patch +Patch40: backport-0002-CVE-2023-28320.patch +Patch41: backport-0003-CVE-2023-28320.patch BuildRequires: automake brotli-devel coreutils gcc groff krb5-devel BuildRequires: libidn2-devel libnghttp2-devel libpsl-devel @@ -224,6 +227,12 @@ rm -rf ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la %{_mandir}/man3/* %changelog +* Thu Jun 08 2023 xingwei - 7.79.1-18 +- Type:CVE +- CVE:CVE-2023-28320 +- SUG:NA +- DESC:fix CVE-2023-28320 + * Wed May 24 2023 xingwei - 7.79.1-17 - Type:CVE - CVE:CVE-2023-28321,CVE-2023-28322