# DF-3601 VERDICT — hdaa_sysctl_reconfig kernel self-deadlock

**Status: reproduced (deterministic, 2/2 runs) — kernel deadlock / system freeze (dos).**
**Fix: validated on guest (module rebuild + swap + re-trigger).**

## Setup
Guest: DragonFly 6.5-DEVELOPMENT #0 Thu Jul 2 2026, X86_64_GENERIC,
QEMU `-device intel-hda -device hda-duplex` (QEMU's own benign codec,
`Generic (0x1af40022)`), snd_hda loaded as KLD.

## Reproduction timeline (run 2, controlled — see run.log)
1. `kldload snd_hda` → hdac0/hdacc0/hdaa0/pcm0 attach cleanly (boot.log.repro2 tail).
2. Negative control: `sysctl dev.hdaa.0.config=softpcmvol` (a tree-neutral
   hdaa sysctl write) returns instantly — proves ordinary hdaa sysctl
   writes are fine.
3. t=0  session A: `sysctl dev.hdaa.0.reconfig=1`
   - sysctl(8) prints `dev.hdaa.0.reconfig: 0` (the pre-write read-back)
     and then the write syscall NEVER returns; session A killed by an
     external `timeout 30` — `echo RC=$?` / trailing `date` never execute.
4. t+7s session B: `sysctl kern.osreldate` still works (rc=0), `ps` works —
   consistent with the per-CPU lock analysis: the wedged thread holds its
   own CPU's `gd_sysctllock` SHARED and sleeps requesting EXCLUSIVE; CPUs
   whose lock it already acquired EXCLUSIVE (it iterates cpu 0..n-1) are
   poisoned immediately, others poison as soon as lockmgr queues the
   EXCLUSIVE request.
5. t+~120s: even *new* ssh connections hang (login path needs sysctl) —
   `vm.sh status` probe itself timed out. QEMU process alive, serial
   console silent (no panic — sleeping thread, not a crash).
6. Run 1 (accidental, same trigger): identical outcome (boot.log.firstwedge:
   console output simply stops after the attach messages; ssh dead; qemu
   alive). 2/2 deterministic.

## Why (line-level)
- kern_sysctl.c:1572-1577 — `SYSCTL_SLOCK(); error = sysctl_root(...); SYSCTL_SUNLOCK();`
  (SHARED per-CPU global sysctllock held across the handler).
- hdaa.c:6492 — handler calls `device_delete_children(dev)`; hdaa.c:6498 `bus_generic_attach(dev)`.
- sound.c:1233-1237 — pcm child detach frees its sysctl contexts
  (`sysctl_ctx_free(&d->play_sysctl_ctx)` / rec).
- kern_sysctl.c:171-175 — `sysctl_unregister_oid()` → `SYSCTL_XLOCK()`;
  kern_sysctl.c:1642-1653 — `_sysctl_xlock()` lockmgr's **every** CPU's
  `gd_sysctllock` LK_EXCLUSIVE.
- The same thread therefore blocks acquiring its own CPU's lock
  exclusively → sleeps forever; system-wide sysctl poisoning follows.
- Trigger privilege: root only (`caps_priv_check_td(SYSCAP_NOSYSCTL_WR)`,
  kern_sysctl.c:1447). Not reachable by unprivileged users.

## Fix
`fix.diff`: defer `device_delete_children + unconfigure + configure +
bus_generic_attach` into `hdaa_reconfig_task()` on
`taskqueue_thread[mycpuid]`; the sysctl handler only enqueues and returns.
Drain the task in `hdaa_detach` before teardown. Zero-fuzz `patch -p1`.

### Fix validation (fix_validation.log)
- `cd /usr/src/sys/dev/sound/driver/hda && make` → snd_hda.ko builds clean with -Werror.
- Swapped module, re-attached (hdaa0/pcm0 up).
- `sysctl dev.hdaa.0.reconfig=1` → returns RC=0 in <1s; dmesg:
  `pcm0: detached` then `pcm0: <Generic (0x1af40022) (Analog)> at nid 3 and 5 on hdaa0`.
- Second reconfig: RC=0, `/dev/dsp0` present, `sysctl kern.osreldate` responsive — HEALTH_OK.

## Impact ceiling
Whole-kernel freeze from a single root sysctl write on any machine with
an HDA codec (the standard "apply new pin config" workflow). Not a
privilege escalation; no memory corruption. Bucket: base:dos.

## 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.
