From eb9ebe3db7119c9b556a7b8e94a31eddfbd34174 Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Tue, 10 Apr 2018 12:46:39 +0100 Subject: [PATCH 1/9] Use the `__has_include` and `GRND_RANDOM` macros --- stdlib/public/stubs/LibcShims.cpp | 33 ++++++------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index d2838eb1ee55d..f5752452be196 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -16,30 +16,6 @@ # include #endif -#if defined(__CYGWIN__) -# include -# if (CYGWIN_VERSION_API_MAJOR > 0) || (CYGWIN_VERSION_API_MINOR >= 306) -# include -# define SWIFT_STDLIB_USING_GETRANDOM -# endif -#endif - -#if defined(__Fuchsia__) -# include -# define SWIFT_STDLIB_USING_GETENTROPY -#endif - -#if defined(__linux__) -# include -# if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) -# include -# if defined(__BIONIC__) || (defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,25)) -# include -# define SWIFT_STDLIB_USING_GETRANDOM -# endif -# endif -#endif - #if defined(_WIN32) && !defined(__CYGWIN__) # include # define WIN32_LEAN_AND_MEAN @@ -63,6 +39,9 @@ #include #include #include +#if __has_include() +# include +#endif #include #include #include @@ -370,7 +349,7 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { } } -#elif defined(SWIFT_STDLIB_USING_GETENTROPY) +#elif defined(__Fuchsia__) SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { @@ -390,14 +369,14 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { -#if !defined(SWIFT_STDLIB_USING_GETRANDOM) +#if !defined(GRND_RANDOM) static const int fd = _stdlib_open("/dev/urandom", O_RDONLY, 0); if (fd < 0) { fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); } #endif while (nbytes > 0) { -#if !defined(SWIFT_STDLIB_USING_GETRANDOM) +#if !defined(GRND_RANDOM) __swift_ssize_t actual_nbytes = _stdlib_read(fd, buf, nbytes); #else __swift_ssize_t actual_nbytes = getrandom(buf, nbytes, 0); From fa06580e68e97fc7a740441ce7c9fa4b7f897d7c Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Tue, 10 Apr 2018 16:36:32 +0100 Subject: [PATCH 2/9] Use `getentropy` instead of `getrandom` --- stdlib/public/stubs/LibcShims.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index f5752452be196..41d8c0436d91f 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -349,7 +349,9 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { } } -#elif defined(__Fuchsia__) +#else + +static int getentropy_using_dev_urandom(void *buf, __swift_size_t nbytes); SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { @@ -357,7 +359,11 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { constexpr __swift_size_t max_nbytes = 256; __swift_size_t actual_nbytes = (nbytes < max_nbytes ? nbytes : max_nbytes); - if (0 != getentropy(buf, actual_nbytes)) { + if ( +#if __has_include() + getentropy(buf, actual_nbytes) && +#endif + getentropy_using_dev_urandom(buf, actual_nbytes)) { fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); } buf = static_cast(buf) + actual_nbytes; @@ -365,29 +371,19 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { } } -#else - -SWIFT_RUNTIME_STDLIB_INTERNAL -void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { -#if !defined(GRND_RANDOM) +static int getentropy_using_dev_urandom(void *buf, __swift_size_t nbytes) { static const int fd = _stdlib_open("/dev/urandom", O_RDONLY, 0); - if (fd < 0) { - fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); - } -#endif + if (fd < 0) { return -1; } while (nbytes > 0) { -#if !defined(GRND_RANDOM) __swift_ssize_t actual_nbytes = _stdlib_read(fd, buf, nbytes); -#else - __swift_ssize_t actual_nbytes = getrandom(buf, nbytes, 0); -#endif if (actual_nbytes < 1) { if (errno == EINTR) { continue; } - fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); + return -1; } buf = static_cast(buf) + actual_nbytes; nbytes -= actual_nbytes; } + return 0; } #endif From 5853f7a722bdd34dc029836a7487347f96f8f2ed Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Tue, 10 Apr 2018 17:30:30 +0100 Subject: [PATCH 3/9] Use `std::min` from the header --- stdlib/public/stubs/LibcShims.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 41d8c0436d91f..795ca4805afb0 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -32,6 +32,7 @@ # include #endif +#include #include #include #include @@ -356,9 +357,7 @@ static int getentropy_using_dev_urandom(void *buf, __swift_size_t nbytes); SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { while (nbytes > 0) { - constexpr __swift_size_t max_nbytes = 256; - __swift_size_t actual_nbytes = (nbytes < max_nbytes ? - nbytes : max_nbytes); + __swift_size_t actual_nbytes = std::min(nbytes, __swift_size_t{256}); if ( #if __has_include() getentropy(buf, actual_nbytes) && From 411d2a47c2d97157dfae5d28e44334cf8353bb1b Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Tue, 10 Apr 2018 19:28:58 +0100 Subject: [PATCH 4/9] Move `#if` out of the `_stdlib_random` function --- stdlib/public/stubs/LibcShims.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 795ca4805afb0..9b47e7df0e513 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -352,17 +352,20 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { #else -static int getentropy_using_dev_urandom(void *buf, __swift_size_t nbytes); +#if __has_include() +# define getentropy_using_system(...) getentropy(__VA_ARGS__) +#else +# define getentropy_using_system(...) -1 +#endif + +static int getentropy_using_device(void *buf, __swift_size_t nbytes); SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { while (nbytes > 0) { __swift_size_t actual_nbytes = std::min(nbytes, __swift_size_t{256}); - if ( -#if __has_include() - getentropy(buf, actual_nbytes) && -#endif - getentropy_using_dev_urandom(buf, actual_nbytes)) { + if (getentropy_using_system(buf, actual_nbytes) && + getentropy_using_device(buf, actual_nbytes)) { fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); } buf = static_cast(buf) + actual_nbytes; @@ -370,7 +373,7 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { } } -static int getentropy_using_dev_urandom(void *buf, __swift_size_t nbytes) { +static int getentropy_using_device(void *buf, __swift_size_t nbytes) { static const int fd = _stdlib_open("/dev/urandom", O_RDONLY, 0); if (fd < 0) { return -1; } while (nbytes > 0) { From 70270b289d1a4a85da5479395ed03d64ea4da4c9 Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Thu, 12 Apr 2018 05:39:17 +0100 Subject: [PATCH 5/9] Use `getrandom` with "/dev/urandom" fallback --- stdlib/public/stubs/LibcShims.cpp | 45 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 9b47e7df0e513..e5bb075215ec0 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -352,40 +352,35 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { #else -#if __has_include() -# define getentropy_using_system(...) getentropy(__VA_ARGS__) -#else -# define getentropy_using_system(...) -1 -#endif - -static int getentropy_using_device(void *buf, __swift_size_t nbytes); +#undef WHILE_EINTR +#define WHILE_EINTR(expression) ({ \ + decltype(expression) result = -1; \ + do { result = (expression); } while (result == -1 && errno == EINTR); \ + result; \ +}) SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { while (nbytes > 0) { - __swift_size_t actual_nbytes = std::min(nbytes, __swift_size_t{256}); - if (getentropy_using_system(buf, actual_nbytes) && - getentropy_using_device(buf, actual_nbytes)) { - fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); + __swift_size_t expected_nbytes = std::min(nbytes, __swift_size_t{256}); + __swift_ssize_t actual_nbytes = -1; +#if defined(GRND_RANDOM) + actual_nbytes = WHILE_EINTR(getrandom(buf, expected_nbytes, 0)); +#elif defined(__Fuchsia__) + actual_nbytes = getentropy(buf, expected_nbytes) ?: expected_nbytes; +#endif + if (actual_nbytes == -1) { + static const int fd = + WHILE_EINTR(_stdlib_open("/dev/urandom", O_RDONLY, 0)); + actual_nbytes = (fd == -1) ? -1 : + WHILE_EINTR(_stdlib_read(fd, buf, expected_nbytes)); } - buf = static_cast(buf) + actual_nbytes; - nbytes -= actual_nbytes; - } -} - -static int getentropy_using_device(void *buf, __swift_size_t nbytes) { - static const int fd = _stdlib_open("/dev/urandom", O_RDONLY, 0); - if (fd < 0) { return -1; } - while (nbytes > 0) { - __swift_ssize_t actual_nbytes = _stdlib_read(fd, buf, nbytes); - if (actual_nbytes < 1) { - if (errno == EINTR) { continue; } - return -1; + if (actual_nbytes == -1) { + fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); } buf = static_cast(buf) + actual_nbytes; nbytes -= actual_nbytes; } - return 0; } #endif From 0012e008e9bec170506eafd4d1e2374674a53a49 Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Sat, 14 Apr 2018 04:13:11 +0100 Subject: [PATCH 6/9] Use `#pragma comment` to import "Bcrypt.lib" * * --- stdlib/public/core/CMakeLists.txt | 4 ---- stdlib/public/stubs/LibcShims.cpp | 13 +++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 0b29c13ae2752..cac5ca7c887b0 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -228,10 +228,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ${EXECINFO_LIBRARY}) endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - list(APPEND swift_core_link_flags "$ENV{SystemRoot}/system32/bcrypt.dll") -endif() - option(SWIFT_CHECK_ESSENTIAL_STDLIB "Check core standard library layering by linking its essential subset" FALSE) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index e5bb075215ec0..aed7157db2054 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -19,12 +19,9 @@ #if defined(_WIN32) && !defined(__CYGWIN__) # include # define WIN32_LEAN_AND_MEAN -# define WIN32_NO_STATUS -# include -# undef WIN32_NO_STATUS -# include -# include +# include # include +# pragma comment(lib, "Bcrypt.lib") #else # include # include @@ -337,7 +334,7 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { } #elif defined(_WIN32) && !defined(__CYGWIN__) -// TODO: Test on Windows +#error TODO: Test on Windows SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { @@ -345,8 +342,8 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { static_cast(buf), static_cast(nbytes), BCRYPT_USE_SYSTEM_PREFERRED_RNG); - if (!NT_SUCCESS(status)) { - fatalError(0, "Fatal error: %#.8x in '%s'\n", status, __func__); + if (!BCRYPT_SUCCESS(status)) { + fatalError(0, "Fatal error: 0x%.8X in '%s'\n", status, __func__); } } From 0f6302f9c5a0189e963675cf406e13303981f40b Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Thu, 19 Apr 2018 14:14:55 +0100 Subject: [PATCH 7/9] Use "/dev/urandom" instead of `SecRandomCopyBytes` --- stdlib/public/core/CMakeLists.txt | 1 - stdlib/public/stubs/LibcShims.cpp | 34 ++++++++++++------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index cac5ca7c887b0..1ffe22ba7f86a 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -193,7 +193,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") list(APPEND swift_core_link_flags "-all_load") list(APPEND swift_core_framework_depends Foundation) list(APPEND swift_core_framework_depends CoreFoundation) - list(APPEND swift_core_framework_depends Security) list(APPEND swift_core_private_link_libraries icucore) else() # With the GNU linker the equivalent of -all_load is to tell the linker diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index aed7157db2054..f26a0d562c2d1 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -13,7 +13,6 @@ #if defined(__APPLE__) # define _REENTRANT # include -# include #endif #if defined(_WIN32) && !defined(__CYGWIN__) @@ -319,22 +318,8 @@ swift::_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound) { return RandomUniform(getGlobalMT19937()); } -#if defined(__APPLE__) - -SWIFT_RUNTIME_STDLIB_INTERNAL -void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { - if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) { - arc4random_buf(buf, nbytes); - } else { - OSStatus status = SecRandomCopyBytes(kSecRandomDefault, nbytes, buf); - if (status != errSecSuccess) { - fatalError(0, "Fatal error: %d in '%s'\n", status, __func__); - } - } -} - -#elif defined(_WIN32) && !defined(__CYGWIN__) -#error TODO: Test on Windows +#if defined(_WIN32) && !defined(__CYGWIN__) +#error TODO: Test _stdlib_random on Windows SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { @@ -359,18 +344,25 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { SWIFT_RUNTIME_STDLIB_INTERNAL void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { while (nbytes > 0) { - __swift_size_t expected_nbytes = std::min(nbytes, __swift_size_t{256}); __swift_ssize_t actual_nbytes = -1; #if defined(GRND_RANDOM) - actual_nbytes = WHILE_EINTR(getrandom(buf, expected_nbytes, 0)); + actual_nbytes = WHILE_EINTR(getrandom(buf, nbytes, 0)); #elif defined(__Fuchsia__) - actual_nbytes = getentropy(buf, expected_nbytes) ?: expected_nbytes; + __swift_size_t getentropy_nbytes = std::min(nbytes, __swift_size_t{256}); + if (0 == getentropy(buf, getentropy_nbytes)) { + actual_nbytes = getentropy_nbytes; + } +#elif defined(__APPLE__) + if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) { + arc4random_buf(buf, nbytes); + actual_nbytes = nbytes; + } #endif if (actual_nbytes == -1) { static const int fd = WHILE_EINTR(_stdlib_open("/dev/urandom", O_RDONLY, 0)); actual_nbytes = (fd == -1) ? -1 : - WHILE_EINTR(_stdlib_read(fd, buf, expected_nbytes)); + WHILE_EINTR(_stdlib_read(fd, buf, nbytes)); } if (actual_nbytes == -1) { fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); From 90fd95a2fe6321cba72b792796562f51349bef04 Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Fri, 20 Apr 2018 18:11:32 +0100 Subject: [PATCH 8/9] Use `swift::StaticMutex` for shared "/dev/urandom" --- stdlib/public/stubs/LibcShims.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index f26a0d562c2d1..e2887b9998503 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -47,6 +47,7 @@ #include "swift/Basic/Lazy.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Mutex.h" #include "../SwiftShims/LibcShims.h" using namespace swift; @@ -361,8 +362,12 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { if (actual_nbytes == -1) { static const int fd = WHILE_EINTR(_stdlib_open("/dev/urandom", O_RDONLY, 0)); - actual_nbytes = (fd == -1) ? -1 : - WHILE_EINTR(_stdlib_read(fd, buf, nbytes)); + if (fd != -1) { + static StaticMutex mutex; + mutex.withLock([&] { + actual_nbytes = WHILE_EINTR(_stdlib_read(fd, buf, nbytes)); + }); + } } if (actual_nbytes == -1) { fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__); From c9f177f438305ea8b34437bd7ee61f2abb16f71f Mon Sep 17 00:00:00 2001 From: Ben Rimmington Date: Sun, 22 Apr 2018 13:16:49 +0100 Subject: [PATCH 9/9] Add `getrandom_available`; use `O_CLOEXEC` flag --- stdlib/public/stubs/LibcShims.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index e2887b9998503..93dd8069b2a95 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -347,7 +347,11 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { while (nbytes > 0) { __swift_ssize_t actual_nbytes = -1; #if defined(GRND_RANDOM) - actual_nbytes = WHILE_EINTR(getrandom(buf, nbytes, 0)); + static const bool getrandom_available = + !(getrandom(nullptr, 0, 0) == -1 && errno == ENOSYS); + if (getrandom_available) { + actual_nbytes = WHILE_EINTR(getrandom(buf, nbytes, 0)); + } #elif defined(__Fuchsia__) __swift_size_t getentropy_nbytes = std::min(nbytes, __swift_size_t{256}); if (0 == getentropy(buf, getentropy_nbytes)) { @@ -361,7 +365,7 @@ void swift::_stdlib_random(void *buf, __swift_size_t nbytes) { #endif if (actual_nbytes == -1) { static const int fd = - WHILE_EINTR(_stdlib_open("/dev/urandom", O_RDONLY, 0)); + WHILE_EINTR(_stdlib_open("/dev/urandom", O_RDONLY | O_CLOEXEC, 0)); if (fd != -1) { static StaticMutex mutex; mutex.withLock([&] {