No CCB timeout handler (callout block #if 0'd, 'XXX Need a timeout handler') plus ignored bus_dmamap error β lost commands wedge the SIM queue forever
Summary
trm_ExecuteSRB never arms ccb_h.timeout_ch - the only code is '#if 0 /* XXX Need a timeout handler */' and trmtimeout does not exist in the tree. A command accepted by a target but never completed (mid-phase stall; the selection-timeout path only covers selection) freezes the single-command-per-target SIM queue with no recovery. The dmamap callback also ignores its error argument, so a failed bus_dmamap_load orphans the CCB with no xpt_done - unrecoverable without a timeout. Any local I/O through trm(4) with a hung/unplugged/hostile SCSI target -> permanent queue wedge (local DoS until reboot).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3831 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.7 KB | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| verdict.json | β | 2.5 KB | view raw | |
| fix.diff | β | 2.3 KB | view raw | |
| env.txt | β | 1.1 KB | view raw | |
| manifest.json | β | 598 B | view raw |
DF-3831 β trm(4) has no CCB timeout handler (callout commented out) β lost commands wedge the SIM queue forever
- File:
sys/dev/disk/trm/trm.c(pass 2) - Class: CWE-1089 (missing recovery path / unbounded wait) β Local DoS
- Severity: Low (requires a hung/malicious SCSI target on a Tekram bus)
Build / Run / Expected
Hardware-gated (no Tekram HBA on the audit guest β env.txt). On hardware, the trigger is any command that is accepted by a target but never completed (device that stalls the data phase, yanked disk, malicious SCSI target emulation):
# start I/O through trm(4), then hang the target (or unplug it mid-transfer) dd if=/dev/da0 of=/dev/null bs=1m
Expected on vulnerable code: the CCB never times out β CAM's periph error recovery (which relies
on ccb_h.timeout_ch armed by the SIM) never fires; the trb SIM stays wedged until reboot.
Root cause
trm_ExecuteSRB β trm.c:470-474:
static void
trm_ExecuteSRB(...)
{
...
#if 0
/* XXX Need a timeout handler */
callout_reset(&ccb->ccb_h.timeout_ch, (ccb->ccb_h.timeout * hz) / 1000,
trmtimeout, srb);
#endif
trm_SendSRB(pACB, pSRB);
The driver author never implemented the timeout. There is also no ccb_h.timeout_ch
callout_stop in the completion path (trm_SRBdone) β consistent with it never being armed.
Aggravator: trm_ExecuteSRB ignores the error argument of the bus_dmamap callback
(trm.c:414) β if bus_dmamap_load fails (e.g. EFBIG for a >33-segment pass(4) buffer against
TRM_NSEG = btoc(MAXPHYS)+1, trm.h:98), the CCB is either orphaned (never queued, never done)
or run with zero data, and without a timeout there is no recovery in either case.
VERDICT β DF-3831
status: inconclusive (source-certain, hardware-gated) β reproduced: 0 β guest impact: none.
Trace
- The only timeout machinery in the whole driver is the
#if 0block at trm.c:470-474, annotated "XXX Need a timeout handler" βtrmtimeoutdoes not exist anywhere in the tree (grep -rn trmtimeout sys/-> only that comment). - CAM contract: the SIM arms
ccb->ccb_h.timeout_chwhen it accepts a CCB; the periph layer (da/pass) depends on that callout to drive error recovery. With it never armed, a command that the chip never completes (target stops responding mid-phase β the exact scenario the selection-timeout logic at trm.c:1217-1229 only partially covers: it handles selection timeouts, not mid-transfer stalls) leaves the SRB onpDCB->pGoingSRBforever and the SIM queue frozen forever (single-command-per-target activation, trm.c:338-376). - Aggravator (same no-recovery family): the
bus_dmamap_loadcallbacktrm_ExecuteSRB(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)at trm.c:414 never inspectserror. On a load failure the CCB is orphaned withoutxpt_doneβ and with no timeout there is no path that ever completes it -> permanent hang of that device queue plus a leaked SRB slot.
Why inconclusive, not false-positive
The missing callout is unambiguous in source (the author's own XXX concedes it). It cannot be exercised on the audit guest because trm(4) requires a Tekram DC395U/U2 PCI adapter (trm.c:3677-3688) and the guest has none (env.txt). On hardware the failure needs a hung/removed/malicious target β ordinary operational hazard for parallel SCSI.
Fix
fix.diff arms the ccb timeout callout in trm_ExecuteSRB, stops it in trm_SRBdone, adds the
missing error check for the dmamap callback (fail the CCB instead of orphaning it), and adds a
minimal trm_timeout that resets the bus (reusing the existing trm_reset machinery).
git-apply --check passes against sys/dev/disk/trm/trm.c.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableBoth baseline and patched runs need an attached Tekram adapter with a hangable target; absent on the audit guest. fix.diff is git-apply-able (verified).
fix.diff
Confirmed kernel references
Detail
Exploit chain
any local I/O through a trm(4) disk whose target hangs mid-phase -> CCB never times out -> SIM queue frozen permanently -> all I/O to that bus wedges (local DoS). No privilege gain.
Evidence (decisive lines)
VERDICT.md (trace of the #if 0 block and the ignored error arg); env.txt; fix.diff (arm/stop callout + trm_timeout + error check, git-apply --check passes)
PoC changes
No runnable PoC without the PCI card; pack is analysis + fix only.
Verified recommended fix
Arm ccb_h.timeout_ch in trm_ExecuteSRB, stop it in trm_SRBdone, add trm_timeout (bus reset), and fail the CCB when the dmamap callback reports error (fix.diff).
Verdict
trm(4) never arms the CAM CCB timeout: the callout_reset for ccb_h.timeout_ch is inside '#if 0 / XXX Need a timeout handler /' (sys/dev/disk/trm/trm.c:470-474) and no trm_timeout function exists in the tree. A command accepted by a target but never completed (mid-transfer stall, unplugged disk, hostile target emulator - the selection-timeout logic at trm.c:1217-1229 only covers selection, not mid-phase stalls) therefore wedges the single-command-per-target SIM queue forever with no recovery short of reboot. Aggravator: trm_ExecuteSRB ignores the bus_dmamap callback 'error' argument (trm.c:414), so a failed bus_dmamap_load (e.g. EFBIG for >TRM_NSEG=btoc(MAXPHYS)+1 segment pass(4) buffers, trm.h:98) orphans the CCB with no xpt_done - and with no timeout there is no path that ever completes it. Source-certain; hardware-gated (no Tekram PCI device on the audit guest, env.txt), hence inconclusive rather than reproduced.
No comments yet.