Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 104637 Details for
Bug 158781
Linux 2.6.x squashfs double free (CVE-2006-5701)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
patch (text/plain), 11.93 KB, created by
Daniel Drake (RETIRED)
on 2006-12-23 08:07:29 UTC
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Daniel Drake (RETIRED)
Created:
2006-12-23 08:07:29 UTC
Size:
11.93 KB
patch
obsolete
>diff -Nurp linux/fs/squashfs/inode.c linux-mokb/fs/squashfs/inode.c >--- linux/fs/squashfs/inode.c 2006-11-14 23:36:59.000000000 +0000 >+++ linux-mokb/fs/squashfs/inode.c 2006-11-15 02:15:26.000000000 +0000 >@@ -173,14 +173,15 @@ out: > > 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; >@@ -191,8 +192,11 @@ SQSH_EXTERN unsigned int squashfs_read_d > 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; >@@ -204,6 +208,9 @@ SQSH_EXTERN unsigned int squashfs_read_d > } > 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; >@@ -216,6 +223,9 @@ SQSH_EXTERN unsigned int squashfs_read_d > 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; >@@ -227,7 +237,7 @@ SQSH_EXTERN unsigned int squashfs_read_d > 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; >@@ -249,7 +259,7 @@ SQSH_EXTERN unsigned int squashfs_read_d > 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)) >@@ -271,8 +281,8 @@ SQSH_EXTERN unsigned int squashfs_read_d > 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); >@@ -336,14 +346,20 @@ SQSH_EXTERN int squashfs_get_cached_bloc > 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); >@@ -357,7 +373,11 @@ SQSH_EXTERN int squashfs_get_cached_bloc > 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); >@@ -442,6 +462,7 @@ SQSH_EXTERN struct squashfs_fragment_cac > { > 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); >@@ -487,7 +508,8 @@ SQSH_EXTERN struct squashfs_fragment_cac > > 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; >@@ -876,6 +898,10 @@ static int read_fragment_index_table(str > { > 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 >@@ -884,13 +910,9 @@ static int read_fragment_index_table(str > 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; > } >@@ -982,9 +1004,11 @@ static int squashfs_fill_super(struct su > 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; > } >@@ -1012,6 +1036,15 @@ static int squashfs_fill_super(struct su > 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 >@@ -1081,7 +1114,9 @@ static int squashfs_fill_super(struct su > 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; > } >@@ -1092,7 +1127,9 @@ static int squashfs_fill_super(struct su > 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; > } >@@ -1518,7 +1555,8 @@ static int squashfs_readpage(struct file > 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); >@@ -1618,15 +1656,12 @@ static int squashfs_readpage4K(struct fi > > 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; > } > >@@ -1638,11 +1673,12 @@ static int squashfs_readpage4K(struct fi > > 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); >@@ -1652,11 +1688,12 @@ static int squashfs_readpage4K(struct fi > 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", >@@ -1666,6 +1703,7 @@ static int squashfs_readpage4K(struct fi > } > > 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); >diff -Nurp linux/fs/squashfs/squashfs2_0.c linux-mokb/fs/squashfs/squashfs2_0.c >--- linux/fs/squashfs/squashfs2_0.c 2006-11-14 23:36:59.000000000 +0000 >+++ linux-mokb/fs/squashfs/squashfs2_0.c 2006-11-15 02:18:15.000000000 +0000 >@@ -73,12 +73,13 @@ static int read_fragment_index_table_2(s > } > > if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && >- !squashfs_read_data(s, (char *) >- msblk->fragment_index_2, >- sblk->fragment_table_start, >- SQUASHFS_FRAGMENT_INDEX_BYTES_2 >- (sblk->fragments) | >- SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { >+ !squashfs_read_data(s, (char *) >+ msblk->fragment_index_2, >+ sblk->fragment_table_start, >+ SQUASHFS_FRAGMENT_INDEX_BYTES_2 >+ (sblk->fragments) | >+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, >+ SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { > ERROR("unable to read fragment index table\n"); > return 0; > } >diff -Nurp linux/fs/squashfs/squashfs.h linux-mokb/fs/squashfs/squashfs.h >--- linux/fs/squashfs/squashfs.h 2006-11-14 23:36:59.000000000 +0000 >+++ linux-mokb/fs/squashfs/squashfs.h 2006-11-15 01:59:01.000000000 +0000 >@@ -49,7 +49,7 @@ static inline struct squashfs_inode_info > #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,
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 158781
: 104637