summaryrefslogtreecommitdiff
path: root/drivers/scsi/scsi.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2009-11-03 12:33:07 -0600
committerJames Bottomley <James.Bottomley@suse.de>2010-01-18 10:48:05 -0600
commite3deec090558d5cb5ffdc574e5560f3ed9723394 (patch)
treec76a5e26a3e08598ada0a2de34adcdf714aa7168 /drivers/scsi/scsi.c
parent534ef056db8a8fb6b9d50188d88ed5d1fbc66673 (diff)
downloadlwn-e3deec090558d5cb5ffdc574e5560f3ed9723394.tar.gz
lwn-e3deec090558d5cb5ffdc574e5560f3ed9723394.zip
[SCSI] eliminate potential kmalloc failure in scsi_get_vpd_page()
The best way to fix this is to eliminate the intenal kmalloc() and make the caller allocate the required amount of storage. Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r--drivers/scsi/scsi.c40
1 files changed, 12 insertions, 28 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a60da5555577..513661f45e5f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1026,55 +1026,39 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
* responsible for calling kfree() on this pointer when it is no longer
* needed. If we cannot retrieve the VPD page this routine returns %NULL.
*/
-unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
+int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
+ int buf_len)
{
int i, result;
- unsigned int len;
- 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, init_vpd_len);
+ result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
if (result)
goto fail;
/* If the user actually wanted this page, we can skip the rest */
if (page == 0)
- return buf;
+ return -EINVAL;
- for (i = 0; i < buf[3]; i++)
+ for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
if (buf[i + 4] == page)
goto found;
+
+ if (i < buf[3] && i > buf_len)
+ /* ran off the end of the buffer, give us benefit of doubt */
+ goto found;
/* The device claims it doesn't support the requested page */
goto fail;
found:
- result = scsi_vpd_inquiry(sdev, buf, page, 255);
+ result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
if (result)
goto fail;
- /*
- * Some pages are longer than 255 bytes. The actual length of
- * the page is returned in the header.
- */
- len = ((buf[2] << 8) | buf[3]) + 4;
- if (len <= init_vpd_len)
- return buf;
-
- kfree(buf);
- buf = kmalloc(len, GFP_KERNEL);
- result = scsi_vpd_inquiry(sdev, buf, page, len);
- if (result)
- goto fail;
-
- return buf;
+ return 0;
fail:
- kfree(buf);
- return NULL;
+ return -EINVAL;
}
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);