DF-3601 / verdict.json
{ "finding_id": "DF-3601", "status": "reproduced", "reproduced": 1, "impact": "dos", "confidence": "certain", "verdict": "Deterministic kernel self-deadlock: writing dev.hdaa.N.reconfig=1 (root-only, the documented audio reconfiguration interface) never returns and freezes the whole system. The sysctl handler mutates the newbus device tree (device_delete_children/bus_generic_attach) from inside sysctl-handler context where userland_sysctl() holds the per-CPU global sysctllock SHARED, while pcm child (un)registration takes _sysctl_xlock() = every CPUs gd_sysctllock EXCLUSIVE \u2014 the thread waits for its own shared hold forever and poisons sysctl system-wide. Reproduced 2/2 on QEMU intel-hda+hda-duplex (benign codec \u2014 hardware-independent). Fixed by deferring the reconfiguration to a taskqueue; fix validated on-guest (trigger returns rc=0, pcm0 detaches/re-attaches, system healthy, second reconfig clean).", "exploit_chain": "root: sysctl dev.hdaa.0.reconfig=1 -> hdaa_sysctl_reconfig (hdaa.c:6474) -> device_delete_children (hdaa.c:6492) -> hdaa_pcm_detach -> pcm_unregister -> sysctl_ctx_free (sound.c:1233) -> sysctl_unregister_oid -> SYSCTL_XLOCK (kern_sysctl.c:171) -> _sysctl_xlock takes every CPUs gd_sysctllock EXCLUSIVE (kern_sysctl.c:1642) while the same thread holds its own CPUs lock SHARED (kern_sysctl.c:1572) -> permanent sleep; wedge spreads system-wide.", "evidence": "run.log (write syscall never returns; t+120s even new ssh hangs; qemu alive, no panic); boot.log.firstwedge / boot.log.repro2 (console silent after attach); fix_validation.log (patched module: RC=0, pcm0: detached then re-attach, HEALTH_OK, 2 consecutive reconfigs); fix.diff (taskqueue deferral, patch -p1 zero fuzz).", "kernel_refs": [ "sys/dev/sound/pci/hda/hdaa.c:6474", "sys/dev/sound/pci/hda/hdaa.c:6492", "sys/dev/sound/pci/hda/hdaa.c:6498", "sys/kern/kern_sysctl.c:1572", "sys/kern/kern_sysctl.c:1642", "sys/kern/kern_sysctl.c:171", "sys/dev/sound/pcm/sound.c:1233" ], "poc_changes": "No code PoC needed beyond `sysctl dev.hdaa.0.reconfig=1`; guest needed booting with -device intel-hda -device hda-duplex (vm.sh temporarily extended via HDA_ARGS env var, reverted after).", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 1500, "guest_dirty": 0, "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Deferred-taskqueue fix (hdaa.c: sysctl handler enqueues reconfig_task; hdaa.h: struct task member; attach TASK_INIT; detach taskqueue_drain) built as a module (-Werror clean) and swapped into the guest: the previously-hanging sysctl now returns rc=0 in <1s, dmesg shows pcm0 detach/re-attach cycle, /dev/dsp0 recreated, two consecutive reconfigs and full sysctl/ssh health verified.", "fix_evidence": "findings/poc/DF-3601/fix_validation.log; findings/poc/DF-3601/fix.diff", "build_cmd": "cd /usr/src/sys/dev/sound/driver/hda && make", "run_cmd": "kldload snd_hda && sysctl dev.hdaa.0.reconfig=1", "code_hash": "", "notes": "Trigger requires root (SYSCAP_NOSYSCTL_WR gate, kern_sysctl.c:1447) \u2014 privilege-gated kernel freeze, hence dos severity Medium not High. Guest HDA args reverted and guest reset to with-src snapshot after validation. attempts=3: two baseline reproductions (both wedged) + one patched validation run.", "recommended_fix": "Defer device_delete_children/unconfigure/configure/bus_generic_attach out of the sysctl handler into a taskqueue (hdaa_reconfig_task on taskqueue_thread[mycpuid]); drain it in hdaa_detach." } |