mirror of
https://github.com/curl/curl.git
synced 2026-05-16 10:26:20 +03:00
src: add curlx_memzero() to clear buffers securely
To safely zero memory, introduce `curlx_memzero()`, and map it to `memset_s()` (C11) or `memset_explicit()` (C23) if auto-detected, or `explicit_bzero()` or `explicit_memset()` for platforms opted-in, or fall back to a local workaround if all unavailable. On Windows, always use `SecureZeroMemory()`, or `SecureZeroMemory2()` with Visual Studio and Windows SDK 10.0.26100.0+. Details above are experimental and may change if they cause issues. Also add macros/functions that zero memory before freeing a buffer: - `curlx_safefreezero()`: for buffers with size. - `curlx_safefreezeroz()`: for null-terminated buffers. - `curlx_freezero()`: for buffers with size. - `curlx_freezeroz()`: for null-terminated buffers. `curlx_memzero()` must not be passed a NULL pointer because in some implementations it is undefined behavior. Also: - curl_sha512_256: Replace hard-wired `explicit_memset()` call with new `curlx_memzero()`. Refs: https://en.cppreference.com/c/string/byte/memset https://man7.org/linux/man-pages/man3/explicit_bzero.3.html https://man.freebsd.org/cgi/man.cgi?query=explicit_bzero https://man.netbsd.org/NetBSD-7.2/explicit_memset.3 https://learn.microsoft.com/previous-versions/windows/desktop/legacy/aa366877(v=vs.85) https://learn.microsoft.com/windows/win32/memory/winbase-securezeromemory2 https://learn.microsoft.com/cpp/overview/compiler-versions https://learn.microsoft.com/windows/apps/windows-sdk/downloads https://jtsoya539.github.io/windows-sdk-versions/ Credits-to: Daniel Gustafsson Credits-to: Will Cosgrove and co-authors in libssh2 Ref: #13589 (original attempt) Ref: #21588 Closes #21598
This commit is contained in:
parent
831a151484
commit
066478f634
10 changed files with 195 additions and 9 deletions
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
|
|
@ -36,7 +36,7 @@ permissions: {}
|
|||
# or runtime:
|
||||
#
|
||||
# - 10.7 Lion (2011) - GSS (build-time, deprecated MIT Kerberos shim)
|
||||
# - 10.9 Mavericks (2013) - LDAP (build-time, deprecated), OCSP (runtime)
|
||||
# - 10.9 Mavericks (2013) - LDAP (build-time, deprecated), memset_s(), OCSP (runtime)
|
||||
# - 10.11 El Capitan (2015) - connectx() (runtime)
|
||||
# - 10.12 Sierra (2016) - clock_gettime() (build-time, runtime)
|
||||
# - 10.14 Mojave (2018) - SecTrustEvaluateWithError() (runtime)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
|
|||
CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
set(HAVE_EVENTFD 1)
|
||||
endif()
|
||||
if(ANDROID AND ANDROID_PLATFORM_LEVEL GREATER_EQUAL 34)
|
||||
set(HAVE_MEMSET_EXPLICIT 1)
|
||||
endif()
|
||||
if((APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.9) OR
|
||||
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR # v6+
|
||||
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # v11.2+
|
||||
set(HAVE_MEMSET_S 1)
|
||||
elseif(NOT APPLE)
|
||||
set(HAVE_MEMSET_S 0)
|
||||
endif()
|
||||
set(HAVE_FCNTL 1)
|
||||
set(HAVE_FCNTL_H 1)
|
||||
set(HAVE_FCNTL_O_NONBLOCK 1)
|
||||
|
|
|
|||
|
|
@ -1672,6 +1672,11 @@ if(NOT WIN32)
|
|||
check_symbol_exists("strcasecmp" "string.h" HAVE_STRCASECMP)
|
||||
check_symbol_exists("stricmp" "string.h" HAVE_STRICMP)
|
||||
check_symbol_exists("strcmpi" "string.h" HAVE_STRCMPI)
|
||||
|
||||
check_symbol_exists("memset_s" "string.h" HAVE_MEMSET_S)
|
||||
if(NOT HAVE_MEMSET_S)
|
||||
check_function_exists("memset_explicit" HAVE_MEMSET_EXPLICIT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(AMIGA)
|
||||
|
|
|
|||
|
|
@ -4152,6 +4152,11 @@ if test "$curl_cv_native_windows" != "yes"; then
|
|||
CURL_CHECK_FUNC_STRCASECMP
|
||||
CURL_CHECK_FUNC_STRCMPI
|
||||
CURL_CHECK_FUNC_STRICMP
|
||||
|
||||
CURL_CHECK_FUNC_MEMSET_S
|
||||
if test "$curl_cv_func_memset_s" = "no"; then
|
||||
AC_CHECK_FUNCS([memset_explicit])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$ssl_backends"; then
|
||||
|
|
|
|||
|
|
@ -49,11 +49,6 @@
|
|||
#include <inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef __DragonFly__
|
||||
/* Required for __DragonFly_version */
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
#include "curl_trc.h"
|
||||
#include "if2ip.h"
|
||||
|
|
|
|||
|
|
@ -234,6 +234,12 @@
|
|||
/* Define to 1 if you have the `opendir' function. */
|
||||
#cmakedefine HAVE_OPENDIR 1
|
||||
|
||||
/* Define to 1 if you have the memset_explicit (C23) function. */
|
||||
#cmakedefine HAVE_MEMSET_EXPLICIT 1
|
||||
|
||||
/* Define to 1 if you have the memset_s (C11) function. */
|
||||
#cmakedefine HAVE_MEMSET_S 1
|
||||
|
||||
/* Define to 1 if you have the fcntl function. */
|
||||
#cmakedefine HAVE_FCNTL 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1329,6 +1329,20 @@ extern curl_calloc_callback Curl_ccalloc;
|
|||
(ptr) = NULL; \
|
||||
} while(0)
|
||||
|
||||
/* Same as curlx_safefree() but zeroes memory before freeing */
|
||||
#define curlx_safefreezero(ptr, size) \
|
||||
do { \
|
||||
curlx_freezero(ptr, size); \
|
||||
(ptr) = NULL; \
|
||||
} while(0)
|
||||
|
||||
/* Same as curlx_safefreezero() but determines length with strlen() */
|
||||
#define curlx_safefreezeroz(ptr) \
|
||||
do { \
|
||||
curlx_freezeroz(ptr); \
|
||||
(ptr) = NULL; \
|
||||
} while(0)
|
||||
|
||||
#include <curl/curl.h> /* for CURL_EXTERN, curl_socket_t, mprintf.h */
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
|
@ -1608,4 +1622,42 @@ typedef struct sockaddr_un {
|
|||
#define NOVERBOSE(x) x
|
||||
#endif
|
||||
|
||||
/* For FreeBSD it is included from curl/curl.h */
|
||||
#if defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#include <sys/param.h> /* for __DragonFly_version, OpenBSD,
|
||||
__NetBSD_Version__ */
|
||||
#endif
|
||||
|
||||
#ifndef _CURL_LOCAL_MEMZERO /* to be removed after a couple of releases */
|
||||
#ifdef _WIN32
|
||||
#if defined(_MSC_VER) && defined(NTDDI_VERSION) && \
|
||||
(NTDDI_VERSION >= 0x0A000010) /* MS SDK 10.0.26100.0+ */
|
||||
#pragma comment(lib, "volatileaccessu.lib")
|
||||
#define curlx_memzero(buf, size) SecureZeroMemory2(buf, size)
|
||||
#else
|
||||
#define curlx_memzero(buf, size) SecureZeroMemory(buf, size)
|
||||
#endif
|
||||
#elif defined(HAVE_MEMSET_S)
|
||||
#define curlx_memzero(buf, size) (void)memset_s(buf, size, 0, size)
|
||||
#elif defined(HAVE_MEMSET_EXPLICIT)
|
||||
#define curlx_memzero(buf, size) (void)memset_explicit(buf, 0, size)
|
||||
#elif defined(__CYGWIN__) || defined(__NEWLIB__) || \
|
||||
(defined(__GLIBC__) && \
|
||||
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) || \
|
||||
(defined(__DragonFly__) && __DragonFly_version >= 500600 /* v5.6+ */) || \
|
||||
(defined(__FreeBSD__) && __FreeBSD_version >= 1100037 /* v11.0+ */) || \
|
||||
(defined(__OpenBSD__) && OpenBSD >= 201405 /* v5.5+ */)
|
||||
#define curlx_memzero(buf, size) explicit_bzero(buf, size)
|
||||
#elif defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 /* v7.2+ */
|
||||
#define curlx_memzero(buf, size) (void)explicit_memset(buf, 0, size)
|
||||
#endif
|
||||
#endif /* !_CURL_LOCAL_MEMZERO */
|
||||
|
||||
#ifndef curlx_memzero
|
||||
#define USE_CURLX_MEMZERO
|
||||
void curlx_memzero(void *buf, size_t size);
|
||||
#endif
|
||||
void curlx_freezero(void *buf, size_t size);
|
||||
void curlx_freezeroz(void *buf);
|
||||
|
||||
#endif /* HEADER_CURL_SETUP_H */
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
* NetBSD 10.99.11 development.
|
||||
* It is safe to apply the workaround even if the bug is not present, as
|
||||
* the workaround reduces performance slightly. */
|
||||
# include <sys/param.h>
|
||||
# if __NetBSD_Version__ < 904000000 || \
|
||||
(__NetBSD_Version__ >= 999000000 && \
|
||||
__NetBSD_Version__ < 1000000000) || \
|
||||
|
|
@ -173,7 +172,7 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
|
|||
tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
|
||||
if(result == CURLE_OK)
|
||||
memcpy(digest, tmp_digest, CURL_SHA512_256_DIGEST_SIZE);
|
||||
explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
|
||||
curlx_memzero(tmp_digest, sizeof(tmp_digest));
|
||||
#else /* !NEED_NETBSD_SHA512_256_WORKAROUND */
|
||||
result = EVP_DigestFinal_ex(*ctx, digest, NULL) ?
|
||||
CURLE_OK : CURLE_SSL_CIPHER;
|
||||
|
|
|
|||
|
|
@ -94,3 +94,32 @@ void *curlx_memdup0(const char *src, size_t length)
|
|||
buf[length] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef USE_CURLX_MEMZERO
|
||||
static void *(* const volatile p_curlx_memset)(void *buf, int val,
|
||||
size_t size) = memset;
|
||||
|
||||
/* Local fallback in case there is no system function to securely zero a memory
|
||||
buffer. */
|
||||
void curlx_memzero(void *buf, size_t size)
|
||||
{
|
||||
if(buf)
|
||||
p_curlx_memset(buf, 0, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Free 'buf' after zeroing its content. */
|
||||
void curlx_freezero(void *buf, size_t size)
|
||||
{
|
||||
if(buf)
|
||||
curlx_memzero(buf, size);
|
||||
curlx_free(buf);
|
||||
}
|
||||
|
||||
/* Free 'buf' after zeroing its content, where 'buf' is null-terminated. */
|
||||
void curlx_freezeroz(void *buf)
|
||||
{
|
||||
if(buf)
|
||||
curlx_memzero(buf, strlen(buf));
|
||||
curlx_free(buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4111,7 +4111,6 @@ AC_DEFUN([CURL_CHECK_FUNC_STRERROR_R], [
|
|||
test "$tst_allow_strerror_r" = "unknown"; then
|
||||
AC_MSG_WARN([cannot determine strerror_r() style: edit lib/curl_config.h manually.])
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
|
@ -4199,6 +4198,92 @@ AC_DEFUN([CURL_CHECK_FUNC_STRICMP], [
|
|||
fi
|
||||
])
|
||||
|
||||
|
||||
dnl CURL_CHECK_FUNC_MEMSET_S
|
||||
dnl -------------------------------------------------
|
||||
dnl Verify if memset_s is available, prototyped, and
|
||||
dnl can be compiled. If all of these are true, and
|
||||
dnl usage has not been previously disallowed with
|
||||
dnl shell variable curl_disallow_memset_s, then
|
||||
dnl HAVE_MEMSET_S will be defined.
|
||||
|
||||
AC_DEFUN([CURL_CHECK_FUNC_MEMSET_S], [
|
||||
AC_REQUIRE([CURL_INCLUDES_STRING])
|
||||
|
||||
tst_links_memset_s="unknown"
|
||||
tst_proto_memset_s="unknown"
|
||||
tst_compi_memset_s="unknown"
|
||||
tst_allow_memset_s="unknown"
|
||||
|
||||
AC_MSG_CHECKING([if memset_s can be linked])
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_FUNC_LINK_TRY([memset_s])
|
||||
],[
|
||||
AC_MSG_RESULT([yes])
|
||||
tst_links_memset_s="yes"
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
tst_links_memset_s="no"
|
||||
])
|
||||
|
||||
if test "$tst_links_memset_s" = "yes"; then
|
||||
AC_MSG_CHECKING([if memset_s is prototyped])
|
||||
AC_EGREP_CPP([memset_s],[
|
||||
$curl_includes_string
|
||||
],[
|
||||
AC_MSG_RESULT([yes])
|
||||
tst_proto_memset_s="yes"
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
tst_proto_memset_s="no"
|
||||
])
|
||||
fi
|
||||
|
||||
if test "$tst_proto_memset_s" = "yes"; then
|
||||
AC_MSG_CHECKING([if memset_s is compilable])
|
||||
AC_COMPILE_IFELSE([
|
||||
AC_LANG_PROGRAM([[
|
||||
$curl_includes_string
|
||||
]],[[
|
||||
char buf[2];
|
||||
if(memset_s(buf, sizeof(buf), 0, sizeof(buf)) != 0)
|
||||
return 1;
|
||||
]])
|
||||
],[
|
||||
AC_MSG_RESULT([yes])
|
||||
tst_compi_memset_s="yes"
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
tst_compi_memset_s="no"
|
||||
])
|
||||
fi
|
||||
|
||||
if test "$tst_compi_memset_s" = "yes"; then
|
||||
AC_MSG_CHECKING([if memset_s usage allowed])
|
||||
if test "x$curl_disallow_memset_s" != "xyes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
tst_allow_memset_s="yes"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
tst_allow_memset_s="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if memset_s might be used])
|
||||
if test "$tst_links_memset_s" = "yes" &&
|
||||
test "$tst_proto_memset_s" = "yes" &&
|
||||
test "$tst_compi_memset_s" = "yes" &&
|
||||
test "$tst_allow_memset_s" = "yes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE_UNQUOTED(HAVE_MEMSET_S, 1,
|
||||
[Define to 1 if you have the memset_s function.])
|
||||
curl_cv_func_memset_s="yes"
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
curl_cv_func_memset_s="no"
|
||||
fi
|
||||
])
|
||||
|
||||
dnl CURL_RUN_IFELSE
|
||||
dnl -------------------------------------------------
|
||||
dnl Wrapper macro to use instead of AC_RUN_IFELSE. It
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue