Commit 44cff8a9ee8a974f9e931df910688e7fc1f0b0f9
1 parent
003a3194d3
Exists in
master
and in
4 other branches
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
fs/squashfs/dir.c
... | ... | @@ -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); |
fs/squashfs/namei.c
... | ... | @@ -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", |