diff options
author | James Bottomley <James.Bottomley@suse.de> | 2009-11-03 13:33:07 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-01-18 11:48:05 -0500 |
commit | e3deec090558d5cb5ffdc574e5560f3ed9723394 (patch) | |
tree | c76a5e26a3e08598ada0a2de34adcdf714aa7168 | |
parent | 534ef056db8a8fb6b9d50188d88ed5d1fbc66673 (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.c | 40 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 26 | ||||
-rw-r--r-- | drivers/scsi/ses.c | 10 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 3 |
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 | */ |
1029 | unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page) | 1029 | int 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 | } |
1079 | EXPORT_SYMBOL_GPL(scsi_get_vpd_page); | 1063 | EXPORT_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 | */ |
1994 | static void sd_read_block_characteristics(struct scsi_disk *sdkp) | 1995 | static 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 *); |
349 | extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, | 349 | extern 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); |
351 | extern unsigned char *scsi_get_vpd_page(struct scsi_device *, u8 page); | 351 | extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, |
352 | int buf_len); | ||
352 | extern int scsi_device_set_state(struct scsi_device *sdev, | 353 | extern int scsi_device_set_state(struct scsi_device *sdev, |
353 | enum scsi_device_state state); | 354 | enum scsi_device_state state); |
354 | extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, | 355 | extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, |