diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 140ef2aeaa80e181afbe260863b9bea4aee44e9c..e3bcffb3e0d7d434c45b15c97b1a376bf563b282 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -191,6 +191,23 @@ static void usb_msd_packet_complete(MSDState *s) usb_packet_complete(&s->dev, p); } +static void usb_msd_fatal_error(MSDState *s) +{ + trace_usb_msd_fatal_error(); + + if (s->packet) { + s->packet->status = USB_RET_STALL; + usb_msd_packet_complete(s); + } + + /* + * Guest messed up up device state with illegal requests. Go + * ignore any requests until the guests resets the device (and + * brings it into a known state that way). + */ + s->needs_reset = true; +} + static void usb_msd_copy_data(MSDState *s, USBPacket *p) { uint32_t len; @@ -227,7 +244,11 @@ void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; - assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); + if ((s->mode == USB_MSDM_DATAOUT) != (req->cmd.mode == SCSI_XFER_TO_DEV)) { + usb_msd_fatal_error(s); + return; + } + s->scsi_len = len; s->scsi_off = 0; if (p) { @@ -317,6 +338,8 @@ void usb_msd_handle_reset(USBDevice *dev) memset(&s->csw, 0, sizeof(s->csw)); s->mode = USB_MSDM_CBW; + + s->needs_reset = false; } static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, @@ -382,6 +405,11 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) SCSIDevice *scsi_dev; uint32_t len; + if (s->needs_reset) { + p->status = USB_RET_STALL; + return; + } + switch (p->pid) { case USB_TOKEN_OUT: if (devep != 2) diff --git a/hw/usb/trace-events b/hw/usb/trace-events index 914ca71668293659bd8a6ff2731757a143955df8..b65269892c5e1f2ca4975659d8848cb8ba2f0fa5 100644 --- a/hw/usb/trace-events +++ b/hw/usb/trace-events @@ -263,6 +263,7 @@ usb_msd_packet_complete(void) "" usb_msd_cmd_submit(unsigned lun, unsigned tag, unsigned flags, unsigned len, unsigned data_len) "lun %u, tag 0x%x, flags 0x%08x, len %d, data-len %d" usb_msd_cmd_complete(unsigned status, unsigned tag) "status %d, tag 0x%x" usb_msd_cmd_cancel(unsigned tag) "tag 0x%x" +usb_msd_fatal_error(void) "" # dev-uas.c usb_uas_reset(int addr) "dev %d" diff --git a/include/hw/usb/msd.h b/include/hw/usb/msd.h index 54e9f38bda463b8c932bf24363a1a12e9ada98b0..f9fd862b529a70cb4a3c97bdb2a17d4a378913ab 100644 --- a/include/hw/usb/msd.h +++ b/include/hw/usb/msd.h @@ -40,6 +40,7 @@ struct MSDState { bool removable; bool commandlog; SCSIDevice *scsi_dev; + bool needs_reset; }; typedef struct MSDState MSDState;