squashfs-tools/0008-CVE-2021-41072.patch
2021-11-09 20:42:27 +08:00

307 lines
9.2 KiB
Diff

From 9938154174756ee48a94ea0b076397a2944b028d Mon Sep 17 00:00:00 2001
From: Phillip Lougher <phillip@squashfs.org.uk>
Date: Sun, 12 Sep 2021 22:58:11 +0100
Subject: [PATCH] unsquashfs: use linked list to store directory names
This should bring higher performance, and it allows sorting
if necessary (1.x and 2.0 filesystems).
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
---
squashfs-tools/unsquash-1.c | 30 +++++++++++++++---------------
squashfs-tools/unsquash-1234.c | 12 ++++++++----
squashfs-tools/unsquash-2.c | 29 +++++++++++++++--------------
squashfs-tools/unsquash-3.c | 29 +++++++++++++++--------------
squashfs-tools/unsquash-4.c | 29 +++++++++++++++--------------
squashfs-tools/unsquashfs.c | 16 ++++++++++------
squashfs-tools/unsquashfs.h | 3 ++-
7 files changed, 80 insertions(+), 68 deletions(-)
--- a/squashfs-tools/unsquash-1.c
+++ b/squashfs-tools/unsquash-1.c
@@ -207,7 +207,7 @@ static struct dir *squashfs_opendir(unsi
long long start;
int bytes;
int dir_count, size;
- struct dir_ent *new_dir;
+ struct dir_ent *ent, *cur_ent = NULL;
struct dir *dir;
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
@@ -220,7 +220,7 @@ static struct dir *squashfs_opendir(unsi
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
dir->dir_count = 0;
- dir->cur_entry = 0;
+ dir->cur_entry = NULL;
dir->mode = (*i)->mode;
dir->uid = (*i)->uid;
dir->guid = (*i)->gid;
@@ -295,19 +295,20 @@ static struct dir *squashfs_opendir(unsi
TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
- if((dir->dir_count % DIR_ENT_SIZE) == 0) {
- new_dir = realloc(dir->dirs, (dir->dir_count +
- DIR_ENT_SIZE) * sizeof(struct dir_ent));
- if(new_dir == NULL)
- EXIT_UNSQUASH("squashfs_opendir: "
- "realloc failed!\n");
- dir->dirs = new_dir;
- }
- dir->dirs[dir->dir_count].name = strdup(dire->name);
- dir->dirs[dir->dir_count].start_block =
- dirh.start_block;
- dir->dirs[dir->dir_count].offset = dire->offset;
- dir->dirs[dir->dir_count].type = dire->type;
+ ent = malloc(sizeof(struct dir_ent));
+ if(ent == NULL)
+ MEM_ERROR();
+
+ ent->name = strdup(dire->name);
+ ent->start_block = dirh.start_block;
+ ent->offset = dire->offset;
+ ent->type = dire->type;
+ ent->next = NULL;
+ if(cur_ent == NULL)
+ dir->dirs = ent;
+ else
+ cur_ent->next = ent;
+ cur_ent = ent;
dir->dir_count ++;
bytes += dire->size + 1;
}
--- a/squashfs-tools/unsquash-1234.c
+++ b/squashfs-tools/unsquash-1234.c
@@ -60,11 +60,15 @@ int check_name(char *name, int size)
void squashfs_closedir(struct dir *dir)
{
- int i;
+ struct dir_ent *ent = dir->dirs;
- for(i = 0; i < dir->dir_count; i++)
- free(dir->dirs[i].name);
+ while(ent) {
+ struct dir_ent *tmp = ent;
+
+ ent = ent->next;
+ free(tmp->name);
+ free(tmp);
+ }
- free(dir->dirs);
free(dir);
}
--- a/squashfs-tools/unsquash-2.c
+++ b/squashfs-tools/unsquash-2.c
@@ -308,7 +308,7 @@ static struct dir *squashfs_opendir(unsi
long long start;
int bytes;
int dir_count, size;
- struct dir_ent *new_dir;
+ struct dir_ent *ent, *cur_ent = NULL;
struct dir *dir;
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
@@ -321,7 +321,7 @@ static struct dir *squashfs_opendir(unsi
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
dir->dir_count = 0;
- dir->cur_entry = 0;
+ dir->cur_entry = NULL;
dir->mode = (*i)->mode;
dir->uid = (*i)->uid;
dir->guid = (*i)->gid;
@@ -396,19 +396,20 @@ static struct dir *squashfs_opendir(unsi
TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
- if((dir->dir_count % DIR_ENT_SIZE) == 0) {
- new_dir = realloc(dir->dirs, (dir->dir_count +
- DIR_ENT_SIZE) * sizeof(struct dir_ent));
- if(new_dir == NULL)
- EXIT_UNSQUASH("squashfs_opendir: "
- "realloc failed!\n");
- dir->dirs = new_dir;
- }
- dir->dirs[dir->dir_count].name = strdup(dire->name);
- dir->dirs[dir->dir_count].start_block =
- dirh.start_block;
- dir->dirs[dir->dir_count].offset = dire->offset;
- dir->dirs[dir->dir_count].type = dire->type;
+ ent = malloc(sizeof(struct dir_ent));
+ if(ent == NULL)
+ MEM_ERROR();
+
+ ent->name = strdup(dire->name);
+ ent->start_block = dirh.start_block;
+ ent->offset = dire->offset;
+ ent->type = dire->type;
+ ent->next = NULL;
+ if(cur_ent == NULL)
+ dir->dirs = ent;
+ else
+ cur_ent->next = ent;
+ cur_ent = ent;
dir->dir_count ++;
bytes += dire->size + 1;
}
--- a/squashfs-tools/unsquash-3.c
+++ b/squashfs-tools/unsquash-3.c
@@ -334,7 +334,7 @@ static struct dir *squashfs_opendir(unsi
long long start;
int bytes;
int dir_count, size;
- struct dir_ent *new_dir;
+ struct dir_ent *ent, *cur_ent = NULL;
struct dir *dir;
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
@@ -347,7 +347,7 @@ static struct dir *squashfs_opendir(unsi
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
dir->dir_count = 0;
- dir->cur_entry = 0;
+ dir->cur_entry = NULL;
dir->mode = (*i)->mode;
dir->uid = (*i)->uid;
dir->guid = (*i)->gid;
@@ -423,19 +423,20 @@ static struct dir *squashfs_opendir(unsi
TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
- if((dir->dir_count % DIR_ENT_SIZE) == 0) {
- new_dir = realloc(dir->dirs, (dir->dir_count +
- DIR_ENT_SIZE) * sizeof(struct dir_ent));
- if(new_dir == NULL)
- EXIT_UNSQUASH("squashfs_opendir: "
- "realloc failed!\n");
- dir->dirs = new_dir;
- }
- dir->dirs[dir->dir_count].name = strdup(dire->name);
- dir->dirs[dir->dir_count].start_block =
- dirh.start_block;
- dir->dirs[dir->dir_count].offset = dire->offset;
- dir->dirs[dir->dir_count].type = dire->type;
+ ent = malloc(sizeof(struct dir_ent));
+ if(ent == NULL)
+ MEM_ERROR();
+
+ ent->name = strdup(dire->name);
+ ent->start_block = dirh.start_block;
+ ent->offset = dire->offset;
+ ent->type = dire->type;
+ ent->next = NULL;
+ if(cur_ent == NULL)
+ dir->dirs = ent;
+ else
+ cur_ent->next = ent;
+ cur_ent = ent;
dir->dir_count ++;
bytes += dire->size + 1;
}
--- a/squashfs-tools/unsquash-4.c
+++ b/squashfs-tools/unsquash-4.c
@@ -281,7 +281,7 @@ static struct dir *squashfs_opendir(unsi
long long start;
long long bytes;
int dir_count, size;
- struct dir_ent *new_dir;
+ struct dir_ent *ent, *cur_ent = NULL;
struct dir *dir;
TRACE("squashfs_opendir: inode start block %d, offset %d\n",
@@ -294,7 +294,7 @@ static struct dir *squashfs_opendir(unsi
EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");
dir->dir_count = 0;
- dir->cur_entry = 0;
+ dir->cur_entry = NULL;
dir->mode = (*i)->mode;
dir->uid = (*i)->uid;
dir->guid = (*i)->gid;
@@ -359,19 +359,20 @@ static struct dir *squashfs_opendir(unsi
TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
- if((dir->dir_count % DIR_ENT_SIZE) == 0) {
- new_dir = realloc(dir->dirs, (dir->dir_count +
- DIR_ENT_SIZE) * sizeof(struct dir_ent));
- if(new_dir == NULL)
- EXIT_UNSQUASH("squashfs_opendir: "
- "realloc failed!\n");
- dir->dirs = new_dir;
- }
- dir->dirs[dir->dir_count].name = strdup(dire->name);
- dir->dirs[dir->dir_count].start_block =
- dirh.start_block;
- dir->dirs[dir->dir_count].offset = dire->offset;
- dir->dirs[dir->dir_count].type = dire->type;
+ ent = malloc(sizeof(struct dir_ent));
+ if(ent == NULL)
+ MEM_ERROR();
+
+ ent->name = strdup(dire->name);
+ ent->start_block = dirh.start_block;
+ ent->offset = dire->offset;
+ ent->type = dire->type;
+ ent->next = NULL;
+ if(cur_ent == NULL)
+ dir->dirs = ent;
+ else
+ cur_ent->next = ent;
+ cur_ent = ent;
dir->dir_count ++;
bytes += dire->size + 1;
}
--- a/squashfs-tools/unsquashfs.c
+++ b/squashfs-tools/unsquashfs.c
@@ -1277,14 +1277,18 @@ failed:
int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block,
unsigned int *offset, unsigned int *type)
{
- if(dir->cur_entry == dir->dir_count)
+ if(dir->cur_entry == NULL)
+ dir->cur_entry = dir->dirs;
+ else
+ dir->cur_entry = dir->cur_entry->next;
+
+ if(dir->cur_entry == NULL)
return FALSE;
- *name = dir->dirs[dir->cur_entry].name;
- *start_block = dir->dirs[dir->cur_entry].start_block;
- *offset = dir->dirs[dir->cur_entry].offset;
- *type = dir->dirs[dir->cur_entry].type;
- dir->cur_entry ++;
+ *name = dir->cur_entry->name;
+ *start_block = dir->cur_entry->start_block;
+ *offset = dir->cur_entry->offset;
+ *type = dir->cur_entry->type;
return TRUE;
}
--- a/squashfs-tools/unsquashfs.h
+++ b/squashfs-tools/unsquashfs.h
@@ -169,17 +169,18 @@ struct dir_ent {
unsigned int start_block;
unsigned int offset;
unsigned int type;
+ struct dir_ent *next;
};
struct dir {
int dir_count;
- int cur_entry;
unsigned int mode;
uid_t uid;
gid_t guid;
unsigned int mtime;
unsigned int xattr;
struct dir_ent *dirs;
+ struct dir_ent *cur_entry;
};
struct file_entry {