From 82de647e1f81fd89afc48608d889dd3b33cb8983 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Fri, 20 May 2011 02:26:43 +0100 Subject: Squashfs: move table allocation into squashfs_read_table() This eliminates a lot of duplicate code. Signed-off-by: Phillip Lougher --- fs/squashfs/cache.c | 29 +++++++++++++++++++++++------ fs/squashfs/export.c | 19 +------------------ fs/squashfs/fragment.c | 19 +------------------ fs/squashfs/id.c | 18 +----------------- fs/squashfs/squashfs.h | 2 +- fs/squashfs/super.c | 21 ++++++++------------- fs/squashfs/xattr_id.c | 34 +++++++++------------------------- 7 files changed, 44 insertions(+), 98 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 26b15ae34d6..20c8df1b7ef 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -393,19 +393,36 @@ struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb, /* * Read a filesystem table (uncompressed sequence of bytes) from disk */ -int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, - int length) +void *squashfs_read_table(struct super_block *sb, u64 block, int length) { int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; int i, res; - void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; + void *table, *buffer, **data; + + table = buffer = kmalloc(length, GFP_KERNEL); + if (table == NULL) + return ERR_PTR(-ENOMEM); + + data = kcalloc(pages, sizeof(void *), GFP_KERNEL); + if (data == NULL) { + res = -ENOMEM; + goto failed; + } for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) data[i] = buffer; + res = squashfs_read_data(sb, data, block, length | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); + kfree(data); - return res; + + if (res < 0) + goto failed; + + return table; + +failed: + kfree(table); + return ERR_PTR(res); } diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c index 7f93d5a9ee0..cc6dd90cee6 100644 --- a/fs/squashfs/export.c +++ b/fs/squashfs/export.c @@ -124,27 +124,10 @@ __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, u64 lookup_table_start, unsigned int inodes) { unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); - __le64 *inode_lookup_table; - int err; TRACE("In read_inode_lookup_table, length %d\n", length); - /* Allocate inode lookup table indexes */ - inode_lookup_table = kmalloc(length, GFP_KERNEL); - if (inode_lookup_table == NULL) { - ERROR("Failed to allocate inode lookup table\n"); - return ERR_PTR(-ENOMEM); - } - - err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start, - length); - if (err < 0) { - ERROR("unable to read inode lookup table\n"); - kfree(inode_lookup_table); - return ERR_PTR(err); - } - - return inode_lookup_table; + return squashfs_read_table(sb, lookup_table_start, length); } diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 7eef571443c..567093db587 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -74,23 +74,6 @@ __le64 *squashfs_read_fragment_index_table(struct super_block *sb, u64 fragment_table_start, unsigned int fragments) { unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); - __le64 *fragment_index; - int err; - /* Allocate fragment lookup table indexes */ - fragment_index = kmalloc(length, GFP_KERNEL); - if (fragment_index == NULL) { - ERROR("Failed to allocate fragment index table\n"); - return ERR_PTR(-ENOMEM); - } - - err = squashfs_read_table(sb, fragment_index, fragment_table_start, - length); - if (err < 0) { - ERROR("unable to read fragment index table\n"); - kfree(fragment_index); - return ERR_PTR(err); - } - - return fragment_index; + return squashfs_read_table(sb, fragment_table_start, length); } diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c index d8f32452638..2fdac6703b4 100644 --- a/fs/squashfs/id.c +++ b/fs/squashfs/id.c @@ -69,24 +69,8 @@ __le64 *squashfs_read_id_index_table(struct super_block *sb, u64 id_table_start, unsigned short no_ids) { unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); - __le64 *id_table; - int err; TRACE("In read_id_index_table, length %d\n", length); - /* Allocate id lookup table indexes */ - id_table = kmalloc(length, GFP_KERNEL); - if (id_table == NULL) { - ERROR("Failed to allocate id index table\n"); - return ERR_PTR(-ENOMEM); - } - - err = squashfs_read_table(sb, id_table, id_table_start, length); - if (err < 0) { - ERROR("unable to read id index table\n"); - kfree(id_table); - return ERR_PTR(err); - } - - return id_table; + return squashfs_read_table(sb, id_table_start, length); } diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 1f2e608b878..d622e849a45 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -44,7 +44,7 @@ extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *, u64, int); extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, u64, int); -extern int squashfs_read_table(struct super_block *, void *, u64, int); +extern void *squashfs_read_table(struct super_block *, u64, int); /* decompressor.c */ extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 5c8184c061a..d16c39263f3 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -95,12 +95,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) } msblk = sb->s_fs_info; - sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); - if (sblk == NULL) { - ERROR("Failed to allocate squashfs_super_block\n"); - goto failure; - } - msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); msblk->devblksize_log2 = ffz(~msblk->devblksize); @@ -114,10 +108,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) * of bytes_used) we need to set it to an initial sensible dummy value */ msblk->bytes_used = sizeof(*sblk); - err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk)); + sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk)); - if (err < 0) { + if (IS_ERR(sblk)) { ERROR("unable to read squashfs_super_block\n"); + err = PTR_ERR(sblk); + sblk = NULL; goto failed_mount; } @@ -222,6 +218,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) msblk->id_table = squashfs_read_id_index_table(sb, le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); if (IS_ERR(msblk->id_table)) { + ERROR("unable to read id index table\n"); err = PTR_ERR(msblk->id_table); msblk->id_table = NULL; goto failed_mount; @@ -242,6 +239,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) msblk->fragment_index = squashfs_read_fragment_index_table(sb, le64_to_cpu(sblk->fragment_table_start), fragments); if (IS_ERR(msblk->fragment_index)) { + ERROR("unable to read fragment index table\n"); err = PTR_ERR(msblk->fragment_index); msblk->fragment_index = NULL; goto failed_mount; @@ -256,6 +254,7 @@ allocate_lookup_table: msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, lookup_table_start, msblk->inodes); if (IS_ERR(msblk->inode_lookup_table)) { + ERROR("unable to read inode lookup table\n"); err = PTR_ERR(msblk->inode_lookup_table); msblk->inode_lookup_table = NULL; goto failed_mount; @@ -273,6 +272,7 @@ allocate_xattr_table: msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); if (IS_ERR(msblk->xattr_id_table)) { + ERROR("unable to read xattr id index table\n"); err = PTR_ERR(msblk->xattr_id_table); msblk->xattr_id_table = NULL; if (err != -ENOTSUPP) @@ -318,11 +318,6 @@ failed_mount: sb->s_fs_info = NULL; kfree(sblk); return err; - -failure: - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - return -ENOMEM; } diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index 05385dbe146..51a7bd0cc44 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c @@ -67,34 +67,18 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, u64 *xattr_table_start, int *xattr_ids) { unsigned int len; - __le64 *xid_table; - struct squashfs_xattr_id_table id_table; - int err; + struct squashfs_xattr_id_table *id_table; + + id_table = squashfs_read_table(sb, start, sizeof(*id_table)); + if (IS_ERR(id_table)) + return (__le64 *) id_table; - err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); - if (err < 0) { - ERROR("unable to read xattr id table\n"); - return ERR_PTR(err); - } - *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); - *xattr_ids = le32_to_cpu(id_table.xattr_ids); + *xattr_table_start = le64_to_cpu(id_table->xattr_table_start); + *xattr_ids = le32_to_cpu(id_table->xattr_ids); + kfree(id_table); len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); TRACE("In read_xattr_index_table, length %d\n", len); - /* Allocate xattr id lookup table indexes */ - xid_table = kmalloc(len, GFP_KERNEL); - if (xid_table == NULL) { - ERROR("Failed to allocate xattr id index table\n"); - return ERR_PTR(-ENOMEM); - } - - err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); - if (err < 0) { - ERROR("unable to read xattr id index table\n"); - kfree(xid_table); - return ERR_PTR(err); - } - - return xid_table; + return squashfs_read_table(sb, start + sizeof(*id_table), len); } -- cgit v1.2.3 From 76e002f755b61aa79228f4e751bbca8674aba0f6 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 02:57:05 +0100 Subject: Squashfs: reverse order of filesystem table reading Reverse order of table reading from mostly first to last in placement order, to last to first. This is to enable extra superblock sanity checks to be added in later patches. Signed-off-by: Phillip Lougher --- fs/squashfs/super.c | 71 ++++++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index d16c39263f3..401cc8c7608 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -214,6 +214,24 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } + /* Handle xattrs */ + sb->s_xattr = squashfs_xattr_handlers; + xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); + if (xattr_id_table_start == SQUASHFS_INVALID_BLK) + goto allocate_id_index_table; + + /* Allocate and read xattr id lookup table */ + msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, + xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); + if (IS_ERR(msblk->xattr_id_table)) { + ERROR("unable to read xattr id index table\n"); + err = PTR_ERR(msblk->xattr_id_table); + msblk->xattr_id_table = NULL; + if (err != -ENOTSUPP) + goto failed_mount; + } + +allocate_id_index_table: /* Allocate and read id index table */ msblk->id_table = squashfs_read_id_index_table(sb, le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); @@ -224,9 +242,27 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } + /* Handle inode lookup table */ + lookup_table_start = le64_to_cpu(sblk->lookup_table_start); + if (lookup_table_start == SQUASHFS_INVALID_BLK) + goto handle_fragments; + + /* Allocate and read inode lookup table */ + msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, + lookup_table_start, msblk->inodes); + if (IS_ERR(msblk->inode_lookup_table)) { + ERROR("unable to read inode lookup table\n"); + err = PTR_ERR(msblk->inode_lookup_table); + msblk->inode_lookup_table = NULL; + goto failed_mount; + } + + sb->s_export_op = &squashfs_export_ops; + +handle_fragments: fragments = le32_to_cpu(sblk->fragments); if (fragments == 0) - goto allocate_lookup_table; + goto allocate_root; msblk->fragment_cache = squashfs_cache_init("fragment", SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); @@ -245,39 +281,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount; } -allocate_lookup_table: - lookup_table_start = le64_to_cpu(sblk->lookup_table_start); - if (lookup_table_start == SQUASHFS_INVALID_BLK) - goto allocate_xattr_table; - - /* Allocate and read inode lookup table */ - msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, - lookup_table_start, msblk->inodes); - if (IS_ERR(msblk->inode_lookup_table)) { - ERROR("unable to read inode lookup table\n"); - err = PTR_ERR(msblk->inode_lookup_table); - msblk->inode_lookup_table = NULL; - goto failed_mount; - } - - sb->s_export_op = &squashfs_export_ops; - -allocate_xattr_table: - sb->s_xattr = squashfs_xattr_handlers; - xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); - if (xattr_id_table_start == SQUASHFS_INVALID_BLK) - goto allocate_root; - - /* Allocate and read xattr id lookup table */ - msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, - xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); - if (IS_ERR(msblk->xattr_id_table)) { - ERROR("unable to read xattr id index table\n"); - err = PTR_ERR(msblk->xattr_id_table); - msblk->xattr_id_table = NULL; - if (err != -ENOTSUPP) - goto failed_mount; - } allocate_root: root = new_inode(sb); if (!root) { -- cgit v1.2.3 From 6f04864515365e135adc9f1cee4ac1251bb0ed35 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 03:20:27 +0100 Subject: Squashfs: add sanity checks to xattr reading at mount time These checks add sanity checking of the mount-time xattr structures. Signed-off-by: Phillip Lougher --- fs/squashfs/xattr_id.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'fs/squashfs') diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index 51a7bd0cc44..f60fb3cce18 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c @@ -76,6 +76,17 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, *xattr_table_start = le64_to_cpu(id_table->xattr_table_start); *xattr_ids = le32_to_cpu(id_table->xattr_ids); kfree(id_table); + + /* Sanity check values */ + + /* there is always at least one xattr id */ + if (*xattr_ids == 0) + return ERR_PTR(-EINVAL); + + /* xattr_table should be less than start */ + if (*xattr_table_start >= start) + return ERR_PTR(-EINVAL); + len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); TRACE("In read_xattr_index_table, length %d\n", len); -- cgit v1.2.3 From 37986f63c81bf23c856f65fc5e4830550e7f3d5b Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 04:05:22 +0100 Subject: Squashfs: add sanity checks to id reading at mount time Fsfuzzer generates corrupted filesystems which throw a warn_on in kmalloc. One of these is due to a corrupted superblock no_ids 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 id table structures. Signed-off-by: Phillip Lougher --- fs/squashfs/id.c | 30 ++++++++++++++++++++++++++++-- fs/squashfs/squashfs.h | 2 +- fs/squashfs/super.c | 10 +++++++--- fs/squashfs/xattr.h | 1 + 4 files changed, 37 insertions(+), 6 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c index 2fdac6703b4..499d08a1f34 100644 --- a/fs/squashfs/id.c +++ b/fs/squashfs/id.c @@ -66,11 +66,37 @@ int squashfs_get_id(struct super_block *sb, unsigned int index, * Read uncompressed id lookup table indexes from disk into memory */ __le64 *squashfs_read_id_index_table(struct super_block *sb, - u64 id_table_start, unsigned short no_ids) + u64 id_table_start, u64 next_table, unsigned short no_ids) { unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); + __le64 *table; TRACE("In read_id_index_table, length %d\n", length); - return squashfs_read_table(sb, id_table_start, length); + /* Sanity check values */ + + /* there should always be at least one id */ + if (no_ids == 0) + return ERR_PTR(-EINVAL); + + /* + * length bytes should not extend into the next table - this check + * also traps instances where id_table_start is incorrectly larger + * than the next table start + */ + if (id_table_start + length > next_table) + return ERR_PTR(-EINVAL); + + table = squashfs_read_table(sb, id_table_start, length); + + /* + * table[0] points to the first id lookup table metadata block, this + * should be less than id_table_start + */ + if (!IS_ERR(table) && table[0] >= id_table_start) { + kfree(table); + return ERR_PTR(-EINVAL); + } + + return table; } diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index d622e849a45..0e3d220defd 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -61,7 +61,7 @@ extern __le64 *squashfs_read_fragment_index_table(struct super_block *, /* id.c */ extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); -extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, +extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, unsigned short); /* inode.c */ diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 401cc8c7608..8f5f2781a60 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -83,7 +83,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) long long root_inode; unsigned short flags; unsigned int fragments; - u64 lookup_table_start, xattr_id_table_start; + u64 lookup_table_start, xattr_id_table_start, next_table; int err; TRACE("Entered squashfs_fill_superblock\n"); @@ -217,8 +217,10 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) /* Handle xattrs */ sb->s_xattr = squashfs_xattr_handlers; xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); - if (xattr_id_table_start == SQUASHFS_INVALID_BLK) + if (xattr_id_table_start == SQUASHFS_INVALID_BLK) { + next_table = msblk->bytes_used; goto allocate_id_index_table; + } /* Allocate and read xattr id lookup table */ msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, @@ -230,11 +232,13 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) if (err != -ENOTSUPP) goto failed_mount; } + next_table = msblk->xattr_table; allocate_id_index_table: /* Allocate and read id index table */ msblk->id_table = squashfs_read_id_index_table(sb, - le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); + le64_to_cpu(sblk->id_table_start), next_table, + le16_to_cpu(sblk->no_ids)); if (IS_ERR(msblk->id_table)) { ERROR("unable to read id index table\n"); err = PTR_ERR(msblk->id_table); diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index b634efce4bd..9b3dd6c4c1f 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h @@ -31,6 +31,7 @@ static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, u64 *xattr_table_start, int *xattr_ids) { ERROR("Xattrs in filesystem, these will be ignored\n"); + *xattr_table_start = start; return ERR_PTR(-ENOTSUPP); } -- cgit v1.2.3 From ac51a0a7139aa93bf1176b701c86fa3d2bdf6106 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 04:15:21 +0100 Subject: 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 --- fs/squashfs/export.c | 29 +++++++++++++++++++++++++++-- fs/squashfs/squashfs.h | 2 +- fs/squashfs/super.c | 3 ++- 3 files changed, 30 insertions(+), 4 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c index cc6dd90cee6..e3108711a40 100644 --- a/fs/squashfs/export.c +++ b/fs/squashfs/export.c @@ -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; } diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 0e3d220defd..3b705f137eb 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -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 */ diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 8f5f2781a60..80a7119870a 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.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); -- cgit v1.2.3 From 1cac63cc9b2ff0d16ab2d16232b1a6ee8676a47b Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 04:33:34 +0100 Subject: Squashfs: add sanity checks to fragment reading at mount time Fsfuzzer generates corrupted filesystems which throw a warn_on in kmalloc. One of these is due to a corrupted superblock fragments 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 fragment table structures. Signed-off-by: Phillip Lougher --- fs/squashfs/fragment.c | 24 ++++++++++++++++++++++-- fs/squashfs/squashfs.h | 2 +- fs/squashfs/super.c | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index 567093db587..bfd707569ab 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -71,9 +71,29 @@ int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, * Read the uncompressed fragment lookup table indexes off disk into memory */ __le64 *squashfs_read_fragment_index_table(struct super_block *sb, - u64 fragment_table_start, unsigned int fragments) + u64 fragment_table_start, u64 next_table, unsigned int fragments) { unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); + __le64 *table; - return squashfs_read_table(sb, fragment_table_start, length); + /* + * Sanity check, length bytes should not extend into the next table - + * this check also traps instances where fragment_table_start is + * incorrectly larger than the next table start + */ + if (fragment_table_start + length > next_table) + return ERR_PTR(-EINVAL); + + table = squashfs_read_table(sb, fragment_table_start, length); + + /* + * table[0] points to the first fragment table metadata block, this + * should be less than fragment_table_start + */ + if (!IS_ERR(table) && table[0] >= fragment_table_start) { + kfree(table); + return ERR_PTR(-EINVAL); + } + + return table; } diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 3b705f137eb..647b81b477d 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -57,7 +57,7 @@ extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64, /* fragment.c */ extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); extern __le64 *squashfs_read_fragment_index_table(struct super_block *, - u64, unsigned int); + u64, u64, unsigned int); /* id.c */ extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 80a7119870a..efa8118260d 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -261,6 +261,7 @@ allocate_id_index_table: msblk->inode_lookup_table = NULL; goto failed_mount; } + next_table = msblk->inode_lookup_table[0]; sb->s_export_op = &squashfs_export_ops; @@ -278,7 +279,7 @@ handle_fragments: /* Allocate and read fragment index table */ msblk->fragment_index = squashfs_read_fragment_index_table(sb, - le64_to_cpu(sblk->fragment_table_start), fragments); + le64_to_cpu(sblk->fragment_table_start), next_table, fragments); if (IS_ERR(msblk->fragment_index)) { ERROR("unable to read fragment index table\n"); err = PTR_ERR(msblk->fragment_index); -- cgit v1.2.3 From 1094a4a6118019255bf0e4adaa96bb17ccec3a82 Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Tue, 24 May 2011 04:45:33 +0100 Subject: Squashfs: add extra sanity checks at mount time Add some extra sanity checks of the inode and directory structures. Signed-off-by: Phillip Lougher --- fs/squashfs/super.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'fs/squashfs') diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index efa8118260d..984d6c86192 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -268,7 +268,7 @@ allocate_id_index_table: handle_fragments: fragments = le32_to_cpu(sblk->fragments); if (fragments == 0) - goto allocate_root; + goto check_directory_table; msblk->fragment_cache = squashfs_cache_init("fragment", SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); @@ -286,8 +286,22 @@ handle_fragments: msblk->fragment_index = NULL; goto failed_mount; } + next_table = msblk->fragment_index[0]; -allocate_root: +check_directory_table: + /* Sanity check directory_table */ + if (msblk->directory_table >= next_table) { + err = -EINVAL; + goto failed_mount; + } + + /* Sanity check inode_table */ + if (msblk->inode_table >= msblk->directory_table) { + err = -EINVAL; + goto failed_mount; + } + + /* allocate root */ root = new_inode(sb); if (!root) { err = -ENOMEM; -- cgit v1.2.3 From d7f2ff6718efa155fd92e481a5960496d084c63f Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Thu, 26 May 2011 10:39:56 +0100 Subject: Squashfs: update email address My existing email address may stop working in a month or two, so update email to one that will continue working. Signed-off-by: Phillip Lougher --- MAINTAINERS | 2 +- fs/squashfs/block.c | 2 +- fs/squashfs/cache.c | 2 +- fs/squashfs/decompressor.c | 2 +- fs/squashfs/decompressor.h | 2 +- fs/squashfs/dir.c | 2 +- fs/squashfs/export.c | 2 +- fs/squashfs/file.c | 2 +- fs/squashfs/fragment.c | 2 +- fs/squashfs/id.c | 2 +- fs/squashfs/inode.c | 2 +- fs/squashfs/namei.c | 2 +- fs/squashfs/squashfs.h | 2 +- fs/squashfs/squashfs_fs.h | 2 +- fs/squashfs/squashfs_fs_i.h | 2 +- fs/squashfs/squashfs_fs_sb.h | 2 +- fs/squashfs/super.c | 4 ++-- fs/squashfs/symlink.c | 2 +- fs/squashfs/xattr.c | 2 +- fs/squashfs/xattr.h | 2 +- fs/squashfs/xattr_id.c | 2 +- fs/squashfs/xz_wrapper.c | 2 +- fs/squashfs/zlib_wrapper.c | 2 +- 23 files changed, 24 insertions(+), 24 deletions(-) (limited to 'fs/squashfs') diff --git a/MAINTAINERS b/MAINTAINERS index 531c5cf150b..b28f6a7ca9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5906,7 +5906,7 @@ F: Documentation/filesystems/spufs.txt F: arch/powerpc/platforms/cell/spufs/ SQUASHFS FILE SYSTEM -M: Phillip Lougher +M: Phillip Lougher L: squashfs-devel@lists.sourceforge.net (subscribers-only) W: http://squashfs.org.uk S: Maintained diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 8ab48bc2fa7..ed0eb2a921f 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index 20c8df1b7ef..7567f737419 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index e921bd21373..9f1b0bb96f1 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 099745ad569..8ba70cff09a 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h @@ -4,7 +4,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c index 3f79cd1d0c1..9dfe2ce0fb7 100644 --- a/fs/squashfs/dir.c +++ b/fs/squashfs/dir.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c index e3108711a40..730c56248c9 100644 --- a/fs/squashfs/export.c +++ b/fs/squashfs/export.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index a25c5060bdc..38bb1c64055 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c index bfd707569ab..1516a6490bf 100644 --- a/fs/squashfs/fragment.c +++ b/fs/squashfs/fragment.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c index 499d08a1f34..a70858e0fb4 100644 --- a/fs/squashfs/id.c +++ b/fs/squashfs/id.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 62e63ad2507..04bebcaa237 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 5d922a6701a..4bc63ac64bc 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 647b81b477d..e3be6a71cfa 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 4582c568ef4..b4a4e539a08 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h @@ -4,7 +4,7 @@ * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h index 359baefc01f..73588e7700e 100644 --- a/fs/squashfs/squashfs_fs_i.h +++ b/fs/squashfs/squashfs_fs_i.h @@ -4,7 +4,7 @@ * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index d9037a5215f..651f0b31d29 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -4,7 +4,7 @@ * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 984d6c86192..6f26abee359 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -493,5 +493,5 @@ static const struct super_operations squashfs_super_ops = { module_init(init_squashfs_fs); module_exit(exit_squashfs_fs); MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); -MODULE_AUTHOR("Phillip Lougher "); +MODULE_AUTHOR("Phillip Lougher "); MODULE_LICENSE("GPL"); diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index ec86434921e..1191817264c 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 3876c36699a..92fcde7b4d6 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2010 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index 9b3dd6c4c1f..c83f5d9ec12 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2010 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index f60fb3cce18..c89607d690c 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2010 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index aa47a286d1f..1760b7d108f 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index 517688b32ff..55d918fd2d8 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c @@ -2,7 +2,7 @@ * Squashfs - a compressed read only filesystem for Linux * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - * Phillip Lougher + * Phillip Lougher * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License -- cgit v1.2.3