unsquashfs-4: Add more sanity checks + fix CVE-2015-4645/6

Add more filesystem table sanity checks to Unsquashfs-4 and
also properly fix CVE-2015-4645 and CVE-2015-4646.

The CVEs were raised due to Unsquashfs having variable
oveflow and stack overflow in a number of vulnerable
functions.

The suggested patch only "fixed" one such function and fixed
it badly, and so it was buggy and introduced extra bugs!

The suggested patch was not only buggy, but, it used the
essentially wrong approach too.  It was "fixing" the
symptom but not the cause.  The symptom is wrong values
causing overflow, the cause is filesystem corruption.
This corruption should be detected and the filesystem
rejected *before* trying to allocate memory.

This patch applies the following fixes:

1. The filesystem super-block tables are checked, and the values
   must match across the filesystem.

   This will trap corrupted filesystems created by Mksquashfs.

2. The maximum (theorectical) size the filesystem tables could grow
   to, were analysed, and some variables were increased from int to
   long long.

   This analysis has been added as comments.

3. Stack allocation was removed, and a shared buffer (which is
   checked and increased as necessary) is used to read the
   table indexes.

Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
int set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
	unsigned int xattr, unsigned int set_mode)
{
	struct utimbuf times = { time, time };

	if(utime(pathname, &times) == -1) {
		ERROR("set_attributes: failed to set time on %s, because %s\n",
			pathname, strerror(errno));
		return FALSE;
	}

	if(root_process) {
		if(chown(pathname, uid, guid) == -1) {
			ERROR("set_attributes: failed to change uid and gids "
				"on %s, because %s\n", pathname,
				strerror(errno));
			return FALSE;
		}
	} else
		mode &= ~07000;

	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
		ERROR("set_attributes: failed to change mode %s, because %s\n",
			pathname, strerror(errno));
		return FALSE;
	}

	write_xattr(pathname, xattr);

	return TRUE;
}

int set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time,
	unsigned int xattr, unsigned int set_mode)
{
	struct utimbuf times = { time, time };

	if(utime(pathname, &times) == -1) {
		ERROR("set_attributes: failed to set time on %s, because %s\n",
			pathname, strerror(errno));
		return FALSE;
	}

	if(root_process) {
		if(chown(pathname, uid, guid) == -1) {
			ERROR("set_attributes: failed to change uid and gids "
				"on %s, because %s\n", pathname,
				strerror(errno));
			return FALSE;
		}
	} else
		mode &= ~07000;

	if((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) {
		ERROR("set_attributes: failed to change mode %s, because %s\n",
			pathname, strerror(errno));
		return FALSE;
	}

	write_xattr(pathname, xattr);

	return TRUE;
}
