summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2017-08-14 14:53:47 +0000
committerKostya Kortchinsky <kostyak@google.com>2017-08-14 14:53:47 +0000
commit83db677110a0953642661a2e526521e30c358c53 (patch)
tree83e3ae739a17343b4a7d56e6aed1b424c50fe35b /lib
parent1c85aaf50b80c5e1233ca176b13359d39b040c02 (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.h4
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc21
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc2
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc20
-rw-r--r--lib/scudo/scudo_utils.h13
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;
}