β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3710

arcmsr_srb_timeout vs interrupt completion: unsynchronized srb_state check-then-act double-completes one CCB (double xpt_done, srboutstandingcount underflow)

Summary

The timeout callout runs with isr_lock held (callout_init_lk, CALLOUT_AUTOLOCK) but the hardware interrupt handler calls arcmsr_interrupt() with NO lock - the two contexts both check-then-act on srb->srb_state with no common serialization. A completion landing while the timeout handler is between its guard and its state write runs arcmsr_srb_complete() twice for one pccb: double xpt_done (CAM double-completion panic/periph corruption), double srboutstandingcount decrement (underflow breaking queue-freeze logic), and double dmamap sync/unload; the reverse interleave overwrites srb_state of an already-recycled free-list slot. DF-3673 (mpt) callout-vs-completion class. VERIFIED: pthread model of the exact unsynchronized state machines - phase A forced interleave -> 'xpt_done called 2 time(s); srboutstandingcount = -1'; phase B 2M natural iterations -> ~1.66M double-completions, proving no synchronization excludes the interleaving. Fix validated on rebuilt kernel (acquire isr_lock in the handler).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3710 Β· 9 files
FileTypeDescriptionSize
harness.c trigger-source pthread model of arcmsr_srb_timeout vs arcmsr_drain_donequeue unsynchronized check-then-act on srb_state 4.7 KB view raw
build.sh build cc -O2 -Wall -pthread -o harness harness.c 65 B view raw
run.sh run executes harness (phase A forced, phase B 2M natural iterations) 89 B view raw
build.log log untrimmed guest build output 66 B view raw
run.log log decisive run: forced double-complete + 1658716/2000000 natural races 410 B view raw
run.2.log log repeat run: 1681935/2000000 410 B view raw
fix.diff fix serialize arcmsr_intr_handler under acb->isr_lock (the callout's CALLOUT_AUTOLOCK) 612 B view raw
fix_build.log log patched-source kernel build log (arcmsr.c compiled -Werror clean, in-kernel + KLD) 870 B view raw
env.txt env guest uname/compiler/no-HW evidence 643 B view raw

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

fix.diff (isr_lock in arcmsr_intr_handler) applied to guest /usr/src copy; arcmsr.c recompiled clean with -Werror in-kernel and KLD builds (fix_build.log). On-hardware behavioral validation impossible in this guest.

fix_build.log arcmsr compile lines with -Werror and 0 arcmsr-related errors; serialization visible at arcmsr.c:2337-2338 in guest tree before restore
↓ fix.diffper-fix-DF-3710

Confirmed kernel references

Detail

Exploit chain

unprivileged disk I/O on arcmsr volume + hung command -> 60s+ timeout callout racing the late interrupt completion -> double xpt_done of one ccb -> CAM periph corruption/panic; no deterministic uid=0 chain (timing window is microseconds against a 60s period)

Evidence (decisive lines)

run.log: 'phase A (forced interleave): xpt_done called 2 time(s) for one ccb; srboutstandingcount = -1 (started at 1)'; 'phase B ... 1658716 double-completions'; run.2.log: 1681935; VERDICT.md traces all cited kernel lines

PoC changes

authored from scratch (no seed)

Verified recommended fix

acquire acb->isr_lock in arcmsr_intr_handler() around arcmsr_interrupt() so the ISR serializes with the timeout callout (which already holds it); optionally add atomic_cmpset claim of srb_state in both paths

Verdict

arcmsr_srb_timeout() (callout context, isr_lock held via CALLOUT_AUTOLOCK at arcmsr.c:2875) and arcmsr_drain_donequeue() (hardware-interrupt context, arcmsr_intr_handler() at arcmsr.c:2323-2328 takes NO lock) run check-then-act on srb->srb_state with no common serialization. A completion landing while the timeout handler is between its guard (arcmsr.c:856) and its state write (:859) makes arcmsr_srb_complete() run twice for one CCB: double xpt_done(pccb) (:752), double srboutstandingcount decrement (:741, underflow), double dmamap sync/unload; the reverse interleave overwrites srb_state of an already-recycled free-list slot. Pthread model of the exact unsynchronized state machine on the guest: forced interleave yields xpt_done x2 and counter -1; 1.66M/2M natural iterations double-complete, proving no synchronization excludes the interleaving. In-driver manifestation needs an Areca HBA (guest has none) plus a completion coinciding with the 60s+ timeout -- rare but load-dependent, reachable through ordinary unprivileged disk I/O during error recovery. Realistic impact: CAM double-completion panic (DoS); corruption of CAM periph state.