mirror of
https://github.com/RGBCube/serenity
synced 2025-05-22 19:35:06 +00:00
Kernel: Make Random work on CPUs without rdrand
- If rdseed is not available, fallback to rdrand. - If rdrand is not available, block for entropy, or use insecure prng depending on if user wants fast or good random.
This commit is contained in:
parent
1eb338ab71
commit
e1aef94a40
4 changed files with 71 additions and 12 deletions
|
@ -44,24 +44,48 @@ KernelRng& KernelRng::the()
|
||||||
|
|
||||||
KernelRng::KernelRng()
|
KernelRng::KernelRng()
|
||||||
{
|
{
|
||||||
if (g_cpu_supports_rdseed) {
|
if (g_cpu_supports_rdseed || g_cpu_supports_rdrand) {
|
||||||
for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) {
|
for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) {
|
||||||
u32 value = 0;
|
u32 value = 0;
|
||||||
asm volatile(
|
if (g_cpu_supports_rdseed) {
|
||||||
"1:\n"
|
asm volatile(
|
||||||
"rdseed %0\n"
|
"1:\n"
|
||||||
"jnc 1b\n"
|
"rdseed %0\n"
|
||||||
: "=r"(value));
|
"jnc 1b\n"
|
||||||
|
: "=r"(value));
|
||||||
|
} else {
|
||||||
|
asm volatile(
|
||||||
|
"1:\n"
|
||||||
|
"rdrand %0\n"
|
||||||
|
"jnc 1b\n"
|
||||||
|
: "=r"(value));
|
||||||
|
}
|
||||||
|
|
||||||
this->resource().add_random_event(value, i % 32);
|
this->resource().add_random_event(value, i % 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KernelRng::wait_for_entropy()
|
||||||
|
{
|
||||||
|
if (!resource().is_ready()) {
|
||||||
|
Thread::current->wait_on(m_seed_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelRng::wake_if_ready()
|
||||||
|
{
|
||||||
|
if (resource().is_ready()) {
|
||||||
|
m_seed_queue.wake_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t EntropySource::next_source { 0 };
|
size_t EntropySource::next_source { 0 };
|
||||||
|
|
||||||
void get_good_random_bytes(u8* buffer, size_t buffer_size)
|
void get_good_random_bytes(u8* buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
|
KernelRng::the().wait_for_entropy();
|
||||||
|
|
||||||
// FIXME: What if interrupts are disabled because we're in an interrupt?
|
// FIXME: What if interrupts are disabled because we're in an interrupt?
|
||||||
if (are_interrupts_enabled()) {
|
if (are_interrupts_enabled()) {
|
||||||
LOCKER(KernelRng::the().lock());
|
LOCKER(KernelRng::the().lock());
|
||||||
|
@ -73,7 +97,25 @@ void get_good_random_bytes(u8* buffer, size_t buffer_size)
|
||||||
|
|
||||||
void get_fast_random_bytes(u8* buffer, size_t buffer_size)
|
void get_fast_random_bytes(u8* buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
return get_good_random_bytes(buffer, buffer_size);
|
if (KernelRng::the().resource().is_ready()) {
|
||||||
|
return get_good_random_bytes(buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 next = 1;
|
||||||
|
|
||||||
|
union {
|
||||||
|
u8 bytes[4];
|
||||||
|
u32 value;
|
||||||
|
} u;
|
||||||
|
size_t offset = 4;
|
||||||
|
for (size_t i = 0; i < buffer_size; ++i) {
|
||||||
|
if (offset >= 4) {
|
||||||
|
next = next * 1103515245 + 12345;
|
||||||
|
u.value = next;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
buffer[i] = u.bytes[offset++];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
this->reseed();
|
this->reseed();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(m_reseed_number > 0);
|
ASSERT(is_seeded());
|
||||||
|
|
||||||
// FIXME: More than 2^20 bytes cannot be generated without refreshing the key.
|
// FIXME: More than 2^20 bytes cannot be generated without refreshing the key.
|
||||||
ASSERT(n < (1 << 20));
|
ASSERT(n < (1 << 20));
|
||||||
|
@ -86,6 +86,16 @@ public:
|
||||||
m_pools[pool].update(reinterpret_cast<const u8*>(&event_data), sizeof(T));
|
m_pools[pool].update(reinterpret_cast<const u8*>(&event_data), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_seeded() const
|
||||||
|
{
|
||||||
|
return m_reseed_number > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ready() const
|
||||||
|
{
|
||||||
|
return is_seeded() || m_p0_len >= reseed_threshold;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reseed()
|
void reseed()
|
||||||
{
|
{
|
||||||
|
@ -118,8 +128,14 @@ class KernelRng : public Lockable<FortunaPRNG<Crypto::Cipher::AESCipher, Crypto:
|
||||||
public:
|
public:
|
||||||
static KernelRng& the();
|
static KernelRng& the();
|
||||||
|
|
||||||
|
void wait_for_entropy();
|
||||||
|
|
||||||
|
void wake_if_ready();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelRng();
|
KernelRng();
|
||||||
|
|
||||||
|
WaitQueue m_seed_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntropySource {
|
class EntropySource {
|
||||||
|
@ -143,6 +159,7 @@ public:
|
||||||
Event<T> event = { read_tsc(), m_source, event_data };
|
Event<T> event = { read_tsc(), m_source, event_data };
|
||||||
KernelRng::the().resource().add_random_event(event, m_pool);
|
KernelRng::the().resource().add_random_event(event, m_pool);
|
||||||
m_pool++;
|
m_pool++;
|
||||||
|
KernelRng::the().wake_if_ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -153,7 +170,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: These API's are primarily about expressing intent/needs in the calling code.
|
// 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.
|
// The only difference is that get_fast_random is guaranteed not to block.
|
||||||
|
|
||||||
void get_fast_random_bytes(u8*, size_t);
|
void get_fast_random_bytes(u8*, size_t);
|
||||||
void get_good_random_bytes(u8*, size_t);
|
void get_good_random_bytes(u8*, size_t);
|
||||||
|
|
|
@ -79,7 +79,7 @@ PageDirectory::PageDirectory(Process& process, const RangeAllocator* parent_rang
|
||||||
if (parent_range_allocator) {
|
if (parent_range_allocator) {
|
||||||
m_range_allocator.initialize_from_parent(*parent_range_allocator);
|
m_range_allocator.initialize_from_parent(*parent_range_allocator);
|
||||||
} else {
|
} else {
|
||||||
size_t random_offset = (get_good_random<u32>() % 32 * MB) & PAGE_MASK;
|
size_t random_offset = (get_fast_random<u32>() % 32 * MB) & PAGE_MASK;
|
||||||
u32 base = userspace_range_base + random_offset;
|
u32 base = userspace_range_base + random_offset;
|
||||||
m_range_allocator.initialize_with_range(VirtualAddress(base), userspace_range_ceiling - base);
|
m_range_allocator.initialize_with_range(VirtualAddress(base), userspace_range_ceiling - base);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ extern "C" [[noreturn]] void init()
|
||||||
|
|
||||||
klog() << "Starting SerenityOS...";
|
klog() << "Starting SerenityOS...";
|
||||||
|
|
||||||
__stack_chk_guard = get_good_random<u32>();
|
__stack_chk_guard = get_fast_random<u32>();
|
||||||
|
|
||||||
TimeManagement::initialize();
|
TimeManagement::initialize();
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ extern "C" [[noreturn]] void init()
|
||||||
extern "C" [[noreturn]] void init_ap(u32 cpu)
|
extern "C" [[noreturn]] void init_ap(u32 cpu)
|
||||||
{
|
{
|
||||||
APIC::the().enable(cpu);
|
APIC::the().enable(cpu);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
Scheduler::idle_loop();
|
Scheduler::idle_loop();
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue