Skip to content

Commit 506220d

Browse files
ploughertorvalds
authored andcommitted
squashfs: add more sanity checks in xattr id lookup
Sysbot has reported a warning where a kmalloc() attempt exceeds the maximum limit. This has been identified as corruption of the xattr_ids count when reading the xattr id lookup table. This patch adds a number of additional sanity checks to detect this corruption and others. 1. It checks for a corrupted xattr index read from the inode. This could be because the metadata block is uncompressed, or because the "compression" bit has been corrupted (turning a compressed block into an uncompressed block). This would cause an out of bounds read. 2. It checks against corruption of the xattr_ids count. This can either lead to the above kmalloc failure, or a smaller than expected table to be read. 3. It checks the contents of the index table for corruption. [[email protected]: fix checkpatch issue] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Phillip Lougher <[email protected]> Reported-by: [email protected] Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent eabac19 commit 506220d

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

fs/squashfs/xattr_id.c

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
3131
struct squashfs_sb_info *msblk = sb->s_fs_info;
3232
int block = SQUASHFS_XATTR_BLOCK(index);
3333
int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index);
34-
u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]);
34+
u64 start_block;
3535
struct squashfs_xattr_id id;
3636
int err;
3737

38+
if (index >= msblk->xattr_ids)
39+
return -EINVAL;
40+
41+
start_block = le64_to_cpu(msblk->xattr_id_table[block]);
42+
3843
err = squashfs_read_metadata(sb, &id, &start_block, &offset,
3944
sizeof(id));
4045
if (err < 0)
@@ -50,13 +55,17 @@ int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
5055
/*
5156
* Read uncompressed xattr id lookup table indexes from disk into memory
5257
*/
53-
__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
58+
__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start,
5459
u64 *xattr_table_start, int *xattr_ids)
5560
{
56-
unsigned int len;
61+
struct squashfs_sb_info *msblk = sb->s_fs_info;
62+
unsigned int len, indexes;
5763
struct squashfs_xattr_id_table *id_table;
64+
__le64 *table;
65+
u64 start, end;
66+
int n;
5867

59-
id_table = squashfs_read_table(sb, start, sizeof(*id_table));
68+
id_table = squashfs_read_table(sb, table_start, sizeof(*id_table));
6069
if (IS_ERR(id_table))
6170
return (__le64 *) id_table;
6271

@@ -70,13 +79,52 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
7079
if (*xattr_ids == 0)
7180
return ERR_PTR(-EINVAL);
7281

73-
/* xattr_table should be less than start */
74-
if (*xattr_table_start >= start)
82+
len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
83+
indexes = SQUASHFS_XATTR_BLOCKS(*xattr_ids);
84+
85+
/*
86+
* The computed size of the index table (len bytes) should exactly
87+
* match the table start and end points
88+
*/
89+
start = table_start + sizeof(*id_table);
90+
end = msblk->bytes_used;
91+
92+
if (len != (end - start))
7593
return ERR_PTR(-EINVAL);
7694

77-
len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
95+
table = squashfs_read_table(sb, start, len);
96+
if (IS_ERR(table))
97+
return table;
98+
99+
/* table[0], table[1], ... table[indexes - 1] store the locations
100+
* of the compressed xattr id blocks. Each entry should be less than
101+
* the next (i.e. table[0] < table[1]), and the difference between them
102+
* should be SQUASHFS_METADATA_SIZE or less. table[indexes - 1]
103+
* should be less than table_start, and again the difference
104+
* shouls be SQUASHFS_METADATA_SIZE or less.
105+
*
106+
* Finally xattr_table_start should be less than table[0].
107+
*/
108+
for (n = 0; n < (indexes - 1); n++) {
109+
start = le64_to_cpu(table[n]);
110+
end = le64_to_cpu(table[n + 1]);
111+
112+
if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) {
113+
kfree(table);
114+
return ERR_PTR(-EINVAL);
115+
}
116+
}
117+
118+
start = le64_to_cpu(table[indexes - 1]);
119+
if (start >= table_start || (table_start - start) > SQUASHFS_METADATA_SIZE) {
120+
kfree(table);
121+
return ERR_PTR(-EINVAL);
122+
}
78123

79-
TRACE("In read_xattr_index_table, length %d\n", len);
124+
if (*xattr_table_start >= le64_to_cpu(table[0])) {
125+
kfree(table);
126+
return ERR_PTR(-EINVAL);
127+
}
80128

81-
return squashfs_read_table(sb, start + sizeof(*id_table), len);
129+
return table;
82130
}

0 commit comments

Comments
 (0)