|
| 1 | +// This file is part of KASLD - https://github.com/bcoles/kasld |
| 2 | +// |
| 3 | +// Inference plugin: riscv64 KASLR disabled when FDT kaslr-seed absent |
| 4 | +// (PRE_COLLECTION) |
| 5 | +// |
| 6 | +// On riscv64, arch/riscv/mm/init.c setup_vm() randomises only when the seed |
| 7 | +// is non-zero: |
| 8 | +// |
| 9 | +// kaslr_seed = get_kaslr_seed_dt(dtb_va); |
| 10 | +// if (IS_ENABLED(CONFIG_EFI)) |
| 11 | +// kaslr_seed ^= efi_kaslr_seed; |
| 12 | +// if (!kaslr_seed) |
| 13 | +// return; // no KASLR; kernel loads at KERNEL_LINK_ADDR |
| 14 | +// |
| 15 | +// On a non-EFI system where the FDT has no /chosen/kaslr-seed property |
| 16 | +// (U-Boot not configured to provide entropy, e.g. missing |
| 17 | +// CONFIG_BOARD_RNG_SEED), get_kaslr_seed_dt() returns 0. With CONFIG_EFI |
| 18 | +// not enabled (non-EFI build) there is no efi_kaslr_seed contribution, |
| 19 | +// so kaslr_seed stays 0 and the kernel loads at the compile-time default |
| 20 | +// KERNEL_LINK_ADDR = 0xffffffff80000000. |
| 21 | +// |
| 22 | +// Detection guards (in order): |
| 23 | +// 1. access("/sys/firmware/efi", F_OK) == 0 → EFI present; skip. |
| 24 | +// On EFI systems kaslr_seed = fdt_seed ^ efi_seed; absence of the FDT |
| 25 | +// property alone does not disable KASLR. |
| 26 | +// 2. access("/proc/device-tree", F_OK) != 0 → no FDT mounted; seed |
| 27 | +// state unknown; skip. |
| 28 | +// 3. access("/proc/device-tree/chosen/kaslr-seed", F_OK) == 0 → property |
| 29 | +// present; KASLR may be active; fall back to riscv64_fdt_kaslr_seed. |
| 30 | +// |
| 31 | +// Trigger only on ENOENT (property absent), not on all-zero content. |
| 32 | +// If the kernel zeroes the property after consuming it (seed-wiping, as |
| 33 | +// noted in sysfs_devicetree_initrd.c), all-zero content is ambiguous |
| 34 | +// ("active seed wiped" vs "no seed ever provided") and is unsafe for |
| 35 | +// pinning without real-host confirmation. |
| 36 | +// |
| 37 | +// TODO: once seed-wiping behaviour is verified on a real riscv64 host, an |
| 38 | +// additional trigger can be added for the all-zero case. |
| 39 | +// |
| 40 | +// Phase: PRE_COLLECTION — access() checks need no component results. |
| 41 | +// Applicable: riscv64 only. See riscv64 H8. |
| 42 | +// --- |
| 43 | +// <bcoles@gmail.com> |
| 44 | + |
| 45 | +#define _POSIX_C_SOURCE 200809L |
| 46 | + |
| 47 | +#include "../include/kasld_inference.h" |
| 48 | + |
| 49 | +#include <errno.h> |
| 50 | +#include <stdio.h> |
| 51 | +#include <unistd.h> |
| 52 | + |
| 53 | +static void riscv64_no_seed_default_run(struct kasld_analysis_ctx *ctx) { |
| 54 | +#if (defined(__riscv) || defined(__riscv__)) && __riscv_xlen == 64 |
| 55 | + |
| 56 | + /* On EFI systems the combined seed (fdt ^ efi) can be non-zero even |
| 57 | + * when the FDT property is absent; pinning would be wrong. */ |
| 58 | + if (access("/sys/firmware/efi", F_OK) == 0) |
| 59 | + return; |
| 60 | + |
| 61 | + /* FDT not mounted: seed state unknown. */ |
| 62 | + if (access("/proc/device-tree", F_OK) != 0) |
| 63 | + return; |
| 64 | + |
| 65 | + /* Property present: KASLR may be active; fall back to riscv64_fdt_kaslr_seed. |
| 66 | + */ |
| 67 | + if (access("/proc/device-tree/chosen/kaslr-seed", F_OK) == 0) |
| 68 | + return; |
| 69 | + |
| 70 | + /* access() failed: only pin on ENOENT (property definitively absent). |
| 71 | + * Any other error (EACCES, EIO) leaves seed state unknown. */ |
| 72 | + if (errno != ENOENT) |
| 73 | + return; |
| 74 | + |
| 75 | + /* Property absent (ENOENT): get_kaslr_seed_dt() returned 0; KASLR disabled. |
| 76 | + */ |
| 77 | + |
| 78 | + const unsigned long link_addr = (unsigned long)KERNEL_LINK_ADDR; |
| 79 | + |
| 80 | + /* Safety guard: only pin if KERNEL_LINK_ADDR is within the established |
| 81 | + * window. */ |
| 82 | + if (link_addr < ctx->text_base_min || link_addr > ctx->text_base_max) |
| 83 | + return; |
| 84 | + |
| 85 | + if (verbose && !quiet) |
| 86 | + fprintf(stderr, |
| 87 | + "[layout] text_base pinned by riscv64_no_seed_default:" |
| 88 | + " [%#lx, %#lx] -> %#lx" |
| 89 | + " (non-EFI, FDT kaslr-seed absent -> KASLR disabled)\n", |
| 90 | + ctx->text_base_min, ctx->text_base_max, link_addr); |
| 91 | + |
| 92 | + ctx->text_base_min = link_addr; |
| 93 | + ctx->text_base_max = link_addr; |
| 94 | + |
| 95 | +#else |
| 96 | + (void)ctx; |
| 97 | +#endif /* riscv64 */ |
| 98 | +} |
| 99 | + |
| 100 | +static const struct kasld_inference riscv64_no_seed_default = { |
| 101 | + .name = "riscv64_no_seed_default", |
| 102 | + .phase = KASLD_INFER_PHASE_PRE_COLLECTION, |
| 103 | + .run = riscv64_no_seed_default_run, |
| 104 | +}; |
| 105 | + |
| 106 | +KASLD_REGISTER_INFERENCE(riscv64_no_seed_default); |
0 commit comments