Skip to content

Commit

Permalink
Merge tag 'squashfs-updates' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/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
  • Loading branch information
Linus Torvalds committed Sep 11, 2013
2 parents e831cbf + 9e01242 commit 53bf710
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 14 deletions.
11 changes: 4 additions & 7 deletions fs/squashfs/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,14 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
/*
* Block is uncompressed.
*/
int i, in, pg_offset = 0;

for (i = 0; i < b; i++) {
wait_on_buffer(bh[i]);
if (!buffer_uptodate(bh[i]))
goto block_release;
}
int in, pg_offset = 0;

for (bytes = length; k < b; k++) {
in = min(bytes, msblk->devblksize - offset);
bytes -= in;
wait_on_buffer(bh[k]);
if (!buffer_uptodate(bh[k]))
goto block_release;
while (in) {
if (pg_offset == PAGE_CACHE_SIZE) {
page++;
Expand Down
17 changes: 13 additions & 4 deletions fs/squashfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static int get_dir_index_using_offset(struct super_block *sb,
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
int err, i, index, length = 0;
unsigned int size;
struct squashfs_dir_index dir_index;

TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
Expand Down Expand Up @@ -81,8 +82,14 @@ static int get_dir_index_using_offset(struct super_block *sb,
*/
break;

size = le32_to_cpu(dir_index.size) + 1;

/* size should never be larger than SQUASHFS_NAME_LEN */
if (size > SQUASHFS_NAME_LEN)
break;

err = squashfs_read_metadata(sb, NULL, &index_start,
&index_offset, le32_to_cpu(dir_index.size) + 1);
&index_offset, size);
if (err < 0)
break;

Expand All @@ -105,9 +112,8 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
struct inode *inode = file_inode(file);
struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
u64 block = squashfs_i(inode)->start + msblk->directory_table;
int offset = squashfs_i(inode)->offset, length, dir_count, size,
type, err;
unsigned int inode_number;
int offset = squashfs_i(inode)->offset, length, err;
unsigned int inode_number, dir_count, size, type;
struct squashfs_dir_header dirh;
struct squashfs_dir_entry *dire;

Expand Down Expand Up @@ -200,6 +206,9 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
((short) le16_to_cpu(dire->inode_number));
type = le16_to_cpu(dire->type);

if (type > SQUASHFS_MAX_DIR_TYPE)
goto failed_read;

if (!dir_emit(ctx, dire->name, size,
inode_number,
squashfs_filetype_table[type]))
Expand Down
8 changes: 6 additions & 2 deletions fs/squashfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ static int get_dir_index_using_name(struct super_block *sb,
int len)
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
int i, size, length = 0, err;
int i, length = 0, err;
unsigned int size;
struct squashfs_dir_index *index;
char *str;

Expand All @@ -103,6 +104,8 @@ static int get_dir_index_using_name(struct super_block *sb,


size = le32_to_cpu(index->size) + 1;
if (size > SQUASHFS_NAME_LEN)
break;

err = squashfs_read_metadata(sb, index->name, &index_start,
&index_offset, size);
Expand Down Expand Up @@ -144,7 +147,8 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
struct squashfs_dir_entry *dire;
u64 block = squashfs_i(dir)->start + msblk->directory_table;
int offset = squashfs_i(dir)->offset;
int err, length, dir_count, size;
int err, length;
unsigned int dir_count, size;

TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);

Expand Down
5 changes: 4 additions & 1 deletion fs/squashfs/squashfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
#define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \
SQUASHFS_COMP_OPT)

/* Max number of types and file types */
/* Inode types including extended types */
#define SQUASHFS_DIR_TYPE 1
#define SQUASHFS_REG_TYPE 2
#define SQUASHFS_SYMLINK_TYPE 3
Expand All @@ -103,6 +103,9 @@
#define SQUASHFS_LFIFO_TYPE 13
#define SQUASHFS_LSOCKET_TYPE 14

/* Max type value stored in directory entry */
#define SQUASHFS_MAX_DIR_TYPE 7

/* Xattr types */
#define SQUASHFS_XATTR_USER 0
#define SQUASHFS_XATTR_TRUSTED 1
Expand Down

0 comments on commit 53bf710

Please sign in to comment.