[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Please unblock squashfs 3.0-6.1



Hi,

version 3.0-6.1 of squashfs does fix the security problem in #415530,
please unblock the package, debdiff is attached.

Regards,
Daniel

-- 
Address:        Daniel Baumann, Burgunderstrasse 3, CH-4562 Biberist
Email:          daniel.baumann@panthera-systems.net
Internet:       http://people.panthera-systems.net/~daniel-baumann/
diff -u squashfs-3.1r2/debian/changelog squashfs-3.1r2/debian/changelog
--- squashfs-3.1r2/debian/changelog
+++ squashfs-3.1r2/debian/changelog
@@ -1,3 +1,12 @@
+squashfs (1:3.1r2-6.1) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Added patch from upstream to linux-2.6.18/squashfs3.1-patch to fix kernel
+    crash on special crafted squashfs file systems CVE-2006-5701
+    (Closes: #415530).
+
+ -- Daniel Baumann <daniel@debian.org>  Fri, 30 Mar 2007 08:52:00 +0200
+
 squashfs (1:3.1r2-6) unstable; urgency=low
 
   * Add manpage for unsquashfs command.
only in patch2:
unchanged:
--- squashfs-3.1r2.orig/linux-2.6.18/squashfs3.1-patch
+++ squashfs-3.1r2/linux-2.6.18/squashfs3.1-patch
@@ -87,7 +87,7 @@
 diff --new-file -urp linux-2.6.18/fs/squashfs/inode.c linux-2.6.18-squashfs3.1/fs/squashfs/inode.c
 --- linux-2.6.18/fs/squashfs/inode.c	1970-01-01 01:00:00.000000000 +0100
 +++ linux-2.6.18-squashfs3.1/fs/squashfs/inode.c	2006-08-21 00:15:29.000000000 +0100
-@@ -0,0 +1,2156 @@
+@@ -0,0 +1,2194 @@
 +/*
 + * Squashfs - a compressed read only filesystem for Linux
 + *
@@ -263,14 +263,15 @@
 +
 +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;
@@ -281,8 +282,11 @@
 +		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;
@@ -294,6 +298,9 @@
 +		}
 +		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;
@@ -306,6 +313,9 @@
 +		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;
@@ -317,7 +327,7 @@
 +	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;
@@ -339,7 +349,7 @@
 +		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))
@@ -361,8 +371,8 @@
 +	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);
@@ -426,14 +436,20 @@
 +			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);
@@ -447,7 +463,11 @@
 +			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);
@@ -532,6 +552,7 @@
 +{
 +	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);
@@ -577,7 +598,8 @@
 +
 +			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;
@@ -966,6 +988,10 @@
 +{
 +	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
@@ -974,13 +1000,9 @@
 +		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;
 +	}
@@ -1072,9 +1094,11 @@
 +	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;
 +	}
@@ -1102,6 +1126,15 @@
 +	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
@@ -1171,7 +1204,9 @@
 +		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;
 +		}
@@ -1182,7 +1217,9 @@
 +		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;
 +		}
@@ -1608,7 +1645,8 @@
 +		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);
@@ -1708,15 +1746,12 @@
 +
 +	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;
 +	}
 +
@@ -1728,11 +1763,12 @@
 +
 +		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);
@@ -1742,11 +1778,12 @@
 +					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",
@@ -1756,6 +1793,7 @@
 +	}
 +
 +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);
@@ -2258,7 +2296,7 @@
 diff --new-file -urp linux-2.6.18/fs/squashfs/squashfs2_0.c linux-2.6.18-squashfs3.1/fs/squashfs/squashfs2_0.c
 --- linux-2.6.18/fs/squashfs/squashfs2_0.c	1970-01-01 01:00:00.000000000 +0100
 +++ linux-2.6.18-squashfs3.1/fs/squashfs/squashfs2_0.c	2006-08-21 00:14:55.000000000 +0100
-@@ -0,0 +1,779 @@
+@@ -0,0 +1,780 @@
 +/*
 + * Squashfs - a compressed read only filesystem for Linux
 + *
@@ -2339,7 +2377,8 @@
 +					sblk->fragment_table_start,
 +					SQUASHFS_FRAGMENT_INDEX_BYTES_2
 +					(sblk->fragments) |
-+					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL,
++					SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
 +		ERROR("unable to read fragment index table\n");
 +		return 0;
 +	}
@@ -3093,7 +3132,7 @@
 +#define SQSH_EXTERN
 +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);
 +extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
 +				long long block, unsigned int offset,
 +				int length, long long *next_block,
@@ -4206,19 +4245,21 @@
  	memset(buf, 0xe5, size);
  
  	/*
-@@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
+@@ -101,6 +105,20 @@ identify_ramdisk_image(int fd, int start
  		goto done;
  	}
  
 +	/* squashfs is at block zero too */
 +	if (squashfsb->s_magic == SQUASHFS_MAGIC) {
++		int bytes_used;
 +		printk(KERN_NOTICE
 +		       "RAMDISK: squashfs filesystem found at block %d\n",
 +		       start_block);
 +		if (squashfsb->s_major < 3)
-+			nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++			bytes_used = squashfsb->bytes_used_2;
 +		else
-+			nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++			bytes_used = squashfsb->bytes_used;
++		nblocks = (bytes_used +  BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 +		goto done;
 +	}
 +

Reply to: