# DF-1642 — `kfree` of uninitialized `msg` pointer in `dm_message_ioctl`

## Summary
`dm_ioctl.c:1006` declares `char *msg;` with **no initializer** (stack garbage).
Line 1028 `prop_dictionary_get_cstring(dm_dict, DM_MESSAGE_STR, &msg)` only writes
`*cpp` on success; on failure `msg` stays as stack garbage.  Line 1058
`kfree(msg, M_TEMP)` then frees whatever garbage pointer was on the stack → either a
page fault in `_kfree` (most common, observed: fault on `0x2e2e7a4a7054` — ASCII
stack residue) or, if the garbage happens to be a valid slab pointer, silent heap
corruption.

## Severity / impact
- **Severity filed:** High
- **Verified impact:** `panic` (local DoS).  The `msg` pointer is **not
  attacker-controlled** in any reliable way (it is stack residue from the ioctl
  dispatch path).  Most of the time the garbage is an unmapped address → page fault
  in `_kfree` → panic.  This is a valid blocker: the freed pointer is uncontrolled,
  so there is no reliable exploitation primitive.
- **Trigger credential:** operator group.
- **Precondition:** admin has loaded `dm` KLD + a dm device with a loaded table
  entry must exist (so `found==1` at `dm_ioctl.c:1037` and the code reaches
  `kfree(msg)`).

## Reproduce
```sh
kldload dm
pw groupmod operator -m <user>
./build.sh
./dm_poc create          # create device "pocdev"
./dm_poc load_zero       # load a zero target table entry (so found==1)
./run.sh                 # message command with NO message key
# expected (BUG): Fatal trap 12 in _kfree (fault on garbage addr)
# expected (FIXED): EINVAL, guest stays up
```

## Mechanism (line-accurate)
1. `dm_ioctl.c:1006` `char *msg;` — uninitialized, stack garbage (in the observed
   run: `0x2e2e7a4a7000`, ASCII residue).
2. `dm_ioctl.c:1022` `dm_dev_lookup` succeeds (device exists).
3. `dm_ioctl.c:1028` `get_cstring(dm_dict, "message", &msg)` — key absent → returns
   false, **msg unchanged**.
4. `dm_ioctl.c:1034-1038` `sector==0`, table non-empty → `found=1`, `table_en` set.
5. `dm_ioctl.c:1051-1053` `table_en->target->message` — the zero target has no
   `->message` callback, so this is skipped.
6. `dm_ioctl.c:1058` `kfree(msg, M_TEMP)` — frees the garbage pointer →
   `_kfree+0x45: movl 0x54(%rax),%r13d` where `rax = 0x2e2e7a4a7000` →
   `Fatal trap 12: page fault`.

## Fix
`fix.diff`: (1) initialize `msg = NULL` at declaration; (2) check the return value
of `prop_dictionary_get_cstring` and return `EINVAL` early if the message key is
absent (after `dm_dev_unbusy`).  Matches the finding's proposed fix.

## Fix validation
Patched `dm.ko`, re-ran PoC: returns `EINVAL` (errno 22), **no panic**, guest stays up.
