aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/scsi/scsi.c40
-rw-r--r--drivers/scsi/sd.c26
-rw-r--r--drivers/scsi/ses.c10
-rw-r--r--include/scsi/scsi_device.h3
4 files changed, 36 insertions, 43 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
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 255da53e5a01..c5e9a99d4066 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1946,13 +1946,13 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
1946{ 1946{
1947 struct request_queue *q = sdkp->disk->queue; 1947 struct request_queue *q = sdkp->disk->queue;
1948 unsigned int sector_sz = sdkp->device->sector_size; 1948 unsigned int sector_sz = sdkp->device->sector_size;
1949 char *buffer; 1949 const int vpd_len = 32;
1950 unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
1950 1951
1951 /* Block Limits VPD */ 1952 if (!buffer ||
1952 buffer = scsi_get_vpd_page(sdkp->device, 0xb0); 1953 /* Block Limits VPD */
1953 1954 scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
1954 if (buffer == NULL) 1955 goto out;
1955 return;
1956 1956
1957 blk_queue_io_min(sdkp->disk->queue, 1957 blk_queue_io_min(sdkp->disk->queue,
1958 get_unaligned_be16(&buffer[6]) * sector_sz); 1958 get_unaligned_be16(&buffer[6]) * sector_sz);
@@ -1984,6 +1984,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
1984 get_unaligned_be32(&buffer[32]) & ~(1 << 31); 1984 get_unaligned_be32(&buffer[32]) & ~(1 << 31);
1985 } 1985 }
1986 1986
1987 out:
1987 kfree(buffer); 1988 kfree(buffer);
1988} 1989}
1989 1990
@@ -1993,20 +1994,23 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
1993 */ 1994 */
1994static void sd_read_block_characteristics(struct scsi_disk *sdkp) 1995static void sd_read_block_characteristics(struct scsi_disk *sdkp)
1995{ 1996{
1996 char *buffer; 1997 unsigned char *buffer;
1997 u16 rot; 1998 u16 rot;
1999 const int vpd_len = 32;
1998 2000
1999 /* Block Device Characteristics VPD */ 2001 buffer = kmalloc(vpd_len, GFP_KERNEL);
2000 buffer = scsi_get_vpd_page(sdkp->device, 0xb1);
2001 2002
2002 if (buffer == NULL) 2003 if (!buffer ||
2003 return; 2004 /* Block Device Characteristics VPD */
2005 scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len))
2006 goto out;
2004 2007
2005 rot = get_unaligned_be16(&buffer[4]); 2008 rot = get_unaligned_be16(&buffer[4]);
2006 2009
2007 if (rot == 1) 2010 if (rot == 1)
2008 queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue); 2011 queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
2009 2012
2013 out:
2010 kfree(buffer); 2014 kfree(buffer);
2011} 2015}
2012 2016
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 55b034b72708..1d7a8780e00c 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -448,13 +448,17 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
448 .addr = 0, 448 .addr = 0,
449 }; 449 };
450 450
451 buf = scsi_get_vpd_page(sdev, 0x83); 451 buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
452 if (!buf) 452 if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE))
453 return; 453 goto free;
454 454
455 ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); 455 ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
456 456
457 vpd_len = ((buf[2] << 8) | buf[3]) + 4; 457 vpd_len = ((buf[2] << 8) | buf[3]) + 4;
458 kfree(buf);
459 buf = kmalloc(vpd_len, GFP_KERNEL);
460 if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len))
461 goto free;
458 462
459 desc = buf + 4; 463 desc = buf + 4;
460 while (desc < buf + vpd_len) { 464 while (desc < buf + vpd_len) {
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 7c4449900c24..d80b6dbed1ca 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -348,7 +348,8 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
348 struct scsi_sense_hdr *); 348 struct scsi_sense_hdr *);
349extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, 349extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
350 int retries, struct scsi_sense_hdr *sshdr); 350 int retries, struct scsi_sense_hdr *sshdr);
351extern unsigned char *scsi_get_vpd_page(struct scsi_device *, u8 page); 351extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf,
352 int buf_len);
352extern int scsi_device_set_state(struct scsi_device *sdev, 353extern int scsi_device_set_state(struct scsi_device *sdev,
353 enum scsi_device_state state); 354 enum scsi_device_state state);
354extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, 355extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,