SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
long long index, unsigned int length,
- long long *next_index)
+ long long *next_index, int srclength)
{
struct squashfs_sb_info *msblk = s->s_fs_info;
+ struct squashfs_super_block *sblk = &msblk->sblk;
struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
msblk->devblksize_log2) + 2];
unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
unsigned int cur_index = index >> msblk->devblksize_log2;
- int bytes, avail_bytes, b = 0, k;
+ int bytes, avail_bytes, b = 0, k = 0;
char *c_buffer;
unsigned int compressed;
unsigned int c_byte = length;
c_buffer = compressed ? msblk->read_data : buffer;
c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
- TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
- ? "" : "un", (unsigned int) c_byte);
+ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed
+ ? "" : "un", (unsigned int) c_byte, srclength);
+
+ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
+ goto read_failure;
if (!(bh[0] = sb_getblk(s, cur_index)))
goto block_release;
}
ll_rw_block(READ, b, bh);
} else {
+ if (index < 0 || (index + 2) > sblk->bytes_used)
+ goto read_failure;
+
if (!(bh[0] = get_block_length(s, &cur_index, &offset,
&c_byte)))
goto read_failure;
TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
? "" : "un", (unsigned int) c_byte);
+ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
+ goto read_failure;
+
for (b = 1; bytes < c_byte; b++) {
if (!(bh[b] = sb_getblk(s, ++cur_index)))
goto block_release;
if (compressed)
down(&msblk->read_data_mutex);
- for (bytes = 0, k = 0; k < b; k++) {
+ for (bytes = 0; k < b; k++) {
avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
msblk->devblksize - offset :
c_byte - bytes;
msblk->stream.next_in = c_buffer;
msblk->stream.avail_in = c_byte;
msblk->stream.next_out = buffer;
- msblk->stream.avail_out = msblk->read_size;
+ msblk->stream.avail_out = srclength;
if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) ||
((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH))
return bytes;
block_release:
- while (--b >= 0)
- brelse(bh[b]);
+ for (; k < b; k++)
+ brelse(bh[k]);
read_failure:
ERROR("sb_bread failed reading block 0x%x\n", cur_index);
msblk->block_cache[i].block = SQUASHFS_USED_BLK;
up(&msblk->block_cache_mutex);
- if (!(msblk->block_cache[i].length =
- squashfs_read_data(s,
- msblk->block_cache[i].data,
- block, 0, &next_index))) {
- ERROR("Unable to read cache block [%llx:%x]\n",
- block, offset);
- goto out;
- }
+ msblk->block_cache[i].length = squashfs_read_data(s,
+ msblk->block_cache[i].data, block, 0, &next_index,
+ SQUASHFS_METADATA_SIZE);
+
+ if (msblk->block_cache[i].length == 0) {
+ ERROR("Unable to read cache block [%llx:%x]\n",
+ block, offset);
+ down(&msblk->block_cache_mutex);
+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
+ kfree(msblk->block_cache[i].data);
+ wake_up(&msblk->waitq);
+ up(&msblk->block_cache_mutex);
+ goto out;
+ }
down(&msblk->block_cache_mutex);
wake_up(&msblk->waitq);
continue;
}
- if ((bytes = msblk->block_cache[i].length - offset) >= length) {
+ bytes = msblk->block_cache[i].length - offset;
+
+ if (bytes < 1)
+ goto out;
+ else if (bytes >= length) {
if (buffer)
memcpy(buffer, msblk->block_cache[i].data +
offset, length);
{
int i, n;
struct squashfs_sb_info *msblk = s->s_fs_info;
+ struct squashfs_super_block *sblk = &msblk->sblk;
while ( 1 ) {
down(&msblk->fragment_mutex);
if (!(msblk->fragment[i].length = squashfs_read_data(s,
msblk->fragment[i].data,
- start_block, length, NULL))) {
+ start_block, length, NULL,
+ sblk->block_size))) {
ERROR("Unable to read fragment cache block "
"[%llx]\n", start_block);
msblk->fragment[i].locked = 0;
{
struct squashfs_sb_info *msblk = s->s_fs_info;
struct squashfs_super_block *sblk = &msblk->sblk;
+ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
+
+ if (length == 0)
+ return 1;
/* Allocate fragment index table */
if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
return 0;
}
- if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
- !squashfs_read_data(s, (char *)
- msblk->fragment_index,
- sblk->fragment_table_start,
- SQUASHFS_FRAGMENT_INDEX_BYTES
- (sblk->fragments) |
- SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ if (!squashfs_read_data(s, (char *) msblk->fragment_index,
+ sblk->fragment_table_start, length |
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
ERROR("unable to read fragment index table\n");
return 0;
}
init_waitqueue_head(&msblk->waitq);
init_waitqueue_head(&msblk->fragment_wait_queue);
+ sblk->bytes_used = sizeof(struct squashfs_super_block);
if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
sizeof(struct squashfs_super_block) |
- SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL,
+ sizeof(struct squashfs_super_block))) {
SERROR("unable to read superblock\n");
goto failed_mount;
}
if(!supported_squashfs_filesystem(msblk, silent))
goto failed_mount;
+ /* Check the filesystem does not extend beyond the end of the
+ block device */
+ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
+ goto failed_mount;
+
+ /* Check the root inode for sanity */
+ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
+ goto failed_mount;
+
TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
TRACE("Inodes are %scompressed\n",
SQUASHFS_UNCOMPRESSED_INODES
if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
((sblk->no_uids + sblk->no_guids) *
sizeof(unsigned int)) |
- SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL,
+ (sblk->no_uids + sblk->no_guids) *
+ sizeof(unsigned int))) {
ERROR("unable to read uid/gid table\n");
goto failed_mount;
}
if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
((sblk->no_uids + sblk->no_guids) *
sizeof(unsigned int)) |
- SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL,
+ (sblk->no_uids + sblk->no_guids) *
+ sizeof(unsigned int))) {
ERROR("unable to read uid/gid table\n");
goto failed_mount;
}
down(&msblk->read_page_mutex);
if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
- block, bsize, NULL))) {
+ block, bsize, NULL,
+ msblk->read_size))) {
ERROR("Unable to read page, block %llx, size %x\n", block,
bsize);
up(&msblk->read_page_mutex);
if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT)) {
- pageaddr = kmap_atomic(page, KM_USER0);
block_list = NULL;
goto skip_read;
}
if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
ERROR("Failed to allocate block_list\n");
- pageaddr = kmap_atomic(page, KM_USER0);
- block_list = NULL;
goto skip_read;
}
down(&msblk->read_page_mutex);
bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
- bsize, NULL);
- pageaddr = kmap_atomic(page, KM_USER0);
- if (bytes)
+ bsize, NULL, msblk->read_size);
+ if (bytes) {
+ pageaddr = kmap_atomic(page, KM_USER0);
memcpy(pageaddr, msblk->read_page, bytes);
- else
+ kunmap_atomic(pageaddr, KM_USER0);
+ } else
ERROR("Unable to read page, block %llx, size %x\n",
block, bsize);
up(&msblk->read_page_mutex);
SQUASHFS_I(inode)->
u.s1.fragment_start_block,
SQUASHFS_I(inode)-> u.s1.fragment_size);
- pageaddr = kmap_atomic(page, KM_USER0);
if (fragment) {
bytes = i_size_read(inode) & (sblk->block_size - 1);
+ pageaddr = kmap_atomic(page, KM_USER0);
memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
u.s1.fragment_offset, bytes);
+ kunmap_atomic(pageaddr, KM_USER0);
release_cached_fragment(msblk, fragment);
} else
ERROR("Unable to read page, block %llx, size %x\n",
}
skip_read:
+ pageaddr = kmap_atomic(page, KM_USER0);
memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
kunmap_atomic(pageaddr, KM_USER0);
flush_dcache_page(page);