diff options
author | Kostya Kortchinsky <kostyak@google.com> | 2017-08-14 14:53:47 +0000 |
---|---|---|
committer | Kostya Kortchinsky <kostyak@google.com> | 2017-08-14 14:53:47 +0000 |
commit | 83db677110a0953642661a2e526521e30c358c53 (patch) | |
tree | 83e3ae739a17343b4a7d56e6aed1b424c50fe35b /lib | |
parent | 1c85aaf50b80c5e1233ca176b13359d39b040c02 (diff) |
[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
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@310839 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 21 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_mac.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_common_test.cc | 20 | ||||
-rw-r--r-- | lib/scudo/scudo_utils.h | 13 |
6 files changed, 39 insertions, 23 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 9e65639b9..048101295 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -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 diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 3ca762782..7923078a6 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -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, uptr alignment, uptr left_padding, 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; diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index 38b418314..6cb75266b 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -992,7 +992,7 @@ void CheckNoDeepBind(const char *filename, int flag) { } // FIXME: implement on this platform. -bool GetRandom(void *buffer, uptr length) { +bool GetRandom(void *buffer, uptr length, bool blocking) { UNIMPLEMENTED(); } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index c7772213a..a13a4c5a5 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -1022,7 +1022,7 @@ void CheckNoDeepBind(const char *filename, int flag) { } // FIXME: implement on this platform. -bool GetRandom(void *buffer, uptr length) { +bool GetRandom(void *buffer, uptr length, bool blocking) { UNIMPLEMENTED(); } diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index d92c9d9c3..9c62b4593 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -304,15 +304,17 @@ TEST(SanitizerCommon, InternalScopedString) { #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); + } } } } diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index 6c6c9d893..13269195b 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -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; } |