yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
9ae3a8
From 6a7dafce7c4fb8e13e331efb301baedffce08e3f Mon Sep 17 00:00:00 2001
9ae3a8
From: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Date: Mon, 2 Jun 2014 13:54:46 +0200
9ae3a8
Subject: [PATCH 29/31] qcow1: Validate L2 table size (CVE-2014-0222)
9ae3a8
9ae3a8
RH-Author: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Message-id: <1401717288-3918-5-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: 59099
9ae3a8
O-Subject: [RHEL-7.1/7.0.z qemu-kvm PATCH 4/6] qcow1: Validate L2 table size (CVE-2014-0222)
9ae3a8
Bugzilla: 1097229 1097230
9ae3a8
RH-Acked-by: Max Reitz <mreitz@redhat.com>
9ae3a8
RH-Acked-by: Fam Zheng <famz@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1097230
9ae3a8
9ae3a8
Too large L2 table sizes cause unbounded allocations. Images actually
9ae3a8
created by qemu-img only have 512 byte or 4k L2 tables.
9ae3a8
9ae3a8
To keep things consistent with cluster sizes, allow ranges between 512
9ae3a8
bytes and 64k (in fact, down to 1 entry = 8 bytes is technically
9ae3a8
working, but L2 table sizes smaller than a cluster don't make a lot of
9ae3a8
sense).
9ae3a8
9ae3a8
This also means that the number of bytes on the virtual disk that are
9ae3a8
described by the same L2 table is limited to at most 8k * 64k or 2^29,
9ae3a8
preventively avoiding any integer overflows.
9ae3a8
9ae3a8
Cc: qemu-stable@nongnu.org
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Reviewed-by: Benoit Canet <benoit@irqsave.net>
9ae3a8
(cherry picked from commit 42eb58179b3b215bb507da3262b682b8a2ec10b5)
9ae3a8
---
9ae3a8
 block/qcow.c               |  8 ++++++++
9ae3a8
 tests/qemu-iotests/092     | 15 +++++++++++++++
9ae3a8
 tests/qemu-iotests/092.out | 11 +++++++++++
9ae3a8
 3 files changed, 34 insertions(+)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 block/qcow.c               |    8 ++++++++
9ae3a8
 tests/qemu-iotests/092     |   15 +++++++++++++++
9ae3a8
 tests/qemu-iotests/092.out |   11 +++++++++++
9ae3a8
 3 files changed, 34 insertions(+), 0 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/qcow.c b/block/qcow.c
9ae3a8
index 2efe2fc..f266701 100644
9ae3a8
--- a/block/qcow.c
9ae3a8
+++ b/block/qcow.c
9ae3a8
@@ -137,6 +137,14 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
         goto fail;
9ae3a8
     }
9ae3a8
 
9ae3a8
+    /* l2_bits specifies number of entries; storing a uint64_t in each entry,
9ae3a8
+     * so bytes = num_entries << 3. */
9ae3a8
+    if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
9ae3a8
+        error_setg(errp, "L2 table size must be between 512 and 64k");
9ae3a8
+        ret = -EINVAL;
9ae3a8
+        goto fail;
9ae3a8
+    }
9ae3a8
+
9ae3a8
     if (header.crypt_method > QCOW_CRYPT_AES) {
9ae3a8
         error_setg(errp, "invalid encryption method in qcow header");
9ae3a8
         ret = -EINVAL;
9ae3a8
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
9ae3a8
index d060e6f..fb8bacc 100755
9ae3a8
--- a/tests/qemu-iotests/092
9ae3a8
+++ b/tests/qemu-iotests/092
9ae3a8
@@ -44,6 +44,7 @@ _supported_proto generic
9ae3a8
 _supported_os Linux
9ae3a8
 
9ae3a8
 offset_cluster_bits=32
9ae3a8
+offset_l2_bits=33
9ae3a8
 
9ae3a8
 echo
9ae3a8
 echo "== Invalid cluster size =="
9ae3a8
@@ -57,6 +58,20 @@ poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
9ae3a8
 poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
9ae3a8
 { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
 
9ae3a8
+echo
9ae3a8
+echo "== Invalid L2 table size =="
9ae3a8
+_make_test_img 64M
9ae3a8
+poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
9ae3a8
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
9ae3a8
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
9ae3a8
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
9ae3a8
+
9ae3a8
+# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
9ae3a8
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
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
 rm -f $seq.full
9ae3a8
diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out
9ae3a8
index 8bf8158..73918b3 100644
9ae3a8
--- a/tests/qemu-iotests/092.out
9ae3a8
+++ b/tests/qemu-iotests/092.out
9ae3a8
@@ -10,4 +10,15 @@ qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and
9ae3a8
 no file open, try 'help open'
9ae3a8
 qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
9ae3a8
 no file open, try 'help open'
9ae3a8
+
9ae3a8
+== Invalid L2 table size ==
9ae3a8
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
9ae3a8
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
9ae3a8
+no file open, try 'help open'
9ae3a8
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
9ae3a8
+no file open, try 'help open'
9ae3a8
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
9ae3a8
+no file open, try 'help open'
9ae3a8
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
9ae3a8
+no file open, try 'help open'
9ae3a8
 *** done
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8