summaryrefslogtreecommitdiff
path: root/drivers/usb/storage
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/protocol.c3
-rw-r--r--drivers/usb/storage/sddr55.c6
-rw-r--r--drivers/usb/storage/transport.c16
-rw-r--r--drivers/usb/storage/uas.c30
-rw-r--r--drivers/usb/storage/unusual_devs.h2
-rw-r--r--drivers/usb/storage/unusual_uas.h2
6 files changed, 45 insertions, 14 deletions
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 9033e505db7f..0cff54ad90fa 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -139,8 +139,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
return cnt;
while (sg_miter_next(&miter) && cnt < buflen) {
- unsigned int len = min_t(unsigned int, miter.length,
- buflen - cnt);
+ unsigned int len = min(miter.length, buflen - cnt);
if (dir == FROM_XFER_BUF)
memcpy(buffer + cnt, miter.addr, len);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index b323f0a36260..9d813727e65f 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -469,6 +469,12 @@ static int sddr55_write_data(struct us_data *us,
new_pba = (status[3] + (status[4] << 8) + (status[5] << 16))
>> info->blockshift;
+ /* check if device-reported new_pba is out of range */
+ if (new_pba >= (info->capacity >> (info->blockshift + info->pageshift))) {
+ result = USB_STOR_TRANSPORT_FAILED;
+ goto leave;
+ }
+
/* check status for error */
if (status[0] == 0xff && status[1] == 0x4) {
info->pba_to_lba[new_pba] = BAD_BLOCK;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 1aa1bd26c81f..9a4bf86e7b6a 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1200,7 +1200,23 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
US_BULK_CS_WRAP_LEN &&
bcs->Signature ==
cpu_to_le32(US_BULK_CS_SIGN)) {
+ unsigned char buf[US_BULK_CS_WRAP_LEN];
+
usb_stor_dbg(us, "Device skipped data phase\n");
+
+ /*
+ * Devices skipping data phase might leave CSW data in srb's
+ * transfer buffer. Zero it to prevent USB protocol leakage.
+ */
+ sg = NULL;
+ offset = 0;
+ memset(buf, 0, sizeof(buf));
+ if (usb_stor_access_xfer_buf(buf,
+ US_BULK_CS_WRAP_LEN, srb, &sg,
+ &offset, TO_XFER_BUF) !=
+ US_BULK_CS_WRAP_LEN)
+ usb_stor_dbg(us, "Failed to clear CSW data\n");
+
scsi_set_resid(srb, transfer_length);
goto skipped_data_phase;
}
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 4ed0dc19afe0..73b1981cb1d5 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -309,18 +309,18 @@ static void uas_stat_cmplt(struct urb *urb)
int status = urb->status;
bool success;
- spin_lock_irqsave(&devinfo->lock, flags);
-
- if (devinfo->resetting)
- goto out;
-
if (status) {
if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN)
dev_err(&urb->dev->dev, "stat urb: status %d\n", status);
- goto out;
+ goto bail;
}
idx = be16_to_cpup(&iu->tag) - 1;
+
+ spin_lock_irqsave(&devinfo->lock, flags);
+
+ if (devinfo->resetting)
+ goto out;
if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) {
dev_err(&urb->dev->dev,
"stat urb: no pending cmd for uas-tag %d\n", idx + 1);
@@ -375,9 +375,8 @@ static void uas_stat_cmplt(struct urb *urb)
default:
uas_log_cmd_state(cmnd, "bogus IU", iu->iu_id);
}
-out:
- usb_free_urb(urb);
spin_unlock_irqrestore(&devinfo->lock, flags);
+ usb_free_urb(urb);
/* Unlinking of data urbs must be done without holding the lock */
if (data_in_urb) {
@@ -388,6 +387,12 @@ out:
usb_unlink_urb(data_out_urb);
usb_put_urb(data_out_urb);
}
+ return;
+
+out:
+ spin_unlock_irqrestore(&devinfo->lock, flags);
+bail:
+ usb_free_urb(urb);
}
static void uas_data_cmplt(struct urb *urb)
@@ -429,8 +434,8 @@ static void uas_data_cmplt(struct urb *urb)
}
uas_try_complete(cmnd, __func__);
out:
- usb_free_urb(urb);
spin_unlock_irqrestore(&devinfo->lock, flags);
+ usb_free_urb(urb);
}
static void uas_cmd_cmplt(struct urb *urb)
@@ -698,6 +703,10 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd)
* of queueing, no matter how fatal the error
*/
if (err == -ENODEV) {
+ if (cmdinfo->state & (COMMAND_INFLIGHT | DATA_IN_URB_INFLIGHT |
+ DATA_OUT_URB_INFLIGHT))
+ goto out;
+
set_host_byte(cmnd, DID_NO_CONNECT);
scsi_done(cmnd);
goto zombie;
@@ -711,6 +720,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd)
uas_add_work(cmnd);
}
+out:
devinfo->cmnd[idx] = cmnd;
zombie:
spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -1265,7 +1275,7 @@ static int __init uas_init(void)
{
int rv;
- workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM, 0);
+ workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!workqueue)
return -ENOMEM;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index dfa5276a5a43..47f50d7a385c 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -938,7 +938,7 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,
UNUSUAL_DEV( 0x0603, 0x8611, 0x0000, 0xffff,
"Novatek",
"NTK96550-based camera",
- USB_SC_SCSI, USB_PR_BULK, NULL,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BULK_IGNORE_TAG ),
/*
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index 1477e31d7763..b695f5ba9a40 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160,
US_FL_NO_ATA_1X),
/* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
-UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
+UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309,
"Initio Corporation",
"INIC-3069",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,