DF-3659 / trig_note.c
/* * DF-3659 - ISP_TSK_MGMT double FC_SCRATCH_RELEASE race (source note). * * Bug: sys/dev/disk/isp/isp_freebsd.c:662-669 (ispioctl, ISP_TSK_MGMT, * IS_24XX branch): * * retval = isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); * ... * FC_SCRATCH_RELEASE(isp, chan); // line 665 (release #1) * if (retval || sp->req_completion_status != 0) { * FC_SCRATCH_RELEASE(isp, chan); // line 667 (release #2!) * retval = EIO; * } * * FC_SCRATCH_RELEASE(isp, chan) expands to * `isp->isp_osinfo.pc.fc[chan].fcbsy = 0` (isp_freebsd.h:380). The second * call is unconditional on the error path even though the scratch was * already released one line earlier. If, between release #1 and #2, another * consumer (FC kthread fabric/portdb scan via isp_control(ISPCTL_SCAN_*), * or a concurrent ISP_TSK_MGMT/ISP_RESCAN ioctl) legitimately acquires the * scratch (fcbsy 0->1), release #2 clobbers its ownership and a third party * enters: two kernel contexts then share fcp->isp_scratch as the DMA target * of MBOX_EXEC_COMMAND_IOCB_A64 -> IOCB/response corruption. * * Trigger requirements: ISP 24xx/25xx HBA + root (cdev is 0600 root) issuing * a task-management ioctl that the firmware fails (e.g. IPT_TARGET_RESET to * an absent loop id) while the FC worker thread is mid-scan. None of this * exists on the audit guest (no QLogic PCI device). This file documents the * sequence; runtime reproduction requires the hardware. * * Compare isp.c's own TMF/reset paths (e.g. ISPCTL_RESET_DEV isp.c:4557-4581, * ISPCTL_ABORT_CMD isp.c:4658-4682): each releases exactly once per acquire, * on both success and error branches. */ int main(void) { return 0; } |