The commit is required by the fix for CVE-2021-41072. Update context for version 4.4. Upstream-Status: Backport [https://github.com/plougher/squashfs-tools/commit/9938154] Signed-off-by: Kai Kang From 9938154174756ee48a94ea0b076397a2944b028d Mon Sep 17 00:00:00 2001 From: Phillip Lougher 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 --- 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 @@ -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; } 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 @@ -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; } 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 @@ -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; } 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 @@ -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; } 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 @@ -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; } 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 @@ -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 { -- 2.17.1