[WTF] Introduce WTF::RandomDevice which keeps /dev/urandom opened
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Apr 2017 07:04:38 +0000 (07:04 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Apr 2017 07:04:38 +0000 (07:04 +0000)
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
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/OSRandomSource.cpp
Source/WTF/wtf/RandomDevice.cpp [new file with mode: 0644]
Source/WTF/wtf/RandomDevice.h [new file with mode: 0644]

index d0a6c52..330259f 100644 (file)
@@ -1,3 +1,33 @@
+2017-04-03  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [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  <fpizlo@apple.com>
 
         WTF::Liveness should have an API that focuses on actions at instruction boundaries
index 2725e1b..f58f19b 100644 (file)
                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 */
                FE8925AF1D00DAEC0046907E /* Indenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Indenter.h; sourceTree = "<group>"; };
                FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = "<group>"; };
                FEDACD3C1630F83F00C69634 /* StackStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackStats.h; sourceTree = "<group>"; };
+               24F1B248619F412296D1C19C /* RandomDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RandomDevice.h; path = RandomDevice.h; sourceTree = "<group>"; };
+               C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RandomDevice.cpp; path = RandomDevice.cpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                                0FC4488216FE9FE100844BE9 /* ProcessID.h */,
                                143F611D1565F0F900DB514A /* RAMSize.cpp */,
                                143F611E1565F0F900DB514A /* RAMSize.h */,
+                               24F1B248619F412296D1C19C /* RandomDevice.h */,
+                               C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */,
                                A8A472FB151A825B004123FF /* RandomNumber.cpp */,
                                A8A472FC151A825B004123FF /* RandomNumber.h */,
                                A8A472FD151A825B004123FF /* RandomNumberSeed.h */,
                                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 */,
                                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 */,
index 11f283d..a341911 100644 (file)
@@ -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
index 378795d..c3d0895 100644 (file)
 #include "config.h"
 #include "OSRandomSource.h"
 
-#include <stdint.h>
-#include <stdlib.h>
-
-#if !OS(DARWIN) && OS(UNIX)
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-
-#if OS(WINDOWS)
-#include <windows.h>
-#include <wincrypt.h> // windows.h must be included before wincrypt.h.
-#endif
-
-#if OS(DARWIN)
-#include "CommonCryptoSPI.h"
-#endif
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RandomDevice.h>
 
 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<size_t>(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<RandomDevice> device;
+    device.get().cryptographicallyRandomValues(buffer, length);
 }
 
 }
diff --git a/Source/WTF/wtf/RandomDevice.cpp b/Source/WTF/wtf/RandomDevice.cpp
new file mode 100644 (file)
index 0000000..61d6057
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+
+#if !OS(DARWIN) && OS(UNIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#if OS(WINDOWS)
+#include <windows.h>
+#include <wincrypt.h> // 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<size_t>(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 (file)
index 0000000..86636c9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * 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 <wtf/Noncopyable.h>
+#include <wtf/StdLibExtras.h>
+
+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
+};
+
+}