[compiler-rt] r310839 - [sanitizers] Add a blocking boolean to GetRandom prototype

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 14 07:53:47 PDT 2017


Author: cryptoad
Date: Mon Aug 14 07:53:47 2017
New Revision: 310839

URL: http://llvm.org/viewvc/llvm-project?rev=310839&view=rev
Log:
[sanitizers] Add a blocking boolean to GetRandom prototype

Summary:
On platforms with `getrandom`, the system call defaults to blocking. This
becomes an issue in the very early stage of the boot for Scudo, when the RNG
source is not set-up yet: the syscall will block and we'll stall.

Introduce a parameter to specify that the function should not block, defaulting
to blocking as the underlying syscall does.

Update Scudo to use the non-blocking version.

Reviewers: alekseyshl

Reviewed By: alekseyshl

Subscribers: llvm-commits, kubamracek

Differential Revision: https://reviews.llvm.org/D36399

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
    compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc
    compiler-rt/trunk/lib/scudo/scudo_utils.h

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common.h Mon Aug 14 07:53:47 2017
@@ -857,8 +857,8 @@ const s32 kReleaseToOSIntervalNever = -1
 void CheckNoDeepBind(const char *filename, int flag);
 
 // Returns the requested amount of random data (up to 256 bytes) that can then
-// be used to seed a PRNG.
-bool GetRandom(void *buffer, uptr length);
+// be used to seed a PRNG. Defaults to blocking like the underlying syscall.
+bool GetRandom(void *buffer, uptr length, bool blocking = true);
 
 }  // namespace __sanitizer
 

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux.cc Mon Aug 14 07:53:47 2017
@@ -135,6 +135,15 @@ extern void internal_sigreturn();
 }
 #endif
 
+#if SANITIZER_LINUX && defined(__NR_getrandom)
+# if !defined(GRND_NONBLOCK)
+#  define GRND_NONBLOCK 1
+# endif
+# define SANITIZER_USE_GETRANDOM 1
+#else
+# define SANITIZER_USE_GETRANDOM 0
+#endif  // SANITIZER_LINUX && defined(__NR_getrandom)
+
 namespace __sanitizer {
 
 #if SANITIZER_LINUX && defined(__x86_64__)
@@ -1768,25 +1777,27 @@ uptr FindAvailableMemoryRange(uptr size,
   return 0;
 }
 
-bool GetRandom(void *buffer, uptr length) {
+bool GetRandom(void *buffer, uptr length, bool blocking) {
   if (!buffer || !length || length > 256)
     return false;
-#if defined(__NR_getrandom)
+#if SANITIZER_USE_GETRANDOM
   static atomic_uint8_t skip_getrandom_syscall;
   if (!atomic_load_relaxed(&skip_getrandom_syscall)) {
     // Up to 256 bytes, getrandom will not be interrupted.
-    uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, 0);
+    uptr res = internal_syscall(SYSCALL(getrandom), buffer, length,
+                                blocking ? 0 : GRND_NONBLOCK);
     int rverrno = 0;
     if (internal_iserror(res, &rverrno) && rverrno == ENOSYS)
       atomic_store_relaxed(&skip_getrandom_syscall, 1);
     else if (res == length)
       return true;
   }
-#endif
+#endif  // SANITIZER_USE_GETRANDOM
+  // Up to 256 bytes, a read off /dev/urandom will not be interrupted.
+  // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.
   uptr fd = internal_open("/dev/urandom", O_RDONLY);
   if (internal_iserror(fd))
     return false;
-  // internal_read deals with EINTR.
   uptr res = internal_read(fd, buffer, length);
   if (internal_iserror(res))
     return false;

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc Mon Aug 14 07:53:47 2017
@@ -992,7 +992,7 @@ void CheckNoDeepBind(const char *filenam
 }
 
 // FIXME: implement on this platform.
-bool GetRandom(void *buffer, uptr length) {
+bool GetRandom(void *buffer, uptr length, bool blocking) {
   UNIMPLEMENTED();
 }
 

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc Mon Aug 14 07:53:47 2017
@@ -1022,7 +1022,7 @@ void CheckNoDeepBind(const char *filenam
 }
 
 // FIXME: implement on this platform.
-bool GetRandom(void *buffer, uptr length) {
+bool GetRandom(void *buffer, uptr length, bool blocking) {
   UNIMPLEMENTED();
 }
 

Modified: compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_common_test.cc Mon Aug 14 07:53:47 2017
@@ -304,15 +304,17 @@ TEST(SanitizerCommon, InternalScopedStri
 #if SANITIZER_LINUX
 TEST(SanitizerCommon, GetRandom) {
   u8 buffer_1[32], buffer_2[32];
-  EXPECT_FALSE(GetRandom(nullptr, 32));
-  EXPECT_FALSE(GetRandom(buffer_1, 0));
-  EXPECT_FALSE(GetRandom(buffer_1, 512));
-  EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2));
-  for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) {
-    for (uptr i = 0; i < 100; i++) {
-      EXPECT_TRUE(GetRandom(buffer_1, size));
-      EXPECT_TRUE(GetRandom(buffer_2, size));
-      EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0);
+  for (bool blocking : { false, true }) {
+    EXPECT_FALSE(GetRandom(nullptr, 32, blocking));
+    EXPECT_FALSE(GetRandom(buffer_1, 0, blocking));
+    EXPECT_FALSE(GetRandom(buffer_1, 512, blocking));
+    EXPECT_EQ(ARRAY_SIZE(buffer_1), ARRAY_SIZE(buffer_2));
+    for (uptr size = 4; size <= ARRAY_SIZE(buffer_1); size += 4) {
+      for (uptr i = 0; i < 100; i++) {
+        EXPECT_TRUE(GetRandom(buffer_1, size, blocking));
+        EXPECT_TRUE(GetRandom(buffer_2, size, blocking));
+        EXPECT_NE(internal_memcmp(buffer_1, buffer_2, size), 0);
+      }
     }
   }
 }

Modified: compiler-rt/trunk/lib/scudo/scudo_utils.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_utils.h?rev=310839&r1=310838&r2=310839&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_utils.h (original)
+++ compiler-rt/trunk/lib/scudo/scudo_utils.h Mon Aug 14 07:53:47 2017
@@ -44,11 +44,14 @@ INLINE u64 rotl(const u64 X, int K) {
 struct XoRoShiRo128Plus {
  public:
   void init() {
-    if (UNLIKELY(!GetRandom(reinterpret_cast<void *>(State), sizeof(State)))) {
-      // Early processes (eg: init) do not have /dev/urandom yet, but we still
-      // have to provide them with some degree of entropy. Not having a secure
-      // seed is not as problematic for them, as they are less likely to be
-      // the target of heap based vulnerabilities exploitation attempts.
+    if (UNLIKELY(!GetRandom(reinterpret_cast<void *>(State), sizeof(State),
+                            /*blocking=*/false))) {
+      // On some platforms, early processes like `init` do not have an
+      // initialized random pool (getrandom blocks and /dev/urandom doesn't
+      // exist yet), but we still have to provide them with some degree of
+      // entropy. Not having a secure seed is not as problematic for them, as
+      // they are less likely to be the target of heap based vulnerabilities
+      // exploitation attempts.
       State[0] = NanoTime();
       State[1] = 0;
     }




More information about the llvm-commits mailing list