# DF-1639 — VERDICT

## Verdict: REPRODUCED (panic / local DoS)

## Root cause
`sys/dev/disk/dm/dm_ioctl.c:707-708`:
```c
cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
iter = prop_array_iterator(cmd_array);
```
When the user-supplied prop_dictionary omits the `cmd_data` key,
`prop_dictionary_get` returns NULL.  `prop_array_iterator(NULL)` then executes
`_PROP_RWLOCK_RDLOCK(pa->pa_rwlock)` with `pa==NULL`, i.e. a `lock cmpxchg` at
address `NULL + offsetof(pa_rwlock) = 0x40` — an unmapped page → page fault → panic.

## Evidence (baseline, unpatched dm.ko)
```
Fatal trap 12: page fault while in kernel mode
cpuid = 3; lapic id = 3
fault virtual address     = 0x40
instruction pointer        = 0x8:0xffffffff809d9a7b
current process           = 1050
Stopped at      prop_array_iterator+0x1b:       lock cmpxchgl   %edx,0x40(%rdi)
db>
```
Guest went down (DDB).  Triggered by operator-group user `maxx` (uid 1001) via a
single `NETBSD_DM_IOCTL` (`command=reload`) with no `cmd_data` key.  No device,
no table, no setup beyond `kldload dm` + `pw groupmod operator -m maxx`.

## Exploit-chain assessment
This is a **read-only NULL-deref at a fixed low address (0x40)**.  There is no
write primitive — the fault is a read of `NULL->pa_rwlock`.  On DragonFly the NULL
page cannot be mapped by userspace (`vm.mmap_min_addr` enforced), so there is no
way to control the dereferenced data.  **Valid hard blocker: read-only primitive,
no escalation path.**  Impact ceiling = local DoS (panic).

## PoC changes
Authored `dm_poc.c` from scratch — the finding folder was empty.  The PoC
constructs the prop_dictionary plist XML by hand (no libprop dependency) so the
malformed input (missing `cmd_data`) can be crafted precisely, and dispatches it
via the standard `plistref` ioctl transport.

## Fix (fix.diff)
```diff
 cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
+if (cmd_array == NULL) {
+    dmdebug("dm_table_load_ioctl: missing cmd_data array\n");
+    return EINVAL;
+}
 iter = prop_array_iterator(cmd_array);
```
Matches the finding's proposed fix (`check cmd_array!=NULL`).

## Fix validation
Built patched `dm.ko` (DF-1639 + DF-1640 + DF-1642 fixes combined), `kldload`-ed,
re-ran PoC:
```
DF-1639 reload(no cmd_data): rc=-1 errno=22 (Invalid argument)
EXIT=0
```
Guest stayed up.  Baseline (unpatched) panicked every time.  **fix_status = fixed.**

Validation method: dm is a KLD module (not in GENERIC), so the fix was validated by
rebuilding `dm.ko` and reloading it — equivalent to a single-fix kernel rebuild for
module-only bugs, and dramatically faster.
