Skip to content

Commit

Permalink
Kernel: Add a more expressive API for getting random bytes
Browse files Browse the repository at this point in the history
We now have these API's in <Kernel/Random.h>:

    - get_fast_random_bytes(u8* buffer, size_t buffer_size)
    - get_good_random_bytes(u8* buffer, size_t buffer_size)
    - get_fast_random<T>()
    - get_good_random<T>()

Internally they both use x86 RDRAND if available, otherwise they fall
back to the same LCG we had in RandomDevice all along.

The main purpose of this patch is to give kernel code a way to better
express its needs for random data.

Randomness is something that will require a lot more work, but this is
hopefully a step in the right direction.
  • Loading branch information
awesomekling committed Jan 3, 2020
1 parent 24cc67d commit 9026598
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 48 deletions.
2 changes: 2 additions & 0 deletions Kernel/Arch/i386/CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
Expand Down
1 change: 1 addition & 0 deletions Kernel/Arch/i386/CPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 4 additions & 25 deletions Kernel/Devices/RandomDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "RandomDevice.h"
#include <AK/StdLibExtras.h>
#include <Kernel/Devices/RandomDevice.h>
#include <Kernel/Random.h>

RandomDevice::RandomDevice()
: CharacterDevice(1, 8)
Expand All @@ -10,36 +10,15 @@ 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;
}

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)
Expand Down
2 changes: 0 additions & 2 deletions Kernel/Devices/RandomDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions Kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ OBJS = \
ProcessTracer.o \
Profiling.o \
RTC.o \
Random.o \
Scheduler.o \
SharedBuffer.o \
StdLib.o \
Expand Down
3 changes: 2 additions & 1 deletion Kernel/Net/TCPSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
#include <Kernel/Process.h>
#include <Kernel/Random.h>

//#define TCP_SOCKET_DEBUG

Expand Down Expand Up @@ -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<u16>() % ephemeral_port_range_size;

LOCKER(sockets_by_tuple().lock());
for (u16 port = first_scan_port;;) {
Expand Down
3 changes: 2 additions & 1 deletion Kernel/Net/UDPSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <Kernel/Net/UDP.h>
#include <Kernel/Net/UDPSocket.h>
#include <Kernel/Process.h>
#include <Kernel/Random.h>

void UDPSocket::for_each(Function<void(UDPSocket&)> callback)
{
Expand Down Expand Up @@ -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<u16>() % ephemeral_port_range_size;

LOCKER(sockets_by_port().lock());
for (u16 port = first_scan_port;;) {
Expand Down
21 changes: 2 additions & 19 deletions Kernel/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <Kernel/ProcessTracer.h>
#include <Kernel/Profiling.h>
#include <Kernel/RTC.h>
#include <Kernel/Random.h>
#include <Kernel/Scheduler.h>
#include <Kernel/SharedBuffer.h>
#include <Kernel/StdLib.h>
Expand Down Expand Up @@ -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;
}

Expand Down
41 changes: 41 additions & 0 deletions Kernel/Random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <Kernel/Arch/i386/CPU.h>
#include <Kernel/Random.h>
#include <Kernel/Devices/RandomDevice.h>

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);
}
26 changes: 26 additions & 0 deletions Kernel/Random.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <AK/Types.h>

// 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<typename T>
inline T get_fast_random()
{
T value;
get_fast_random_bytes(reinterpret_cast<u8*>(&value), sizeof(T));
return value;
}

template<typename T>
inline T get_good_random()
{
T value;
get_good_random_bytes(reinterpret_cast<u8*>(&value), sizeof(T));
return value;
}

6 changes: 6 additions & 0 deletions Kernel/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit 9026598

Please sign in to comment.