@@ -29,30 +29,63 @@
static struct squashfs_fragment_entry *fragment_table;
static unsigned int *id_table;
static int read_fragment_table ( long long *directory_table_end )
long long *alloc_index_table ( int indexes )
{
static long long *alloc_table = NULL ;
static int alloc_size = 0 ;
int length = indexes * sizeof (long long );
if (alloc_size < length) {
long long *table = realloc (alloc_table, length);
if (table == NULL )
EXIT_UNSQUASH (" alloc_index_table: failed to allocate "
" index table\n " );
alloc_table = table;
alloc_size = length;
}
return alloc_table;
}
static int read_fragment_table (long long *table_start)
{
/*
* Note on overflow limits:
* Size of SBlk.s.fragments is 2^32 (unsigned int)
* Max size of bytes is 2^32*16 or 2^36
* Max indexes is (2^32*16)/8K or 2^23
* Max length is ((2^32*16)/8K)*8 or 2^26 or 64M
*/
int res, i;
int bytes = SQUASHFS_FRAGMENT_BYTES (sBlk .s .fragments );
int indexes = SQUASHFS_FRAGMENT_INDEXES (sBlk .s .fragments );
long long fragment_table_index[indexes];
long long bytes = SQUASHFS_FRAGMENT_BYTES ((long long ) sBlk .s .fragments );
int indexes = SQUASHFS_FRAGMENT_INDEXES ((long long ) sBlk .s .fragments );
int length = SQUASHFS_FRAGMENT_INDEX_BYTES ((long long ) sBlk .s .fragments );
long long *fragment_table_index;
/*
* The size of the index table (length bytes) should match the
* table start and end points
*/
if (length != (*table_start - sBlk .s .fragment_table_start )) {
ERROR (" read_fragment_table: Bad fragment count in super block\n " );
return FALSE ;
}
TRACE (" read_fragment_table: %d fragments, reading %d fragment indexes "
" from 0x%llx \n " , sBlk .s .fragments , indexes,
sBlk .s .fragment_table_start );
if (sBlk .s .fragments == 0 ) {
*directory_table_end = sBlk .s .fragment_table_start ;
return TRUE ;
}
fragment_table_index = alloc_index_table (indexes);
fragment_table = malloc (bytes);
if (fragment_table == NULL )
EXIT_UNSQUASH (" read_fragment_table: failed to allocate "
" fragment table\n " );
res = read_fs_bytes (fd, sBlk .s .fragment_table_start ,
SQUASHFS_FRAGMENT_INDEX_BYTES (sBlk .s .fragments ),
fragment_table_index);
res = read_fs_bytes (fd, sBlk .s .fragment_table_start , length,
fragment_table_index);
if (res == FALSE ) {
ERROR (" read_fragment_table: failed to read fragment table "
" index\n " );
@@ -78,7 +111,7 @@ static int read_fragment_table(long long *directory_table_end)
for (i = 0 ; i < sBlk .s .fragments ; i++)
SQUASHFS_INSWAP_FRAGMENT_ENTRY (&fragment_table[i]);
*directory_table_end = fragment_table_index[0 ];
*table_start = fragment_table_index[0 ];
return TRUE ;
}
@@ -356,25 +389,42 @@ struct dir *squashfs_opendir_4(unsigned int block_start, unsigned int offset,
}
static int read_uids_guids (long long *table_start)
static int read_id_table (long long *table_start)
{
/*
* Note on overflow limits:
* Size of SBlk.s.no_ids is 2^16 (unsigned short)
* Max size of bytes is 2^16*4 or 256K
* Max indexes is (2^16*4)/8K or 32
* Max length is ((2^16*4)/8K)*8 or 256
*/
int res, i;
int bytes = SQUASHFS_ID_BYTES (sBlk .s .no_ids );
int indexes = SQUASHFS_ID_BLOCKS (sBlk .s .no_ids );
long long id_index_table[indexes];
int length = SQUASHFS_ID_BLOCK_BYTES (sBlk .s .no_ids );
long long *id_index_table;
/*
* The size of the index table (length bytes) should match the
* table start and end points
*/
if (length != (*table_start - sBlk .s .id_table_start )) {
ERROR (" read_id_table: Bad id count in super block\n " );
return FALSE ;
}
TRACE (" read_uids_guids : no_ids %d \n " , sBlk .s .no_ids );
TRACE (" read_id_table : no_ids %d \n " , sBlk .s .no_ids );
id_index_table = alloc_index_table (indexes);
id_table = malloc (bytes);
if (id_table == NULL ) {
ERROR (" read_uids_guids : failed to allocate id table\n " );
ERROR (" read_id_table : failed to allocate id table\n " );
return FALSE ;
}
res = read_fs_bytes (fd, sBlk .s .id_table_start ,
SQUASHFS_ID_BLOCK_BYTES (sBlk .s .no_ids ), id_index_table);
res = read_fs_bytes (fd, sBlk .s .id_table_start , length, id_index_table);
if (res == FALSE ) {
ERROR (" read_uids_guids : failed to read id index table\n " );
ERROR (" read_id_table : failed to read id index table\n " );
return FALSE ;
}
SQUASHFS_INSWAP_ID_BLOCKS (id_index_table, indexes);
@@ -393,7 +443,7 @@ static int read_uids_guids(long long *table_start)
res = read_block (fd, id_index_table[i], NULL , expected,
((char *) id_table) + i * SQUASHFS_METADATA_SIZE);
if (res == FALSE ) {
ERROR (" read_uids_guids : failed to read id table block"
ERROR (" read_id_table : failed to read id table block"
" \n " );
return FALSE ;
}
@@ -407,12 +457,30 @@ static int read_uids_guids(long long *table_start)
static int parse_exports_table (long long *table_start)
{
/*
* Note on overflow limits:
* Size of SBlk.s.inodes is 2^32 (unsigned int)
* Max indexes is (2^32*8)/8K or 2^22
* Max length is ((2^32*8)/8K)*8 or 2^25
*/
int res;
int indexes = SQUASHFS_LOOKUP_BLOCKS (sBlk .s .inodes );
long long export_index_table[indexes];
int indexes = SQUASHFS_LOOKUP_BLOCKS ((long long ) sBlk .s .inodes );
int length = SQUASHFS_LOOKUP_BLOCK_BYTES ((long long ) sBlk .s .inodes );
long long *export_index_table;
/*
* The size of the index table (length bytes) should match the
* table start and end points
*/
if (length != (*table_start - sBlk .s .lookup_table_start )) {
ERROR (" parse_exports_table: Bad inode count in super block\n " );
return FALSE ;
}
res = read_fs_bytes (fd, sBlk .s .lookup_table_start ,
SQUASHFS_LOOKUP_BLOCK_BYTES (sBlk .s .inodes ), export_index_table);
export_index_table = alloc_index_table (indexes);
res = read_fs_bytes (fd, sBlk .s .lookup_table_start , length,
export_index_table);
if (res == FALSE ) {
ERROR (" parse_exports_table: failed to read export index table\n " );
return FALSE ;
@@ -432,30 +500,118 @@ static int parse_exports_table(long long *table_start)
int read_filesystem_tables_4 ()
{
long long directory_table_end, table_start;
long long table_start;
if (read_xattrs_from_disk (fd, &sBlk .s , no_xattrs, &table_start) == 0 )
return FALSE ;
/* Read xattrs */
if (sBlk .s .xattr_id_table_start != SQUASHFS_INVALID_BLK) {
/* sanity check super block contents */
if (sBlk .s .xattr_id_table_start >= sBlk .s .bytes_used ) {
ERROR (" read_filesystem_tables: xattr id table start too large in super block\n " );
goto corrupted;
}
if (read_uids_guids (&table_start) == FALSE )
return FALSE ;
if (read_xattrs_from_disk (fd, &sBlk .s , no_xattrs, &table_start) == 0 )
goto corrupted;
} else
table_start = sBlk .s .bytes_used ;
if (parse_exports_table (&table_start) == FALSE )
return FALSE ;
/* Read id lookup table */
if (read_fragment_table (&directory_table_end) == FALSE )
return FALSE ;
/* Sanity check super block contents */
if (sBlk .s .id_table_start >= table_start) {
ERROR (" read_filesystem_tables: id table start too large in super block\n " );
goto corrupted;
}
if (read_inode_table (sBlk .s .inode_table_start ,
sBlk .s .directory_table_start ) == FALSE )
return FALSE ;
/* there should always be at least one id */
if (sBlk .s .no_ids == 0 ) {
ERROR (" read_filesystem_tables: Bad id count in super block\n " );
goto corrupted;
}
/*
* the number of ids can never be more than double the number of inodes
* (the maximum is a unique uid and gid for each inode).
*/
if (sBlk .s .no_ids > (sBlk .s .inodes * 2L )) {
ERROR (" read_filesystem_tables: Bad id count in super block\n " );
goto corrupted;
}
if (read_id_table (&table_start) == FALSE )
goto corrupted;
/* Read exports table */
if (sBlk .s .lookup_table_start != SQUASHFS_INVALID_BLK) {
/* sanity check super block contents */
if (sBlk .s .lookup_table_start >= table_start) {
ERROR (" read_filesystem_tables: lookup table start too large in super block\n " );
goto corrupted;
}
if (parse_exports_table (&table_start) == FALSE )
goto corrupted;
}
/* Read fragment table */
if (sBlk .s .fragments != 0 ) {
/* Sanity check super block contents */
if (sBlk .s .fragment_table_start >= table_start) {
ERROR (" read_filesystem_tables: fragment table start too large in super block\n " );
goto corrupted;
}
/* The number of fragments should not exceed the number of inodes */
if (sBlk .s .fragments > sBlk .s .inodes ) {
ERROR (" read_filesystem_tables: Bad fragment count in super block\n " );
goto corrupted;
}
if (read_fragment_table (&table_start) == FALSE )
goto corrupted;
} else {
/*
* Sanity check super block contents - with 0 fragments,
* the fragment table should be empty
*/
if (sBlk .s .fragment_table_start != table_start) {
ERROR (" read_filesystem_tables: fragment table start invalid in super block\n " );
goto corrupted;
}
}
/* Read directory table */
/* Sanity check super block contents */
if (sBlk .s .directory_table_start >= table_start) {
ERROR (" read_filesystem_tables: directory table start too large in super block\n " );
goto corrupted;
}
if (read_directory_table (sBlk .s .directory_table_start ,
directory_table_end) == FALSE )
return FALSE ;
table_start) == FALSE )
goto corrupted;
/* Read inode table */
/* Sanity check super block contents */
if (sBlk .s .inode_table_start >= sBlk .s .directory_table_start ) {
ERROR (" read_filesystem_tables: inode table start too large in super block\n " );
goto corrupted;
}
if (read_inode_table (sBlk .s .inode_table_start ,
sBlk .s .directory_table_start ) == FALSE )
goto corrupted;
if (no_xattrs)
sBlk .s .xattr_id_table_start = SQUASHFS_INVALID_BLK;
return TRUE ;
corrupted:
ERROR (" File system corruption detected\n " );
return FALSE ;
}