diff options
-rw-r--r-- | lib/sanitizer_common/sanitizer_common.h | 4 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 26 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_mac.cc | 5 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_win.cc | 5 | ||||
-rw-r--r-- | lib/sanitizer_common/tests/sanitizer_common_test.cc | 17 |
5 files changed, 57 insertions, 0 deletions
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 875a46009..46678b4ad 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -919,6 +919,10 @@ 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); + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index d31c49d69..a94a63c7f 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -1604,6 +1604,32 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { return 0; } +bool GetRandom(void *buffer, uptr length) { + if (!buffer || !length || length > 256) + return false; +#if defined(__NR_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); + int rverrno = 0; + if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) + atomic_store_relaxed(&skip_getrandom_syscall, 1); + else if (res == length) + return true; + } +#endif + 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; + internal_close(fd); + return true; +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index a788a0915..b48238106 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -923,6 +923,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index 506e7374a..40800c158 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -1002,6 +1002,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index ebc885db7..ebadef3e2 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -300,4 +300,21 @@ TEST(SanitizerCommon, InternalScopedString) { EXPECT_STREQ("012345678", str.data()); } +#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); + } + } +} +#endif + } // namespace __sanitizer |