DF-3985 / fix.diff
--- a/sys/dev/disk/sbp/sbp.c +++ b/sys/dev/disk/sbp/sbp.c @@ -1982,6 +1982,9 @@ if (sdev == NULL) return; + /* login_callout is armed by sbp_login(); it must never be left + * pending when the sdev is freed (DF-3981 use-after-free). */ + callout_stop(&sdev->login_callout); for (i = 0; i < SBP_QUEUE_LEN; i++) bus_dmamap_destroy(sdev->target->sbp->dmat, sdev->ocb[i].dmamap); @@ -1995,21 +1998,24 @@ struct fw_xfer *xfer, *next; int i; - if (target->luns == NULL) - return; + /* also reached for luns == NULL: release the target slot (DF-3985) + * and stop both callouts so nothing dangles */ + callout_stop(&target->scan_callout); callout_stop(&target->mgm_ocb_timeout); - for (i = 0; i < target->num_lun; i++) - sbp_free_sdev(target->luns[i]); + if (target->luns != NULL) { + for (i = 0; i < target->num_lun; i++) + sbp_free_sdev(target->luns[i]); - for (xfer = STAILQ_FIRST(&target->xferlist); - xfer != NULL; xfer = next) { - next = STAILQ_NEXT(xfer, link); - fw_xfer_free_buf(xfer); + for (xfer = STAILQ_FIRST(&target->xferlist); + xfer != NULL; xfer = next) { + next = STAILQ_NEXT(xfer, link); + fw_xfer_free_buf(xfer); + } + STAILQ_INIT(&target->xferlist); + kfree(target->luns, M_SBP); + target->num_lun = 0; + target->luns = NULL; } - STAILQ_INIT(&target->xferlist); - kfree(target->luns, M_SBP); - target->num_lun = 0; - target->luns = NULL; target->fwdev = NULL; } |