aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@suse.de>2009-11-03 13:33:07 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-01-18 11:48:05 -0500
commite3deec090558d5cb5ffdc574e5560f3ed9723394 (patch)
treec76a5e26a3e08598ada0a2de34adcdf714aa7168 /drivers/scsi/scsi.c
parent534ef056db8a8fb6b9d50188d88ed5d1fbc66673 (diff)
[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,
1026 * responsible for calling kfree() on this pointer when it is no longer 1026 * responsible for calling kfree() on this pointer when it is no longer
1027 * needed. If we cannot retrieve the VPD page this routine returns %NULL. 1027 * needed. If we cannot retrieve the VPD page this routine returns %NULL.
1028 */ 1028 */
1029unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) 1029int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
1030 int buf_len)
1030{ 1031{
1031 int i, result; 1032 int i, result;
1032 unsigned int len;
1033 const unsigned int init_vpd_len = 255;
1034 unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
1035
1036 if (!buf)
1037 return NULL;
1038 1033
1039 /* Ask for all the pages supported by this device */ 1034 /* Ask for all the pages supported by this device */
1040 result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len); 1035 result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
1041 if (result) 1036 if (result)
1042 goto fail; 1037 goto fail;
1043 1038
1044 /* If the user actually wanted this page, we can skip the rest */ 1039 /* If the user actually wanted this page, we can skip the rest */
1045 if (page == 0) 1040 if (page == 0)
1046 return buf; 1041 return -EINVAL;
1047 1042
1048 for (i = 0; i < buf[3]; i++) 1043 for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
1049 if (buf[i + 4] == page) 1044 if (buf[i + 4] == page)
1050 goto found; 1045 goto found;
1046
1047 if (i < buf[3] && i > buf_len)
1048 /* ran off the end of the buffer, give us benefit of doubt */
1049 goto found;
1051 /* The device claims it doesn't support the requested page */ 1050 /* The device claims it doesn't support the requested page */
1052 goto fail; 1051 goto fail;
1053 1052
1054 found: 1053 found:
1055 result = scsi_vpd_inquiry(sdev, buf, page, 255); 1054 result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
1056 if (result) 1055 if (result)
1057 goto fail; 1056 goto fail;
1058 1057
1059 /* 1058 return 0;
1060 * Some pages are longer than 255 bytes. The actual length of
1061 * the page is returned in the header.
1062 */
1063 len = ((buf[2] << 8) | buf[3]) + 4;
1064 if (len <= init_vpd_len)
1065 return buf;
1066
1067 kfree(buf);
1068 buf = kmalloc(len, GFP_KERNEL);
1069 result = scsi_vpd_inquiry(sdev, buf, page, len);
1070 if (result)
1071 goto fail;
1072
1073 return buf;
1074 1059
1075 fail: 1060 fail:
1076 kfree(buf); 1061 return -EINVAL;
1077 return NULL;
1078} 1062}
1079EXPORT_SYMBOL_GPL(scsi_get_vpd_page); 1063EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
1080 1064