diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-05-03 01:56:18 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-05-03 01:56:18 +0800 |
| commit | 511da6d35e778aa709571fb48772212567377f0c (patch) | |
| tree | a11545e0b23bb2a25798928576dec00723a43b54 /na | |
| parent | 2b237b24c4db5513f8046e15d24501257e7feeaa (diff) | |
| download | lume-511da6d35e778aa709571fb48772212567377f0c.tar.gz lume-511da6d35e778aa709571fb48772212567377f0c.tar.xz | |
feat: enhance KASLR support with early seed metadata and validation checks
Co-authored-by: Copilot <copilot@github.com>
Diffstat (limited to 'na')
| -rw-r--r-- | na/arch/riscv/config.cc | 134 | ||||
| -rw-r--r-- | na/include/lume/random.h | 12 | ||||
| -rw-r--r-- | na/lib/random.cc | 38 |
3 files changed, 178 insertions, 6 deletions
diff --git a/na/arch/riscv/config.cc b/na/arch/riscv/config.cc index 9b4cc6e..421817d 100644 --- a/na/arch/riscv/config.cc +++ b/na/arch/riscv/config.cc @@ -22,8 +22,14 @@ */ #include <arch/config.h> -#include <lume/random.h> +#include <lume/fdt.h> +#include <lume/frame.h> +#include <lume/config.h> +#include <lume/klog.h> #include <lume/kprintf.h> +#include <lume/random.h> + +extern "C" char _stext[], _kernel_end[]; namespace arch { @@ -31,6 +37,118 @@ namespace arch { uint64 g_direct_map_base = kDirectMapBaseDefault; uint64 g_vmemmap_base = kVmemmapBaseDefault; +struct VaRange { + const char* name; + uint64 start; + uint64 end; // exclusive +}; + +static inline uint64 align_down_page(uint64 v) +{ + return v & ~(kPageSize - 1); +} + +static inline uint64 align_up_page(uint64 v) +{ + return (v + kPageSize - 1) & ~(kPageSize - 1); +} + +static uint64 checked_add_u64(uint64 a, uint64 b, const char* detail) +{ + if (a > (~0ULL - b)) { + kernel_panic("kaslr: address overflow", detail); + } + return a + b; +} + +/* SV39 canonical VA check: bits [63:39] must equal sign bit 38. */ +static bool is_sv39_canonical(uint64 va) +{ + uint64 sign = (va >> 38) & 1ULL; + uint64 upper = va >> 39; + return sign ? (upper == ((1ULL << 25) - 1ULL)) : (upper == 0); +} + +static bool is_sv39_kernel_half(uint64 va) +{ + return is_sv39_canonical(va) && (((va >> 38) & 1ULL) == 1ULL); +} + +static bool ranges_overlap(const VaRange& a, const VaRange& b) +{ + return (a.start < b.end) && (b.start < a.end); +} + +static void kaslr_self_check(uint64 slot) +{ + uint64 mem_base = 0; + uint64 mem_size = 0; + fdt_early_get_mem_info(&mem_base, &mem_size); + if (mem_size == 0) { + kernel_panic("kaslr: invalid memory size from FDT"); + } + + /* Direct-map covers the discovered physical memory window. */ + VaRange direct_map { + "direct-map", + checked_add_u64(g_direct_map_base, mem_base, "direct_map start"), + checked_add_u64(checked_add_u64(g_direct_map_base, mem_base, + "direct_map start"), + mem_size, "direct_map end"), + }; + + /* Vmemmap covers the Frame descriptor array span. */ + uint64 num_frames = mem_size / kPageSize; + uint64 frame_bytes = num_frames * sizeof(Frame); + uint64 frame_span = align_up_page(frame_bytes); + VaRange vmemmap { + "vmemmap", + g_vmemmap_base, + checked_add_u64(g_vmemmap_base, frame_span, "vmemmap end"), + }; + + /* Kernel image window is linked at fixed higher-half addresses. */ + VaRange kernel_img { + "kernel-image", + align_down_page(reinterpret_cast<uint64>(_stext)), + align_up_page(reinterpret_cast<uint64>(_kernel_end)), + }; + + auto check_kernel_half = [](const VaRange& r) { + if (r.start >= r.end) { + kernel_panic("kaslr: invalid VA range", r.name); + } + if (!is_sv39_kernel_half(r.start) || !is_sv39_kernel_half(r.end - 1)) { + kernel_panic("kaslr: non-canonical kernel VA range", r.name); + } + }; + + check_kernel_half(direct_map); + check_kernel_half(vmemmap); + check_kernel_half(kernel_img); + + if (ranges_overlap(direct_map, kernel_img)) { + kernel_panic("kaslr: direct-map overlaps kernel image"); + } + if (ranges_overlap(vmemmap, kernel_img)) { + kernel_panic("kaslr: vmemmap overlaps kernel image"); + } + if (ranges_overlap(direct_map, vmemmap)) { + kernel_panic("kaslr: direct-map overlaps vmemmap"); + } + + kprintf("[boot][kaslr] seed=0x%llx source=%s slot=%llu slide_gb=%llu\n", + random_early_seed_value(), + random_seed_source_name(random_early_seed_source()), + slot, slot); + kprintf("[boot][kaslr] direct-map=[0x%llx,0x%llx)\n", + direct_map.start, direct_map.end); + kprintf("[boot][kaslr] vmemmap=[0x%llx,0x%llx)\n", + vmemmap.start, vmemmap.end); + kprintf("[boot][kaslr] kernel-image=[0x%llx,0x%llx)\n", + kernel_img.start, kernel_img.end); +} + void kaslr_init() { #ifdef CONFIG_KASLR @@ -58,11 +176,17 @@ void kaslr_init() g_direct_map_base = kDirectMapBaseDefault + slide; g_vmemmap_base = kVmemmapBaseDefault + slide; - kprintf("[kaslr] slide = %llu GB (slot %llu/64)\n", slide >> 30, slot); - kprintf("[kaslr] direct_map_base = 0x%llx\n", g_direct_map_base); - kprintf("[kaslr] vmemmap_base = 0x%llx\n", g_vmemmap_base); + kaslr_self_check(slot); #else - kprintf("[kaslr] CONFIG_KASLR disabled, using fixed layout\n"); + g_direct_map_base = kDirectMapBaseDefault; + g_vmemmap_base = kVmemmapBaseDefault; + kprintf("[boot][kaslr] disabled source=%s seed=0x%llx slot=0 slide_gb=0\n", + random_seed_source_name(random_early_seed_source()), + random_early_seed_value()); + kprintf("[boot][kaslr] direct-map=[0x%llx,0x%llx)\n", + g_direct_map_base, g_direct_map_base); + kprintf("[boot][kaslr] vmemmap=[0x%llx,0x%llx)\n", + g_vmemmap_base, g_vmemmap_base); #endif } diff --git a/na/include/lume/random.h b/na/include/lume/random.h index 0705b1b..740b060 100644 --- a/na/include/lume/random.h +++ b/na/include/lume/random.h @@ -5,6 +5,13 @@ #include <lume/types.h> +enum class RandomSeedSource : uint8 { + Unknown = 0, + FdtProvided, + HwRandom, + CycleFallback, +}; + /* * MI: Machine-Independent Random Number Generator API * @@ -24,3 +31,8 @@ void get_random_bytes(void* buf, size_t len); /* Inject entropy (for future interrupt/device mixing) */ void add_device_randomness(const void* buf, size_t len); + +/* Early-seed metadata (for boot diagnostics/KASLR logs). */ +RandomSeedSource random_early_seed_source(); +uint64 random_early_seed_value(); +const char* random_seed_source_name(RandomSeedSource source); diff --git a/na/lib/random.cc b/na/lib/random.cc index c607e5f..428c75c 100644 --- a/na/lib/random.cc +++ b/na/lib/random.cc @@ -15,6 +15,8 @@ static uint64 g_state[4]; static bool g_initialized = false; +static uint64 g_init_seed = 0; +static RandomSeedSource g_seed_source = RandomSeedSource::Unknown; static inline uint64 rotl(const uint64 x, int k) { return (x << k) | (x >> (64 - k)); @@ -32,15 +34,21 @@ void random_early_init(uint64 seed) { if (g_initialized) return; + RandomSeedSource source = RandomSeedSource::Unknown; + /* If seed is 0 (not provided by bootloader), try hardware */ if (seed == 0) { uint64 hw_val; if (arch::get_hw_random(hw_val)) { seed = hw_val; + source = RandomSeedSource::HwRandom; } else { /* Fallback: use boot cycles mixed with a constant */ seed = arch::get_cycles() ^ 0xdeadbeefbadc0ffeULL; + source = RandomSeedSource::CycleFallback; } + } else { + source = RandomSeedSource::FdtProvided; } uint64 sm_state = seed; @@ -49,8 +57,11 @@ void random_early_init(uint64 seed) g_state[2] = splitmix64(sm_state); g_state[3] = splitmix64(sm_state); + g_init_seed = seed; + g_seed_source = source; g_initialized = true; - kprintf("[random] early PRNG initialized, seed=0x%llx\n", seed); + kprintf("[random] early PRNG initialized, seed=0x%llx, source=%s\n", + seed, random_seed_source_name(source)); } uint64 get_random_u64() @@ -114,3 +125,28 @@ void add_device_randomness(const void* buf, size_t len) g_state[0] ^= mix; g_state[1] ^= arch::get_cycles(); } + +RandomSeedSource random_early_seed_source() +{ + return g_seed_source; +} + +uint64 random_early_seed_value() +{ + return g_init_seed; +} + +const char* random_seed_source_name(RandomSeedSource source) +{ + switch (source) { + case RandomSeedSource::FdtProvided: + return "fdt"; + case RandomSeedSource::HwRandom: + return "hw"; + case RandomSeedSource::CycleFallback: + return "cycle"; + case RandomSeedSource::Unknown: + default: + return "unknown"; + } +} |
