summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-12-25 11:57:36 +0100
committerAndreas Kling <kling@serenityos.org>2021-12-25 14:20:13 +0100
commitae07660587a6bcfe7e8ef69afa44256720558386 (patch)
tree38474a5051bc5321bb93be8052663161d1590191 /Userland/Libraries
parent9965e59ad8313cdbd758c06099c5e83cf241b15a (diff)
downloadserenity-ae07660587a6bcfe7e8ef69afa44256720558386.zip
LibC: Buffer randomness to avoid syscall in every arc4random_buf()
Keep a page-sized buffer of random bytes cached and work through it before calling the kernel again.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibC/stdlib.cpp44
1 files changed, 37 insertions, 7 deletions
diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp
index 6f020acc11..713373fad9 100644
--- a/Userland/Libraries/LibC/stdlib.cpp
+++ b/Userland/Libraries/LibC/stdlib.cpp
@@ -1166,21 +1166,51 @@ unsigned long long strtoull(const char* str, char** endptr, int base)
return digits.number();
}
-// Serenity's PRNG is not cryptographically secure. Do not rely on this for
-// any real crypto! These functions (for now) are for compatibility.
-// TODO: In the future, rand can be made deterministic and this not.
uint32_t arc4random(void)
{
uint32_t buf;
- syscall(SC_getrandom, &buf, sizeof(buf), 0);
+ arc4random_buf(&buf, sizeof(buf));
return buf;
}
+static pthread_mutex_t s_randomness_mutex = PTHREAD_MUTEX_INITIALIZER;
+static u8* s_randomness_buffer;
+static size_t s_randomness_index;
+
void arc4random_buf(void* buffer, size_t buffer_size)
{
- // arc4random_buf should never fail, but user supplied buffers could fail.
- // However, if the user passes a garbage buffer, that's on them.
- syscall(SC_getrandom, buffer, buffer_size, 0);
+ pthread_mutex_lock(&s_randomness_mutex);
+
+ size_t bytes_needed = buffer_size;
+ auto* ptr = static_cast<u8*>(buffer);
+
+ while (bytes_needed > 0) {
+ if (!s_randomness_buffer || s_randomness_index >= PAGE_SIZE) {
+ if (!s_randomness_buffer) {
+ s_randomness_buffer = static_cast<u8*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_RANDOMIZED, 0, 0));
+ VERIFY(s_randomness_buffer != MAP_FAILED);
+ __pthread_fork_atfork_register_child(
+ [] {
+ munmap(s_randomness_buffer, PAGE_SIZE);
+ s_randomness_buffer = nullptr;
+ s_randomness_index = 0;
+ });
+ }
+ syscall(SC_getrandom, s_randomness_buffer, PAGE_SIZE);
+ s_randomness_index = 0;
+ }
+
+ size_t available_bytes = PAGE_SIZE - s_randomness_index;
+ size_t bytes_to_copy = min(bytes_needed, available_bytes);
+
+ memcpy(ptr, s_randomness_buffer + s_randomness_index, bytes_to_copy);
+
+ s_randomness_index += bytes_to_copy;
+ bytes_needed -= bytes_to_copy;
+ ptr += bytes_to_copy;
+ }
+
+ pthread_mutex_unlock(&s_randomness_mutex);
}
uint32_t arc4random_uniform(uint32_t max_bounds)