diff --git a/Kernel/Arch/i386/CPU.cpp b/Kernel/Arch/i386/CPU.cpp index acb08e19ede6d4..efe2a67ddf62ed 100644 --- a/Kernel/Arch/i386/CPU.cpp +++ b/Kernel/Arch/i386/CPU.cpp @@ -524,6 +524,7 @@ void sse_init() bool g_cpu_supports_nx; bool g_cpu_supports_pae; bool g_cpu_supports_pge; +bool g_cpu_supports_rdrand; bool g_cpu_supports_smep; bool g_cpu_supports_sse; bool g_cpu_supports_tsc; @@ -536,6 +537,7 @@ void detect_cpu_features() g_cpu_supports_pge = (processor_info.edx() & (1 << 13)); g_cpu_supports_sse = (processor_info.edx() & (1 << 25)); g_cpu_supports_tsc = (processor_info.edx() & (1 << 4)); + g_cpu_supports_rdrand = (processor_info.ecx() & (1 << 30)); CPUID extended_processor_info(0x80000001); g_cpu_supports_nx = (extended_processor_info.edx() & (1 << 20)); diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index 482247a2d2635d..96d579cfeb4c55 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -519,6 +519,7 @@ void detect_cpu_features(); extern bool g_cpu_supports_nx; extern bool g_cpu_supports_pae; extern bool g_cpu_supports_pge; +extern bool g_cpu_supports_rdrand; extern bool g_cpu_supports_smep; extern bool g_cpu_supports_sse; extern bool g_cpu_supports_tsc; diff --git a/Kernel/Devices/RandomDevice.cpp b/Kernel/Devices/RandomDevice.cpp index 9df6a2c23ac0d2..19d81225a7c13f 100644 --- a/Kernel/Devices/RandomDevice.cpp +++ b/Kernel/Devices/RandomDevice.cpp @@ -1,5 +1,5 @@ -#include "RandomDevice.h" -#include +#include +#include RandomDevice::RandomDevice() : CharacterDevice(1, 8) @@ -10,22 +10,6 @@ RandomDevice::~RandomDevice() { } -static u32 next = 1; - -#define MY_RAND_MAX 4294967295U -u32 RandomDevice::random_value() -{ - next = next * 1103515245 + 12345; - return next; -} - -#if 0 -static void mysrand(unsigned seed) -{ - next = seed; -} -#endif - bool RandomDevice::can_read(const FileDescription&) const { return true; @@ -33,13 +17,8 @@ bool RandomDevice::can_read(const FileDescription&) const ssize_t RandomDevice::read(FileDescription&, u8* buffer, ssize_t size) { - const int range = 'z' - 'a'; - ssize_t nread = min(size, PAGE_SIZE); - for (ssize_t i = 0; i < nread; ++i) { - u32 r = random_value() % range; - buffer[i] = (u8)('a' + r); - } - return nread; + get_good_random_bytes(buffer, size); + return size; } ssize_t RandomDevice::write(FileDescription&, const u8*, ssize_t size) diff --git a/Kernel/Devices/RandomDevice.h b/Kernel/Devices/RandomDevice.h index a11589d310dc8e..48065d4c62782f 100644 --- a/Kernel/Devices/RandomDevice.h +++ b/Kernel/Devices/RandomDevice.h @@ -8,8 +8,6 @@ class RandomDevice final : public CharacterDevice { RandomDevice(); virtual ~RandomDevice() override; - static u32 random_value(); - private: // ^CharacterDevice virtual ssize_t read(FileDescription&, u8*, ssize_t) override; diff --git a/Kernel/Makefile b/Kernel/Makefile index f6a253e22ca459..e36a87f3db43d3 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -78,6 +78,7 @@ OBJS = \ ProcessTracer.o \ Profiling.o \ RTC.o \ + Random.o \ Scheduler.o \ SharedBuffer.o \ StdLib.o \ diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp index 98cdcb68e9cd68..38e4f1024fae7d 100644 --- a/Kernel/Net/TCPSocket.cpp +++ b/Kernel/Net/TCPSocket.cpp @@ -6,6 +6,7 @@ #include #include #include +#include //#define TCP_SOCKET_DEBUG @@ -358,7 +359,7 @@ int TCPSocket::protocol_allocate_local_port() static const u16 first_ephemeral_port = 32768; static const u16 last_ephemeral_port = 60999; static const u16 ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; - u16 first_scan_port = first_ephemeral_port + RandomDevice::random_value() % ephemeral_port_range_size; + u16 first_scan_port = first_ephemeral_port + get_good_random() % ephemeral_port_range_size; LOCKER(sockets_by_tuple().lock()); for (u16 port = first_scan_port;;) { diff --git a/Kernel/Net/UDPSocket.cpp b/Kernel/Net/UDPSocket.cpp index 8d3890f6ab5f6c..cec270126a9380 100644 --- a/Kernel/Net/UDPSocket.cpp +++ b/Kernel/Net/UDPSocket.cpp @@ -4,6 +4,7 @@ #include #include #include +#include void UDPSocket::for_each(Function callback) { @@ -92,7 +93,7 @@ int UDPSocket::protocol_allocate_local_port() static const u16 first_ephemeral_port = 32768; static const u16 last_ephemeral_port = 60999; static const u16 ephemeral_port_range_size = last_ephemeral_port - first_ephemeral_port; - u16 first_scan_port = first_ephemeral_port + RandomDevice::random_value() % ephemeral_port_range_size; + u16 first_scan_port = first_ephemeral_port + get_good_random() % ephemeral_port_range_size; LOCKER(sockets_by_port().lock()); for (u16 port = first_scan_port;;) { diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index df406e92e1e881..5a4ea76001339b 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -3612,25 +3613,7 @@ int Process::sys$getrandom(void* buffer, size_t buffer_size, unsigned int flags if (!validate_write(buffer, buffer_size)) return -EFAULT; - // We prefer to get whole words of entropy. - // If the length is unaligned, we can work with bytes instead. - // Mask out the bottom two bits for words. - size_t words_len = buffer_size & ~3; - if (words_len) { - uint32_t* words = (uint32_t*)buffer; - for (size_t i = 0; i < words_len / 4; i++) - words[i] = RandomDevice::random_value(); - } - // The remaining non-whole word bytes we can fill in. - size_t bytes_len = buffer_size & 3; - if (bytes_len) { - uint8_t* bytes = (uint8_t*)buffer + words_len; - // Get a whole word of entropy to use. - uint32_t word = RandomDevice::random_value(); - for (size_t i = 0; i < bytes_len; i++) - bytes[i] = ((uint8_t*)&word)[i]; - } - + get_good_random_bytes((u8*)buffer, buffer_size); return 0; } diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp new file mode 100644 index 00000000000000..d517ae5cef38c0 --- /dev/null +++ b/Kernel/Random.cpp @@ -0,0 +1,41 @@ +#include +#include +#include + +static u32 random32() +{ + if (g_cpu_supports_rdrand) { + u32 value = 0; + asm volatile( + "1%=:\n" + "rdrand %0\n" + "jnc 1%=\n" + : "=r"(value)); + return value; + } + // FIXME: This sucks lol + static u32 next = 1; + next = next * 1103515245 + 12345; + return next; +} + +void get_good_random_bytes(u8* buffer, size_t buffer_size) +{ + union { + u8 bytes[4]; + u32 value; + } u; + size_t offset = 4; + for (size_t i = 0; i < buffer_size; ++i) { + if (offset >= 4) { + u.value = random32(); + offset = 0; + } + buffer[i] = u.bytes[offset++]; + } +} + +void get_fast_random_bytes(u8* buffer, size_t buffer_size) +{ + return get_good_random_bytes(buffer, buffer_size); +} diff --git a/Kernel/Random.h b/Kernel/Random.h new file mode 100644 index 00000000000000..9e02335e892ff3 --- /dev/null +++ b/Kernel/Random.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +// NOTE: These API's are primarily about expressing intent/needs in the calling code. +// We don't make any guarantees about actual fastness or goodness yet. + +void get_fast_random_bytes(u8*, size_t); +void get_good_random_bytes(u8*, size_t); + +template +inline T get_fast_random() +{ + T value; + get_fast_random_bytes(reinterpret_cast(&value), sizeof(T)); + return value; +} + +template +inline T get_good_random() +{ + T value; + get_good_random_bytes(reinterpret_cast(&value), sizeof(T)); + return value; +} + diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 24f1fd0ea85ef5..b01d496abee33d 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -307,6 +307,12 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables) kprintf("x86: RDTSC support restricted\n"); } + if (g_cpu_supports_rdrand) { + kprintf("x86: Using RDRAND for good randomness\n"); + } else { + kprintf("x86: No RDRAND support detected. Randomness will be shitty\n"); + } + RTC::initialize(); PIC::initialize(); gdt_init();