diff options
author | Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | 2021-11-01 18:35:15 +0000 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2021-11-02 15:57:27 +0100 |
commit | de7e2cb15586a61d26fc3983ba2cbcbc5c234e15 (patch) | |
tree | 6f192f6b4cd7936ab89612747715804a303ad771 | |
parent | cabf9862e42ffeab9de9b1bfa12cddaf125c53e8 (diff) | |
download | qemu-de7e2cb15586a61d26fc3983ba2cbcbc5c234e15.zip qemu-de7e2cb15586a61d26fc3983ba2cbcbc5c234e15.tar.gz qemu-de7e2cb15586a61d26fc3983ba2cbcbc5c234e15.tar.bz2 |
esp: ensure in-flight SCSI requests are always cancelled
There is currently a check in esp_select() to cancel any in-flight SCSI requests
to ensure that issuing multiple select commands without continuing through the
rest of the ESP state machine ignores all but the last SCSI request. This is
also enforced through the addition of assert()s in esp_transfer_data() and
scsi_read_data().
The get_cmd() function does not call esp_select() when TC == 0 which means it is
possible for a fuzzer to trigger these assert()s by sending a select command when
TC == 0 immediately after a valid SCSI CDB has been submitted.
Since esp_select() is only called from get_cmd(), hoist the check to cancel
in-flight SCSI requests from esp_select() into get_cmd() to ensure it is always
called when executing a select command to initiate a new SCSI request.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Closes: https://gitlab.com/qemu-project/qemu/-/issues/662
Closes: https://gitlab.com/qemu-project/qemu/-/issues/663
Message-Id: <20211101183516.8455-2-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | hw/scsi/esp.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 8454ed1..84f935b 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -204,11 +204,6 @@ static int esp_select(ESPState *s) s->ti_size = 0; fifo8_reset(&s->fifo); - if (s->current_req) { - /* Started a new command before the old one finished. Cancel it. */ - scsi_req_cancel(s->current_req); - } - s->current_dev = scsi_device_find(&s->bus, 0, target, 0); if (!s->current_dev) { /* No such drive */ @@ -235,6 +230,11 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen) uint32_t dmalen, n; int target; + if (s->current_req) { + /* Started a new command before the old one finished. Cancel it. */ + scsi_req_cancel(s->current_req); + } + target = s->wregs[ESP_WBUSID] & BUSID_DID; if (s->dma) { dmalen = MIN(esp_get_tc(s), maxlen); |