From patchwork Wed Mar 26 12:05:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 333883 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 6D83C14003E for ; Thu, 27 Mar 2014 00:14:21 +1100 (EST) Received: from localhost ([::1]:47579 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmpe-00015J-B6 for incoming@patchwork.ozlabs.org; Wed, 26 Mar 2014 08:21:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50178) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmbg-0001JR-SY for qemu-devel@nongnu.org; Wed, 26 Mar 2014 08:07:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WSmba-00042d-SG for qemu-devel@nongnu.org; Wed, 26 Mar 2014 08:06:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49678) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmba-00042O-Jy; Wed, 26 Mar 2014 08:06:50 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s2QC6oQX022914 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 26 Mar 2014 08:06:50 -0400 Received: from localhost (dhcp-64-106.muc.redhat.com [10.32.64.106]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id s2QC6mTi009928; Wed, 26 Mar 2014 08:06:49 -0400 From: Stefan Hajnoczi To: Date: Wed, 26 Mar 2014 13:05:44 +0100 Message-Id: <1395835569-21193-23-git-send-email-stefanha@redhat.com> In-Reply-To: <1395835569-21193-1-git-send-email-stefanha@redhat.com> References: <1395835569-21193-1-git-send-email-stefanha@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , pmatouse@redhat.com, qemu-stable@nongnu.org Subject: [Qemu-devel] [PATCH for-2.0 22/47] qcow2: Validate refcount table offset 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: Kevin Wolf The end of the refcount table must not exceed INT64_MAX so that integer overflows are avoided. Also check for misaligned refcount table. Such images are invalid and probably the result of data corruption. Error out to avoid further corruption. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/qcow2.c | 33 +++++++++++++++++++++++++++++++++ tests/qemu-iotests/080 | 13 +++++++++++++ tests/qemu-iotests/080.out | 10 ++++++++++ 3 files changed, 56 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index f900869..e813a5e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -329,6 +329,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result, return ret; } +static int validate_table_offset(BlockDriverState *bs, uint64_t offset, + uint64_t entries, size_t entry_len) +{ + BDRVQcowState *s = bs->opaque; + uint64_t size; + + /* Use signed INT64_MAX as the maximum even for uint64_t header fields, + * because values will be passed to qemu functions taking int64_t. */ + if (entries > INT64_MAX / entry_len) { + return -EINVAL; + } + + size = entries * entry_len; + + if (INT64_MAX - size < offset) { + return -EINVAL; + } + + /* Tables must be cluster aligned */ + if (offset & (s->cluster_size - 1)) { + return -EINVAL; + } + + return 0; +} + static QemuOptsList qcow2_runtime_opts = { .name = "qcow2", .head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head), @@ -589,6 +615,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + ret = validate_table_offset(bs, s->refcount_table_offset, + s->refcount_table_size, sizeof(uint64_t)); + if (ret < 0) { + error_setg(errp, "Invalid reference count table offset"); + goto fail; + } + s->snapshots_offset = header.snapshots_offset; s->nb_snapshots = header.nb_snapshots; diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 index 6179e05..f58ac73 100755 --- a/tests/qemu-iotests/080 +++ b/tests/qemu-iotests/080 @@ -45,6 +45,7 @@ _supported_os Linux header_size=104 offset_backing_file_offset=8 +offset_refcount_table_offset=48 offset_refcount_table_clusters=56 offset_header_size=100 offset_ext_magic=$header_size @@ -76,6 +77,18 @@ poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\xff\xff\xff\xff" poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x02\x00\x01" { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir +echo +echo "== Misaligned refcount table ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\x12\x34\x56\x78\x90\xab\xcd\xef" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "== Huge refcount offset ==" +_make_test_img 64M +poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\xff\xff\xff\xff\xff\xff\x00\x00" +poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x00\x00\x7f" +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir # success, all done echo "*** done" diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out index 6fef6d9..f919b58 100644 --- a/tests/qemu-iotests/080.out +++ b/tests/qemu-iotests/080.out @@ -20,4 +20,14 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large no file open, try 'help open' qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large no file open, try 'help open' + +== Misaligned refcount table == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset +no file open, try 'help open' + +== Huge refcount offset == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset +no file open, try 'help open' *** done