Squashfs: add sanity checks to lookup table reading at mount time
Fsfuzzer generates corrupted filesystems which throw a warn_on in kmalloc. One of these is due to a corrupted superblock inodes field. Fix this by checking that the number of bytes to be read (and allocated) does not extend into the next filesystem structure. Also add a couple of other sanity checks of the mount-time lookup table structures. Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
This commit is contained in:
Родитель
37986f63c8
Коммит
ac51a0a713
|
@ -121,13 +121,38 @@ static struct dentry *squashfs_get_parent(struct dentry *child)
|
|||
* Read uncompressed inode lookup table indexes off disk into memory
|
||||
*/
|
||||
__le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
|
||||
u64 lookup_table_start, unsigned int inodes)
|
||||
u64 lookup_table_start, u64 next_table, unsigned int inodes)
|
||||
{
|
||||
unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
|
||||
__le64 *table;
|
||||
|
||||
TRACE("In read_inode_lookup_table, length %d\n", length);
|
||||
|
||||
return squashfs_read_table(sb, lookup_table_start, length);
|
||||
/* Sanity check values */
|
||||
|
||||
/* there should always be at least one inode */
|
||||
if (inodes == 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* length bytes should not extend into the next table - this check
|
||||
* also traps instances where lookup_table_start is incorrectly larger
|
||||
* than the next table start
|
||||
*/
|
||||
if (lookup_table_start + length > next_table)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
table = squashfs_read_table(sb, lookup_table_start, length);
|
||||
|
||||
/*
|
||||
* table[0] points to the first inode lookup table metadata block,
|
||||
* this should be less than lookup_table_start
|
||||
*/
|
||||
if (!IS_ERR(table) && table[0] >= lookup_table_start) {
|
||||
kfree(table);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
|
|||
extern void *squashfs_decompressor_init(struct super_block *, unsigned short);
|
||||
|
||||
/* export.c */
|
||||
extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
|
||||
extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64,
|
||||
unsigned int);
|
||||
|
||||
/* fragment.c */
|
||||
|
|
|
@ -245,6 +245,7 @@ allocate_id_index_table:
|
|||
msblk->id_table = NULL;
|
||||
goto failed_mount;
|
||||
}
|
||||
next_table = msblk->id_table[0];
|
||||
|
||||
/* Handle inode lookup table */
|
||||
lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
|
||||
|
@ -253,7 +254,7 @@ allocate_id_index_table:
|
|||
|
||||
/* Allocate and read inode lookup table */
|
||||
msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
|
||||
lookup_table_start, msblk->inodes);
|
||||
lookup_table_start, next_table, msblk->inodes);
|
||||
if (IS_ERR(msblk->inode_lookup_table)) {
|
||||
ERROR("unable to read inode lookup table\n");
|
||||
err = PTR_ERR(msblk->inode_lookup_table);
|
||||
|
|
Загрузка…
Ссылка в новой задаче