fs/squashfs: sqfs_read: fix memory leak on finfo.blk_sizes

finfo.blk_sizes may not be freed in case of error in the for loop
Setting it to null and freeing it at the end makes prevents that from
happening.

Reviewed-by: Joao Marcos Costa <jmcosta944@gmail.com>
Signed-off-by: Richard Genoud <richard.genoud@posteo.net>
This commit is contained in:
Richard Genoud 2020-11-03 12:11:18 +01:00 committed by Tom Rini
parent 33686804d2
commit 571b67ee1d

View File

@ -1305,8 +1305,8 @@ static int sqfs_get_lregfile_info(struct squashfs_lreg_inode *lreg,
int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len, int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
loff_t *actread) loff_t *actread)
{ {
char *dir, *fragment_block, *datablock = NULL, *data_buffer = NULL; char *dir = NULL, *fragment_block, *datablock = NULL, *data_buffer = NULL;
char *fragment, *file, *resolved, *data; char *fragment = NULL, *file = NULL, *resolved, *data;
u64 start, n_blks, table_size, data_offset, table_offset; u64 start, n_blks, table_size, data_offset, table_offset;
int ret, j, i_number, datablk_count = 0; int ret, j, i_number, datablk_count = 0;
struct squashfs_super_block *sblk = ctxt.sblk; struct squashfs_super_block *sblk = ctxt.sblk;
@ -1331,7 +1331,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
sqfs_split_path(&file, &dir, filename); sqfs_split_path(&file, &dir, filename);
ret = sqfs_opendir(dir, &dirsp); ret = sqfs_opendir(dir, &dirsp);
if (ret) { if (ret) {
goto free_paths; goto out;
} }
dirs = (struct squashfs_dir_stream *)dirsp; dirs = (struct squashfs_dir_stream *)dirsp;
@ -1350,7 +1350,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
printf("File not found.\n"); printf("File not found.\n");
*actread = 0; *actread = 0;
ret = -ENOENT; ret = -ENOENT;
goto free_paths; goto out;
} }
i_number = dirs->dir_header->inode_number + dirs->entry->inode_offset; i_number = dirs->dir_header->inode_number + dirs->entry->inode_offset;
@ -1365,7 +1365,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
sblk->block_size); sblk->block_size);
if (datablk_count < 0) { if (datablk_count < 0) {
ret = -EINVAL; ret = -EINVAL;
goto free_paths; goto out;
} }
memcpy(finfo.blk_sizes, ipos + sizeof(*reg), memcpy(finfo.blk_sizes, ipos + sizeof(*reg),
@ -1378,7 +1378,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
sblk->block_size); sblk->block_size);
if (datablk_count < 0) { if (datablk_count < 0) {
ret = -EINVAL; ret = -EINVAL;
goto free_paths; goto out;
} }
memcpy(finfo.blk_sizes, ipos + sizeof(*lreg), memcpy(finfo.blk_sizes, ipos + sizeof(*lreg),
@ -1390,7 +1390,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
resolved = sqfs_resolve_symlink(symlink, filename); resolved = sqfs_resolve_symlink(symlink, filename);
ret = sqfs_read(resolved, buf, offset, len, actread); ret = sqfs_read(resolved, buf, offset, len, actread);
free(resolved); free(resolved);
goto free_paths; goto out;
case SQFS_BLKDEV_TYPE: case SQFS_BLKDEV_TYPE:
case SQFS_CHRDEV_TYPE: case SQFS_CHRDEV_TYPE:
case SQFS_LBLKDEV_TYPE: case SQFS_LBLKDEV_TYPE:
@ -1402,14 +1402,14 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
default: default:
printf("Unsupported entry type\n"); printf("Unsupported entry type\n");
ret = -EINVAL; ret = -EINVAL;
goto free_paths; goto out;
} }
/* If the user specifies a length, check its sanity */ /* If the user specifies a length, check its sanity */
if (len) { if (len) {
if (len > finfo.size) { if (len > finfo.size) {
ret = -EINVAL; ret = -EINVAL;
goto free_paths; goto out;
} }
finfo.size = len; finfo.size = len;
@ -1420,7 +1420,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
datablock = malloc(get_unaligned_le32(&sblk->block_size)); datablock = malloc(get_unaligned_le32(&sblk->block_size));
if (!datablock) { if (!datablock) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_paths; goto out;
} }
} }
@ -1435,7 +1435,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
if (!data_buffer) { if (!data_buffer) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_datablk; goto out;
} }
ret = sqfs_disk_read(start, n_blks, data_buffer); ret = sqfs_disk_read(start, n_blks, data_buffer);
@ -1446,7 +1446,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
* image with mksquashfs's -b <block_size> option. * image with mksquashfs's -b <block_size> option.
*/ */
printf("Error: too many data blocks to be read.\n"); printf("Error: too many data blocks to be read.\n");
goto free_buffer; goto out;
} }
data = data_buffer + table_offset; data = data_buffer + table_offset;
@ -1457,7 +1457,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
ret = sqfs_decompress(&ctxt, datablock, &dest_len, ret = sqfs_decompress(&ctxt, datablock, &dest_len,
data, table_size); data, table_size);
if (ret) if (ret)
goto free_buffer; goto out;
memcpy(buf + offset + *actread, datablock, dest_len); memcpy(buf + offset + *actread, datablock, dest_len);
*actread += dest_len; *actread += dest_len;
@ -1471,14 +1471,12 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
data_buffer = NULL; data_buffer = NULL;
} }
free(finfo.blk_sizes);
/* /*
* There is no need to continue if the file is not fragmented. * There is no need to continue if the file is not fragmented.
*/ */
if (!finfo.frag) { if (!finfo.frag) {
ret = 0; ret = 0;
goto free_buffer; goto out;
} }
start = frag_entry.start / ctxt.cur_dev->blksz; start = frag_entry.start / ctxt.cur_dev->blksz;
@ -1490,12 +1488,12 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
if (!fragment) { if (!fragment) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_buffer; goto out;
} }
ret = sqfs_disk_read(start, n_blks, fragment); ret = sqfs_disk_read(start, n_blks, fragment);
if (ret < 0) if (ret < 0)
goto free_fragment; goto out;
/* File compressed and fragmented */ /* File compressed and fragmented */
if (finfo.frag && finfo.comp) { if (finfo.frag && finfo.comp) {
@ -1503,7 +1501,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
fragment_block = malloc(dest_len); fragment_block = malloc(dest_len);
if (!fragment_block) { if (!fragment_block) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_fragment; goto out;
} }
ret = sqfs_decompress(&ctxt, fragment_block, &dest_len, ret = sqfs_decompress(&ctxt, fragment_block, &dest_len,
@ -1511,7 +1509,7 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
frag_entry.size); frag_entry.size);
if (ret) { if (ret) {
free(fragment_block); free(fragment_block);
goto free_fragment; goto out;
} }
for (j = offset + *actread; j < finfo.size; j++) { for (j = offset + *actread; j < finfo.size; j++) {
@ -1530,17 +1528,15 @@ int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
} }
} }
free_fragment: out:
free(fragment); free(fragment);
free_buffer: if (datablk_count) {
if (datablk_count)
free(data_buffer); free(data_buffer);
free_datablk:
if (datablk_count)
free(datablock); free(datablock);
free_paths: }
free(file); free(file);
free(dir); free(dir);
free(finfo.blk_sizes);
sqfs_closedir(dirsp); sqfs_closedir(dirsp);
return ret; return ret;