Andrew Geissler | 595f630 | 2022-01-24 19:11:47 +0000 | [diff] [blame] | 1 | The commit is required by the fix for CVE-2021-41072. |
| 2 | |
| 3 | Upstream-Status: Backport [https://github.com/plougher/squashfs-tools/commit/9938154] |
| 4 | |
| 5 | Signed-off-by: Kai Kang <kai.kang@windriver.com> |
| 6 | |
| 7 | From 9938154174756ee48a94ea0b076397a2944b028d Mon Sep 17 00:00:00 2001 |
| 8 | From: Phillip Lougher <phillip@squashfs.org.uk> |
| 9 | Date: Sun, 12 Sep 2021 22:58:11 +0100 |
| 10 | Subject: [PATCH] unsquashfs: use linked list to store directory names |
| 11 | |
| 12 | This should bring higher performance, and it allows sorting |
| 13 | if necessary (1.x and 2.0 filesystems). |
| 14 | |
| 15 | Signed-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 | |
| 26 | diff --git a/squashfs-tools/unsquash-1.c b/squashfs-tools/unsquash-1.c |
| 27 | index 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 | } |
| 82 | diff --git a/squashfs-tools/unsquash-1234.c b/squashfs-tools/unsquash-1234.c |
| 83 | index 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 | } |
| 106 | diff --git a/squashfs-tools/unsquash-2.c b/squashfs-tools/unsquash-2.c |
| 107 | index 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 | } |
| 161 | diff --git a/squashfs-tools/unsquash-3.c b/squashfs-tools/unsquash-3.c |
| 162 | index 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 | } |
| 216 | diff --git a/squashfs-tools/unsquash-4.c b/squashfs-tools/unsquash-4.c |
| 217 | index 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 | } |
| 271 | diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c |
| 272 | index 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 | } |
| 300 | diff --git a/squashfs-tools/unsquashfs.h b/squashfs-tools/unsquashfs.h |
| 301 | index 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 | -- |
| 325 | 2.17.1 |
| 326 | |