diff options
author | Andreas Kling <kling@serenityos.org> | 2021-12-25 11:57:36 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-12-25 14:20:13 +0100 |
commit | ae07660587a6bcfe7e8ef69afa44256720558386 (patch) | |
tree | 38474a5051bc5321bb93be8052663161d1590191 /Userland/Libraries | |
parent | 9965e59ad8313cdbd758c06099c5e83cf241b15a (diff) | |
download | serenity-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.cpp | 44 |
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) |