cryptospore / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
0a122b
From cba6c4e21a8dce857af0ed08d26801ebd5d5598a Mon Sep 17 00:00:00 2001
0a122b
From: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Date: Tue, 25 Mar 2014 14:23:14 +0100
0a122b
Subject: [PATCH 07/49] block/cloop: refuse images with bogus offsets (CVE-2014-0144)
0a122b
0a122b
RH-Author: Kevin Wolf <kwolf@redhat.com>
0a122b
Message-id: <1395753835-7591-8-git-send-email-kwolf@redhat.com>
0a122b
Patchwork-id: n/a
0a122b
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 07/48] block/cloop: refuse images with bogus offsets (CVE-2014-0144)
0a122b
Bugzilla: 1079455
0a122b
RH-Acked-by: Jeff Cody <jcody@redhat.com>
0a122b
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
0a122b
0a122b
From: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
0a122b
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079455
0a122b
Upstream status: Embargoed
0a122b
0a122b
The offsets[] array allows efficient seeking and tells us the maximum
0a122b
compressed data size. If the offsets are bogus the maximum compressed
0a122b
data size will be unrealistic.
0a122b
0a122b
This could cause g_malloc() to abort and bogus offsets mean the image is
0a122b
broken anyway. Therefore we should refuse such images.
0a122b
0a122b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
0a122b
---
0a122b
 block/cloop.c              |   34 +++++++++++++++++++++++++++++-----
0a122b
 tests/qemu-iotests/075     |   15 +++++++++++++++
0a122b
 tests/qemu-iotests/075.out |    8 ++++++++
0a122b
 3 files changed, 52 insertions(+), 5 deletions(-)
0a122b
0a122b
diff --git a/block/cloop.c b/block/cloop.c
0a122b
index 844665e..55a804f 100644
0a122b
--- a/block/cloop.c
0a122b
+++ b/block/cloop.c
0a122b
@@ -124,12 +124,36 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
0a122b
     }
0a122b
 
0a122b
     for(i=0;i<s->n_blocks;i++) {
0a122b
+        uint64_t size;
0a122b
+
0a122b
         s->offsets[i] = be64_to_cpu(s->offsets[i]);
0a122b
-        if (i > 0) {
0a122b
-            uint32_t size = s->offsets[i] - s->offsets[i - 1];
0a122b
-            if (size > max_compressed_block_size) {
0a122b
-                max_compressed_block_size = size;
0a122b
-            }
0a122b
+        if (i == 0) {
0a122b
+            continue;
0a122b
+        }
0a122b
+
0a122b
+        if (s->offsets[i] < s->offsets[i - 1]) {
0a122b
+            error_setg(errp, "offsets not monotonically increasing at "
0a122b
+                       "index %u, image file is corrupt", i);
0a122b
+            ret = -EINVAL;
0a122b
+            goto fail;
0a122b
+        }
0a122b
+
0a122b
+        size = s->offsets[i] - s->offsets[i - 1];
0a122b
+
0a122b
+        /* Compressed blocks should be smaller than the uncompressed block size
0a122b
+         * but maybe compression performed poorly so the compressed block is
0a122b
+         * actually bigger.  Clamp down on unrealistic values to prevent
0a122b
+         * ridiculous s->compressed_block allocation.
0a122b
+         */
0a122b
+        if (size > 2 * MAX_BLOCK_SIZE) {
0a122b
+            error_setg(errp, "invalid compressed block size at index %u, "
0a122b
+                       "image file is corrupt", i);
0a122b
+            ret = -EINVAL;
0a122b
+            goto fail;
0a122b
+        }
0a122b
+
0a122b
+        if (size > max_compressed_block_size) {
0a122b
+            max_compressed_block_size = size;
0a122b
         }
0a122b
     }
0a122b
 
0a122b
diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075
0a122b
index 9c00fa8..d74fb33 100755
0a122b
--- a/tests/qemu-iotests/075
0a122b
+++ b/tests/qemu-iotests/075
0a122b
@@ -44,6 +44,7 @@ _supported_os Linux
0a122b
 
0a122b
 block_size_offset=128
0a122b
 n_blocks_offset=132
0a122b
+offsets_offset=136
0a122b
 
0a122b
 echo
0a122b
 echo "== check that the first sector can be read =="
0a122b
@@ -80,6 +81,20 @@ _use_sample_img simple-pattern.cloop.bz2
0a122b
 poke_file "$TEST_IMG" "$n_blocks_offset" "\x04\x00\x00\x01"
0a122b
 $QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
0a122b
 
0a122b
+echo
0a122b
+echo "== refuse images with non-monotonically increasing offsets =="
0a122b
+_use_sample_img simple-pattern.cloop.bz2
0a122b
+poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\xff\xff\xff\xff"
0a122b
+poke_file "$TEST_IMG" $((offsets_offset + 8)) "\x00\x00\x00\x00\xff\xfe\x00\x00"
0a122b
+$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
0a122b
+
0a122b
+echo
0a122b
+echo "== refuse images with invalid compressed block size =="
0a122b
+_use_sample_img simple-pattern.cloop.bz2
0a122b
+poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
0a122b
+poke_file "$TEST_IMG" $((offsets_offset + 8)) "\xff\xff\xff\xff\xff\xff\xff\xff"
0a122b
+$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir
0a122b
+
0a122b
 # success, all done
0a122b
 echo "*** done"
0a122b
 rm -f $seq.full
0a122b
diff --git a/tests/qemu-iotests/075.out b/tests/qemu-iotests/075.out
0a122b
index 7cdaee1..911cd3b 100644
0a122b
--- a/tests/qemu-iotests/075.out
0a122b
+++ b/tests/qemu-iotests/075.out
0a122b
@@ -23,4 +23,12 @@ no file open, try 'help open'
0a122b
 == refuse images that require too many offsets ===
0a122b
 qemu-io: can't open device TEST_DIR/simple-pattern.cloop: image requires too many offsets, try increasing block size
0a122b
 no file open, try 'help open'
0a122b
+
0a122b
+== refuse images with non-monotonically increasing offsets ==
0a122b
+qemu-io: can't open device TEST_DIR/simple-pattern.cloop: offsets not monotonically increasing at index 1, image file is corrupt
0a122b
+no file open, try 'help open'
0a122b
+
0a122b
+== refuse images with invalid compressed block size ==
0a122b
+qemu-io: can't open device TEST_DIR/simple-pattern.cloop: invalid compressed block size at index 1, image file is corrupt
0a122b
+no file open, try 'help open'
0a122b
 *** done
0a122b
-- 
0a122b
1.7.1
0a122b