1The commit is required by the fix for CVE-2021-41072. 2 3Upstream-Status: Backport [https://github.com/plougher/squashfs-tools/commit/9938154] 4 5Signed-off-by: Kai Kang <kai.kang@windriver.com> 6 7From 9938154174756ee48a94ea0b076397a2944b028d Mon Sep 17 00:00:00 2001 8From: Phillip Lougher <phillip@squashfs.org.uk> 9Date: Sun, 12 Sep 2021 22:58:11 +0100 10Subject: [PATCH] unsquashfs: use linked list to store directory names 11 12This should bring higher performance, and it allows sorting 13if necessary (1.x and 2.0 filesystems). 14 15Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk> 16--- 17 squashfs-tools/unsquash-1.c | 30 +++++++++++++++--------------- 18 squashfs-tools/unsquash-1234.c | 12 ++++++++---- 19 squashfs-tools/unsquash-2.c | 29 +++++++++++++++-------------- 20 squashfs-tools/unsquash-3.c | 29 +++++++++++++++-------------- 21 squashfs-tools/unsquash-4.c | 29 +++++++++++++++-------------- 22 squashfs-tools/unsquashfs.c | 16 ++++++++++------ 23 squashfs-tools/unsquashfs.h | 3 ++- 24 7 files changed, 80 insertions(+), 68 deletions(-) 25 26diff --git a/squashfs-tools/unsquash-1.c b/squashfs-tools/unsquash-1.c 27index d0121c6..b604434 100644 28--- a/squashfs-tools/unsquash-1.c 29+++ b/squashfs-tools/unsquash-1.c 30@@ -254,7 +254,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 31 long long start; 32 int bytes = 0; 33 int dir_count, size, res; 34- struct dir_ent *new_dir; 35+ struct dir_ent *ent, *cur_ent = NULL; 36 struct dir *dir; 37 38 TRACE("squashfs_opendir: inode start block %d, offset %d\n", 39@@ -267,7 +267,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 40 MEM_ERROR(); 41 42 dir->dir_count = 0; 43- dir->cur_entry = 0; 44+ dir->cur_entry = NULL; 45 dir->mode = (*i)->mode; 46 dir->uid = (*i)->uid; 47 dir->guid = (*i)->gid; 48@@ -351,20 +351,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 49 "%d:%d, type %d\n", dire->name, 50 dirh.start_block, dire->offset, dire->type); 51 52- if((dir->dir_count % DIR_ENT_SIZE) == 0) { 53- new_dir = realloc(dir->dirs, (dir->dir_count + 54- DIR_ENT_SIZE) * sizeof(struct dir_ent)); 55- if(new_dir == NULL) 56- MEM_ERROR(); 57- 58- dir->dirs = new_dir; 59- } 60+ ent = malloc(sizeof(struct dir_ent)); 61+ if(ent == NULL) 62+ MEM_ERROR(); 63 64- dir->dirs[dir->dir_count].name = strdup(dire->name); 65- dir->dirs[dir->dir_count].start_block = 66- dirh.start_block; 67- dir->dirs[dir->dir_count].offset = dire->offset; 68- dir->dirs[dir->dir_count].type = dire->type; 69+ ent->name = strdup(dire->name); 70+ ent->start_block = dirh.start_block; 71+ ent->offset = dire->offset; 72+ ent->type = dire->type; 73+ ent->next = NULL; 74+ if(cur_ent == NULL) 75+ dir->dirs = ent; 76+ else 77+ cur_ent->next = ent; 78+ cur_ent = ent; 79 dir->dir_count ++; 80 bytes += dire->size + 1; 81 } 82diff --git a/squashfs-tools/unsquash-1234.c b/squashfs-tools/unsquash-1234.c 83index ac46d9d..e389f8d 100644 84--- a/squashfs-tools/unsquash-1234.c 85+++ b/squashfs-tools/unsquash-1234.c 86@@ -60,11 +60,15 @@ int check_name(char *name, int size) 87 88 void squashfs_closedir(struct dir *dir) 89 { 90- int i; 91+ struct dir_ent *ent = dir->dirs; 92 93- for(i = 0; i < dir->dir_count; i++) 94- free(dir->dirs[i].name); 95+ while(ent) { 96+ struct dir_ent *tmp = ent; 97+ 98+ ent = ent->next; 99+ free(tmp->name); 100+ free(tmp); 101+ } 102 103- free(dir->dirs); 104 free(dir); 105 } 106diff --git a/squashfs-tools/unsquash-2.c b/squashfs-tools/unsquash-2.c 107index e847980..956f96f 100644 108--- a/squashfs-tools/unsquash-2.c 109+++ b/squashfs-tools/unsquash-2.c 110@@ -347,7 +347,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 111 long long start; 112 int bytes = 0; 113 int dir_count, size, res; 114- struct dir_ent *new_dir; 115+ struct dir_ent *ent, *cur_ent = NULL; 116 struct dir *dir; 117 118 TRACE("squashfs_opendir: inode start block %d, offset %d\n", 119@@ -360,7 +360,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 120 MEM_ERROR(); 121 122 dir->dir_count = 0; 123- dir->cur_entry = 0; 124+ dir->cur_entry = NULL; 125 dir->mode = (*i)->mode; 126 dir->uid = (*i)->uid; 127 dir->guid = (*i)->gid; 128@@ -444,19 +444,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 129 "%d:%d, type %d\n", dire->name, 130 dirh.start_block, dire->offset, dire->type); 131 132- if((dir->dir_count % DIR_ENT_SIZE) == 0) { 133- new_dir = realloc(dir->dirs, (dir->dir_count + 134- DIR_ENT_SIZE) * sizeof(struct dir_ent)); 135- if(new_dir == NULL) 136- MEM_ERROR(); 137- dir->dirs = new_dir; 138- } 139+ ent = malloc(sizeof(struct dir_ent)); 140+ if(ent == NULL) 141+ MEM_ERROR(); 142 143- dir->dirs[dir->dir_count].name = strdup(dire->name); 144- dir->dirs[dir->dir_count].start_block = 145- dirh.start_block; 146- dir->dirs[dir->dir_count].offset = dire->offset; 147- dir->dirs[dir->dir_count].type = dire->type; 148+ ent->name = strdup(dire->name); 149+ ent->start_block = dirh.start_block; 150+ ent->offset = dire->offset; 151+ ent->type = dire->type; 152+ ent->next = NULL; 153+ if(cur_ent == NULL) 154+ dir->dirs = ent; 155+ else 156+ cur_ent->next = ent; 157+ cur_ent = ent; 158 dir->dir_count ++; 159 bytes += dire->size + 1; 160 } 161diff --git a/squashfs-tools/unsquash-3.c b/squashfs-tools/unsquash-3.c 162index 8223f27..835a574 100644 163--- a/squashfs-tools/unsquash-3.c 164+++ b/squashfs-tools/unsquash-3.c 165@@ -381,7 +381,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 166 long long start; 167 int bytes = 0; 168 int dir_count, size, res; 169- struct dir_ent *new_dir; 170+ struct dir_ent *ent, *cur_ent = NULL; 171 struct dir *dir; 172 173 TRACE("squashfs_opendir: inode start block %d, offset %d\n", 174@@ -394,7 +394,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 175 MEM_ERROR(); 176 177 dir->dir_count = 0; 178- dir->cur_entry = 0; 179+ dir->cur_entry = NULL; 180 dir->mode = (*i)->mode; 181 dir->uid = (*i)->uid; 182 dir->guid = (*i)->gid; 183@@ -478,19 +478,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 184 "%d:%d, type %d\n", dire->name, 185 dirh.start_block, dire->offset, dire->type); 186 187- if((dir->dir_count % DIR_ENT_SIZE) == 0) { 188- new_dir = realloc(dir->dirs, (dir->dir_count + 189- DIR_ENT_SIZE) * sizeof(struct dir_ent)); 190- if(new_dir == NULL) 191- MEM_ERROR(); 192- dir->dirs = new_dir; 193- } 194+ ent = malloc(sizeof(struct dir_ent)); 195+ if(ent == NULL) 196+ MEM_ERROR(); 197 198- dir->dirs[dir->dir_count].name = strdup(dire->name); 199- dir->dirs[dir->dir_count].start_block = 200- dirh.start_block; 201- dir->dirs[dir->dir_count].offset = dire->offset; 202- dir->dirs[dir->dir_count].type = dire->type; 203+ ent->name = strdup(dire->name); 204+ ent->start_block = dirh.start_block; 205+ ent->offset = dire->offset; 206+ ent->type = dire->type; 207+ ent->next = NULL; 208+ if(cur_ent == NULL) 209+ dir->dirs = ent; 210+ else 211+ cur_ent->next = ent; 212+ cur_ent = ent; 213 dir->dir_count ++; 214 bytes += dire->size + 1; 215 } 216diff --git a/squashfs-tools/unsquash-4.c b/squashfs-tools/unsquash-4.c 217index 1e199a7..694783d 100644 218--- a/squashfs-tools/unsquash-4.c 219+++ b/squashfs-tools/unsquash-4.c 220@@ -331,7 +331,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 221 struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer; 222 long long start; 223 int bytes = 0, dir_count, size, res; 224- struct dir_ent *new_dir; 225+ struct dir_ent *ent, *cur_ent = NULL; 226 struct dir *dir; 227 228 TRACE("squashfs_opendir: inode start block %d, offset %d\n", 229@@ -344,7 +344,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 230 MEM_ERROR(); 231 232 dir->dir_count = 0; 233- dir->cur_entry = 0; 234+ dir->cur_entry = NULL; 235 dir->mode = (*i)->mode; 236 dir->uid = (*i)->uid; 237 dir->guid = (*i)->gid; 238@@ -415,19 +415,20 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse 239 "%d:%d, type %d\n", dire->name, 240 dirh.start_block, dire->offset, dire->type); 241 242- if((dir->dir_count % DIR_ENT_SIZE) == 0) { 243- new_dir = realloc(dir->dirs, (dir->dir_count + 244- DIR_ENT_SIZE) * sizeof(struct dir_ent)); 245- if(new_dir == NULL) 246- MEM_ERROR(); 247- dir->dirs = new_dir; 248- } 249+ ent = malloc(sizeof(struct dir_ent)); 250+ if(ent == NULL) 251+ MEM_ERROR(); 252 253- dir->dirs[dir->dir_count].name = strdup(dire->name); 254- dir->dirs[dir->dir_count].start_block = 255- dirh.start_block; 256- dir->dirs[dir->dir_count].offset = dire->offset; 257- dir->dirs[dir->dir_count].type = dire->type; 258+ ent->name = strdup(dire->name); 259+ ent->start_block = dirh.start_block; 260+ ent->offset = dire->offset; 261+ ent->type = dire->type; 262+ ent->next = NULL; 263+ if(cur_ent == NULL) 264+ dir->dirs = ent; 265+ else 266+ cur_ent->next = ent; 267+ cur_ent = ent; 268 dir->dir_count ++; 269 bytes += dire->size + 1; 270 } 271diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c 272index 04be53c..fee28ec 100644 273--- a/squashfs-tools/unsquashfs.c 274+++ b/squashfs-tools/unsquashfs.c 275@@ -1337,14 +1337,18 @@ failed: 276 int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, 277 unsigned int *offset, unsigned int *type) 278 { 279- if(dir->cur_entry == dir->dir_count) 280+ if(dir->cur_entry == NULL) 281+ dir->cur_entry = dir->dirs; 282+ else 283+ dir->cur_entry = dir->cur_entry->next; 284+ 285+ if(dir->cur_entry == NULL) 286 return FALSE; 287 288- *name = dir->dirs[dir->cur_entry].name; 289- *start_block = dir->dirs[dir->cur_entry].start_block; 290- *offset = dir->dirs[dir->cur_entry].offset; 291- *type = dir->dirs[dir->cur_entry].type; 292- dir->cur_entry ++; 293+ *name = dir->cur_entry->name; 294+ *start_block = dir->cur_entry->start_block; 295+ *offset = dir->cur_entry->offset; 296+ *type = dir->cur_entry->type; 297 298 return TRUE; 299 } 300diff --git a/squashfs-tools/unsquashfs.h b/squashfs-tools/unsquashfs.h 301index 583fbe4..f8cf78c 100644 302--- a/squashfs-tools/unsquashfs.h 303+++ b/squashfs-tools/unsquashfs.h 304@@ -168,17 +168,18 @@ struct dir_ent { 305 unsigned int start_block; 306 unsigned int offset; 307 unsigned int type; 308+ struct dir_ent *next; 309 }; 310 311 struct dir { 312 int dir_count; 313- int cur_entry; 314 unsigned int mode; 315 uid_t uid; 316 gid_t guid; 317 unsigned int mtime; 318 unsigned int xattr; 319 struct dir_ent *dirs; 320+ struct dir_ent *cur_entry; 321 }; 322 323 struct file_entry { 324-- 3252.17.1 326 327