diff mbox series

[for-5.1] qcow2: Don't open images with a backing file and the data-file-raw bit

Message ID 20200415190207.21118-1-berto@igalia.com
State New
Headers show
Series [for-5.1] qcow2: Don't open images with a backing file and the data-file-raw bit | expand

Commit Message

Alberto Garcia April 15, 2020, 7:02 p.m. UTC
Although we cannot create these images with qemu-img it is still
possible to do it using an external tool. QEMU should refuse to open
them until the data-file-raw bit is cleared with 'qemu-img check'.

Signed-off-by: Alberto Garcia <berto@igalia.com>
---
 block/qcow2.c              | 39 ++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/244     | 13 +++++++++++++
 tests/qemu-iotests/244.out | 14 ++++++++++++++
 3 files changed, 66 insertions(+)
diff mbox series

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index b524b0c53f..fcc3810391 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -588,16 +588,49 @@  static void qcow2_add_check_result(BdrvCheckResult *out,
     }
 }
 
+static int qcow2_check_header(BlockDriverState *bs, BdrvCheckResult *result,
+                              BdrvCheckMode fix)
+{
+    BDRVQcow2State *s = bs->opaque;
+    int ret;
+
+    if (bs->backing && data_file_is_raw(bs)) {
+        fprintf(stderr, "%s header: data-file-raw cannot be set "
+                "when there is a backing file.\n",
+                fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR in");
+        if (fix & BDRV_FIX_ERRORS) {
+            s->autoclear_features &= ~QCOW2_AUTOCLEAR_DATA_FILE_RAW;
+            ret = qcow2_update_header(bs);
+            if (ret < 0) {
+                result->check_errors++;
+                return ret;
+            }
+            result->corruptions_fixed++;
+        } else {
+            result->corruptions++;
+        }
+    }
+
+    return 0;
+}
+
 static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
                                               BdrvCheckResult *result,
                                               BdrvCheckMode fix)
 {
+    BdrvCheckResult header_res = {};
     BdrvCheckResult snapshot_res = {};
     BdrvCheckResult refcount_res = {};
     int ret;
 
     memset(result, 0, sizeof(*result));
 
+    ret = qcow2_check_header(bs, &header_res, fix);
+    qcow2_add_check_result(result, &header_res, false);
+    if (ret < 0) {
+        return ret;
+    }
+
     ret = qcow2_check_read_snapshot_table(bs, &snapshot_res, fix);
     if (ret < 0) {
         qcow2_add_check_result(result, &snapshot_res, false);
@@ -1604,6 +1637,12 @@  static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
 
     /* read the backing file name */
     if (header.backing_file_offset != 0) {
+        if (data_file_is_raw(bs) && (!(flags & BDRV_O_CHECK))) {
+            error_setg(errp, "data-file-raw cannot be set when "
+                       "there is a backing file");
+            ret = -EINVAL;
+            goto fail;
+        }
         len = header.backing_file_size;
         if (len > MIN(1023, s->cluster_size - header.backing_file_offset) ||
             len >= sizeof(bs->backing_file)) {
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
index 2ec1815e6f..159941acd4 100755
--- a/tests/qemu-iotests/244
+++ b/tests/qemu-iotests/244
@@ -211,6 +211,19 @@  $QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
 $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
 $QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
 
+echo
+echo "=== Using and repairing an image with backing file and the data_file_raw bit ==="
+echo
+
+# Create an image with a backing file and an external data file
+TEST_IMG_FILE="$TEST_IMG.base" _make_test_img 1M
+_make_test_img -o "data_file=$TEST_IMG.data" -b "$TEST_IMG.base"
+# Set 'data_file_raw' directly on the header (qemu-img amend won't let us)
+poke_file "$TEST_IMG" 95 "\x02"
+# Trying to open the image should produce an error
+$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir
+_check_test_img -r all
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
index 56329deb4b..cab367dfb5 100644
--- a/tests/qemu-iotests/244.out
+++ b/tests/qemu-iotests/244.out
@@ -128,4 +128,18 @@  Offset          Length          Mapped to       File
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
 Images are identical.
 Images are identical.
+
+=== Using and repairing an image with backing file and the data_file_raw bit ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base data_file=TEST_DIR/t.IMGFMT.data
+qemu-img: Could not open 'TEST_DIR/t.qcow2': data-file-raw cannot be set when there is a backing file
+Repairing header: data-file-raw cannot be set when there is a backing file.
+The following inconsistencies were found and repaired:
+
+    0 leaked clusters
+    1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
 *** done