From aa4569c5ae76b5fa8f9285e8d06f2ba3321db8a9 Mon Sep 17 00:00:00 2001 From: "utatane.tea@gmail.com" Date: Tue, 4 Apr 2017 07:04:38 +0000 Subject: [PATCH] [WTF] Introduce WTF::RandomDevice which keeps /dev/urandom opened https://bugs.webkit.org/show_bug.cgi?id=170095 Reviewed by Michael Catanzaro. In this patch, we introduce RandomDevice, which keeps /dev/urandom opened to avoid repeatedly open and close urandom file descriptor in Linux. The purpose is similar to std::random_device, but WTF::RandomDevice explicitly avoids using ARC4, which is recently attempted to be removed from the WebKit tree[1]. [1]: https://trac.webkit.org/r214329 * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/OSRandomSource.cpp: (WTF::cryptographicallyRandomValuesFromOS): (WTF::crashUnableToOpenURandom): Deleted. (WTF::crashUnableToReadFromURandom): Deleted. * wtf/RandomDevice.cpp: Copied from Source/WTF/wtf/OSRandomSource.cpp. (WTF::crashUnableToOpenURandom): (WTF::crashUnableToReadFromURandom): (WTF::RandomDevice::RandomDevice): (WTF::RandomDevice::~RandomDevice): (WTF::RandomDevice::cryptographicallyRandomValues): * wtf/RandomDevice.h: Added. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214867 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/WTF/ChangeLog | 30 ++++++++ Source/WTF/WTF.xcodeproj/project.pbxproj | 8 +++ Source/WTF/wtf/CMakeLists.txt | 2 + Source/WTF/wtf/OSRandomSource.cpp | 66 ++---------------- Source/WTF/wtf/RandomDevice.cpp | 116 +++++++++++++++++++++++++++++++ Source/WTF/wtf/RandomDevice.h | 60 ++++++++++++++++ 6 files changed, 220 insertions(+), 62 deletions(-) create mode 100644 Source/WTF/wtf/RandomDevice.cpp create mode 100644 Source/WTF/wtf/RandomDevice.h diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog index d0a6c52..330259f 100644 --- a/Source/WTF/ChangeLog +++ b/Source/WTF/ChangeLog @@ -1,3 +1,33 @@ +2017-04-03 Yusuke Suzuki + + [WTF] Introduce WTF::RandomDevice which keeps /dev/urandom opened + https://bugs.webkit.org/show_bug.cgi?id=170095 + + Reviewed by Michael Catanzaro. + + In this patch, we introduce RandomDevice, which keeps /dev/urandom opened + to avoid repeatedly open and close urandom file descriptor in Linux. + + The purpose is similar to std::random_device, but WTF::RandomDevice explicitly + avoids using ARC4, which is recently attempted to be removed from the WebKit + tree[1]. + + [1]: https://trac.webkit.org/r214329 + + * WTF.xcodeproj/project.pbxproj: + * wtf/CMakeLists.txt: + * wtf/OSRandomSource.cpp: + (WTF::cryptographicallyRandomValuesFromOS): + (WTF::crashUnableToOpenURandom): Deleted. + (WTF::crashUnableToReadFromURandom): Deleted. + * wtf/RandomDevice.cpp: Copied from Source/WTF/wtf/OSRandomSource.cpp. + (WTF::crashUnableToOpenURandom): + (WTF::crashUnableToReadFromURandom): + (WTF::RandomDevice::RandomDevice): + (WTF::RandomDevice::~RandomDevice): + (WTF::RandomDevice::cryptographicallyRandomValues): + * wtf/RandomDevice.h: Added. + 2017-04-03 Filip Pizlo WTF::Liveness should have an API that focuses on actions at instruction boundaries diff --git a/Source/WTF/WTF.xcodeproj/project.pbxproj b/Source/WTF/WTF.xcodeproj/project.pbxproj index 2725e1b..f58f19b 100644 --- a/Source/WTF/WTF.xcodeproj/project.pbxproj +++ b/Source/WTF/WTF.xcodeproj/project.pbxproj @@ -388,6 +388,8 @@ FE8925B01D00DAEC0046907E /* Indenter.h in Headers */ = {isa = PBXBuildFile; fileRef = FE8925AF1D00DAEC0046907E /* Indenter.h */; }; FEDACD3D1630F83F00C69634 /* StackStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDACD3B1630F83F00C69634 /* StackStats.cpp */; }; FEDACD3E1630F83F00C69634 /* StackStats.h in Headers */ = {isa = PBXBuildFile; fileRef = FEDACD3C1630F83F00C69634 /* StackStats.h */; }; + FC6EC2BF20F849969C6A5BE1 /* RandomDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 24F1B248619F412296D1C19C /* RandomDevice.h */; }; + A3B725EC987446AD93F1A440 /* RandomDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -788,6 +790,8 @@ FE8925AF1D00DAEC0046907E /* Indenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Indenter.h; sourceTree = ""; }; FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = ""; }; FEDACD3C1630F83F00C69634 /* StackStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackStats.h; sourceTree = ""; }; + 24F1B248619F412296D1C19C /* RandomDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RandomDevice.h; path = RandomDevice.h; sourceTree = ""; }; + C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RandomDevice.cpp; path = RandomDevice.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1102,6 +1106,8 @@ 0FC4488216FE9FE100844BE9 /* ProcessID.h */, 143F611D1565F0F900DB514A /* RAMSize.cpp */, 143F611E1565F0F900DB514A /* RAMSize.h */, + 24F1B248619F412296D1C19C /* RandomDevice.h */, + C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */, A8A472FB151A825B004123FF /* RandomNumber.cpp */, A8A472FC151A825B004123FF /* RandomNumber.h */, A8A472FD151A825B004123FF /* RandomNumberSeed.h */, @@ -1550,6 +1556,7 @@ 0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */, 0FC4488316FE9FE100844BE9 /* ProcessID.h in Headers */, 143F61201565F0F900DB514A /* RAMSize.h in Headers */, + FC6EC2BF20F849969C6A5BE1 /* RandomDevice.h in Headers */, A8A47415151A825B004123FF /* RandomNumber.h in Headers */, A8A47416151A825B004123FF /* RandomNumberSeed.h in Headers */, 0F725CAC1C50461600AD943A /* RangeSet.h in Headers */, @@ -1806,6 +1813,7 @@ DCEE22031CEA7551000C2396 /* PlatformUserPreferredLanguagesMac.mm in Sources */, 0F9D3362165DBA73005AD387 /* PrintStream.cpp in Sources */, 143F611F1565F0F900DB514A /* RAMSize.cpp in Sources */, + A3B725EC987446AD93F1A440 /* RandomDevice.cpp in Sources */, A8A47414151A825B004123FF /* RandomNumber.cpp in Sources */, A8A4741A151A825B004123FF /* RefCountedLeakCounter.cpp in Sources */, 2CDED0F318115C85004DBA70 /* RunLoop.cpp in Sources */, diff --git a/Source/WTF/wtf/CMakeLists.txt b/Source/WTF/wtf/CMakeLists.txt index 11f283d..a341911 100644 --- a/Source/WTF/wtf/CMakeLists.txt +++ b/Source/WTF/wtf/CMakeLists.txt @@ -98,6 +98,7 @@ set(WTF_HEADERS PrintStream.h ProcessID.h RAMSize.h + RandomDevice.h RandomNumber.h RandomNumberSeed.h Range.h @@ -227,6 +228,7 @@ set(WTF_SOURCES ParkingLot.cpp PrintStream.cpp RAMSize.cpp + RandomDevice.cpp RandomNumber.cpp RefCountedLeakCounter.cpp RunLoop.cpp diff --git a/Source/WTF/wtf/OSRandomSource.cpp b/Source/WTF/wtf/OSRandomSource.cpp index 378795d..c3d0895 100644 --- a/Source/WTF/wtf/OSRandomSource.cpp +++ b/Source/WTF/wtf/OSRandomSource.cpp @@ -26,73 +26,15 @@ #include "config.h" #include "OSRandomSource.h" -#include -#include - -#if !OS(DARWIN) && OS(UNIX) -#include -#include -#include -#endif - -#if OS(WINDOWS) -#include -#include // windows.h must be included before wincrypt.h. -#endif - -#if OS(DARWIN) -#include "CommonCryptoSPI.h" -#endif +#include +#include namespace WTF { -#if !OS(DARWIN) && OS(UNIX) -NEVER_INLINE NO_RETURN_DUE_TO_CRASH static void crashUnableToOpenURandom() -{ - CRASH(); -} - -NEVER_INLINE NO_RETURN_DUE_TO_CRASH static void crashUnableToReadFromURandom() -{ - CRASH(); -} -#endif - void cryptographicallyRandomValuesFromOS(unsigned char* buffer, size_t length) { -#if OS(DARWIN) - RELEASE_ASSERT(!CCRandomCopyBytes(kCCRandomDefault, buffer, length)); -#elif OS(UNIX) - int fd = open("/dev/urandom", O_RDONLY, 0); - if (fd < 0) - crashUnableToOpenURandom(); // We need /dev/urandom for this API to work... - - ssize_t amountRead = 0; - while (static_cast(amountRead) < length) { - ssize_t currentRead = read(fd, buffer + amountRead, length - amountRead); - // We need to check for both EAGAIN and EINTR since on some systems /dev/urandom - // is blocking and on others it is non-blocking. - if (currentRead == -1) { - if (!(errno == EAGAIN || errno == EINTR)) - crashUnableToReadFromURandom(); - } else - amountRead += currentRead; - } - - close(fd); - -#elif OS(WINDOWS) - HCRYPTPROV hCryptProv = 0; - if (!CryptAcquireContext(&hCryptProv, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - CRASH(); - if (!CryptGenRandom(hCryptProv, length, buffer)) - CRASH(); - CryptReleaseContext(hCryptProv, 0); -#else - #error "This configuration doesn't have a strong source of randomness." - // WARNING: When adding new sources of OS randomness, the randomness must - // be of cryptographic quality! -#endif + static NeverDestroyed device; + device.get().cryptographicallyRandomValues(buffer, length); } } diff --git a/Source/WTF/wtf/RandomDevice.cpp b/Source/WTF/wtf/RandomDevice.cpp new file mode 100644 index 0000000..61d6057 --- /dev/null +++ b/Source/WTF/wtf/RandomDevice.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2017 Yusuke Suzuki + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RandomDevice.h" + +#include +#include + +#if !OS(DARWIN) && OS(UNIX) +#include +#include +#include +#endif + +#if OS(WINDOWS) +#include +#include // windows.h must be included before wincrypt.h. +#endif + +#if OS(DARWIN) +#include "CommonCryptoSPI.h" +#endif + +namespace WTF { + +#if !OS(DARWIN) && OS(UNIX) +NEVER_INLINE NO_RETURN_DUE_TO_CRASH static void crashUnableToOpenURandom() +{ + CRASH(); +} + +NEVER_INLINE NO_RETURN_DUE_TO_CRASH static void crashUnableToReadFromURandom() +{ + CRASH(); +} +#endif + +#if !OS(DARWIN) && !OS(WINDOWS) +RandomDevice::RandomDevice() +{ + int ret = 0; + do { + ret = open("/dev/urandom", O_RDONLY, 0); + } while (ret == -1 && errno == EINTR); + m_fd = ret; + if (m_fd < 0) + crashUnableToOpenURandom(); // We need /dev/urandom for this API to work... +} +#endif + +#if !OS(DARWIN) && !OS(WINDOWS) +RandomDevice::~RandomDevice() +{ + close(m_fd); +} +#endif + +// FIXME: Make this call fast by creating the pool in RandomDevice. +// https://bugs.webkit.org/show_bug.cgi?id=170190 +void RandomDevice::cryptographicallyRandomValues(unsigned char* buffer, size_t length) +{ +#if OS(DARWIN) + RELEASE_ASSERT(!CCRandomCopyBytes(kCCRandomDefault, buffer, length)); +#elif OS(UNIX) + ssize_t amountRead = 0; + while (static_cast(amountRead) < length) { + ssize_t currentRead = read(m_fd, buffer + amountRead, length - amountRead); + // We need to check for both EAGAIN and EINTR since on some systems /dev/urandom + // is blocking and on others it is non-blocking. + if (currentRead == -1) { + if (!(errno == EAGAIN || errno == EINTR)) + crashUnableToReadFromURandom(); + } else + amountRead += currentRead; + } +#elif OS(WINDOWS) + // FIXME: We cannot ensure that Cryptographic Service Provider context and CryptGenRandom are safe across threads. + // If it is safe, we can acquire context per RandomDevice. + HCRYPTPROV hCryptProv = 0; + if (!CryptAcquireContext(&hCryptProv, 0, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + CRASH(); + if (!CryptGenRandom(hCryptProv, length, buffer)) + CRASH(); + CryptReleaseContext(hCryptProv, 0); +#else +#error "This configuration doesn't have a strong source of randomness." +// WARNING: When adding new sources of OS randomness, the randomness must +// be of cryptographic quality! +#endif +} + +} diff --git a/Source/WTF/wtf/RandomDevice.h b/Source/WTF/wtf/RandomDevice.h new file mode 100644 index 0000000..86636c9 --- /dev/null +++ b/Source/WTF/wtf/RandomDevice.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Google Inc. + * Copyright (C) 2017 Yusuke Suzuki + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace WTF { + +class RandomDevice { + WTF_MAKE_NONCOPYABLE(RandomDevice); +public: +#if OS(DARWIN) || OS(WINDOWS) + RandomDevice() = default; +#else + RandomDevice(); + ~RandomDevice(); +#endif + + // This function attempts to fill buffer with randomness from the operating + // system. Rather than calling this function directly, consider calling + // cryptographicallyRandomNumber or cryptographicallyRandomValues. + void cryptographicallyRandomValues(unsigned char* buffer, size_t length); + +private: +#if OS(DARWIN) || OS(WINDOWS) +#elif OS(UNIX) + int m_fd { -1 }; +#else +#error "This configuration doesn't have a strong source of randomness." +// WARNING: When adding new sources of OS randomness, the randomness must +// be of cryptographic quality! +#endif +}; + +} -- 1.8.3.1