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