Serenity Operating System
at master 176 lines 5.6 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2020, Peter Elliott <pelliott@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Singleton.h> 9#include <Kernel/Arch/Processor.h> 10#if ARCH(X86_64) 11# include <Kernel/Arch/x86_64/Time/HPET.h> 12# include <Kernel/Arch/x86_64/Time/RTC.h> 13#elif ARCH(AARCH64) 14# include <Kernel/Arch/aarch64/ASM_wrapper.h> 15#endif 16#include <Kernel/Devices/RandomDevice.h> 17#include <Kernel/Random.h> 18#include <Kernel/Sections.h> 19#include <Kernel/Time/TimeManagement.h> 20 21namespace Kernel { 22 23static Singleton<KernelRng> s_the; 24static Atomic<u32, AK::MemoryOrder::memory_order_relaxed> s_next_random_value = 1; 25 26KernelRng& KernelRng::the() 27{ 28 return *s_the; 29} 30 31UNMAP_AFTER_INIT KernelRng::KernelRng() 32{ 33#if ARCH(X86_64) 34 if (Processor::current().has_feature(CPUFeature::RDSEED)) { 35 dmesgln("KernelRng: Using RDSEED as entropy source"); 36 37 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 38 add_random_event(Kernel::read_rdseed(), i % 32); 39 } 40 } else if (Processor::current().has_feature(CPUFeature::RDRAND)) { 41 dmesgln("KernelRng: Using RDRAND as entropy source"); 42 43 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 44 add_random_event(Kernel::read_rdrand(), i % 32); 45 } 46 } else if (TimeManagement::the().can_query_precise_time()) { 47 // Add HPET as entropy source if we don't have anything better. 48 dmesgln("KernelRng: Using HPET as entropy source"); 49 50 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 51 u64 hpet_time = HPET::the().read_main_counter_unsafe(); 52 add_random_event(hpet_time, i % 32); 53 } 54 } else { 55 // Fallback to RTC 56 dmesgln("KernelRng: Using RTC as entropy source (bad!)"); 57 auto current_time = static_cast<u64>(RTC::now()); 58 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 59 add_random_event(current_time, i % 32); 60 current_time *= 0x574au; 61 current_time += 0x40b2u; 62 } 63 } 64#elif ARCH(AARCH64) 65 if (Processor::current().has_feature(CPUFeature::RNG)) { 66 dmesgln("KernelRng: Using RNDRRS as entropy source"); 67 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 68 add_random_event(Aarch64::Asm::read_rndrrs(), i % 32); 69 } 70 } else { 71 // Fallback to TimeManagement as entropy 72 dmesgln("KernelRng: Using bad entropy source TimeManagement"); 73 auto current_time = static_cast<u64>(TimeManagement::the().now().to_milliseconds()); 74 for (size_t i = 0; i < pool_count * reseed_threshold; ++i) { 75 add_random_event(current_time, i % 32); 76 current_time *= 0x574au; 77 current_time += 0x40b2u; 78 } 79 } 80#else 81 dmesgln("KernelRng: No entropy source available!"); 82#endif 83} 84 85void KernelRng::wait_for_entropy() 86{ 87 SpinlockLocker lock(get_lock()); 88 if (!is_ready()) { 89 dbgln("Entropy starvation..."); 90 m_seed_queue.wait_forever("KernelRng"sv); 91 } 92} 93 94void KernelRng::wake_if_ready() 95{ 96 VERIFY(get_lock().is_locked()); 97 if (is_ready()) { 98 m_seed_queue.wake_all(); 99 } 100} 101 102size_t EntropySource::next_source { static_cast<size_t>(EntropySource::Static::MaxHardcodedSourceIndex) }; 103 104static void do_get_fast_random_bytes(Bytes buffer) 105{ 106 107 union { 108 u8 bytes[4]; 109 u32 value; 110 } u; 111 size_t offset = 4; 112 for (size_t i = 0; i < buffer.size(); ++i) { 113 if (offset >= 4) { 114 auto current_next = s_next_random_value.load(); 115 for (;;) { 116 auto new_next = current_next * 1103515245 + 12345; 117 if (s_next_random_value.compare_exchange_strong(current_next, new_next)) { 118 u.value = new_next; 119 break; 120 } 121 } 122 offset = 0; 123 } 124 buffer[i] = u.bytes[offset++]; 125 } 126} 127 128bool get_good_random_bytes(Bytes buffer, bool allow_wait, bool fallback_to_fast) 129{ 130 bool result = false; 131 auto& kernel_rng = KernelRng::the(); 132 // FIXME: What if interrupts are disabled because we're in an interrupt? 133 bool can_wait = Processor::are_interrupts_enabled(); 134 if (!can_wait && allow_wait) { 135 // If we can't wait but the caller would be ok with it, then we 136 // need to definitely fallback to *something*, even if it's less 137 // secure... 138 fallback_to_fast = true; 139 } 140 if (can_wait && allow_wait) { 141 for (;;) { 142 { 143 if (kernel_rng.get_random_bytes(buffer)) { 144 result = true; 145 break; 146 } 147 } 148 kernel_rng.wait_for_entropy(); 149 } 150 } else { 151 // We can't wait/block here, or we are not allowed to block/wait 152 if (kernel_rng.get_random_bytes(buffer)) { 153 result = true; 154 } else if (fallback_to_fast) { 155 // If interrupts are disabled 156 do_get_fast_random_bytes(buffer); 157 result = true; 158 } 159 } 160 161 // NOTE: The only case where this function should ever return false and 162 // not actually return random data is if fallback_to_fast == false and 163 // allow_wait == false and interrupts are enabled! 164 VERIFY(result || !fallback_to_fast); 165 return result; 166} 167 168void get_fast_random_bytes(Bytes buffer) 169{ 170 // Try to get good randomness, but don't block if we can't right now 171 // and allow falling back to fast randomness 172 auto result = get_good_random_bytes(buffer, false, true); 173 VERIFY(result); 174} 175 176}