[SCSI] fix bugs in scsi_vpd_inquiry()
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Tue, 11 Aug 2009 15:59:09 +0000 (10:59 -0500)
committerJames Bottomley <James.Bottomley@suse.de>
Sat, 22 Aug 2009 22:52:23 +0000 (17:52 -0500)
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>
drivers/scsi/scsi.c

index 2de5f3ad640b2da78eba5401454c8415f44841e4..b6e03074cb8f9bff620f47b8838e0345d16f1c2c 100644 (file)
@@ -994,7 +994,7 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
         * all the existing users tried this hard.
         */
        result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
-                                 len + 4, NULL, 30 * HZ, 3, NULL);
+                                 len, NULL, 30 * HZ, 3, NULL);
        if (result)
                return result;
 
@@ -1021,13 +1021,14 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
 {
        int i, result;
        unsigned int len;
-       unsigned char *buf = kmalloc(259, GFP_KERNEL);
+       const unsigned int init_vpd_len = 255;
+       unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
 
        if (!buf)
                return NULL;
 
        /* Ask for all the pages supported by this device */
-       result = scsi_vpd_inquiry(sdev, buf, 0, 255);
+       result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len);
        if (result)
                goto fail;
 
@@ -1050,12 +1051,12 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
         * Some pages are longer than 255 bytes.  The actual length of
         * the page is returned in the header.
         */
-       len = (buf[2] << 8) | buf[3];
-       if (len <= 255)
+       len = ((buf[2] << 8) | buf[3]) + 4;
+       if (len <= init_vpd_len)
                return buf;
 
        kfree(buf);
-       buf = kmalloc(len + 4, GFP_KERNEL);
+       buf = kmalloc(len, GFP_KERNEL);
        result = scsi_vpd_inquiry(sdev, buf, page, len);
        if (result)
                goto fail;