diff options
author | 2020-11-19 13:45:15 +0000 | |
---|---|---|
committer | 2020-11-19 13:45:15 +0000 | |
commit | 6b0aba5f6f8c52d02f186834af6799be60afacd0 (patch) | |
tree | cc0824944e8466ec7acb51a04e4f7e79e099287d /sys/scsi/scsi_base.c | |
parent | Implement address translation for bus_space_mmap(9). (diff) | |
download | wireguard-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.c | 51 |
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; } /* |