From f7960ffbe3b3d686afb0982608818c5341fe057b Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sun, 2 Apr 2023 12:33:15 -0400 Subject: [PATCH] AK: Prevent passing lengths greater than 256 to getentropy() From the getentropy() man page, "The maximum permitted value for the length argument is 256". Several of our tests were passing lengths of several thousand bytes, causing getentropy() to fail with EIO, which we were completely ignoring. This caused these tests to only test long sequences of 0x00. We now loop over the provided buffer to fill it 256 bytes at a time. If getentropy() fails for any reason, we fall back to the default method of filling it with one random byte at a time. --- AK/Random.h | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/AK/Random.h b/AK/Random.h index 1fc7c81c038..80b636b30c6 100644 --- a/AK/Random.h +++ b/AK/Random.h @@ -9,10 +9,7 @@ #include #include #include - -#if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID) -# include -#endif +#include #if defined(__unix__) # include @@ -22,10 +19,6 @@ # include #endif -#if defined(AK_OS_WINDOWS) -# include -#endif - namespace AK { inline void fill_with_random([[maybe_unused]] void* buffer, [[maybe_unused]] size_t length) @@ -33,13 +26,35 @@ inline void fill_with_random([[maybe_unused]] void* buffer, [[maybe_unused]] siz #if defined(AK_OS_SERENITY) || defined(AK_OS_ANDROID) arc4random_buf(buffer, length); #elif defined(OSS_FUZZ) -#elif defined(__unix__) or defined(AK_OS_MACOS) - [[maybe_unused]] int rc = getentropy(buffer, length); #else - char* char_buffer = static_cast(buffer); - for (size_t i = 0; i < length; i++) { - char_buffer[i] = rand(); + auto fill_with_random_fallback = [&]() { + char* char_buffer = static_cast(buffer); + for (size_t i = 0; i < length; i++) + char_buffer[i] = rand(); + }; + +# if defined(__unix__) or defined(AK_OS_MACOS) + // The maximum permitted value for the getentropy length argument. + static constexpr size_t getentropy_length_limit = 256; + + auto iterations = length / getentropy_length_limit; + auto remainder = length % getentropy_length_limit; + auto address = reinterpret_cast(buffer); + + for (size_t i = 0; i < iterations; ++i) { + if (getentropy(reinterpret_cast(address), getentropy_length_limit) != 0) { + fill_with_random_fallback(); + return; + } + + address += getentropy_length_limit; } + + if (remainder == 0 || getentropy(reinterpret_cast(address), remainder) == 0) + return; +# endif + + fill_with_random_fallback(); #endif }