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/arch | |
| 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/arch')
| -rw-r--r-- | na/arch/riscv/config.cc | 134 |
1 files changed, 129 insertions, 5 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 } |
