diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-08-11 11:59:09 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-08-22 18:52:23 -0400 |
commit | 95a3639e275fb7aec5c9a2116c88a2cdd23e0b8b (patch) | |
tree | 115b3d4fecf7e9089000c9f4bf5558be99670bf0 /drivers/scsi/scsi.c | |
parent | 5f91bb050ecc4ff1d8d3d07edbe550c8f431c5e1 (diff) |
[SCSI] fix bugs in scsi_vpd_inquiry()
Universally, SCSI functions assume the lengths fed in are those of the buffer
to DMA data to, not the lengths of the data minus the header.
scsi_vpd_inquiry() assumed the latter and got it wrong, so fix up all the
functions to use the correct assumption (and fix a bug where INQUIRY in SCSI-2
dcannot go over 255).
[jejb: Matthew posted an identical version of this at the same time I did]
Signed-off-by: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r-- | drivers/scsi/scsi.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2de5f3ad640b..b6e03074cb8f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -994,7 +994,7 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, | |||
994 | * all the existing users tried this hard. | 994 | * all the existing users tried this hard. |
995 | */ | 995 | */ |
996 | result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, | 996 | result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, |
997 | len + 4, NULL, 30 * HZ, 3, NULL); | 997 | len, NULL, 30 * HZ, 3, NULL); |
998 | if (result) | 998 | if (result) |
999 | return result; | 999 | return result; |
1000 | 1000 | ||
@@ -1021,13 +1021,14 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) | |||
1021 | { | 1021 | { |
1022 | int i, result; | 1022 | int i, result; |
1023 | unsigned int len; | 1023 | unsigned int len; |
1024 | unsigned char *buf = kmalloc(259, GFP_KERNEL); | 1024 | const unsigned int init_vpd_len = 255; |
1025 | unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL); | ||
1025 | 1026 | ||
1026 | if (!buf) | 1027 | if (!buf) |
1027 | return NULL; | 1028 | return NULL; |
1028 | 1029 | ||
1029 | /* Ask for all the pages supported by this device */ | 1030 | /* Ask for all the pages supported by this device */ |
1030 | result = scsi_vpd_inquiry(sdev, buf, 0, 255); | 1031 | result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); |
1031 | if (result) | 1032 | if (result) |
1032 | goto fail; | 1033 | goto fail; |
1033 | 1034 | ||
@@ -1050,12 +1051,12 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) | |||
1050 | * Some pages are longer than 255 bytes. The actual length of | 1051 | * Some pages are longer than 255 bytes. The actual length of |
1051 | * the page is returned in the header. | 1052 | * the page is returned in the header. |
1052 | */ | 1053 | */ |
1053 | len = (buf[2] << 8) | buf[3]; | 1054 | len = ((buf[2] << 8) | buf[3]) + 4; |
1054 | if (len <= 255) | 1055 | if (len <= init_vpd_len) |
1055 | return buf; | 1056 | return buf; |
1056 | 1057 | ||
1057 | kfree(buf); | 1058 | kfree(buf); |
1058 | buf = kmalloc(len + 4, GFP_KERNEL); | 1059 | buf = kmalloc(len, GFP_KERNEL); |
1059 | result = scsi_vpd_inquiry(sdev, buf, page, len); | 1060 | result = scsi_vpd_inquiry(sdev, buf, page, len); |
1060 | if (result) | 1061 | if (result) |
1061 | goto fail; | 1062 | goto fail; |