Commit 44cff8a9ee8a974f9e931df910688e7fc1f0b0f9

Authored by Phillip Lougher
1 parent 003a3194d3

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: Phillip Lougher <phillip@lougher.demon.co.uk>

Showing 2 changed files with 21 additions and 0 deletions Side-by-side Diff

... ... @@ -172,6 +172,11 @@
172 172 length += sizeof(dirh);
173 173  
174 174 dir_count = le32_to_cpu(dirh.count) + 1;
  175 +
  176 + /* dir_count should never be larger than 256 */
  177 + if (dir_count > 256)
  178 + goto failed_read;
  179 +
175 180 while (dir_count--) {
176 181 /*
177 182 * Read directory entry.
... ... @@ -182,6 +187,10 @@
182 187 goto failed_read;
183 188  
184 189 size = le16_to_cpu(dire->size) + 1;
  190 +
  191 + /* size should never be larger than SQUASHFS_NAME_LEN */
  192 + if (size > SQUASHFS_NAME_LEN)
  193 + goto failed_read;
185 194  
186 195 err = squashfs_read_metadata(inode->i_sb, dire->name,
187 196 &block, &offset, size);
... ... @@ -176,6 +176,11 @@
176 176 length += sizeof(dirh);
177 177  
178 178 dir_count = le32_to_cpu(dirh.count) + 1;
  179 +
  180 + /* dir_count should never be larger than 256 */
  181 + if (dir_count > 256)
  182 + goto data_error;
  183 +
179 184 while (dir_count--) {
180 185 /*
181 186 * Read directory entry.
... ... @@ -187,6 +192,10 @@
187 192  
188 193 size = le16_to_cpu(dire->size) + 1;
189 194  
  195 + /* size should never be larger than SQUASHFS_NAME_LEN */
  196 + if (size > SQUASHFS_NAME_LEN)
  197 + goto data_error;
  198 +
190 199 err = squashfs_read_metadata(dir->i_sb, dire->name,
191 200 &block, &offset, size);
192 201 if (err < 0)
... ... @@ -227,6 +236,9 @@
227 236 return d_splice_alias(inode, dentry);
228 237 d_add(dentry, inode);
229 238 return ERR_PTR(0);
  239 +
  240 +data_error:
  241 + err = -EIO;
230 242  
231 243 read_failure:
232 244 ERROR("Unable to read directory block [%llx:%x]\n",