summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2017-06-21 15:56:03 +0000
committerKostya Kortchinsky <kostyak@google.com>2017-06-21 15:56:03 +0000
commita7d94d30c9484f514213292f9e6f8b8bb9ef0908 (patch)
tree509c268526793d5adbe7dcab6d8639357b21c31b /lib/sanitizer_common
parentd75d4f58e625a84ca1961e51cbc02276b7ebdc65 (diff)
[sanitizer] Add a function to gather random bytes
Summary: AFAICT compiler-rt doesn't have a function that would return 'good' random bytes to seed a PRNG. Currently, the `SizeClassAllocator64` uses addresses returned by `mmap` to seed its PRNG, which is not ideal, and `SizeClassAllocator32` doesn't benefit from the entropy offered by its 64-bit counterpart address space, so right now it has nothing. This function aims at solving this, allowing to implement good 32-bit chunk randomization. Scudo also has a function that does this for Cookie purposes, which would go away in a later CL once this lands. This function will try the `getrandom` syscall if available, and fallback to `/dev/urandom` if not. Unfortunately, I do not have a way to implement and test a Mac and Windows version, so those are unimplemented as of now. Note that `kRandomShuffleChunks` is only used on Linux for now. Reviewers: alekseyshl Reviewed By: alekseyshl Subscribers: zturner, rnk, llvm-commits, kubamracek Differential Revision: https://reviews.llvm.org/D34412 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305922 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r--lib/sanitizer_common/sanitizer_common.h4
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc26
-rw-r--r--lib/sanitizer_common/sanitizer_mac.cc5
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc5
-rw-r--r--lib/sanitizer_common/tests/sanitizer_common_test.cc17
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