diff --git a/block.c b/block.c index 4acfebf0e8..35a372df57 100644 --- a/block.c +++ b/block.c @@ -6139,6 +6139,26 @@ void bdrv_img_create(const char *filename, const char *fmt, error_append_hint(&local_err, "Could not open backing image.\n"); goto out; } else { + if (!backing_fmt) { + warn_report("Deprecated use of backing file without explicit " + "backing format (detected format of %s)", + bs->drv->format_name); + if (bs->drv != &bdrv_raw) { + /* + * A probe of raw deserves the most attention: + * leaving the backing format out of the image + * will ensure bs->probed is set (ensuring we + * don't accidentally commit into the backing + * file), and allow more spots to warn the users + * to fix their toolchain when opening this image + * later. For other images, we can safely record + * the format that we probed. + */ + backing_fmt = bs->drv->format_name; + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, backing_fmt, + NULL); + } + } if (size == -1) { /* Opened BS, have no size */ size = bdrv_getlength(bs); @@ -6152,7 +6172,12 @@ void bdrv_img_create(const char *filename, const char *fmt, } bdrv_unref(bs); } - } /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */ + } else if (backing_file && !backing_fmt) { + warn_report("Deprecated use of unopened backing file without " + "explicit backing format, use of this image requires " + "potentially unsafe format probing"); + } if (size == -1) { error_setg(errp, "Image creation needs a size parameter"); diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index c1f019b9d2..971b65be75 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -439,6 +439,26 @@ image). Rather, any changes to the backing chain should be performed with ``qemu-img rebase -u`` either before or after the remaining changes being performed by amend, as appropriate. +qemu-img backing file without format (since 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''' + +The use of ``qemu-img create``, ``qemu-img rebase``, or ``qemu-img +convert`` to create or modify an image that depends on a backing file +now recommends that an explicit backing format be provided. This is +for safety: if QEMU probes a different format than what you thought, +the data presented to the guest will be corrupt; similarly, presenting +a raw image to a guest allows a potential security exploit if a future +probe sees a non-raw image based on guest writes. + +To avoid the warning message, or even future refusal to create an +unsafe image, you must pass ``-o backing_fmt=`` (or the shorthand +``-F`` during create) to specify the intended backing format. You may +use ``qemu-img rebase -u`` to retroactively add a backing format to an +existing image. However, be aware that there are already potential +security risks to blindly using ``qemu-img info`` to probe the format +of an untrusted backing image, when deciding what format to add into +an existing image. + Backwards compatibility ----------------------- diff --git a/qemu-img.c b/qemu-img.c index a6df64a949..efb6ca139e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2517,6 +2517,13 @@ static int img_convert(int argc, char **argv) goto out; } + if (out_baseimg_param) { + if (!qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT)) { + warn_report("Deprecated use of backing file without explicit " + "backing format"); + } + } + /* Check if compression is supported */ if (s.compressed) { bool encryption = @@ -3797,7 +3804,7 @@ static int img_rebase(int argc, char **argv) * doesn't change when we switch the backing file. */ if (out_baseimg && *out_baseimg) { - ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt, false); + ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt, true); } else { ret = bdrv_change_backing_file(bs, NULL, NULL, false); } diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index 26104fff6c..5a7b0a4998 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -39,12 +39,21 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow2 _supported_proto generic _unsupported_proto vxhs +# At least OpenBSD doesn't seem to have truncate +_supported_os Linux # qcow2.py does not work too well with external data files _unsupported_imgopts data_file +# Intentionally specify backing file without backing format; demonstrate +# the difference in warning messages when backing file could be probed. +# Note that only a non-raw probe result will affect the resulting image. +truncate -s $((64 * 1024 * 1024)) "$TEST_IMG.orig" +_make_test_img -b "$TEST_IMG.orig" 64M TEST_IMG="$TEST_IMG.base" _make_test_img 64M +$QEMU_IMG convert -O qcow2 -B "$TEST_IMG.orig" "$TEST_IMG.orig" "$TEST_IMG" _make_test_img -b "$TEST_IMG.base" 64M +_make_test_img -u -b "$TEST_IMG.base" 64M # Set an invalid backing file format $PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo" @@ -55,6 +64,11 @@ _img_info $QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir $QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io +# Rebase the image, to show that omitting backing format triggers a warning, +# but probing now lets us use the backing file. +$QEMU_IMG rebase -u -b "$TEST_IMG.base" "$TEST_IMG" +$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir + # success, all done echo '*** done' rm -f $seq.full diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out index 67adef37a4..0a37d20c82 100644 --- a/tests/qemu-iotests/114.out +++ b/tests/qemu-iotests/114.out @@ -1,5 +1,11 @@ QA output created by 114 +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +qemu-img: warning: Deprecated use of backing file without explicit backing format +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +qemu-img: warning: Deprecated use of unopened backing file without explicit backing format, use of this image requires potentially unsafe format probing Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base image: TEST_DIR/t.IMGFMT file format: IMGFMT @@ -11,4 +17,7 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknow no file open, try 'help open' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: warning: Deprecated use of backing file without explicit backing format, use of this image requires potentially unsafe format probing +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/301.out b/tests/qemu-iotests/301.out index 281a16d87a..9004dad639 100644 --- a/tests/qemu-iotests/301.out +++ b/tests/qemu-iotests/301.out @@ -2,7 +2,8 @@ QA output created by 301 == qcow backed by qcow == Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of IMGFMT) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT image: TEST_DIR/t.IMGFMT file format: IMGFMT virtual size: 32 MiB (33554432 bytes) @@ -35,6 +36,7 @@ cluster_size: 512 backing file: TEST_DIR/t.IMGFMT.base == qcow backed by raw == +qemu-img: warning: Deprecated use of backing file without explicit backing format (detected format of raw) Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base image: TEST_DIR/t.IMGFMT file format: IMGFMT