Skip to content

Commit 88f835a

Browse files
committed
src/inference/riscv64_no_seed_default.c: add riscv64 KASLR-disabled detection plugin
On non-EFI riscv64, KASLR requires a non-zero seed from the FDT /chosen/kaslr-seed property. When the property is absent (ENOENT), the seed is zero and the kernel loads at KERNEL_LINK_ADDR = 0xffffffff80000000. Bilaterally pin text_base when EFI is absent, the FDT is mounted, and the property is definitively missing.
1 parent 023f2fb commit 88f835a

1 file changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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

Comments
 (0)