Skip to content

Commit 79b5a55

Browse files
committed
Unsquashfs: fix write outside destination directory exploit
An issue on Github (#72) shows how some specially crafted Squashfs filesystems containing invalid file names (with '/' and ..) can cause Unsquashfs to write files outside of the destination directory. This commit fixes this exploit by checking all names for validity. In doing so I have also added checks for '.' and for names that are shorter than they should be (names in the file system should not have '\0' terminators). Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
1 parent 1c6f9df commit 79b5a55

File tree

8 files changed

+99
-7
lines changed

8 files changed

+99
-7
lines changed

Diff for: squashfs-tools/Makefile

+4-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
156156
caches-queues-lists.o
157157

158158
UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
159-
unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o
159+
unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o swap.o \
160+
compressor.o unsquashfs_info.o
160161

161162
CFLAGS ?= -O2
162163
CFLAGS += $(EXTRA_CFLAGS) $(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 \
@@ -350,6 +351,8 @@ unsquash-123.o: unsquashfs.h unsquash-123.c squashfs_fs.h squashfs_compat.h
350351

351352
unsquash-34.o: unsquashfs.h unsquash-34.c
352353

354+
unsquash-1234.o: unsquash-1234.c
355+
353356
unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h
354357

355358
unsquashfs_info.o: unsquashfs.h squashfs_fs.h

Diff for: squashfs-tools/unsquash-1.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Unsquash a squashfs filesystem. This is a highly compressed read only
33
* filesystem.
44
*
5-
* Copyright (c) 2009, 2010, 2011, 2012, 2019
5+
* Copyright (c) 2009, 2010, 2011, 2012, 2019, 2021
66
* Phillip Lougher <phillip@squashfs.org.uk>
77
*
88
* This program is free software; you can redistribute it and/or
@@ -285,6 +285,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
285285
memcpy(dire->name, directory_table + bytes,
286286
dire->size + 1);
287287
dire->name[dire->size + 1] = '\0';
288+
289+
/* check name for invalid characters (i.e /, ., ..) */
290+
if(check_name(dire->name, dire->size + 1) == FALSE) {
291+
ERROR("File system corrupted: invalid characters in name\n");
292+
goto corrupted;
293+
}
294+
288295
TRACE("squashfs_opendir: directory entry %s, inode "
289296
"%d:%d, type %d\n", dire->name,
290297
dirh.start_block, dire->offset, dire->type);

Diff for: squashfs-tools/unsquash-1234.c

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Unsquash a squashfs filesystem. This is a highly compressed read only
3+
* filesystem.
4+
*
5+
* Copyright (c) 2021
6+
* Phillip Lougher <phillip@squashfs.org.uk>
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License
10+
* as published by the Free Software Foundation; either version 2,
11+
* or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program; if not, write to the Free Software
20+
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21+
*
22+
* unsquash-1234.c
23+
*
24+
* Helper functions used by unsquash-1, unsquash-2, unsquash-3 and
25+
* unsquash-4.
26+
*/
27+
28+
#define TRUE 1
29+
#define FALSE 0
30+
/*
31+
* Check name for validity, name should not
32+
* - be ".", "./", or
33+
* - be "..", "../" or
34+
* - have a "/" anywhere in the name, or
35+
* - be shorter than the expected size
36+
*/
37+
int check_name(char *name, int size)
38+
{
39+
char *start = name;
40+
41+
if(name[0] == '.') {
42+
if(name[1] == '.')
43+
name++;
44+
if(name[1] == '/' || name[1] == '\0')
45+
return FALSE;
46+
}
47+
48+
while(name[0] != '/' && name[0] != '\0')
49+
name ++;
50+
51+
if(name[0] == '/')
52+
return FALSE;
53+
54+
if((name - start) != size)
55+
return FALSE;
56+
57+
return TRUE;
58+
}

Diff for: squashfs-tools/unsquash-2.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Unsquash a squashfs filesystem. This is a highly compressed read only
33
* filesystem.
44
*
5-
* Copyright (c) 2009, 2010, 2013, 2019
5+
* Copyright (c) 2009, 2010, 2013, 2019, 2021
66
* Phillip Lougher <phillip@squashfs.org.uk>
77
*
88
* This program is free software; you can redistribute it and/or
@@ -386,6 +386,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
386386
memcpy(dire->name, directory_table + bytes,
387387
dire->size + 1);
388388
dire->name[dire->size + 1] = '\0';
389+
390+
/* check name for invalid characters (i.e /, ., ..) */
391+
if(check_name(dire->name, dire->size + 1) == FALSE) {
392+
ERROR("File system corrupted: invalid characters in name\n");
393+
goto corrupted;
394+
}
395+
389396
TRACE("squashfs_opendir: directory entry %s, inode "
390397
"%d:%d, type %d\n", dire->name,
391398
dirh.start_block, dire->offset, dire->type);

Diff for: squashfs-tools/unsquash-3.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Unsquash a squashfs filesystem. This is a highly compressed read only
33
* filesystem.
44
*
5-
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
5+
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021
66
* Phillip Lougher <phillip@squashfs.org.uk>
77
*
88
* This program is free software; you can redistribute it and/or
@@ -413,6 +413,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
413413
memcpy(dire->name, directory_table + bytes,
414414
dire->size + 1);
415415
dire->name[dire->size + 1] = '\0';
416+
417+
/* check name for invalid characters (i.e /, ., ..) */
418+
if(check_name(dire->name, dire->size + 1) == FALSE) {
419+
ERROR("File system corrupted: invalid characters in name\n");
420+
goto corrupted;
421+
}
422+
416423
TRACE("squashfs_opendir: directory entry %s, inode "
417424
"%d:%d, type %d\n", dire->name,
418425
dirh.start_block, dire->offset, dire->type);

Diff for: squashfs-tools/unsquash-4.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Unsquash a squashfs filesystem. This is a highly compressed read only
33
* filesystem.
44
*
5-
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
5+
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021
66
* Phillip Lougher <phillip@squashfs.org.uk>
77
*
88
* This program is free software; you can redistribute it and/or
@@ -349,6 +349,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
349349
memcpy(dire->name, directory_table + bytes,
350350
dire->size + 1);
351351
dire->name[dire->size + 1] = '\0';
352+
353+
/* check name for invalid characters (i.e /, ., ..) */
354+
if(check_name(dire->name, dire->size + 1) == FALSE) {
355+
ERROR("File system corrupted: invalid characters in name\n");
356+
goto corrupted;
357+
}
358+
352359
TRACE("squashfs_opendir: directory entry %s, inode "
353360
"%d:%d, type %d\n", dire->name,
354361
dirh.start_block, dire->offset, dire->type);

Diff for: squashfs-tools/unsquashfs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2670,7 +2670,7 @@ int parse_number(char *start, int *res)
26702670

26712671

26722672
#define VERSION() \
2673-
printf("unsquashfs version 4.4-git (2021/01/09)\n");\
2673+
printf("unsquashfs version 4.4-git (2021/01/17)\n");\
26742674
printf("copyright (C) 2021 Phillip Lougher "\
26752675
"<phillip@squashfs.org.uk>\n\n");\
26762676
printf("This program is free software; you can redistribute it and/or"\

Diff for: squashfs-tools/unsquashfs.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Unsquash a squashfs filesystem. This is a highly compressed read only
55
* filesystem.
66
*
7-
* Copyright (c) 2009, 2010, 2013, 2014, 2019
7+
* Copyright (c) 2009, 2010, 2013, 2014, 2019, 2021
88
* Phillip Lougher <phillip@squashfs.org.uk>
99
*
1010
* This program is free software; you can redistribute it and/or
@@ -261,4 +261,7 @@ extern int read_ids(int, long long, long long, unsigned int **);
261261

262262
/* unsquash-34.c */
263263
extern long long *alloc_index_table(int);
264+
265+
/* unsquash-1234.c */
266+
extern int check_name(char *, int);
264267
#endif

0 commit comments

Comments
 (0)