# DF-1499 — musycc NGM_TEXT_STATUS heap overflow

## Verdict
**REPRODUCED (source-level harness).** The bug is real; impact ceiling is a
~3.5–10 KiB heap overflow of an `M_NETGRAPH` slab allocation. The kernel path
is reachable only on a host that has the LMC/Siemens `musycc(4)` driver loaded
and a `musycc` netgraph node instantiated (the NIC hardware is PCI
`11f8:83791`/Conexant 83791 framer — QEMU does not emulate it). On the audit
guest, `ngctl show` cannot create a `musycc` type node and the kernel module
isn't loaded. Harness demonstrates the overflow using the genuine per-channel
format string from `musycc.c:443-474`. fix.diff applies cleanly and
`nativekernel` succeeds (rc=0).

## Mechanism (`sys/dev/misc/musycc/musycc.c`)
1. Lines 1000-1001: `NG_MKRESPONSE(*resp, msg, sizeof(struct ng_mesg) +
   NG_TEXTRESPONSE=1024, M_NOWAIT)` — response data area is exactly 1024
   bytes (`ng_message.h:59`).
2. Line 1006: `s = (char *)(*resp)->data;`
3. Line 1007: `status_8370(sc, s)` writes a fixed-format framer status
   header (~150-200 bytes).
4. Line 1008: `status_chans(sc, s)` iterates `NHDLC = 32` channels
   (`musycc.c:156`). For each non-NULL channel it issues **7** `ksprintf`
   calls whose combined length is ~140 bytes (fresh counters) up to ~360
   bytes (stressed counters), with no bound against the response buffer.
5. With all 32 channels open, `status_chans` writes ~4.5 KiB (fresh) to
   ~11.7 KiB (stressed) into the 1024-byte buffer → 3.5 KiB..10.7 KiB
   overflow into adjacent `M_NETGRAPH` slab allocations.
6. Line 1009: `(*resp)->header.arglen = strlen(s) + 1;` further causes a
   massive over-read on the subsequent copyout to the requester (which itself
   panics once the unbounded string runs past the next valid page).

The trigger needs CAP_NETGRAPH / `SYSCAP_RESTRICTEDROOT` (root-equivalent in
the default caps model).

## Harness proof (`harness.c`)
Replicates the per-channel `ksprintf` format string and counts bytes:

```
Per-channel bytes (fresh counters)   : 137
Per-channel bytes (stressed counters): 359
NG_TEXTRESPONSE buffer               : 1024

All 32 channels open (worst case):
  fresh counters    used=4584  OOB=3560 bytes
  stressed counters used=11688 OOB=10664 bytes
  overflow starts at >= 7 open channels (fresh)
```

The math is conservative (status_8370 contributes additional bytes); the
overflow begins with as few as ~7 open hooks.

## Exploit-chain note
Trigger requires a `musycc` netgraph node, which requires the driver loaded
(real hardware). The primitive is a partly-attacker-controlled heap overflow
in `M_NETGRAPH`; on a system that uses the card this is a credible
root→kernel-code-exec primitive. Documented as primitive characterization.

## PoC changes
- Original folder had README only.
- Added harness.c, build/run scripts, env, logs, fix.diff, VERDICT.md,
  manifest.json.

## Fix
`fix.diff` converts `status_chans` to use `ksnprintf` with a running
remaining-capacity tracker and `break` on truncation, and threads
`NG_TEXTRESPONSE` as the bound from the `NGM_TEXT_STATUS` handler. Matches
the finding markdown proposal ("ksnprintf with NG_TEXTRESPONSE-pos bound,
bounded ksnprintf").

## Fix-validation
`patch -p1 --forward` succeeds (hunks at 441 + 1009). `nativekernel` rc=0
(saved as `fix_build.log`). No run-time exercise possible because the
`musycc` netgraph node cannot be created on the guest → `fix_status:
"not_testable"`. Diff applies and compiles; changed logic bounds every
emit.
