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 | ||