diff options
author | smh <smh@FreeBSD.org> | 2014-12-21 16:43:56 +0000 |
---|---|---|
committer | smh <smh@FreeBSD.org> | 2014-12-21 16:43:56 +0000 |
commit | 5f92f0907a2e4697198dd62d1d9ecc01f3c548a0 (patch) | |
tree | 1d51567670b493587db37695b4ae26347d92543c /sys/dev/ahci | |
parent | 3b6e56e0bc47caf7b4d5edad6c18cd5e0773d5fa (diff) | |
download | FreeBSD-src-5f92f0907a2e4697198dd62d1d9ecc01f3c548a0.zip FreeBSD-src-5f92f0907a2e4697198dd62d1d9ecc01f3c548a0.tar.gz |
MFC r272223:
Prevent possible use after free in ahci direct mode
Sponsored by: Multiplay
Diffstat (limited to 'sys/dev/ahci')
-rw-r--r-- | sys/dev/ahci/ahci.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index ce54c77..9a925ea 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -1580,6 +1580,7 @@ ahci_ch_intr_direct(void *arg) struct ahci_channel *ch = device_get_softc(dev); struct ccb_hdr *ccb_h; uint32_t istatus; + STAILQ_HEAD(, ccb_hdr) tmp_doneq = STAILQ_HEAD_INITIALIZER(tmp_doneq); /* Read interrupt statuses. */ istatus = ATA_INL(ch->r_mem, AHCI_P_IS); @@ -1590,9 +1591,14 @@ ahci_ch_intr_direct(void *arg) ch->batch = 1; ahci_ch_intr_main(ch, istatus); ch->batch = 0; + /* + * Prevent the possibility of issues caused by processing the queue + * while unlocked below by moving the contents to a local queue. + */ + STAILQ_CONCAT(&tmp_doneq, &ch->doneq); mtx_unlock(&ch->mtx); - while ((ccb_h = STAILQ_FIRST(&ch->doneq)) != NULL) { - STAILQ_REMOVE_HEAD(&ch->doneq, sim_links.stqe); + while ((ccb_h = STAILQ_FIRST(&tmp_doneq)) != NULL) { + STAILQ_REMOVE_HEAD(&tmp_doneq, sim_links.stqe); xpt_done_direct((union ccb *)ccb_h); } } |