| The commit is required by the fix for CVE-2021-41072. |
| |
| Upstream-Status: Backport [https://github.com/plougher/squashfs-tools/commit/9938154] |
| |
| Signed-off-by: Kai Kang <kai.kang@windriver.com> |
| |
| 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(-) |
| |
| diff --git a/squashfs-tools/unsquash-1.c b/squashfs-tools/unsquash-1.c |
| index d0121c6..b604434 100644 |
| --- a/squashfs-tools/unsquash-1.c |
| +++ b/squashfs-tools/unsquash-1.c |
| @@ -254,7 +254,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| long long start; |
| int bytes = 0; |
| int dir_count, size, res; |
| - 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", |
| @@ -267,7 +267,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| MEM_ERROR(); |
| |
| dir->dir_count = 0; |
| - dir->cur_entry = 0; |
| + dir->cur_entry = NULL; |
| dir->mode = (*i)->mode; |
| dir->uid = (*i)->uid; |
| dir->guid = (*i)->gid; |
| @@ -351,20 +351,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| "%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) |
| - MEM_ERROR(); |
| - |
| - dir->dirs = new_dir; |
| - } |
| + ent = malloc(sizeof(struct dir_ent)); |
| + if(ent == NULL) |
| + MEM_ERROR(); |
| |
| - 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->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; |
| } |
| diff --git a/squashfs-tools/unsquash-1234.c b/squashfs-tools/unsquash-1234.c |
| index ac46d9d..e389f8d 100644 |
| --- 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); |
| } |
| diff --git a/squashfs-tools/unsquash-2.c b/squashfs-tools/unsquash-2.c |
| index e847980..956f96f 100644 |
| --- a/squashfs-tools/unsquash-2.c |
| +++ b/squashfs-tools/unsquash-2.c |
| @@ -347,7 +347,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| long long start; |
| int bytes = 0; |
| int dir_count, size, res; |
| - 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", |
| @@ -360,7 +360,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| MEM_ERROR(); |
| |
| dir->dir_count = 0; |
| - dir->cur_entry = 0; |
| + dir->cur_entry = NULL; |
| dir->mode = (*i)->mode; |
| dir->uid = (*i)->uid; |
| dir->guid = (*i)->gid; |
| @@ -444,19 +444,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| "%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) |
| - MEM_ERROR(); |
| - dir->dirs = new_dir; |
| - } |
| + ent = malloc(sizeof(struct dir_ent)); |
| + if(ent == NULL) |
| + MEM_ERROR(); |
| |
| - 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->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; |
| } |
| diff --git a/squashfs-tools/unsquash-3.c b/squashfs-tools/unsquash-3.c |
| index 8223f27..835a574 100644 |
| --- a/squashfs-tools/unsquash-3.c |
| +++ b/squashfs-tools/unsquash-3.c |
| @@ -381,7 +381,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| long long start; |
| int bytes = 0; |
| int dir_count, size, res; |
| - 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", |
| @@ -394,7 +394,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| MEM_ERROR(); |
| |
| dir->dir_count = 0; |
| - dir->cur_entry = 0; |
| + dir->cur_entry = NULL; |
| dir->mode = (*i)->mode; |
| dir->uid = (*i)->uid; |
| dir->guid = (*i)->gid; |
| @@ -478,19 +478,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| "%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) |
| - MEM_ERROR(); |
| - dir->dirs = new_dir; |
| - } |
| + ent = malloc(sizeof(struct dir_ent)); |
| + if(ent == NULL) |
| + MEM_ERROR(); |
| |
| - 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->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; |
| } |
| diff --git a/squashfs-tools/unsquash-4.c b/squashfs-tools/unsquash-4.c |
| index 1e199a7..694783d 100644 |
| --- a/squashfs-tools/unsquash-4.c |
| +++ b/squashfs-tools/unsquash-4.c |
| @@ -331,7 +331,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer; |
| long long start; |
| int bytes = 0, dir_count, size, res; |
| - 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", |
| @@ -344,7 +344,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| MEM_ERROR(); |
| |
| dir->dir_count = 0; |
| - dir->cur_entry = 0; |
| + dir->cur_entry = NULL; |
| dir->mode = (*i)->mode; |
| dir->uid = (*i)->uid; |
| dir->guid = (*i)->gid; |
| @@ -415,19 +415,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse |
| "%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) |
| - MEM_ERROR(); |
| - dir->dirs = new_dir; |
| - } |
| + ent = malloc(sizeof(struct dir_ent)); |
| + if(ent == NULL) |
| + MEM_ERROR(); |
| |
| - 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->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; |
| } |
| diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c |
| index 04be53c..fee28ec 100644 |
| --- a/squashfs-tools/unsquashfs.c |
| +++ b/squashfs-tools/unsquashfs.c |
| @@ -1337,14 +1337,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; |
| } |
| diff --git a/squashfs-tools/unsquashfs.h b/squashfs-tools/unsquashfs.h |
| index 583fbe4..f8cf78c 100644 |
| --- a/squashfs-tools/unsquashfs.h |
| +++ b/squashfs-tools/unsquashfs.h |
| @@ -168,17 +168,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 { |
| -- |
| 2.17.1 |
| |