summaryrefslogtreecommitdiffstats
path: root/sys/scsi/scsi_base.c
diff options
context:
space:
mode:
authorkrw <krw@openbsd.org>2020-11-19 13:45:15 +0000
committerkrw <krw@openbsd.org>2020-11-19 13:45:15 +0000
commit6b0aba5f6f8c52d02f186834af6799be60afacd0 (patch)
treecc0824944e8466ec7acb51a04e4f7e79e099287d /sys/scsi/scsi_base.c
parentImplement address translation for bus_space_mmap(9). (diff)
downloadwireguard-openbsd-6b0aba5f6f8c52d02f186834af6799be60afacd0.tar.xz
wireguard-openbsd-6b0aba5f6f8c52d02f186834af6799be60afacd0.zip
TL;DR -- don't configure devices that return insufficient INQUIRY data.
Treat INQUIRY data with fewer than SID_SCSI2_HDRLEN bytes as invalid. Use only INQUIRY data returned by the device. Get all available INQUIRY data (up to sizeof(struct scsi_inquiry_data)) even when SCSIDEBUG is not set. Tweak returned INQUIRY data so additional_length field does not point past end of returned data when available data is greater than sizeof(struct scsi_inquiry_data). Missing dmafree() spotted by gnezdo@. ok jmatthew@.
Diffstat (limited to 'sys/scsi/scsi_base.c')
-rw-r--r--sys/scsi/scsi_base.c51
1 files changed, 27 insertions, 24 deletions
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
index dcd9f0e5544..2ba6a702fbc 100644
--- a/sys/scsi/scsi_base.c
+++ b/sys/scsi/scsi_base.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scsi_base.c,v 1.277 2020/10/14 23:40:33 krw Exp $ */
+/* $OpenBSD: scsi_base.c,v 1.278 2020/11/19 13:45:15 krw Exp $ */
/* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */
/*
@@ -841,7 +841,7 @@ scsi_inquire(struct scsi_link *link, struct scsi_inquiry_data *inqbuf,
{
struct scsi_xfer *xs;
size_t bytes;
- int error;
+ int avail, retries, error, received;
/*
* Start by asking for only the basic 36 bytes of SCSI2 inquiry
@@ -849,42 +849,45 @@ scsi_inquire(struct scsi_link *link, struct scsi_inquiry_data *inqbuf,
* supply more.
*/
bytes = SID_SCSI2_HDRLEN + SID_SCSI2_ALEN;
+ retries = 0;
-#ifdef SCSIDEBUG
again:
-#endif /* SCSIDEBUG */
xs = scsi_xs_get(link, flags);
if (xs == NULL)
return EBUSY;
+ if (bytes > sizeof(*inqbuf))
+ bytes = sizeof(*inqbuf);
scsi_init_inquiry(xs, 0, 0, inqbuf, bytes);
- bzero(inqbuf, sizeof(*inqbuf));
- memset(&inqbuf->vendor, ' ', sizeof inqbuf->vendor);
- memset(&inqbuf->product, ' ', sizeof inqbuf->product);
- memset(&inqbuf->revision, ' ', sizeof inqbuf->revision);
- memset(&inqbuf->extra, ' ', sizeof inqbuf->extra);
-
error = scsi_xs_sync(xs);
-
+ received = xs->datalen - xs->resid;
scsi_xs_put(xs);
-#ifdef SCSIDEBUG
- sc_print_addr(link);
- if (bytes > SID_SCSI2_HDRLEN + inqbuf->additional_length)
- bytes = SID_SCSI2_HDRLEN + inqbuf->additional_length;
- printf("got %zu of %u bytes of inquiry data:\n",
- bytes, SID_SCSI2_HDRLEN + inqbuf->additional_length);
- scsi_show_mem((u_char *)inqbuf, bytes);
- if (bytes == SID_SCSI2_HDRLEN + SID_SCSI2_ALEN && bytes <
- SID_SCSI2_HDRLEN + inqbuf->additional_length) {
- bytes = SID_SCSI2_HDRLEN + inqbuf->additional_length;
- if (bytes > sizeof(*inqbuf))
- bytes = sizeof(*inqbuf);
+ if (error != 0)
+ return error;
+ if (received < SID_SCSI2_HDRLEN)
+ return EINVAL;
+
+ avail = SID_SCSI2_HDRLEN + inqbuf->additional_length;
+
+ if (received < avail && retries == 0) {
+ retries++;
+ bytes = avail;
goto again;
}
+
+#ifdef SCSIDEBUG
+ sc_print_addr(link);
+ printf("got %d of %d bytes of inquiry data:\n", received,
+ avail);
+ scsi_show_mem((u_char *)inqbuf, received);
#endif /* SCSIDEBUG */
- return error;
+
+ if (avail > received)
+ inqbuf->additional_length = received - SID_SCSI2_HDRLEN;
+
+ return 0;
}
/*