CVE-2021-40153 (C, published 2021-08-27T15:15Z)
Description: value: squashfs_opendir in unsquash-1.c in Squashfs-Tools 4.5 stores the filename in the directory entry; this is then used by unsquashfs to create the new file during the unsquash. The filename is not validated for traversal outside of the destination directory, and thus allows writing to locations outside of the destination.
Severity: MEDIUM (CVSS v3 base score: 8.1)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/plougher/squashfs-tools
Files changed:
squashfs-tools/Makefile
squashfs-tools/unsquash-1.c
squashfs-tools/unsquash-1234.c
squashfs-tools/unsquash-2.c
squashfs-tools/unsquash-3.c
squashfs-tools/unsquash-4.c
squashfs-tools/unsquashfs.c
squashfs-tools/unsquashfs.h
Commit message: Unsquashfs: fix write outside destination directory exploit

An issue on Github (https://github.com/plougher/squashfs-tools/issues/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>


Vulnerable code:
	unsquash-4.o unsquash-123.o unsquash-34.o swap.o compressor.o unsquashfs_info.o
 * Copyright (c) 2009, 2010, 2011, 2012, 2019
 * Copyright (c) 2009, 2010, 2013, 2019
 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019
	printf("unsquashfs version 4.4-git (2021/01/09)\n");\
 * Copyright (c) 2009, 2010, 2013, 2014, 2019

Fixed code:
	unsquash-4.o unsquash-123.o unsquash-34.o unsquash-1234.o swap.o \
	compressor.o unsquashfs_info.o
unsquash-1234.o: unsquash-1234.c

 * Copyright (c) 2009, 2010, 2011, 2012, 2019, 2021

			/* 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;
			}

/*
 * 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;
}
 * Copyright (c) 2009, 2010, 2013, 2019, 2021

			/* 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;
			}

 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021

			/* 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;
			}

 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2019, 2021

			/* 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;
			}

	printf("unsquashfs version 4.4-git (2021/01/17)\n");\
 * Copyright (c) 2009, 2010, 2013, 2014, 2019, 2021

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