Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44cff8a9 authored by Phillip Lougher's avatar Phillip Lougher
Browse files

Squashfs: handle corruption of directory structure



Handle the rare case where a directory metadata block is uncompressed and
corrupted, leading to a kernel oops in directory scanning (memcpy).
Normally corruption is detected at the decompression stage and dealt with
then, however, this will not happen if:

- metadata isn't compressed (users can optionally request no metadata
  compression), or
- the compressed metadata block was larger than the original, in which
  case the uncompressed version was used, or
- the data was corrupt after decompression

This patch fixes this by adding some sanity checks against known maximum
values.

Signed-off-by: default avatarPhillip Lougher <phillip@lougher.demon.co.uk>
parent 003a3194
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -172,6 +172,11 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		/* dir_count should never be larger than 256 */
		if (dir_count > 256)
			goto failed_read;

		while (dir_count--) {
			/*
			 * Read directory entry.
@@ -183,6 +188,10 @@ static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)

			size = le16_to_cpu(dire->size) + 1;

			/* size should never be larger than SQUASHFS_NAME_LEN */
			if (size > SQUASHFS_NAME_LEN)
				goto failed_read;

			err = squashfs_read_metadata(inode->i_sb, dire->name,
					&block, &offset, size);
			if (err < 0)
+12 −0
Original line number Diff line number Diff line
@@ -176,6 +176,11 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		/* dir_count should never be larger than 256 */
		if (dir_count > 256)
			goto data_error;

		while (dir_count--) {
			/*
			 * Read directory entry.
@@ -187,6 +192,10 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,

			size = le16_to_cpu(dire->size) + 1;

			/* size should never be larger than SQUASHFS_NAME_LEN */
			if (size > SQUASHFS_NAME_LEN)
				goto data_error;

			err = squashfs_read_metadata(dir->i_sb, dire->name,
					&block, &offset, size);
			if (err < 0)
@@ -228,6 +237,9 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
	d_add(dentry, inode);
	return ERR_PTR(0);

data_error:
	err = -EIO;

read_failure:
	ERROR("Unable to read directory block [%llx:%x]\n",
		squashfs_i(dir)->start + msblk->directory_table,