# DF-5102 — apple_fw_probe: kgetenv()==NULL fed to kfreeenv() → kfree(NULL) panic

## What

`sys/dev/apple/fw/apple_fw.c:107-113`:

```c
product = kgetenv("smbios.system.product");
biosver = kgetenv("smbios.bios.version");
ksnprintf(desc, sizeof(desc), "Apple %s EFI Firmware %s", product, biosver);
device_set_desc_copy(dev, desc);
kfreeenv(product);     /* NULL when the kenv entry is absent */
kfreeenv(biosver);
```

`kgetenv()` returns NULL when the variable is absent (kern_environment.c:228-251);
dynamic kenv is the standard post-loader state (`kenv_isdynamic = 1`,
kern_environment.c:592, SI_BOOT1_POST). `kfreeenv()` unconditionally calls
`kfree(env, M_KENV)` when kenv is dynamic (kern_environment.c:331-336), and
DragonFly's `_kfree()` **panics on NULL**:

```c
sys/kern/kern_slaballoc.c:1407-1408
    if (ptr == NULL)
        panic("trying to free NULL pointer");
```

## Precondition (reachability)

The driver only probes its synthetic child when the FADT OEM ID is
`"APPLE "` (apple_fw.c:58-67, identify at :76-92), and the driver must be
present — it is `optional apple_fw acpi` (sys/conf/files:1235; only LINT64
configures it) or root `kldload`s the KMOD (sys/dev/apple/fw/Makefile).
The panic then requires the `smbios.system.product` / `smbios.bios.version`
kenv entries to be **absent** — i.e. Apple-flagged firmware without a parsed
SMBIOS table (VM with injected APPLE FADT and no SMBIOS, or equivalent).
Trigger actor: boot-time auto-probe, or root kldload. Impact: kernel panic
(DoS).

## Files in this pack

- `df5102_nullfree.c` — PoC kernel module reproducing the exact sink
  (kgetenv of an absent variable → kfreeenv(NULL)), i.e. what
  apple_fw.c:112-113 does when the smbios entries are missing.
- `build.sh` / `run.sh` — exact commands.
- `build.log` — full successful module build on the guest.
- `run.log`, `panic.txt`, `console_full.log` — decisive run: panic
  "trying to free NULL pointer" with backtrace through `df5102_load`.
- `env.txt` — guest uname, kenv state, RSDP OEM ("BOCHS " — why the driver
  path itself is not reachable on this guest).
- `fix.diff` — the two-line NULL guard fix.
- `VERDICT.md`, `manifest.json`, `verdict.json`.

## Build / Run

```
# on the guest (root):
cd /root/df5102 && make
kldload ./df5102b.ko        # → instant panic "trying to free NULL pointer"
```
