# DF-5119 VERDICT — reproduced (panic), fix validated

**Status: reproduced / impact: panic / confidence: certain.**

## Root cause (code trace)

`efidev_ioctl()` trusts `struct efi_var_ioc::datasize` / `::namesize`
(`size_t`, fully user-controlled; `sys/sys/efiio.h:40-48`) and hands them to
`kmalloc(..., M_TEMP, M_WAITOK)` with no upper bound — efidev.c:105, 106
(EFIIOC_VAR_GET), efidev.c:140 (EFIIOC_VAR_NEXT), efidev.c:165, 166
(EFIIOC_VAR_SET). The SET path allocates `datasize` *first* (line 164-165),
so a single ioctl reaches the primitive with nothing but `open("/dev/efi")`.

* **Huge non-wrapping sizes**: `_kmalloc()` → large path
  (`sys/kern/kern_slaballoc.c:942`) → `kmem_slab_alloc()` →
  `vm_map_findspace()` fails → `panic("kmem_slab_alloc(): kernel_map ran out
  of space!")` because `M_WAITOK` without `M_NULLOK` is a hard requirement
  (`kern_slaballoc.c:1721-1724`). kmalloc(M_WAITOK) never returns NULL for
  unsatisfiable sizes on DragonFly — it panics.
* **Sizes ≥ 2^64−PAGE_MASK+1**: `size = round_page(size)`
  (`kern_slaballoc.c:945`) wraps to 0 → `kmem_slab_alloc(0, ...)`:
  `vm_map_findspace(len=0)` succeeds, `vm_map_insert()` inserts a
  zero-length entry into `kernel_map`, and `vm_map_set_wired_quick()`
  (`kern_slaballoc.c:1743`) immediately trips the map invariant →
  `panic("vm_map_entry_link: dup addr map ...")`. Even absent that check,
  the returned KVA has no pages and `*kup = 0` (line 953-954), so
  `kfree()` at `efidev.c:184` would fall into the SLZone path
  (`kern_slaballoc.c:1475-1478`, `*kup==0` is not `>0`) on a zone-less
  unmapped pointer → KKASSERT/unmapped-read fault.

Reachability does **not** require UEFI: all allocation happens before
`efi_enter()` (`efirt.c:343-359`). On the BIOS-booted QEMU guest,
`kldload efirt` prints `module_register_init: MOD_LOAD (efirt, ...) error 6`
(`sys/kern/kern_module.c:110-116` tolerates the failure) while the co-packaged
`efidev` module registers and creates `/dev/efi` (0700 root:wheel,
`efidev.c:205-206`). Trigger therefore requires root — same privilege
calibration as DF-2121 (known, not re-reported here).

## What was run (all on DragonFly 6.5-DEVELOPMENT x86_64 guest)

1. **Control (mode 0)**: sane sizes → `ENXIO` (`efi_enter` on BIOS), guest up.
2. **Mode 1** (`datasize=0x4000000000000000`): guest died with
   `panic: kmem_slab_alloc(): kernel_map ran out of space!` —
   trace `_kmalloc ← efidev_ioctl ← dev_dioctl` (panic.m1.txt). Reproduced
   first try.
3. **Mode 2** (`datasize=0xFFFFFFFFFFFFFFFF`): guest died with
   `panic: vm_map_entry_link: dup addr map ...` —
   trace `vm_map_set_wired_quick ← kmem_slab_alloc ← _kmalloc` (panic.m2.txt).
   Reproduced first try.

Both panics are deterministic, single-syscall, and observed via serial console
with `vm.sh status ⇒ down` immediately after.

## Why not uid0

The trigger surface is `0700 root:wheel` — the caller is already root, so
there is no unpriv→root ladder for this node. The memory-corruption flavor
(zero-length kernel_map entry / kup-misclassified pointer) is real but
manifests as a map-invariant panic in this allocator; no controllable
corruption primitive was pursued beyond demonstrating the invariant break.

## Fix validation

`fix.diff` adds `EFI_IOC_MAX_DATA`/`EFI_IOC_MAX_NAME` (1 MiB, Linux-efivarfs
parity) plus `namesize >= sizeof(efi_char)` checks to all three VAR ioctls
(the latter also neutralizes DF-2121's underflow as defense in depth).
Applied to the guest's `/usr/src`, module rebuilt (`-Werror` clean), loaded
as `efirt-patched.ko`:

| run | stock module | patched module |
|---|---|---|
| mode 1 (2^62)  | **panic** kmem_slab_alloc | `EINVAL`, guest up |
| mode 2 (SIZE_MAX) | **panic** vm_map dup addr | `EINVAL`, guest up |
| mode 0 control | `ENXIO` | `ENXIO` (unchanged) |

`fix_status: fixed`.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
