Skip to content

Commit 1db0485

Browse files
committed
src: Update docs and code comments
1 parent 84618d2 commit 1db0485

100 files changed

Lines changed: 317 additions & 233 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ All return `1` on emit, `0` on rejection (stderr warning is written).
648648
649649
| Symbol | Values |
650650
|---|---|
651-
| `enum kasld_addr_type` | `KASLD_TYPE_PHYS`, `KASLD_TYPE_VIRT`, `KASLD_TYPE_DEFAULT_VIRT` |
651+
| `enum kasld_addr_type` | `KASLD_TYPE_UNKNOWN`, `KASLD_TYPE_PHYS`, `KASLD_TYPE_VIRT` |
652652
| `enum kasld_region` | `REGION_KERNEL_TEXT`, `REGION_RAM`, `REGION_INITRD`, `REGION_PCI_MMIO`, … (see [kasld/api.h](src/include/kasld/api.h) for the full list) |
653653
| `enum kasld_confidence` | `CONF_PARSED` > `CONF_DERIVED` > `CONF_INFERRED` > `CONF_HEURISTIC` > `CONF_TIMING` > `CONF_BRUTE` |
654654

docs/architecture.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ identical path. Only the front-end component differs.
5555
Freeing unused kernel memory: 1476K (ffffffff81f41000 - ffffffff820b2000)
5656
```
5757

58-
**2. The component** (`dmesg_free_reserved_area`, shown minimally in
58+
**2. The component** (`dmesg_free_reserved_area`; the same leak is illustrated by
59+
the minimal component in
5960
[CONTRIBUTING → Minimal component](../CONTRIBUTING.md#minimal-component)) finds
6061
the line, parses the start address, recognises it as an address inside the kernel
6162
image, and prints one tagged line to stdout:
@@ -191,7 +192,7 @@ loop.
191192
- **Observations** — the collected results plus scalar system facts (kernel
192193
image size, MemTotal, physical-address bits, …), gathered into an evidence
193194
set.
194-
- **Rules** (`../src/rules/*.c`) — ~60 pure functions that read the evidence and
195+
- **Rules** (`../src/rules/*.c`) — roughly 90 pure functions that read the evidence and
195196
the current estimates and emit *constraints* (`>=`, `<=`, `=`, alignment,
196197
membership, exclusion) or *verdicts* (invalidate a result) on the quantities.
197198
A rule does no I/O and has no side effects, so soundness is provable in
@@ -483,7 +484,7 @@ Key rules for cross-region derivation:
483484
same-`origin` pairing is the tightest signal: it identifies the same kernel
484485
object across both address spaces.
485486
- **`randomize_memory_page_offset`** (x86_64 only) — derives
486-
`virt_page_offset_base` (the randomized direct-map start under
487+
`virt_page_offset` (the randomized direct-map start under
487488
`CONFIG_RANDOMIZE_MEMORY`) from a `VIRT/REGION_DIRECTMAP` leak and a
488489
`PHYS/REGION_RAM` base record, with a 1 GiB alignment check.
489490
- **`directmap_page_offset_bounds`** — bounds `PAGE_OFFSET` from a
@@ -550,7 +551,7 @@ Because the relation is relative, it holds regardless of where the region sits
550551
absolutely — which matters, as the region moves with KASLR and so has no fixed
551552
band to test against. The rule consumes only `REGION_MODULE` (addresses whose
552553
source knows structurally that they belong to a loaded module), never
553-
`REGION_MODULE_REGION` (the band itself, or an address classified as module by
554+
`REGION_MODULE_BAND` (the band itself, or an address classified as module by
554555
falling inside it): on this architecture the validation band spans most of the
555556
kernel address space, so a range-classified address carries no information about
556557
which region it belongs to.

docs/bypass-techniques.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ The following table catalogues known side-channel KASLR attacks.
197197

198198
| Attack | Year | Status | References |
199199
|---|---|---|---|
200-
| KernelSnitch | 2025 | **Implemented (experimental)**: [kernelsnitch.c](../src/components/kernelsnitch.c)<br>Futex hash-table timing leaks `mm_struct` directmap address (not `_stext`). x86_64, unprivileged. Requires `--experimental` (~1–30 min runtime). Mitigated by `CONFIG_FUTEX_PRIVATE_HASH` (mainline ~v6.14+) which removes `mm_struct` from the private futex hash key. | [KernelSnitch: Side-Channel Attacks on Kernel Data Structures](https://lukasmaar.github.io/papers/ndss25-kernelsnitch.pdf) (Maar et al., 2025) — [NDSS 2025](https://www.ndss-symposium.org/ndss-paper/kernelsnitch-side-channel-attacks-on-kernel-data-structures/)<br>[lukasmaar/kernelsnitch](https://github.com/lukasmaar/kernelsnitch) |
200+
| KernelSnitch | 2025 | **Implemented (experimental)**: [kernelsnitch.c](../src/components/kernelsnitch.c)<br>Futex hash-table timing leaks `mm_struct` directmap address (not `_stext`). x86_64, unprivileged. Requires `--experimental` (~1–30 min runtime). Nominally targeted by `CONFIG_FUTEX_PRIVATE_HASH` (v6.14+), but the unprivileged opt-out prctl `PR_FUTEX_HASH_SET_SLOTS=0` pins the process back onto the global `mm_struct`-keyed hash and defeats it, so the leak remains live; upstream status unfixed. | [KernelSnitch: Side-Channel Attacks on Kernel Data Structures](https://lukasmaar.github.io/papers/ndss25-kernelsnitch.pdf) (Maar et al., 2025) — [NDSS 2025](https://www.ndss-symposium.org/ndss-paper/kernelsnitch-side-channel-attacks-on-kernel-data-structures/)<br>[lukasmaar/kernelsnitch](https://github.com/lukasmaar/kernelsnitch) |
201201
| GhostWrite (CVE-2024-44067) | 2024 | T-Head XuanTie C910/C920 RISC-V only (2 CPU models); kernel ≥6.14 disables vector extension as mitigation. | [GhostWrite](https://www.ghostwriteattack.com/)<br>[RISCover: Differential CPU Fuzz Testing](https://ghostwriteattack.com/riscover_ccs25.pdf) (Thomas et al., 2025)<br>[cispa/GhostWrite](https://github.com/cispa/GhostWrite), [cispa/RISCover](https://github.com/cispa/RISCover) |
202202
| SLAM | 2024 | Requires Intel LAM / AMD UAI (no mainstream kernel support yet); Spectre-based, needs specific gadgets. | [Leaky Address Masking: Exploiting Unmasked Spectre Gadgets with Noncanonical Address Translation](https://download.vusec.net/papers/slam_sp24.pdf) (Hertogh et al., 2024)<br>[vusec.net/projects/slam](https://www.vusec.net/projects/slam/), [vusec/slam](https://github.com/vusec/slam) |
203203
| SLUBStick (CVE-2024-26808) | 2024 | Achieves arbitrary kernel read/write (enabling KASLR bypass) via allocator timing side-channel, but requires a pre-existing heap vulnerability (UAF, heap overflow). Not a standalone KASLR bypass. | [SLUBStick: Arbitrary Memory Writes through Practical Software Cross-Cache Attacks within the Linux Kernel](https://www.usenix.org/system/files/usenixsecurity24-maar-slubstick.pdf) (Maar et al., 2024) — [USENIX Security 2024](https://www.usenix.org/conference/usenixsecurity24/presentation/maar-slubstick) |
@@ -313,7 +313,7 @@ The following KASLD components exploit syscall and interface leaks:
313313
* [perf_event_open.c](../src/components/perf_event_open.c) — samples kernel instruction pointer addresses via `perf_event_open()` (requires `kernel.perf_event_paranoid < 2`)
314314
* [mincore.c](../src/components/mincore.c)`mincore()` heap page disclosure via uninitialized memory (CVE-2017-16994; patched in v4.15)
315315
* [bcm_msg_head_struct.c](../src/components/bcm_msg_head_struct.c) — CAN BCM `bcm_msg_head` struct uninitialized 4-byte padding hole leaks kernel stack pointer via `recvmsg()` (CVE-2021-34693; patched in v5.12)
316-
* [pppd_kallsyms.c](../src/components/pppd_kallsyms.c) — set-uid-root `pppd` opens `/proc/kallsyms` as root, bypassing the `kptr_restrict` open-time check in pre-v4.8 kernels
316+
* [pppd_kallsyms.c](../src/components/pppd_kallsyms.c) — set-uid-root `pppd` opens and reads `/proc/kallsyms` as root: pre-v4.8 the `kptr_restrict` `%pK` check ran at `read()` time, which `pppd` performs with root credentials, so the symbols are unrestricted; v4.8 moved the check to `open()`
317317
* [qemu_tcg_iret.c](../src/components/qemu_tcg_iret.c) — QEMU TCG `iret` emulation performs the frame read as ring 0, so a ring-3 guest reads an exception handler's return address off the guest kernel's exception stack — a kernel `.text` pointer (patched in QEMU 9.1; not a kernel bug)
318318

319319
## ioctl leaks

docs/footprint.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ cluster**, not any single primitive:
4747
- device and driver `ioctl`s (GPU, sound, filesystem, and others);
4848
- tight `rdtsc` / `rdtscp` timing loops in the side-channel components
4949
(`databounce`, `echoload`, `entrybleed`, `mincore`, `prefetch`,
50-
`zombieload` — compiled `-O0` to preserve the timing).
50+
`prefetch_directmap`, `zombieload` — compiled `-O0` to preserve the timing).
5151

5252
Any one of these is unremarkable; **all of them from one process subtree in one
5353
burst** is the signal. The detection strength comes from co-occurrence and

docs/kaslr.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ header — the decompression buffer requirement, which is larger than the
137137
final loaded kernel size. On RISC-V (`arch/riscv/mm/init.c`), it is
138138
`_end − _start` — the actual in-memory kernel size with no overhead.
139139
On x86, `MODULES_VADDR` is defined as `__START_KERNEL_map +
140-
KERNEL_IMAGE_SIZE` with no gap, so the ceiling is hard.
140+
KERNEL_IMAGE_SIZE` with no gap, so the ceiling is hard. (KASLD's `Search
141+
space` readout counts a closed range and so reports one more slot than this
142+
column — e.g. `505` on x86_64 where the table shows `504`.)
141143

142144
³ The arm64 row is the `VA_BITS_MIN = 48` case (4K/16K 4-level, plus 52-bit LVA)
143145
— the common one. Sub-48 configs place the image higher and randomize over a
@@ -167,7 +169,7 @@ governs only the high bits of the displacement.
167169
| arm64 | ~1073M | ≈ 50 MiB | ~1073M | <0.01% |
168170

169171
On x86 and RISC-V, where total entropy is ~9 bits (~500 slots), a 3–8%
170-
reduction is material. On s390 (~17 bits) and arm64 (~25 bits) the
172+
reduction is material. On s390 (~17 bits) and arm64 (~30 bits) the
171173
effect is negligible.
172174

173175
### KASLR runtime states
@@ -318,7 +320,7 @@ modules are either at a fixed address or a constant offset from `PAGE_OFFSET`.
318320
A single leak from any section is sufficient to derive the others. On
319321
decoupled architectures like x86_64, each section is randomized independently
320322
— a physical address reveals nothing about the virtual text base, and the
321-
direct map base (`virt_page_offset_base`) is randomized separately.
323+
direct map base (`virt_page_offset`) is randomized separately.
322324

323325
RISC-V64 is notable: the module region is anchored to the kernel image
324326
(`MODULES_VADDR = PFN_ALIGN(&_end) - SZ_2G`, `MODULES_END = PFN_ALIGN(&_start)`),

docs/reproducibility.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -839,18 +839,18 @@ make test-fixtures # assert the resolved window contains the truth, per captu
839839
it runs `extra/validate-bundle` over every captured kernel that carries ground
840840
truth and asserts `truth ∈ [min, max]`, catching the "window excludes the real
841841
base" class of bug without a VM. Captures with no recorded truth report `N/A`
842-
rather than pass. The corpus spans 10 architecture families (Alpine, Debian,
843-
Ubuntu/Raspbian) and kernels from 4.19 to 7.0:
842+
rather than pass. The corpus spans 13 architecture families (Alpine, Debian,
843+
Ubuntu/Raspbian) and kernels from 4.14 to 7.0:
844844

845845
| family | example kernels |
846846
|--------|-----------------|
847847
| x86_64, i686 | 5.15 – 7.0 (Alpine, Debian, Ubuntu) |
848-
| aarch64, armv7 | 5.10 – 7.0 |
849-
| ppc64, ppc32 | 6.16.19 |
850-
| riscv64 | 6.6 – 6.18 |
848+
| aarch64, armv7 | 4.14 – 7.0 |
849+
| ppc64, ppc32 | 5.157.0 |
850+
| riscv64, riscv32 | 5.10 – 6.18 |
851851
| s390x | 5.15 – 6.19 |
852852
| loongarch64 | 6.18 |
853-
| mips32 | 4.19 – 5.10 |
853+
| mips32, mips32el, mips64el | 4.19 – 6.15 |
854854

855855
## Scope
856856

docs/testing.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ KASLD_NATIVE=1 tests/replay tests/fixtures/x86_64/* tests/fixtures/x86_32/*
3030

3131
```sh
3232
make check # runs `make test` then prints "OK: host test suite passed."
33-
make test # build + run all ten test drivers, then the lint guards
33+
make test # build + run all test drivers (~30), then the lint guards
3434
make lint # just the static guards (no test-binary build)
3535
```
3636

@@ -40,6 +40,9 @@ layer) and fuzz harnesses (layer 6 below) live in `build/tests/` and
4040
`build/<arch>/`, so neither is reachable by `make install` (which copies
4141
only the orchestrator binary and the `components/` subdirectory).
4242

43+
The table below is a representative subset; the authoritative list of drivers
44+
that `make test` builds and runs is `TEST_ALL_BINS` in the Makefile.
45+
4346
| Driver | Covers | Links |
4447
|--------|--------|-------|
4548
| `test_estimate` | lattice meet, bottom test, the greedy priority resolver | `estimate.c` + `quantities.c` |

docs/usage.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,19 @@ The Layout table carries one row per quantity and basis:
139139
| `Search space` | how many placements remain, against the set the row narrows — a `guaranteed` row against the window the kernel randomized over, a `likely` row against the `guaranteed` count above it. Reported whether or not evidence narrowed it, so a baseline run states the size of the problem; the denominator is dropped when nothing narrowed, leaving the bare total. `-` means no window is modelled for the quantity, which is the only thing that withholds the figure |
140140
| `Align` | the grid the candidates sit on, which is what reconciles the count with the range |
141141

142+
The `likely` basis is deliberately conservative — "may be wrong" is a worst-case
143+
caveat, not a coin toss. KASLD is build-agnostic: it never trusts a version string
144+
or fingerprint to pin a base, so a signal that *would* fix the base on a specific
145+
build — a leaked symbol pointer read as the base (e.g. `perf_event_open`), a
146+
matched compile-time default — is still held below the sound floor to `likely`,
147+
because the engine cannot assume it is looking at that build. Against a **known
148+
target** (known hardware, known kernel and configuration) those *deterministic*
149+
likely results are in practice effectively certain; the genuinely probabilistic
150+
part is the hardware side channels (`prefetch`, `entrybleed`, …), whose success
151+
varies from run to run. So a `likely` row is a floor on confidence, read together
152+
with the source that produced it: a parsed leak is near-certain on a known target;
153+
a timing oracle is the part that can miss.
154+
142155
Every quantity the architecture randomizes gets a row whether or not the engine
143156
bounded it, so the set of rows is a property of the machine rather than of the
144157
run — rows do not appear and vanish between boots. A row the engine never

extra/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ target, or an architecture the analysis host can only emulate.
8484

8585
```sh
8686
# On the target: capture (add --kallsyms to record ground truth for validation).
87-
extra/collect --kallsyms # -> kasld-bundle-<host>-<date>/
87+
extra/collect --kallsyms # -> kasld-bundle-<arch>-<rel>-<ts>/
8888

8989
# Anywhere: replay the exact same facts through kasld, no target needed.
9090
KASLD_SYSROOT=kasld-bundle-*/sysroot ./build/*/kasld -v

extra/check-hardware-vulnerabilities

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ if grep -s -q Vulnerable /sys/devices/system/cpu/vulnerabilities/reg_file_data_s
8686
fi
8787

8888
if grep -s -q Vulnerable /sys/devices/system/cpu/vulnerabilities/indirect_target_selection ; then
89-
echo "[.] CPU vulnerable to Indirect Target Selection / ITS (CVE-2025-20012)"
89+
echo "[.] CPU vulnerable to Indirect Target Selection / ITS (CVE-2024-28956)"
9090
fi
9191

9292
if grep -s -q Vulnerable /sys/devices/system/cpu/vulnerabilities/tsa ; then

0 commit comments

Comments
 (0)