From patchwork Fri Jul 18 12:41:17 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 371520 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 0E9E914011D for ; Fri, 18 Jul 2014 22:42:14 +1000 (EST) Received: from localhost ([::1]:49639 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X87UJ-0001sF-Oz for incoming@patchwork.ozlabs.org; Fri, 18 Jul 2014 08:42:11 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45346) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X87Th-0000sH-I6 for qemu-devel@nongnu.org; Fri, 18 Jul 2014 08:41:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X87Ta-0004dy-Jm for qemu-devel@nongnu.org; Fri, 18 Jul 2014 08:41:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:9981) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X87Ta-0004da-AP for qemu-devel@nongnu.org; Fri, 18 Jul 2014 08:41:26 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s6ICfOrM019682 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 18 Jul 2014 08:41:24 -0400 Received: from localhost (ovpn-112-33.ams2.redhat.com [10.36.112.33]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s6ICfMW0010354; Fri, 18 Jul 2014 08:41:23 -0400 From: Stefan Hajnoczi To: Date: Fri, 18 Jul 2014 13:41:17 +0100 Message-Id: <1405687280-6603-2-git-send-email-stefanha@redhat.com> In-Reply-To: <1405687280-6603-1-git-send-email-stefanha@redhat.com> References: <1405687280-6603-1-git-send-email-stefanha@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Peter Maydell Subject: [Qemu-devel] [PULL for-2.1 1/4] qcow2: Fix error path for unknown incompatible features 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 qcow2's report_unsupported_feature() had two bugs: A 32 bit truncation would prevent feature table entries for bits 32-63 from being used, and it could assign errp multiple times if there was more than one unknown feature, resulting in an error_set() assertion failure. Fix the truncation, make sure to set the error exactly once and add a qemu-iotests case for it. This fixes https://bugs.launchpad.net/qemu/+bug/1342704/ Reported-by: Maria Kustova Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- block/qcow2.c | 21 +++++++++++++----- tests/qemu-iotests/036 | 52 ++++++++++++++++++++++++++++++++++++++++++++- tests/qemu-iotests/036.out | 35 ++++++++++++++++++++++++++++++ tests/qemu-iotests/qcow2.py | 15 ++++++++----- 4 files changed, 112 insertions(+), 11 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index b0faa69..e1631d5 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -210,20 +210,31 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs, static void report_unsupported_feature(BlockDriverState *bs, Error **errp, Qcow2Feature *table, uint64_t mask) { + char *features = g_strdup(""); + char *old; + while (table && table->name[0] != '\0') { if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) { - if (mask & (1 << table->bit)) { - report_unsupported(bs, errp, "%.46s", table->name); - mask &= ~(1 << table->bit); + if (mask & (1ULL << table->bit)) { + old = features; + features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "", + table->name); + g_free(old); + mask &= ~(1ULL << table->bit); } } table++; } if (mask) { - report_unsupported(bs, errp, "Unknown incompatible feature: %" PRIx64, - mask); + old = features; + features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64, + old, *old ? ", " : "", mask); + g_free(old); } + + report_unsupported(bs, errp, "%s", features); + g_free(features); } /* diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index a773653..392f1ef 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -1,6 +1,6 @@ #!/bin/bash # -# Test that qcow2 unknown autoclear feature bits are cleared +# Test qcow2 feature bits # # Copyright (C) 2011 Red Hat, Inc. # Copyright IBM, Corp. 2010 @@ -50,6 +50,56 @@ _supported_os Linux # Only qcow2v3 and later supports feature bits IMGOPTS="compat=1.1" +echo +echo === Image with unknown incompatible feature bit === +echo +_make_test_img 64M +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 + +# Without feature table +$PYTHON qcow2.py "$TEST_IMG" dump-header +_img_info + +# With feature table containing bit 63 +printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +echo +echo === Image with multiple incompatible feature bits === +echo +_make_test_img 64M +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 61 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 62 +$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 + +# Without feature table +_img_info + +# With feature table containing bit 63 +printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing bit 61 +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing bits 61 and 62 +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s" "test1" "" "test2" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing all bits +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s\x00\x3f%s\x00%40s" "test1" "" "test2" "" "test3" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + +# With feature table containing unrelated bits, including compatible/autoclear +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 +printf "\x01\x3d%s\x00%40s\x00\x3e%s\x00%40s\x02\x3f%s\x00%40s\x00\x3c%s\x00%40s" "test1" "" "test2" "" "test3" "" "test4" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857 +_img_info + + echo === Create image with unknown autoclear feature bit === echo _make_test_img 64M diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 55a3e6e..720bd89 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -1,4 +1,39 @@ QA output created by 036 + +=== Image with unknown incompatible feature bit === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +magic 0x514649fb +version 3 +backing_file_offset 0x0 +backing_file_size 0x0 +cluster_bits 16 +size 67108864 +crypt_method 0 +l1_size 1 +l1_table_offset 0x30000 +refcount_table_offset 0x10000 +refcount_table_clusters 1 +nb_snapshots 0 +snapshot_offset 0x0 +incompatible_features 0x8000000000000000 +compatible_features 0x0 +autoclear_features 0x0 +refcount_order 4 +header_length 104 + +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature + +=== Image with multiple incompatible feature bits === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: e000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: 6000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: c000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, test3 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test2, Unknown incompatible feature: a000000000000000 === Create image with unknown autoclear feature bit === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 44a2b45..2058596 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -176,6 +176,10 @@ def cmd_add_header_ext(fd, magic, data): h.extensions.append(QcowHeaderExtension.create(magic, data)) h.update(fd) +def cmd_add_header_ext_stdio(fd, magic): + data = sys.stdin.read() + cmd_add_header_ext(fd, magic, data) + def cmd_del_header_ext(fd, magic): try: magic = int(magic, 0) @@ -220,11 +224,12 @@ def cmd_set_feature_bit(fd, group, bit): h.update(fd) cmds = [ - [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ], - [ 'set-header', cmd_set_header, 2, 'Set a field in the header'], - [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ], - [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ], - [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], + [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ], + [ 'set-header', cmd_set_header, 2, 'Set a field in the header'], + [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ], + [ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ], + [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ], + [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'], ] def main(filename, cmd, args):