IOCATADETACH/ATTACH/REINIT dispatched unserialized: double channel teardown (double bus_teardown_intr/bus_release_resource/lockuninit) -> sysref_put panic
Summary
The three channel-control ioctls share no lock; ata_detach check-then-acts on ch->r_irq, so concurrent DETACH runs teardown twice (483x unregister_int warnings with corrupted handler names = freed-memory reads), and racing REINIT uses locks a detach destroyed. REPRODUCED on guest: sysref_put assertion panic via destroy_only_dev on channel 1 at ~30s. Distinct from DF-1643: even legitimate privileged concurrent use is unsafe. Fix validated PARTIAL: channel 0 fully clean; channel 1 residual = async disk(9)-core thread needing subr_disk.c synchronization (documented).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4476 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| ata_detach_race.c | poc | 2x detach + attach + reinit threads | 2.8 KB | view raw |
| serial_a2_panic.log | panic | sysref_put assertion capture | 78.0 KB | view raw |
| run.log | run-log | 3 baseline runs | 1.0 KB | view raw |
| fix.diff | suggested-fix | ioctl serialization lock | 2.3 KB | view raw |
| fix_run_ch0.log | run-log | patched ch0: 0 unregister_int | 1.2 KB | view raw |
| fix_run_ch1_panic.serial.txt | panic | patched ch1 residual variant | 1001 B | view raw |
| env.txt | env | guest/kernel info | 314 B | view raw |
Fix verification
fix_failedPARTIAL: fix.diff adds ata_channel_ctl_lock across the three ioctl bodies (build rc=0). Channel 0: baseline 483 unregister_int warnings -> 0 on patched kernel, 356/355/163 racing ops survive. Channel 1: STILL panics via destroy_only_dev <- disk_msg_core (asynchronous disk(9)-core thread racing the newbus child teardown) - a second actor the ioctl-level lock cannot serialize; complete fix requires disk-layer synchronization in kern/subr_disk.c.
fix_run_ch0.log (clean); fix_run_ch1_panic.serial.txt (residual panic trace)
Confirmed kernel references
Detail
Exploit chain
operator/root opens /dev/ata -> 2x IOCATADETACH + IOCATAATTACH + IOCATAREINIT threads on channel 1 -> racing device_delete_child/bus_teardown_intr/lockuninit -> double destroy_only_dev on the same cdev -> panic at db>. Corruption artifacts (garbage handler names) show freed-memory reads in the IRQ teardown path.
Evidence (decisive lines)
serial_a2_panic.log (baseline sysref panic + destroy_only_dev stack + 483 unregister_int lines); run.log (3 baseline runs incl. corrupted-name warnings); fix_run_ch0.log (patched: 0 unregister_int, survived); fix_run_ch1_panic.serial.txt (patched: still panics via disk_msg_core variant)
PoC changes
authored fresh; ioctl constants built with _IOC/_IOW verified against sys/sys/nata.h
Verified recommended fix
Serialize the channel-control ioctls AND synchronize child cdev destruction with the disk-core thread (ioctl lock alone is partial - see fix validation)
Verdict
IOCATADETACH/IOCATAATTACH/IOCATAREINIT are dispatched with no serialization (ata-all.c:369-447); ata_detach is an unlocked check-then-act on ch->r_irq. Concurrent ioctls double-teardown the channel (483 unregister_int warnings, later with corrupted device names = freed-memory reads) and on channels with disk children hit destroy_only_dev twice -> panic: sysref_put SRF_PUTAWAY assertion, 30s into the channel-1 run.
No comments yet.