|
|
9ae3a8 |
From 6707cb9501355de8244d224b3a8140c0fe62a983 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
Date: Tue, 25 Mar 2014 14:23:30 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 23/49] qcow2: Validate refcount table offset
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1395753835-7591-24-git-send-email-kwolf@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: n/a
|
|
|
9ae3a8 |
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 23/48] qcow2: Validate refcount table offset
|
|
|
9ae3a8 |
Bugzilla: 1066691
|
|
|
9ae3a8 |
RH-Acked-by: Jeff Cody <jcody@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1066691
|
|
|
9ae3a8 |
Upstream status: Series embargoed
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
The end of the refcount table must not exceed INT64_MAX so that integer
|
|
|
9ae3a8 |
overflows are avoided.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Also check for misaligned refcount table. Such images are invalid and
|
|
|
9ae3a8 |
probably the result of data corruption. Error out to avoid further
|
|
|
9ae3a8 |
corruption.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
block/qcow2.c | 33 +++++++++++++++++++++++++++++++++
|
|
|
9ae3a8 |
tests/qemu-iotests/080 | 13 +++++++++++++
|
|
|
9ae3a8 |
tests/qemu-iotests/080.out | 10 ++++++++++
|
|
|
9ae3a8 |
3 files changed, 56 insertions(+), 0 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/block/qcow2.c b/block/qcow2.c
|
|
|
9ae3a8 |
index a7780ac..5513fac 100644
|
|
|
9ae3a8 |
--- a/block/qcow2.c
|
|
|
9ae3a8 |
+++ b/block/qcow2.c
|
|
|
9ae3a8 |
@@ -329,6 +329,32 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
|
|
9ae3a8 |
return ret;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
|
|
|
9ae3a8 |
+ uint64_t entries, size_t entry_len)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ BDRVQcowState *s = bs->opaque;
|
|
|
9ae3a8 |
+ uint64_t size;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* Use signed INT64_MAX as the maximum even for uint64_t header fields,
|
|
|
9ae3a8 |
+ * because values will be passed to qemu functions taking int64_t. */
|
|
|
9ae3a8 |
+ if (entries > INT64_MAX / entry_len) {
|
|
|
9ae3a8 |
+ return -EINVAL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ size = entries * entry_len;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (INT64_MAX - size < offset) {
|
|
|
9ae3a8 |
+ return -EINVAL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* Tables must be cluster aligned */
|
|
|
9ae3a8 |
+ if (offset & (s->cluster_size - 1)) {
|
|
|
9ae3a8 |
+ return -EINVAL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ return 0;
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static QemuOptsList qcow2_runtime_opts = {
|
|
|
9ae3a8 |
.name = "qcow2",
|
|
|
9ae3a8 |
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
|
|
|
9ae3a8 |
@@ -589,6 +615,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
9ae3a8 |
goto fail;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ ret = validate_table_offset(bs, s->refcount_table_offset,
|
|
|
9ae3a8 |
+ s->refcount_table_size, sizeof(uint64_t));
|
|
|
9ae3a8 |
+ if (ret < 0) {
|
|
|
9ae3a8 |
+ error_setg(errp, "Invalid reference count table offset");
|
|
|
9ae3a8 |
+ goto fail;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
s->snapshots_offset = header.snapshots_offset;
|
|
|
9ae3a8 |
s->nb_snapshots = header.nb_snapshots;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
|
|
|
9ae3a8 |
index 6179e05..f58ac73 100755
|
|
|
9ae3a8 |
--- a/tests/qemu-iotests/080
|
|
|
9ae3a8 |
+++ b/tests/qemu-iotests/080
|
|
|
9ae3a8 |
@@ -45,6 +45,7 @@ _supported_os Linux
|
|
|
9ae3a8 |
header_size=104
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
offset_backing_file_offset=8
|
|
|
9ae3a8 |
+offset_refcount_table_offset=48
|
|
|
9ae3a8 |
offset_refcount_table_clusters=56
|
|
|
9ae3a8 |
offset_header_size=100
|
|
|
9ae3a8 |
offset_ext_magic=$header_size
|
|
|
9ae3a8 |
@@ -76,6 +77,18 @@ poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\xff\xff\xff\xff"
|
|
|
9ae3a8 |
poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x02\x00\x01"
|
|
|
9ae3a8 |
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+echo
|
|
|
9ae3a8 |
+echo "== Misaligned refcount table =="
|
|
|
9ae3a8 |
+_make_test_img 64M
|
|
|
9ae3a8 |
+poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\x12\x34\x56\x78\x90\xab\xcd\xef"
|
|
|
9ae3a8 |
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+echo
|
|
|
9ae3a8 |
+echo "== Huge refcount offset =="
|
|
|
9ae3a8 |
+_make_test_img 64M
|
|
|
9ae3a8 |
+poke_file "$TEST_IMG" "$offset_refcount_table_offset" "\xff\xff\xff\xff\xff\xff\x00\x00"
|
|
|
9ae3a8 |
+poke_file "$TEST_IMG" "$offset_refcount_table_clusters" "\x00\x00\x00\x7f"
|
|
|
9ae3a8 |
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
# success, all done
|
|
|
9ae3a8 |
echo "*** done"
|
|
|
9ae3a8 |
diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
|
|
|
9ae3a8 |
index 6fef6d9..f919b58 100644
|
|
|
9ae3a8 |
--- a/tests/qemu-iotests/080.out
|
|
|
9ae3a8 |
+++ b/tests/qemu-iotests/080.out
|
|
|
9ae3a8 |
@@ -20,4 +20,14 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large
|
|
|
9ae3a8 |
no file open, try 'help open'
|
|
|
9ae3a8 |
qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large
|
|
|
9ae3a8 |
no file open, try 'help open'
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+== Misaligned refcount table ==
|
|
|
9ae3a8 |
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
|
|
9ae3a8 |
+qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
|
|
|
9ae3a8 |
+no file open, try 'help open'
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+== Huge refcount offset ==
|
|
|
9ae3a8 |
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
|
|
9ae3a8 |
+qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset
|
|
|
9ae3a8 |
+no file open, try 'help open'
|
|
|
9ae3a8 |
*** done
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.7.1
|
|
|
9ae3a8 |
|