aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 15:33:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 15:33:12 -0400
commit53bf710832a7191e023e2bb1e333226e3115cfa0 (patch)
tree9e3db82418efbae09db02b53b36e48d749d73f1e
parente831cbfc1ad843b5542cc45f777e1a00b73c0685 (diff)
parent9e012423869e1efbae3762b87ceab509027231c9 (diff)
Merge tag 'squashfs-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next
Pull squashfs updates from Phillip Lougher: "A couple of minor additional sanity check patches for corrupted information, and some fixes. Apart from that there's a minor loop optimisation. These sanity checks mainly exist to trap maliciously corrupted filesystems either through using a deliberately modified mksquashfs, or where the user has deliberately chosen to generate uncompressed metadata and then corrupted it. Normally metadata in Squashfs filesystems is compressed, which means corruption (either accidental or malicious) is detected when trying to decompress the metadata. So corrupted data does not normally get as far as the code paths in question here" * tag 'squashfs-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next: Squashfs: add corruption check for type in squashfs_readdir() Squashfs: add corruption check in get_dir_index_using_offset() Squashfs: fix corruption checks in squashfs_readdir() Squashfs: fix corruption checks in squashfs_lookup() Squashfs: fix corruption check in get_dir_index_using_name() Squashfs: Optimized uncompressed buffer loop Squashfs: sanity check information from disk
-rw-r--r--fs/squashfs/block.c11
-rw-r--r--fs/squashfs/dir.c17
-rw-r--r--fs/squashfs/namei.c8
-rw-r--r--fs/squashfs/squashfs_fs.h5
4 files changed, 27 insertions, 14 deletions
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index fb50652e4e11..41d108ecc9be 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -167,17 +167,14 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
167 /* 167 /*
168 * Block is uncompressed. 168 * Block is uncompressed.
169 */ 169 */
170 int i, in, pg_offset = 0; 170 int in, pg_offset = 0;
171
172 for (i = 0; i < b; i++) {
173 wait_on_buffer(bh[i]);
174 if (!buffer_uptodate(bh[i]))
175 goto block_release;
176 }
177 171
178 for (bytes = length; k < b; k++) { 172 for (bytes = length; k < b; k++) {
179 in = min(bytes, msblk->devblksize - offset); 173 in = min(bytes, msblk->devblksize - offset);
180 bytes -= in; 174 bytes -= in;
175 wait_on_buffer(bh[k]);
176 if (!buffer_uptodate(bh[k]))
177 goto block_release;
181 while (in) { 178 while (in) {
182 if (pg_offset == PAGE_CACHE_SIZE) { 179 if (pg_offset == PAGE_CACHE_SIZE) {
183 page++; 180 page++;
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
index f7f527bf8c10..d8c2d747be28 100644
--- a/fs/squashfs/dir.c
+++ b/fs/squashfs/dir.c
@@ -54,6 +54,7 @@ static int get_dir_index_using_offset(struct super_block *sb,
54{ 54{
55 struct squashfs_sb_info *msblk = sb->s_fs_info; 55 struct squashfs_sb_info *msblk = sb->s_fs_info;
56 int err, i, index, length = 0; 56 int err, i, index, length = 0;
57 unsigned int size;
57 struct squashfs_dir_index dir_index; 58 struct squashfs_dir_index dir_index;
58 59
59 TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n", 60 TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
@@ -81,8 +82,14 @@ static int get_dir_index_using_offset(struct super_block *sb,
81 */ 82 */
82 break; 83 break;
83 84
85 size = le32_to_cpu(dir_index.size) + 1;
86
87 /* size should never be larger than SQUASHFS_NAME_LEN */
88 if (size > SQUASHFS_NAME_LEN)
89 break;
90
84 err = squashfs_read_metadata(sb, NULL, &index_start, 91 err = squashfs_read_metadata(sb, NULL, &index_start,
85 &index_offset, le32_to_cpu(dir_index.size) + 1); 92 &index_offset, size);
86 if (err < 0) 93 if (err < 0)
87 break; 94 break;
88 95
@@ -105,9 +112,8 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
105 struct inode *inode = file_inode(file); 112 struct inode *inode = file_inode(file);
106 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; 113 struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
107 u64 block = squashfs_i(inode)->start + msblk->directory_table; 114 u64 block = squashfs_i(inode)->start + msblk->directory_table;
108 int offset = squashfs_i(inode)->offset, length, dir_count, size, 115 int offset = squashfs_i(inode)->offset, length, err;
109 type, err; 116 unsigned int inode_number, dir_count, size, type;
110 unsigned int inode_number;
111 struct squashfs_dir_header dirh; 117 struct squashfs_dir_header dirh;
112 struct squashfs_dir_entry *dire; 118 struct squashfs_dir_entry *dire;
113 119
@@ -200,6 +206,9 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
200 ((short) le16_to_cpu(dire->inode_number)); 206 ((short) le16_to_cpu(dire->inode_number));
201 type = le16_to_cpu(dire->type); 207 type = le16_to_cpu(dire->type);
202 208
209 if (type > SQUASHFS_MAX_DIR_TYPE)
210 goto failed_read;
211
203 if (!dir_emit(ctx, dire->name, size, 212 if (!dir_emit(ctx, dire->name, size,
204 inode_number, 213 inode_number,
205 squashfs_filetype_table[type])) 214 squashfs_filetype_table[type]))
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 7834a517f7f4..67cad77fefb4 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -79,7 +79,8 @@ static int get_dir_index_using_name(struct super_block *sb,
79 int len) 79 int len)
80{ 80{
81 struct squashfs_sb_info *msblk = sb->s_fs_info; 81 struct squashfs_sb_info *msblk = sb->s_fs_info;
82 int i, size, length = 0, err; 82 int i, length = 0, err;
83 unsigned int size;
83 struct squashfs_dir_index *index; 84 struct squashfs_dir_index *index;
84 char *str; 85 char *str;
85 86
@@ -103,6 +104,8 @@ static int get_dir_index_using_name(struct super_block *sb,
103 104
104 105
105 size = le32_to_cpu(index->size) + 1; 106 size = le32_to_cpu(index->size) + 1;
107 if (size > SQUASHFS_NAME_LEN)
108 break;
106 109
107 err = squashfs_read_metadata(sb, index->name, &index_start, 110 err = squashfs_read_metadata(sb, index->name, &index_start,
108 &index_offset, size); 111 &index_offset, size);
@@ -144,7 +147,8 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
144 struct squashfs_dir_entry *dire; 147 struct squashfs_dir_entry *dire;
145 u64 block = squashfs_i(dir)->start + msblk->directory_table; 148 u64 block = squashfs_i(dir)->start + msblk->directory_table;
146 int offset = squashfs_i(dir)->offset; 149 int offset = squashfs_i(dir)->offset;
147 int err, length, dir_count, size; 150 int err, length;
151 unsigned int dir_count, size;
148 152
149 TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset); 153 TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
150 154
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
index 9e2349d07cb1..4b2beda49498 100644
--- a/fs/squashfs/squashfs_fs.h
+++ b/fs/squashfs/squashfs_fs.h
@@ -87,7 +87,7 @@
87#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ 87#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \
88 SQUASHFS_COMP_OPT) 88 SQUASHFS_COMP_OPT)
89 89
90/* Max number of types and file types */ 90/* Inode types including extended types */
91#define SQUASHFS_DIR_TYPE 1 91#define SQUASHFS_DIR_TYPE 1
92#define SQUASHFS_REG_TYPE 2 92#define SQUASHFS_REG_TYPE 2
93#define SQUASHFS_SYMLINK_TYPE 3 93#define SQUASHFS_SYMLINK_TYPE 3
@@ -103,6 +103,9 @@
103#define SQUASHFS_LFIFO_TYPE 13 103#define SQUASHFS_LFIFO_TYPE 13
104#define SQUASHFS_LSOCKET_TYPE 14 104#define SQUASHFS_LSOCKET_TYPE 14
105 105
106/* Max type value stored in directory entry */
107#define SQUASHFS_MAX_DIR_TYPE 7
108
106/* Xattr types */ 109/* Xattr types */
107#define SQUASHFS_XATTR_USER 0 110#define SQUASHFS_XATTR_USER 0
108#define SQUASHFS_XATTR_TRUSTED 1 111#define SQUASHFS_XATTR_TRUSTED 1