From patchwork Fri Feb 6 16:40:29 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 437376 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F26AA140083 for ; Sat, 7 Feb 2015 03:51:40 +1100 (AEDT) Received: from localhost ([::1]:49318 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJm82-0005er-OP for incoming@patchwork.ozlabs.org; Fri, 06 Feb 2015 11:51:38 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44723) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJlyA-0004al-Uf for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:28 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YJly6-0000mT-I3 for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:26 -0500 Received: from mx1.redhat.com ([209.132.183.28]:39289) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YJly6-0000mL-6x for qemu-devel@nongnu.org; Fri, 06 Feb 2015 11:41:22 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t16GfLKG003585 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 6 Feb 2015 11:41:21 -0500 Received: from noname.redhat.com (ovpn-116-120.ams2.redhat.com [10.36.116.120]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t16GepF0006422; Fri, 6 Feb 2015 11:41:20 -0500 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Fri, 6 Feb 2015 17:40:29 +0100 Message-Id: <1423240849-15499-23-git-send-email-kwolf@redhat.com> In-Reply-To: <1423240849-15499-1-git-send-email-kwolf@redhat.com> References: <1423240849-15499-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com Subject: [Qemu-devel] [PULL 22/42] block/dmg: extract processing of resource forks X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Peter Wu Besides the offset, also read the resource length. This length is now used in the extracted function to verify the end of the resource fork against "count" from the resource fork. Instead of relying on the value of offset to conclude whether the resource fork is available or not (info_begin==0), check the rsrc_fork_length instead. This would allow a dmg file to begin with a resource fork. This seemingly unnecessary restriction was found while trying to craft a DMG file by hand. Other changes: - Do not require resource data offset to be 0x100 (but check that it is within bounds though). - Further improve boundary checking (resource data must be within the resource fork). - Use correct value for resource data length (spotted by John Snow) - Consider the resource data offset when determining info_end. This fixes an EINVAL on the tuxpaint dmg example. The resource fork format is documented at https://developer.apple.com/legacy/library/documentation/mac/pdf/MoreMacintoshToolbox.pdf#page=151 Signed-off-by: Peter Wu Reviewed-by: John Snow Message-id: 1420566495-13284-4-git-send-email-peter@lekensteyn.nl Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/dmg.c | 104 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index c571ac9..04bae72 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,