[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>
This commit is contained in:
Родитель
534ef056db
Коммит
e3deec0905
|
@ -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
|
* responsible for calling kfree() on this pointer when it is no longer
|
||||||
* needed. If we cannot retrieve the VPD page this routine returns %NULL.
|
* 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;
|
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 */
|
/* 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)
|
if (result)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* If the user actually wanted this page, we can skip the rest */
|
/* If the user actually wanted this page, we can skip the rest */
|
||||||
if (page == 0)
|
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)
|
if (buf[i + 4] == page)
|
||||||
goto found;
|
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 */
|
/* The device claims it doesn't support the requested page */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
result = scsi_vpd_inquiry(sdev, buf, page, 255);
|
result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
|
||||||
if (result)
|
if (result)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/*
|
return 0;
|
||||||
* 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;
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
kfree(buf);
|
return -EINVAL;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
|
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
|
||||||
|
|
||||||
|
|
|
@ -1946,13 +1946,13 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
|
||||||
{
|
{
|
||||||
struct request_queue *q = sdkp->disk->queue;
|
struct request_queue *q = sdkp->disk->queue;
|
||||||
unsigned int sector_sz = sdkp->device->sector_size;
|
unsigned int sector_sz = sdkp->device->sector_size;
|
||||||
char *buffer;
|
const int vpd_len = 32;
|
||||||
|
unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
|
||||||
|
|
||||||
/* Block Limits VPD */
|
if (!buffer ||
|
||||||
buffer = scsi_get_vpd_page(sdkp->device, 0xb0);
|
/* Block Limits VPD */
|
||||||
|
scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
|
||||||
if (buffer == NULL)
|
goto out;
|
||||||
return;
|
|
||||||
|
|
||||||
blk_queue_io_min(sdkp->disk->queue,
|
blk_queue_io_min(sdkp->disk->queue,
|
||||||
get_unaligned_be16(&buffer[6]) * sector_sz);
|
get_unaligned_be16(&buffer[6]) * sector_sz);
|
||||||
|
@ -1984,6 +1984,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
|
||||||
get_unaligned_be32(&buffer[32]) & ~(1 << 31);
|
get_unaligned_be32(&buffer[32]) & ~(1 << 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
kfree(buffer);
|
kfree(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1993,20 +1994,23 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
|
||||||
*/
|
*/
|
||||||
static void sd_read_block_characteristics(struct scsi_disk *sdkp)
|
static void sd_read_block_characteristics(struct scsi_disk *sdkp)
|
||||||
{
|
{
|
||||||
char *buffer;
|
unsigned char *buffer;
|
||||||
u16 rot;
|
u16 rot;
|
||||||
|
const int vpd_len = 32;
|
||||||
|
|
||||||
/* Block Device Characteristics VPD */
|
buffer = kmalloc(vpd_len, GFP_KERNEL);
|
||||||
buffer = scsi_get_vpd_page(sdkp->device, 0xb1);
|
|
||||||
|
|
||||||
if (buffer == NULL)
|
if (!buffer ||
|
||||||
return;
|
/* Block Device Characteristics VPD */
|
||||||
|
scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len))
|
||||||
|
goto out;
|
||||||
|
|
||||||
rot = get_unaligned_be16(&buffer[4]);
|
rot = get_unaligned_be16(&buffer[4]);
|
||||||
|
|
||||||
if (rot == 1)
|
if (rot == 1)
|
||||||
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
|
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue);
|
||||||
|
|
||||||
|
out:
|
||||||
kfree(buffer);
|
kfree(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,13 +448,17 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
|
||||||
.addr = 0,
|
.addr = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
buf = scsi_get_vpd_page(sdev, 0x83);
|
buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
|
||||||
if (!buf)
|
if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE))
|
||||||
return;
|
goto free;
|
||||||
|
|
||||||
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
|
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
|
||||||
|
|
||||||
vpd_len = ((buf[2] << 8) | buf[3]) + 4;
|
vpd_len = ((buf[2] << 8) | buf[3]) + 4;
|
||||||
|
kfree(buf);
|
||||||
|
buf = kmalloc(vpd_len, GFP_KERNEL);
|
||||||
|
if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len))
|
||||||
|
goto free;
|
||||||
|
|
||||||
desc = buf + 4;
|
desc = buf + 4;
|
||||||
while (desc < buf + vpd_len) {
|
while (desc < buf + vpd_len) {
|
||||||
|
|
|
@ -348,7 +348,8 @@ extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
|
||||||
struct scsi_sense_hdr *);
|
struct scsi_sense_hdr *);
|
||||||
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
|
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
|
||||||
int retries, struct scsi_sense_hdr *sshdr);
|
int retries, struct scsi_sense_hdr *sshdr);
|
||||||
extern unsigned char *scsi_get_vpd_page(struct scsi_device *, u8 page);
|
extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf,
|
||||||
|
int buf_len);
|
||||||
extern int scsi_device_set_state(struct scsi_device *sdev,
|
extern int scsi_device_set_state(struct scsi_device *sdev,
|
||||||
enum scsi_device_state state);
|
enum scsi_device_state state);
|
||||||
extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
|
extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче