summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/squashfs/sqfs.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/fs/squashfs/sqfs.c b/fs/squashfs/sqfs.c
index 0768fc4a7b2..55fbe1bcc1a 100644
--- a/fs/squashfs/sqfs.c
+++ b/fs/squashfs/sqfs.c
@@ -496,6 +496,8 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
/* get directory offset in directory table */
offset = sqfs_dir_offset(table, m_list, m_count);
+ if (offset < 0)
+ return offset;
dirs->table = &dirs->dir_table[offset];
/* Setup directory header */
@@ -545,8 +547,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
/* Get reference to inode in the inode table */
table = sqfs_find_inode(dirs->inode_table, new_inode_number,
sblk->inodes, sblk->block_size);
- if (!table)
- return -EINVAL;
+ if (!table) {
+ ret = -EINVAL;
+ goto out;
+ }
dir = (struct squashfs_dir_inode *)table;
/* Check for symbolic link and inode type sanity */
@@ -615,8 +619,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
goto out;
} else if (!sqfs_is_dir(get_unaligned_le16(&dir->inode_type))) {
printf("** Cannot find directory. **\n");
- free(dirs->entry);
- dirs->entry = NULL;
ret = -EINVAL;
goto out;
}
@@ -627,6 +629,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
/* Get dir. offset into the directory table */
offset = sqfs_dir_offset(table, m_list, m_count);
+ if (offset < 0) {
+ ret = offset;
+ goto out;
+ }
dirs->table = &dirs->dir_table[offset];
/* Copy directory header */
@@ -636,8 +642,6 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
/* Check for empty directory */
if (sqfs_is_empty_dir(table)) {
printf("Empty directory.\n");
- free(dirs->entry);
- dirs->entry = NULL;
ret = SQFS_EMPTY_DIR;
goto out;
}
@@ -651,6 +655,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
}
offset = sqfs_dir_offset(table, m_list, m_count);
+ if (offset < 0) {
+ ret = offset;
+ goto out;
+ }
dirs->table = &dirs->dir_table[offset];
if (get_unaligned_le16(&dir->inode_type) == SQFS_DIR_TYPE)
@@ -659,6 +667,10 @@ static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
memcpy(&dirs->i_ldir, ldir, sizeof(*ldir));
out:
+ if (ret < 0) {
+ free(dirs->entry);
+ dirs->entry = NULL;
+ }
free(res);
free(rem);
free(path);
@@ -853,12 +865,16 @@ static int sqfs_read_directory_table(unsigned char **dir_table, u32 **pos_list)
goto out;
*dir_table = malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE);
- if (!*dir_table)
+ if (!*dir_table) {
+ metablks_count = -1;
goto out;
+ }
*pos_list = malloc(metablks_count * sizeof(u32));
- if (!*pos_list)
+ if (!*pos_list) {
+ metablks_count = -1;
goto out;
+ }
ret = sqfs_get_metablk_pos(*pos_list, dtb, table_offset,
metablks_count);
@@ -1473,6 +1489,15 @@ static int sqfs_read_nest(const char *filename, void *buf, loff_t offset,
symlink = (struct squashfs_symlink_inode *)ipos;
resolved = sqfs_resolve_symlink(symlink, filename);
+ /*
+ * Free the parent directory resources before recursing so that
+ * the recursive call can allocate its own inode and directory
+ * tables without exhausting the heap.
+ */
+ free(dirs->entry);
+ dirs->entry = NULL;
+ sqfs_closedir(dirsp);
+ dirsp = NULL;
ret = sqfs_read_nest(resolved, buf, offset, len, actread);
free(resolved);
goto out;
@@ -1731,6 +1756,11 @@ static int sqfs_size_nest(const char *filename, loff_t *size)
symlink = (struct squashfs_symlink_inode *)ipos;
resolved = sqfs_resolve_symlink(symlink, filename);
+ /*
+ * Free the parent directory resources before recursing.
+ */
+ sqfs_closedir(dirsp);
+ dirsp = NULL;
ret = sqfs_size(resolved, size);
free(resolved);
break;