Skip to content

Commit

Permalink
Unsquashfs: fix write outside destination directory exploit
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
plougher committed Jan 17, 2021
1 parent 1c6f9df commit 79b5a55
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 7 deletions.
5 changes: 4 additions & 1 deletion squashfs-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ MKSQUASHFS_OBJS = mksquashfs.o read_fs.o action.o swap.o pseudo.o compressor.o \
caches-queues-lists.o

UNSQUASHFS_OBJS = unsquashfs.o unsquash-1.o unsquash-2.o unsquash-3.o \
unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o
unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o swap.o \
compressor.o unsquashfs_info.o

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

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

unsquash-1234.o: unsquash-1234.c

unsquashfs_xattr.o: unsquashfs_xattr.c unsquashfs.h squashfs_fs.h xattr.h

unsquashfs_info.o: unsquashfs.h squashfs_fs.h
Expand Down
9 changes: 8 additions & 1 deletion squashfs-tools/unsquash-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2011, 2012, 2019
* Copyright (c) 2009, 2010, 2011, 2012, 2019, 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -285,6 +285,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
memcpy(dire->name, directory_table + bytes,
dire->size + 1);
dire->name[dire->size + 1] = '\0';

/* check name for invalid characters (i.e /, ., ..) */
if(check_name(dire->name, dire->size + 1) == FALSE) {
ERROR("File system corrupted: invalid characters in name\n");
goto corrupted;
}

TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
Expand Down
58 changes: 58 additions & 0 deletions squashfs-tools/unsquash-1234.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* unsquash-1234.c
*
* Helper functions used by unsquash-1, unsquash-2, unsquash-3 and
* unsquash-4.
*/

#define TRUE 1
#define FALSE 0
/*
* Check name for validity, name should not
* - be ".", "./", or
* - be "..", "../" or
* - have a "/" anywhere in the name, or
* - be shorter than the expected size
*/
int check_name(char *name, int size)
{
char *start = name;

if(name[0] == '.') {
if(name[1] == '.')
name++;
if(name[1] == '/' || name[1] == '\0')
return FALSE;
}

while(name[0] != '/' && name[0] != '\0')
name ++;

if(name[0] == '/')
return FALSE;

if((name - start) != size)
return FALSE;

return TRUE;
}
9 changes: 8 additions & 1 deletion squashfs-tools/unsquash-2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2013, 2019
* Copyright (c) 2009, 2010, 2013, 2019, 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -386,6 +386,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
memcpy(dire->name, directory_table + bytes,
dire->size + 1);
dire->name[dire->size + 1] = '\0';

/* check name for invalid characters (i.e /, ., ..) */
if(check_name(dire->name, dire->size + 1) == FALSE) {
ERROR("File system corrupted: invalid characters in name\n");
goto corrupted;
}

TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
Expand Down
9 changes: 8 additions & 1 deletion squashfs-tools/unsquash-3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -413,6 +413,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
memcpy(dire->name, directory_table + bytes,
dire->size + 1);
dire->name[dire->size + 1] = '\0';

/* check name for invalid characters (i.e /, ., ..) */
if(check_name(dire->name, dire->size + 1) == FALSE) {
ERROR("File system corrupted: invalid characters in name\n");
goto corrupted;
}

TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
Expand Down
9 changes: 8 additions & 1 deletion squashfs-tools/unsquash-4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -349,6 +349,13 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
memcpy(dire->name, directory_table + bytes,
dire->size + 1);
dire->name[dire->size + 1] = '\0';

/* check name for invalid characters (i.e /, ., ..) */
if(check_name(dire->name, dire->size + 1) == FALSE) {
ERROR("File system corrupted: invalid characters in name\n");
goto corrupted;
}

TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);
Expand Down
2 changes: 1 addition & 1 deletion squashfs-tools/unsquashfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2670,7 +2670,7 @@ int parse_number(char *start, int *res)


#define VERSION() \
printf("unsquashfs version 4.4-git (2021/01/09)\n");\
printf("unsquashfs version 4.4-git (2021/01/17)\n");\
printf("copyright (C) 2021 Phillip Lougher "\
"<phillip@squashfs.org.uk>\n\n");\
printf("This program is free software; you can redistribute it and/or"\
Expand Down
5 changes: 4 additions & 1 deletion squashfs-tools/unsquashfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Unsquash a squashfs filesystem. This is a highly compressed read only
* filesystem.
*
* Copyright (c) 2009, 2010, 2013, 2014, 2019
* Copyright (c) 2009, 2010, 2013, 2014, 2019, 2021
* Phillip Lougher <phillip@squashfs.org.uk>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -261,4 +261,7 @@ extern int read_ids(int, long long, long long, unsigned int **);

/* unsquash-34.c */
extern long long *alloc_index_table(int);

/* unsquash-1234.c */
extern int check_name(char *, int);
#endif

0 comments on commit 79b5a55

Please sign in to comment.