mirror of https://github.com/xemu-project/xemu.git
qcow2: Fix error path for unknown incompatible features
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 <maria.k@catit.be> Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
5a73480450
commit
12ac6d3db7
|
@ -210,20 +210,31 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
|
||||||
static void report_unsupported_feature(BlockDriverState *bs,
|
static void report_unsupported_feature(BlockDriverState *bs,
|
||||||
Error **errp, Qcow2Feature *table, uint64_t mask)
|
Error **errp, Qcow2Feature *table, uint64_t mask)
|
||||||
{
|
{
|
||||||
|
char *features = g_strdup("");
|
||||||
|
char *old;
|
||||||
|
|
||||||
while (table && table->name[0] != '\0') {
|
while (table && table->name[0] != '\0') {
|
||||||
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
|
||||||
if (mask & (1 << table->bit)) {
|
if (mask & (1ULL << table->bit)) {
|
||||||
report_unsupported(bs, errp, "%.46s", table->name);
|
old = features;
|
||||||
mask &= ~(1 << table->bit);
|
features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
|
||||||
|
table->name);
|
||||||
|
g_free(old);
|
||||||
|
mask &= ~(1ULL << table->bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table++;
|
table++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
report_unsupported(bs, errp, "Unknown incompatible feature: %" PRIx64,
|
old = features;
|
||||||
mask);
|
features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
|
||||||
|
old, *old ? ", " : "", mask);
|
||||||
|
g_free(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
report_unsupported(bs, errp, "%s", features);
|
||||||
|
g_free(features);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Test that qcow2 unknown autoclear feature bits are cleared
|
# Test qcow2 feature bits
|
||||||
#
|
#
|
||||||
# Copyright (C) 2011 Red Hat, Inc.
|
# Copyright (C) 2011 Red Hat, Inc.
|
||||||
# Copyright IBM, Corp. 2010
|
# Copyright IBM, Corp. 2010
|
||||||
|
@ -50,6 +50,56 @@ _supported_os Linux
|
||||||
# Only qcow2v3 and later supports feature bits
|
# Only qcow2v3 and later supports feature bits
|
||||||
IMGOPTS="compat=1.1"
|
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 === Create image with unknown autoclear feature bit ===
|
||||||
echo
|
echo
|
||||||
_make_test_img 64M
|
_make_test_img 64M
|
||||||
|
|
|
@ -1,4 +1,39 @@
|
||||||
QA output created by 036
|
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 ===
|
=== Create image with unknown autoclear feature bit ===
|
||||||
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
|
|
|
@ -176,6 +176,10 @@ def cmd_add_header_ext(fd, magic, data):
|
||||||
h.extensions.append(QcowHeaderExtension.create(magic, data))
|
h.extensions.append(QcowHeaderExtension.create(magic, data))
|
||||||
h.update(fd)
|
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):
|
def cmd_del_header_ext(fd, magic):
|
||||||
try:
|
try:
|
||||||
magic = int(magic, 0)
|
magic = int(magic, 0)
|
||||||
|
@ -220,11 +224,12 @@ def cmd_set_feature_bit(fd, group, bit):
|
||||||
h.update(fd)
|
h.update(fd)
|
||||||
|
|
||||||
cmds = [
|
cmds = [
|
||||||
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
|
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
|
||||||
[ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
|
[ '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', cmd_add_header_ext, 2, 'Add a header extension' ],
|
||||||
[ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
|
[ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ],
|
||||||
[ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
|
[ '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):
|
def main(filename, cmd, args):
|
||||||
|
|
Loading…
Reference in New Issue