DF-5191 / verdict.json
{ "finding_id": "DF-5191", "status": "not_reproduced", "reproduced": false, "impact": "none", "confidence": "likely", "verdict": "Code-trace-proven race, not runnable on the audit guest: the guest is QEMU/i440fx with no PCMCIA/pccard hardware (0 pccard lines in dmesg.boot; sio_pccard.c compiles only for optional sio pccard, sys/platform/pc64/conf/files:197), so no sio-pccard device and no detach event can exist there. The defect is established by inspection: sio_pccard_detach (sio_pccard.c:117-143) sets com->gone, calls ttyclose(com->tp) and kfrees com->ibuf without acquiring tty_token, while every sio-core path touching those fields holds it (sioopen gone-check sio.c:1273 sits BEFORE its lwkt_gettoken at sio.c:1277; sioclose takes the token at sio.c:1460 and re-frees com->ibuf at sio.c:1475-1482 when com->gone is set; siosetwater documents called with tty_token held at sio.c:2446 and frees the ibuf alias com->ibufold at sio.c:2438-2441; the callout callbacks siodtrwakeup/siobusycheck also run under the token). Four interleavings reach memory corruption: (1) detach frees com->ibuf (sio_pccard.c:138-139, never NULLed) while a token-holding sioclose passes its gone-check and kfrees the same M_DEVBUF chunk - double free; (2) an open that passed the pre-token gone-check sleeps in comhardopen (DTR wait, sio.c:1284-1295) while detach takes the !TS_ISOPEN branch and frees com->ibuf underneath it - com->iptr = com->ibuf (sio.c:1698) and bcopy(com->ibuf,...) (sio.c:1703-1708) become UAF, and the later close double-frees; (3) detachs forced ttyclose (sio_pccard.c:136) duplicates the linesw-close+ttyclose sequence a concurrent sioclose runs (sio.c:1468-1472), re-freeing clist blocks; (4) detach interleaved with siosetwaters ibuf/ibufold swap frees an alias siosetwater still frees at its tail. Trigger requires a card-eject/power-off/modunload event (physical or root) racing an unprivileged open/close - wide window (seconds of DTR wait). Same function as DF-2191 (callouts) and the detach-side twin of DF-3902 (sioclose-side non-NULLed ibuf); isa/pci/puc sio attachments have no detach method at all (sio.c:193-238), so only pccard exposes this race family.", "exploit_chain": "root/physical triggers pccard detach; unprivileged user holds open/close in flight on /dev/ttydX; detachs tokenless kfree(com->ibuf) lands while sioclose/sioopen/siosetwater still reference it -> M_DEVBUF (1024-8192 byte) double free / UAF write through com->iptr -> kernel heap corruption. Chain NOT developed further: no runtime surface on the audit guest (no pccard hardware), so exploitation could not be attempted.", "evidence": "VERDICT.md (interleaving-by-interleaving trace with path:line); race_harness.c (trigger harness for hardware owners); fix.diff (token + callout_drain + NULL-out fix coordinating DF-2191/DF-3902); env.txt (guest shows no pccard)", "kernel_refs": [ "sys/dev/serial/sio/sio_pccard.c:117", "sys/dev/serial/sio/sio_pccard.c:127", "sys/dev/serial/sio/sio_pccard.c:134", "sys/dev/serial/sio/sio_pccard.c:136", "sys/dev/serial/sio/sio_pccard.c:138", "sys/dev/serial/sio/sio.c:1273", "sys/dev/serial/sio/sio.c:1277", "sys/dev/serial/sio/sio.c:1460", "sys/dev/serial/sio/sio.c:1475", "sys/dev/serial/sio/sio.c:2438", "sys/dev/serial/sio/sio.c:2446", "sys/kern/tty.c:247" ], "poc_changes": "No seed PoC existed. race_harness.c written fresh; explicitly documented as non-runnable on the audit guest.", "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": 0, "guest_dirty": 0, "build_cmd": "cc -O2 -o race_harness race_harness.c (illustrative; NOT executed - guest lacks pccard hardware)", "run_cmd": "./race_harness /dev/ttyd0 & plus repeated pccardc power off/on 0 as root (NOT executed - no pccard on guest)", "code_hash": "a4aee224fa479b940d5ce73f24447b4fe9de46a65e46a20826d85bae4d88d9ac", "notes": "not_reproduced because the target bus does not exist on the audit guest (QEMU i440fx, no PCMCIA; grep -c pccard /var/run/dmesg.boot = 0), not because the code was exonerated - the race is proven by lock-protocol inspection. Guest reset with-src after the environment survey; guest left clean. Fix not validated for the same reason (cannot build a pccard device into existence); fix.diff is compile-reviewed only.", "recommended_fix": "Serialize sio_pccard_detach against the sio core: publish com->gone under tty_token, drop the token, callout_drain dtr_ch/busy_ch (callbacks take the token themselves), re-take the token for the teardown, and NULL com->ibuf/com->ibufold after kfree - see fix.diff", "fix_status": "not_testable", "fix_baseline_reproduced": false, "fix_patched_reproduced": false, "fix_verdict": "Fix validation impossible on the audit guest: no pccard hardware means no baseline detach event exists to race against, patched or unpatched. fix.diff is a lock-protocol-reviewed proposal (release-drain-retake ordering chosen because siodtrwakeup/siobusycheck acquire tty_token, so draining under the token would deadlock).", "fix_evidence": "n/a - no runnable baseline on guest" } |