scsi: sd_zbc: Fix potential memory leak

Rework sd_zbc_check_zone_size() to avoid a memory leak due to an early
return if sd_zbc_report_zones() fails.

Reported-by: David.butterfield <david.butterfield@wdc.com>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Cc: stable@vger.kernel.org
Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Damien Le Moal 2018-03-02 07:19:28 +09:00 committed by Martin K. Petersen
parent 864449eea7
commit 4b433924b2
1 changed files with 15 additions and 20 deletions

View File

@ -486,7 +486,7 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
*/
static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
{
u64 zone_blocks;
u64 zone_blocks = 0;
sector_t block = 0;
unsigned char *buf;
unsigned char *rec;
@ -504,10 +504,8 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
/* Do a report zone to get the same field */
ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0);
if (ret) {
zone_blocks = 0;
goto out;
}
if (ret)
goto out_free;
same = buf[4] & 0x0f;
if (same > 0) {
@ -547,7 +545,7 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
ret = sd_zbc_report_zones(sdkp, buf,
SD_ZBC_BUF_SIZE, block);
if (ret)
return ret;
goto out_free;
}
} while (block < sdkp->capacity);
@ -555,35 +553,32 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
zone_blocks = sdkp->zone_blocks;
out:
kfree(buf);
if (!zone_blocks) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Devices with non constant zone "
"size are not supported\n");
return -ENODEV;
}
if (!is_power_of_2(zone_blocks)) {
ret = -ENODEV;
} else if (!is_power_of_2(zone_blocks)) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Devices with non power of 2 zone "
"size are not supported\n");
return -ENODEV;
}
if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
ret = -ENODEV;
} else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
if (sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp,
"Zone size too large\n");
return -ENODEV;
ret = -ENODEV;
} else {
sdkp->zone_blocks = zone_blocks;
sdkp->zone_shift = ilog2(zone_blocks);
}
sdkp->zone_blocks = zone_blocks;
sdkp->zone_shift = ilog2(zone_blocks);
out_free:
kfree(buf);
return 0;
return ret;
}
static int sd_zbc_setup(struct scsi_disk *sdkp)