diff options
author | Peter Elliott <pelliott@ualberta.ca> | 2020-06-24 14:07:28 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-25 21:05:40 +0200 |
commit | af0b2d1d86761dd7dc89bb605794093968a0a74f (patch) | |
tree | 3c4cc42287c297f59d0229657039a796895a337f | |
parent | 2e8cfe5435f806538fe680235b2e9792ca34b201 (diff) | |
download | serenity-af0b2d1d86761dd7dc89bb605794093968a0a74f.zip |
Kernel: Harvest randomness from various drivers
Random now gets entropy from the following drivers:
- KeyboardDevice
- PATAChannel
- PS2MouseDevice
- E1000NetworkAdapter
- RTL8139NetworkAdapter
Of these devices, PS2MouseDevice and PATAChannel provide the vast
majority of the entropy.
-rw-r--r-- | Kernel/Devices/KeyboardDevice.cpp | 2 | ||||
-rw-r--r-- | Kernel/Devices/KeyboardDevice.h | 2 | ||||
-rw-r--r-- | Kernel/Devices/PATAChannel.cpp | 5 | ||||
-rw-r--r-- | Kernel/Devices/PATAChannel.h | 2 | ||||
-rw-r--r-- | Kernel/Devices/PS2MouseDevice.cpp | 3 | ||||
-rw-r--r-- | Kernel/Devices/PS2MouseDevice.h | 2 | ||||
-rw-r--r-- | Kernel/Net/E1000NetworkAdapter.cpp | 3 | ||||
-rw-r--r-- | Kernel/Net/E1000NetworkAdapter.h | 4 | ||||
-rw-r--r-- | Kernel/Net/RTL8139NetworkAdapter.cpp | 2 | ||||
-rw-r--r-- | Kernel/Net/RTL8139NetworkAdapter.h | 4 | ||||
-rw-r--r-- | Kernel/Random.cpp | 15 | ||||
-rw-r--r-- | Kernel/Random.h | 34 |
12 files changed, 71 insertions, 7 deletions
diff --git a/Kernel/Devices/KeyboardDevice.cpp b/Kernel/Devices/KeyboardDevice.cpp index 01a34c8534..20e26da491 100644 --- a/Kernel/Devices/KeyboardDevice.cpp +++ b/Kernel/Devices/KeyboardDevice.cpp @@ -287,6 +287,8 @@ void KeyboardDevice::handle_irq(const RegisterState&) u8 ch = raw & 0x7f; bool pressed = !(raw & 0x80); + m_entropy_source.add_random_event(raw); + if (raw == 0xe0) { m_has_e0_prefix = true; return; diff --git a/Kernel/Devices/KeyboardDevice.h b/Kernel/Devices/KeyboardDevice.h index acc2297eb7..f35ffd9621 100644 --- a/Kernel/Devices/KeyboardDevice.h +++ b/Kernel/Devices/KeyboardDevice.h @@ -32,6 +32,7 @@ #include <Kernel/Devices/CharacterDevice.h> #include <Kernel/Interrupts/IRQHandler.h> #include <Kernel/KeyCode.h> +#include <Kernel/Random.h> #include <LibKeyboard/CharacterMap.h> namespace Kernel { @@ -82,6 +83,7 @@ private: bool m_caps_lock_on { false }; bool m_num_lock_on { false }; bool m_has_e0_prefix { false }; + EntropySource m_entropy_source; Keyboard::CharacterMap m_character_map = Keyboard::CharacterMap("en"); }; diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Devices/PATAChannel.cpp index 06b88afb16..1fc75745bd 100644 --- a/Kernel/Devices/PATAChannel.cpp +++ b/Kernel/Devices/PATAChannel.cpp @@ -29,9 +29,9 @@ #include <Kernel/Devices/PATAChannel.h> #include <Kernel/Devices/PATADiskDevice.h> #include <Kernel/FileSystem/ProcFS.h> +#include <Kernel/IO.h> #include <Kernel/Process.h> #include <Kernel/VM/MemoryManager.h> -#include <Kernel/IO.h> namespace Kernel { @@ -186,6 +186,9 @@ void PATAChannel::handle_irq(const RegisterState&) // FIXME: We might get random interrupts due to malfunctioning hardware, so we should check that we actually requested something to happen. u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>(); + + m_entropy_source.add_random_event(status); + if (status & ATA_SR_ERR) { print_ide_status(status); m_device_error = m_io_base.offset(ATA_REG_ERROR).in<u8>(); diff --git a/Kernel/Devices/PATAChannel.h b/Kernel/Devices/PATAChannel.h index 09eed4216c..60ed95d6c1 100644 --- a/Kernel/Devices/PATAChannel.h +++ b/Kernel/Devices/PATAChannel.h @@ -44,6 +44,7 @@ #include <Kernel/PCI/Access.h> #include <Kernel/PCI/Device.h> #include <Kernel/PhysicalAddress.h> +#include <Kernel/Random.h> #include <Kernel/VM/PhysicalPage.h> #include <Kernel/WaitQueue.h> @@ -103,6 +104,7 @@ private: RefPtr<PhysicalPage> m_dma_buffer_page; IOAddress m_bus_master_base; Lockable<bool> m_dma_enabled; + EntropySource m_entropy_source; RefPtr<PATADiskDevice> m_master; RefPtr<PATADiskDevice> m_slave; diff --git a/Kernel/Devices/PS2MouseDevice.cpp b/Kernel/Devices/PS2MouseDevice.cpp index e673c02fbd..56852537cd 100644 --- a/Kernel/Devices/PS2MouseDevice.cpp +++ b/Kernel/Devices/PS2MouseDevice.cpp @@ -81,6 +81,7 @@ void PS2MouseDevice::handle_irq(const RegisterState&) if (backdoor->vmmouse_is_absolute()) { IO::in8(I8042_BUFFER); auto packet = backdoor->receive_mouse_packet(); + m_entropy_source.add_random_event(packet); if (packet.has_value()) m_queue.enqueue(packet.value()); return; @@ -99,6 +100,8 @@ void PS2MouseDevice::handle_irq(const RegisterState&) #ifdef PS2MOUSE_DEBUG dbg() << "PS2Mouse: " << m_data[1] << ", " << m_data[2] << " " << ((m_data[0] & 1) ? "Left" : "") << " " << ((m_data[0] & 2) ? "Right" : "") << " (buffered: " << m_queue.size() << ")"; #endif + m_entropy_source.add_random_event(*(u32*)m_data); + parse_data_packet(); }; diff --git a/Kernel/Devices/PS2MouseDevice.h b/Kernel/Devices/PS2MouseDevice.h index 5ed62b52db..cfb2557f85 100644 --- a/Kernel/Devices/PS2MouseDevice.h +++ b/Kernel/Devices/PS2MouseDevice.h @@ -30,6 +30,7 @@ #include <Kernel/Devices/CharacterDevice.h> #include <Kernel/Interrupts/IRQHandler.h> #include <Kernel/MousePacket.h> +#include <Kernel/Random.h> namespace Kernel { @@ -77,6 +78,7 @@ private: u8 m_data[4]; bool m_has_wheel { false }; bool m_has_five_buttons { false }; + EntropySource m_entropy_source; }; } diff --git a/Kernel/Net/E1000NetworkAdapter.cpp b/Kernel/Net/E1000NetworkAdapter.cpp index e8619d6770..3dd74a6cb9 100644 --- a/Kernel/Net/E1000NetworkAdapter.cpp +++ b/Kernel/Net/E1000NetworkAdapter.cpp @@ -204,6 +204,9 @@ void E1000NetworkAdapter::handle_irq(const RegisterState&) out32(REG_INTERRUPT_MASK_CLEAR, 0xffffffff); u32 status = in32(REG_INTERRUPT_CAUSE_READ); + + m_entropy_source.add_random_event(status); + if (status & 4) { u32 flags = in32(REG_CTRL); out32(REG_CTRL, flags | ECTRL_SLU); diff --git a/Kernel/Net/E1000NetworkAdapter.h b/Kernel/Net/E1000NetworkAdapter.h index 96214e9d6d..fd5f864879 100644 --- a/Kernel/Net/E1000NetworkAdapter.h +++ b/Kernel/Net/E1000NetworkAdapter.h @@ -28,11 +28,12 @@ #include <AK/NonnullOwnPtrVector.h> #include <AK/OwnPtr.h> +#include <Kernel/IO.h> #include <Kernel/Interrupts/IRQHandler.h> #include <Kernel/Net/NetworkAdapter.h> #include <Kernel/PCI/Access.h> #include <Kernel/PCI/Device.h> -#include <Kernel/IO.h> +#include <Kernel/Random.h> namespace Kernel { @@ -103,6 +104,7 @@ private: u8 m_interrupt_line { 0 }; bool m_has_eeprom { false }; bool m_use_mmio { false }; + EntropySource m_entropy_source; static const size_t number_of_rx_descriptors = 32; static const size_t number_of_tx_descriptors = 8; diff --git a/Kernel/Net/RTL8139NetworkAdapter.cpp b/Kernel/Net/RTL8139NetworkAdapter.cpp index 4b496fcfd0..82a176e2cc 100644 --- a/Kernel/Net/RTL8139NetworkAdapter.cpp +++ b/Kernel/Net/RTL8139NetworkAdapter.cpp @@ -184,6 +184,8 @@ void RTL8139NetworkAdapter::handle_irq(const RegisterState&) int status = in16(REG_ISR); out16(REG_ISR, status); + m_entropy_source.add_random_event(status); + #ifdef RTL8139_DEBUG klog() << "RTL8139NetworkAdapter::handle_irq status=0x" << String::format("%x", status); #endif diff --git a/Kernel/Net/RTL8139NetworkAdapter.h b/Kernel/Net/RTL8139NetworkAdapter.h index 7db2f361e2..7255f722c9 100644 --- a/Kernel/Net/RTL8139NetworkAdapter.h +++ b/Kernel/Net/RTL8139NetworkAdapter.h @@ -27,10 +27,11 @@ #pragma once #include <AK/OwnPtr.h> +#include <Kernel/IO.h> #include <Kernel/Net/NetworkAdapter.h> #include <Kernel/PCI/Access.h> #include <Kernel/PCI/Device.h> -#include <Kernel/IO.h> +#include <Kernel/Random.h> namespace Kernel { @@ -73,5 +74,6 @@ private: u8 m_tx_next_buffer { 0 }; OwnPtr<Region> m_packet_buffer; bool m_link_up { false }; + EntropySource m_entropy_source; }; } diff --git a/Kernel/Random.cpp b/Kernel/Random.cpp index 0b95698a90..93a84b7227 100644 --- a/Kernel/Random.cpp +++ b/Kernel/Random.cpp @@ -28,6 +28,7 @@ #include <Kernel/Arch/i386/CPU.h> #include <Kernel/Devices/RandomDevice.h> #include <Kernel/Random.h> +#include <Kernel/Time/TimeManagement.h> namespace Kernel { @@ -44,7 +45,7 @@ KernelRng& KernelRng::the() KernelRng::KernelRng() { if (g_cpu_supports_rdrand) { - for (size_t i = 0; i < KernelRng::pool_count * KernelRng::reseed_threshold; ++i) { + for (size_t i = 0; i < resource().pool_count * resource().reseed_threshold; ++i) { u32 value = 0; asm volatile( "1:\n" @@ -52,14 +53,22 @@ KernelRng::KernelRng() "jnc 1b\n" : "=r"(value)); - this->add_random_event(value, i % 32); + this->resource().add_random_event(value, i % 32); } } } +size_t EntropySource::next_source { 0 }; + void get_good_random_bytes(u8* buffer, size_t buffer_size) { - KernelRng::the().get_random_bytes(buffer, buffer_size); + // FIXME: What if interrupts are disabled because we're in an interrupt? + if (are_interrupts_enabled()) { + LOCKER(KernelRng::the().lock()); + KernelRng::the().resource().get_random_bytes(buffer, buffer_size); + } else { + KernelRng::the().resource().get_random_bytes(buffer, buffer_size); + } } void get_fast_random_bytes(u8* buffer, size_t buffer_size) diff --git a/Kernel/Random.h b/Kernel/Random.h index f56e1ccb80..2804731740 100644 --- a/Kernel/Random.h +++ b/Kernel/Random.h @@ -30,6 +30,8 @@ #include <AK/Assertions.h> #include <AK/ByteBuffer.h> #include <AK/Types.h> +#include <Kernel/Arch/i386/CPU.h> +#include <Kernel/Lock.h> #include <Kernel/StdLib.h> #include <LibCrypto/Cipher/AES.h> #include <LibCrypto/Cipher/Cipher.h> @@ -110,7 +112,7 @@ private: HashType m_pools[pool_count]; }; -class KernelRng : public FortunaPRNG<Crypto::Cipher::AESCipher, Crypto::Hash::SHA256, 256> { +class KernelRng : public Lockable<FortunaPRNG<Crypto::Cipher::AESCipher, Crypto::Hash::SHA256, 256>> { AK_MAKE_ETERNAL; public: @@ -120,6 +122,36 @@ private: KernelRng(); }; +class EntropySource { + template<typename T> + struct Event { + u64 timestamp; + size_t source; + T event_data; + }; + +public: + EntropySource() + : m_source(next_source++) + { + } + + template<typename T> + void add_random_event(const T& event_data) + { + // We don't lock this because on the off chance a pool is corrupted, entropy isn't lost. + Event<T> event = { read_tsc(), m_source, event_data }; + KernelRng::the().resource().add_random_event(event, m_pool); + m_pool++; + } + +private: + static size_t next_source; + size_t m_pool { 0 }; + size_t m_source; + Lock m_lock; +}; + // 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. |