aboutsummaryrefslogtreecommitdiff
path: root/hw/usb/dev-storage.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2022-08-30 08:38:27 +0200
committerGerd Hoffmann <kraxel@redhat.com>2022-09-27 07:32:30 +0200
commit12b69878fc7b4b92b1bbd3959f2c3d4c717881fb (patch)
tree63dc05ce5fb3aba25dffc251980849270a09da7e /hw/usb/dev-storage.c
parentcea5aa85691d7f26b7ea995417d41a32802691b7 (diff)
usb/msd: add usb_msd_fatal_error() and fix guest-triggerable assert
Add handler for fatal errors. Moves device into error state where it stops responding until the guest resets it. Guest can send illegal requests where scsi command and usb packet transfer directions are inconsistent. Use the new usb_msd_fatal_error() function instead of assert() in that case. Reported-by: Qiang Liu <cyruscyliu@gmail.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Tested-by: Qiang Liu <cyruscyliu@gmail.com> Message-Id: <20220830063827.813053-3-kraxel@redhat.com>
Diffstat (limited to 'hw/usb/dev-storage.c')
-rw-r--r--hw/usb/dev-storage.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 140ef2aeaa..e3bcffb3e0 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)