forked from OSchip/llvm-project
[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 llvm-svn: 310839
This commit is contained in:
parent
1333aaca97
commit
e1dde07640
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue