diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-23 08:34:11 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-23 08:48:04 +0200 | 
| commit | e6c869ab1753986b032463f2e0bd5fad7bc70e0f (patch) | |
| tree | 6ef2ecc7a55ecb1fa9087e7d0e0628a7eb9616c8 /lib | |
| parent | 88d53c4c124a6e3979a7b4f79b3f95bfc3706604 (diff) | |
Fix tree node scanning
 - Bail early on empty directories without touching the meta readers.
 - Aport the directory read loop if we can't even read a header anymore,
   no matter if there are bytes remaining.
 - Also add that same condition to the inner loop.
The later two actually caused a numeric overflow on some particularly
malformed squashfs images, going into a RAM filling infinite loop.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqfs/deserialize_fstree.c | 16 | 
1 files changed, 10 insertions, 6 deletions
| diff --git a/lib/sqfs/deserialize_fstree.c b/lib/sqfs/deserialize_fstree.c index e90e1c1..bc1d6e4 100644 --- a/lib/sqfs/deserialize_fstree.c +++ b/lib/sqfs/deserialize_fstree.c @@ -38,27 +38,31 @@ static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,  	size_t size, diff;  	uint32_t i; +	size = root->data.dir->size; +	if (size <= sizeof(hdr)) +		return 0; +  	block_start = root->data.dir->start_block;  	block_start += super->directory_table_start;  	if (meta_reader_seek(dr, block_start, root->data.dir->block_offset))  		return -1; -	size = root->data.dir->size; - -	while (size != 0) { +	while (size > sizeof(hdr)) {  		if (meta_reader_read_dir_header(dr, &hdr))  			return -1; -		size -= sizeof(hdr) > size ? size : sizeof(hdr); +		size -= sizeof(hdr); -		for (i = 0; i <= hdr.count; ++i) { +		for (i = 0; i <= hdr.count && size > sizeof(*ent); ++i) {  			ent = meta_reader_read_dir_ent(dr);  			if (ent == NULL)  				return -1;  			diff = sizeof(*ent) + strlen((char *)ent->name); -			size -= diff > size ? size : diff; +			if (diff > size) +				break; +			size -= diff;  			if (should_skip(ent->type, flags)) {  				free(ent); | 
