⬢ DragonFlyBSD Kernel Audit
DF-4537 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4537",
  "status": "untested",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "cs4281_pci_attach() ignores mixer_init()s return at cs4281.c:845 (which publishes a 0666 /dev/mixerN whose si_drv1->devinfo is the AC97 codec, mixer.c:730-733) and keeps a fallible call after it: pcm_register() at cs4281.c:847 returns EINVAL/ENODEV when pcm_veto_load is stuck at its boot-time value (sound.c:1021) or when the pcm unit exceeds PCMMAXUNIT=255 (sound.c:1027). On that failure attach jumps to bad: and ac97_destroy(codec) at cs4281.c:862 kobj_delete()s the method table and kfrees the codec (ac97.c:852-858) plus kfree(sc) at cs4281.c:873, while /dev/mixerN still dispatches any users ioctls into the freed codec/softc -- use-after-free with indirect-dispatch potential, identical to the DF-4156/4193/4299/4334/4344/4421/4457/4468/4504 family (10th instance). Untested rather than demonstrated: the trigger needs a real Cirrus 1013:6005 (CS4281) function whose attach reaches mixer_init and then fails pcm_register; the audit guest has no vendor-1013 PCI function (QEMU has no CS4281 emulation -- env.txt) and both pcm_register failure preconditions are boot-time anomalies an unprivileged user cannot create.",
  "exploit_chain": "",
  "evidence": "findings/poc/DF-4537/VERDICT.md (full source chain); cs4281.c:845 mixer_init ignored vs cs4281.c:847 pcm_register check vs cs4281.c:860-873 bad: ac97_destroy+kfree; mixer.c:730-733 make_dev 0666 + si_drv1=m(devinfo=codec); ac97.c:852-858 kobj_delete+kfree; sound.c:1021/1027 failure set; sound.c:1205 only pcm_unregister->mixer_uninit destroys the cdev; build.log/run.log/env.txt (guest-side absence probe); wedge_episode.txt (pre-reset kldload/kldunload abort, known DF-4116, not this file)",
  "kernel_refs": [
    "sys/dev/sound/pci/cs4281.c:845",
    "sys/dev/sound/pci/cs4281.c:847",
    "sys/dev/sound/pci/cs4281.c:862",
    "sys/dev/sound/pci/cs4281.c:873",
    "sys/dev/sound/pcm/mixer.c:730",
    "sys/dev/sound/pcm/ac97.c:852",
    "sys/dev/sound/pcm/sound.c:1021",
    "sys/dev/sound/pcm/sound.c:1027",
    "sys/dev/sound/pcm/sound.c:1205"
  ],
  "poc_changes": "authored fresh probe (no seed); probe documents the absent trigger environment (no /dev/mixer* nodes, no vendor-1013 PCI function) rather than the UAF itself",
  "attempts": 1,
  "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": 6,
  "guest_dirty": 0,
  "build_cmd": "cc -O -Wall -o /root/cs4281_probe /root/cs4281_probe.c",
  "run_cmd": "/root/cs4281_probe; pciconf -l | grep -i 1013 || echo no vendor-1013 PCI function",
  "code_hash": "19c94f1b781ac9af341782f14e78bc816a96515adcfa4f6ff6c1ebaef2c63dfb",
  "notes": "10th instance of the attach-error-path mixer family; pass-1 missed it (only DF-1681 rate-div filed for this file). Also covers the ignored mixer_init() return, same fix. Pre-reset kldload experiment hit the already-filed DF-4116 sound-core unload panic (wedge_episode.txt); final run is on the clean post-reset guest.",
  "recommended_fix": "Move pcm_register() before AC97_CREATE/mixer_init() and fail attach (pcm_unregister unwind) on mixer_init()/pcm_addchan() error so no failure path exists after the mixer is published",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff reorders pcm_register() ahead of codec creation/mixer publication, checks mixer_init() and both pcm_addchan() returns, and adds a bad_unregister: unwind via pcm_unregister() (which performs mixer_uninit before codec teardown, cf. sound.c:1205); git apply --check is clean. Baseline vs patched behaviour is not observable on the audit guest for the same hardware/precondition absence (no 1013:6005 function, pcm_register failure not creatable).",
  "fix_evidence": "findings/poc/DF-4537/fix.diff; canonical unwind order shown at sound.c:1205 (pcm_unregister does mixer_uninit before codec teardown)"
}