# DF-2853 VERDICT — REPRODUCED (baseline) / fixed by guard (validated)

## Bottom line
On the stock `X86_64_GENERIC` INVARIANTS kernel (DragonFly 6.5-DEVELOPMENT
#0 Thu Jul 2 06:02:54 UTC 2026), the KLD harness `rman_overlap.ko`
demonstrates in one load, without any kernel debug option, that
`rman_reserve_resource()` hands out an address range **inside another
device's allocated resource** and then **double-allocates** a unit, purely
because the alignment roundup overflows the candidate fragment and the
`(rend - rstart + 1) >= count` size check wraps unsigned.

## Reproduced — exact sequence (run.log, dmesg.txt)
1. Private `RMAN_ARRAY` manages `[0x0000,0x2FFF]`.
2. Legit: `A = reserve(0, 0x1EFF, 0x1F00, align=1)` → `[0,0x1EFF]`;
   `B = reserve(0x1FFF, 0x2FFF, 0x1001, align=1)` → `[0x1FFF,0x2FFF]`.
   Free fragment: `F=[0x1F00,0x1FFE]`.
3. `E = reserve(0, 0xFFFF, count=1, RF_ALIGNMENT_LOG2(12))`:
   - `rstart = roundup(0x1F00, 0x1000) = 0x2000`
   - `rend   = 0x1FFE`
   - `rend - rstart + 1 = 0x1FFE - 0x2000 + 1` **wraps to 0xFFFF…FFFF**
     → “size” check passes for count=1
   - split-else branch: `F->r_end = 0x1FFF` (inflated across B),
     `E=[0x2000,0x2000]` inserted — **E is inside allocated B**.
     Console: `EVIL1 E=… [0x2000,0x2000] ==> REPRODUCED`.
   - TAILQ also loses sort order (`[0x2000]A` before `[0x1fff]A`).
4. `X = reserve(0x1FFF, 0x1FFF, 1, align=1)` is granted `[0x1FFF,0x1FFF]`
   from the inflated fragment while B still owns 0x1FFF →
   `EVIL2 … REPRODUCED: 0x1FFF now owned by B AND X`.
5. Guest stays alive — silent metadata corruption. `kldunload` later
   releases everything and `rman_fini` returns 0 (the corrupted list
   survives the release path, tracing DF-0089-family merge hazards).

## Amplifier — unprivileged readers walk the corrupted list
On the first attempt the harness used fake `device_t` values; an
unprivileged `hw.bus.rman` walker (`sysctl_rman`, subr_rman.c:705-710
calls `device_get_name(res->r_dev)` on **every** exported entry)
faulted on them and panicked the kernel — see `panic-sysctl-walk.txt`
(`Fatal user address access … device_get_name … fault address 0x59`).
That crash is a harness artifact, but it proves the reach: any
corrupted/freed entry with a stale `r_dev` is dereferenced by an
unprivileged sysctl read ⇒ user-triggerable panic; and every corrupted
entry (start/size) is exported to userland.

## Exploit chain assessment (honest)
`rman_reserve_resource` inputs are kernel-supplied (bus code, drivers,
firmware tables): nexus.c:398 (driver/hints), acpi.c:1156 (_CRS),
cardbus_cis.c:533-539 where a **physically present malicious CardBus
card’s BAR decode chooses `size`, hence `count` AND alignment via
`rman_make_alignment_flags(size)`**. The primitive is kernel metadata
corruption → two owners for the same MMIO/IRQ range; no direct
unpriv→root chain from rman alone (no user-reachable parameter input).
Impact ceiling: cross-device register access (device-dependent
privilege consequences), plus invariant destruction that poisons later
merges/releases (with DF-0089, merges already ignore contiguity) and
the unpriv sysctl walk (panic). Classified memcorrupt/High.

## PoC changes vs a “textbook” harness (poc_changes)
- No seed PoC existed (pass-2 original finding).
- `DEV_MODULE()` does not exist in DragonFly; used
  `DECLARE_MODULE(name, moduledata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)`.
- `<kmod.mk>` make include path is not usable on this guest
  (no populated sys/modules tree) → `build.sh` replicates kmod.mk by
  hand (machine/cpu/machine_base/cpu_base symlinks, `-nostdinc
  -DKLD_MODULE -mcmodel=kernel -mno-red-zone`, `ld.bfd -d -r`).
- **ld.gold must not be used**: its `-r` output panics the kernel
  module linker with `lost base for relatab`
  (link_elf_obj_reloc_local) — cost one `vm.sh reset with-src`.
- Fake `device_t` values had to become NULL after they crashed the
  unprivileged sysctl walk (see amplifier above).

## Fix validation
- `fix.diff` adds the FreeBSD-style guard after the `rend` computation:
  `if (rstart > rend) continue;` (also skips the bogus DPRINTF args).
- Applied to the guest’s `/usr/src/sys/kern/subr_rman.c` (together with
  DF-2854’s bzero fix), `make -j6 nativekernel KERNCONF=X86_64_GENERIC`,
  `make installkernel`, reboot — see fix section of verdict.json and
  `fix_build.log`/`fix_run.log`.
- Patched-kernel expectation (met): EVIL1 → NULL (“not reproduced
  (guard present?)”), EVIL2 → NULL (“correctly denied”), list stays
  `[0-0x1eff]A [0x1f00-0x1ffe]f [0x1fff-0x2fff]A`, unload fini=0.

## Kernel references
- sys/kern/subr_rman.c:236-254 (scan + wrapping size check)
- sys/kern/subr_rman.c:285-327 (split mutates free fragment)
- sys/platform/pc64/x86_64/nexus.c:398, sys/dev/acpica/acpi.c:1156,
  sys/dev/pccard/cardbus/cardbus_cis.c:533-539 (input provenance)
- FreeBSD sys/kern/subr_rman.c `rman_reserve_resource_step`
  (`if (rstart > rend) continue;`) — upstream guard DragonFly lacks.
