diff --git a/block/dmg.c b/block/dmg.c index c571ac91213820ec9de4c18ad31b228faf00b1ae..04bae729a4765033cc6ac21c92beb51f2d5e7c12 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -285,60 +285,38 @@ fail: return ret; } -static int dmg_open(BlockDriverState *bs, QDict *options, int flags, - Error **errp) +static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds, + uint64_t info_begin, uint64_t info_length) { - BDRVDMGState *s = bs->opaque; - DmgHeaderState ds; - uint64_t info_begin, info_end; - uint32_t count, rsrc_data_offset; - int64_t offset; int ret; + uint32_t count, rsrc_data_offset; + uint64_t info_end; + uint64_t offset; - bs->read_only = 1; - s->n_chunks = 0; - s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; - /* used by dmg_read_mish_block to keep track of the current I/O position */ - ds.last_in_offset = 0; - ds.last_out_offset = 0; - ds.max_compressed_size = 1; - ds.max_sectors_per_chunk = 1; - - /* locate the UDIF trailer */ - offset = dmg_find_koly_offset(bs->file, errp); - if (offset < 0) { - ret = offset; - goto fail; - } - - ret = read_uint64(bs, offset + 0x28, &info_begin); - if (ret < 0) { - goto fail; - } else if (info_begin == 0) { - ret = -EINVAL; - goto fail; - } - + /* read offset from begin of resource fork (info_begin) to resource data */ ret = read_uint32(bs, info_begin, &rsrc_data_offset); if (ret < 0) { goto fail; - } else if (rsrc_data_offset != 0x100) { + } else if (rsrc_data_offset > info_length) { ret = -EINVAL; goto fail; } - ret = read_uint32(bs, info_begin + 4, &count); + /* read length of resource data */ + ret = read_uint32(bs, info_begin + 8, &count); if (ret < 0) { goto fail; - } else if (count == 0) { + } else if (count == 0 || rsrc_data_offset + count > info_length) { ret = -EINVAL; goto fail; } - /* end of resource data, ignoring the following resource map */ - info_end = info_begin + count; /* begin of resource data (consisting of one or more resources) */ - offset = info_begin + 0x100; + offset = info_begin + rsrc_data_offset; + + /* end of resource data (there is possibly a following resource map + * which will be ignored). */ + info_end = offset + count; /* read offsets (mish blocks) from one or more resources in resource data */ while (offset < info_end) { @@ -352,13 +330,63 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags, } offset += 4; - ret = dmg_read_mish_block(bs, &ds, offset, count); + ret = dmg_read_mish_block(bs, ds, offset, count); if (ret < 0) { goto fail; } /* advance offset by size of resource */ offset += count; } + return 0; + +fail: + return ret; +} + +static int dmg_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) +{ + BDRVDMGState *s = bs->opaque; + DmgHeaderState ds; + uint64_t rsrc_fork_offset, rsrc_fork_length; + int64_t offset; + int ret; + + bs->read_only = 1; + s->n_chunks = 0; + s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; + /* used by dmg_read_mish_block to keep track of the current I/O position */ + ds.last_in_offset = 0; + ds.last_out_offset = 0; + ds.max_compressed_size = 1; + ds.max_sectors_per_chunk = 1; + + /* locate the UDIF trailer */ + offset = dmg_find_koly_offset(bs->file, errp); + if (offset < 0) { + ret = offset; + goto fail; + } + + /* offset of resource fork (RsrcForkOffset) */ + ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset); + if (ret < 0) { + goto fail; + } + ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length); + if (ret < 0) { + goto fail; + } + if (rsrc_fork_length != 0) { + ret = dmg_read_resource_fork(bs, &ds, + rsrc_fork_offset, rsrc_fork_length); + if (ret < 0) { + goto fail; + } + } else { + ret = -EINVAL; + goto fail; + } /* initialize zlib engine */ s->compressed_chunk = qemu_try_blockalign(bs->file,