diff options
| author | Phillip Lougher <phillip@lougher.demon.co.uk> | 2011-05-23 23:05:22 -0400 |
|---|---|---|
| committer | Phillip Lougher <phillip@lougher.demon.co.uk> | 2011-05-25 13:21:32 -0400 |
| commit | 37986f63c81bf23c856f65fc5e4830550e7f3d5b (patch) | |
| tree | aafcc2078b469fb8fdb6e43255e136fcc7059dc9 | |
| parent | 6f04864515365e135adc9f1cee4ac1251bb0ed35 (diff) | |
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 <phillip@lougher.demon.co.uk>
| -rw-r--r-- | fs/squashfs/id.c | 30 | ||||
| -rw-r--r-- | fs/squashfs/squashfs.h | 2 | ||||
| -rw-r--r-- | fs/squashfs/super.c | 10 | ||||
| -rw-r--r-- | fs/squashfs/xattr.h | 1 |
4 files changed, 37 insertions, 6 deletions
diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c index 2fdac6703b48..499d08a1f34a 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, | |||
| 66 | * Read uncompressed id lookup table indexes from disk into memory | 66 | * Read uncompressed id lookup table indexes from disk into memory |
| 67 | */ | 67 | */ |
| 68 | __le64 *squashfs_read_id_index_table(struct super_block *sb, | 68 | __le64 *squashfs_read_id_index_table(struct super_block *sb, |
| 69 | u64 id_table_start, unsigned short no_ids) | 69 | u64 id_table_start, u64 next_table, unsigned short no_ids) |
| 70 | { | 70 | { |
| 71 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); | 71 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); |
| 72 | __le64 *table; | ||
| 72 | 73 | ||
| 73 | TRACE("In read_id_index_table, length %d\n", length); | 74 | TRACE("In read_id_index_table, length %d\n", length); |
| 74 | 75 | ||
| 75 | return squashfs_read_table(sb, id_table_start, length); | 76 | /* Sanity check values */ |
| 77 | |||
| 78 | /* there should always be at least one id */ | ||
| 79 | if (no_ids == 0) | ||
| 80 | return ERR_PTR(-EINVAL); | ||
| 81 | |||
| 82 | /* | ||
| 83 | * length bytes should not extend into the next table - this check | ||
| 84 | * also traps instances where id_table_start is incorrectly larger | ||
| 85 | * than the next table start | ||
| 86 | */ | ||
| 87 | if (id_table_start + length > next_table) | ||
| 88 | return ERR_PTR(-EINVAL); | ||
| 89 | |||
| 90 | table = squashfs_read_table(sb, id_table_start, length); | ||
| 91 | |||
| 92 | /* | ||
| 93 | * table[0] points to the first id lookup table metadata block, this | ||
| 94 | * should be less than id_table_start | ||
| 95 | */ | ||
| 96 | if (!IS_ERR(table) && table[0] >= id_table_start) { | ||
| 97 | kfree(table); | ||
| 98 | return ERR_PTR(-EINVAL); | ||
| 99 | } | ||
| 100 | |||
| 101 | return table; | ||
| 76 | } | 102 | } |
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index d622e849a451..0e3d220defd2 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 *, | |||
| 61 | 61 | ||
| 62 | /* id.c */ | 62 | /* id.c */ |
| 63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | 63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); |
| 64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, | 64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, |
| 65 | unsigned short); | 65 | unsigned short); |
| 66 | 66 | ||
| 67 | /* inode.c */ | 67 | /* inode.c */ |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 401cc8c7608f..8f5f2781a60e 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) | |||
| 83 | long long root_inode; | 83 | long long root_inode; |
| 84 | unsigned short flags; | 84 | unsigned short flags; |
| 85 | unsigned int fragments; | 85 | unsigned int fragments; |
| 86 | u64 lookup_table_start, xattr_id_table_start; | 86 | u64 lookup_table_start, xattr_id_table_start, next_table; |
| 87 | int err; | 87 | int err; |
| 88 | 88 | ||
| 89 | TRACE("Entered squashfs_fill_superblock\n"); | 89 | TRACE("Entered squashfs_fill_superblock\n"); |
| @@ -217,8 +217,10 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 217 | /* Handle xattrs */ | 217 | /* Handle xattrs */ |
| 218 | sb->s_xattr = squashfs_xattr_handlers; | 218 | sb->s_xattr = squashfs_xattr_handlers; |
| 219 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); | 219 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); |
| 220 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) | 220 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) { |
| 221 | next_table = msblk->bytes_used; | ||
| 221 | goto allocate_id_index_table; | 222 | goto allocate_id_index_table; |
| 223 | } | ||
| 222 | 224 | ||
| 223 | /* Allocate and read xattr id lookup table */ | 225 | /* Allocate and read xattr id lookup table */ |
| 224 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | 226 | 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) | |||
| 230 | if (err != -ENOTSUPP) | 232 | if (err != -ENOTSUPP) |
| 231 | goto failed_mount; | 233 | goto failed_mount; |
| 232 | } | 234 | } |
| 235 | next_table = msblk->xattr_table; | ||
| 233 | 236 | ||
| 234 | allocate_id_index_table: | 237 | allocate_id_index_table: |
| 235 | /* Allocate and read id index table */ | 238 | /* Allocate and read id index table */ |
| 236 | msblk->id_table = squashfs_read_id_index_table(sb, | 239 | msblk->id_table = squashfs_read_id_index_table(sb, |
| 237 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); | 240 | le64_to_cpu(sblk->id_table_start), next_table, |
| 241 | le16_to_cpu(sblk->no_ids)); | ||
| 238 | if (IS_ERR(msblk->id_table)) { | 242 | if (IS_ERR(msblk->id_table)) { |
| 239 | ERROR("unable to read id index table\n"); | 243 | ERROR("unable to read id index table\n"); |
| 240 | err = PTR_ERR(msblk->id_table); | 244 | err = PTR_ERR(msblk->id_table); |
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index b634efce4bde..9b3dd6c4c1fe 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, | |||
| 31 | u64 start, u64 *xattr_table_start, int *xattr_ids) | 31 | u64 start, u64 *xattr_table_start, int *xattr_ids) |
| 32 | { | 32 | { |
| 33 | ERROR("Xattrs in filesystem, these will be ignored\n"); | 33 | ERROR("Xattrs in filesystem, these will be ignored\n"); |
| 34 | *xattr_table_start = start; | ||
| 34 | return ERR_PTR(-ENOTSUPP); | 35 | return ERR_PTR(-ENOTSUPP); |
| 35 | } | 36 | } |
| 36 | 37 | ||
