yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
9ae3a8
From 0b7385ddaa538c5995d2f16333a80a0f579a6212 Mon Sep 17 00:00:00 2001
9ae3a8
From: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
Date: Tue, 25 Mar 2014 14:23:46 +0100
9ae3a8
Subject: [PATCH 39/49] dmg: prevent chunk buffer overflow (CVE-2014-0145)
9ae3a8
9ae3a8
RH-Author: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Message-id: <1395753835-7591-40-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: n/a
9ae3a8
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 39/48] dmg: prevent chunk buffer overflow (CVE-2014-0145)
9ae3a8
Bugzilla: 1079325
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
From: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
9ae3a8
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079325
9ae3a8
Upstream status: Embargoed
9ae3a8
9ae3a8
Both compressed and uncompressed I/O is buffered. dmg_open() calculates
9ae3a8
the maximum buffer size needed from the metadata in the image file.
9ae3a8
9ae3a8
There is currently a buffer overflow since ->lengths[] is accounted
9ae3a8
against the maximum compressed buffer size but actually uses the
9ae3a8
uncompressed buffer:
9ae3a8
9ae3a8
switch (s->types[chunk]) {
9ae3a8
case 1: /bin /boot /cgroup /dev /etc /home /lib /lib64 /lost+found /media /misc /mnt /net /opt /proc /root /sbin /selinux /srv /sys /tmp /usr /var copy audio/ backends/ block/ bsd-user/ default-configs/ disas/ docs/ dtc/ fpu/ fsdev/ gdb-xml/ hw/ include/ ldscripts/ libcacard/ linux-headers/ linux-user/ net/ pc-bios/ pixman/ po/ qapi/ qga/ QMP/ qobject/ qom/ redhat/ roms/ scripts/ slirp/ stubs/ sysconfigs/ target-alpha/ target-arm/ target-cris/ target-i386/ target-lm32/ target-m68k/ target-microblaze/ target-mips/ target-moxie/ target-openrisc/ target-ppc/ target-s390x/ target-sh4/ target-sparc/ target-unicore32/ target-xtensa/ tcg/ tests/ trace/ ui/ util/
9ae3a8
ret = bdrv_pread(bs->file, s->offsets[chunk],
9ae3a8
s->uncompressed_chunk, s->lengths[chunk]);
9ae3a8
9ae3a8
We must account against the maximum uncompressed buffer size for type=1
9ae3a8
chunks.
9ae3a8
9ae3a8
This patch fixes the maximum buffer size calculation to take into
9ae3a8
account the chunk type. It is critical that we update the correct
9ae3a8
maximum since there are two buffers ->compressed_chunk and
9ae3a8
->uncompressed_chunk.
9ae3a8
9ae3a8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
---
9ae3a8
 block/dmg.c |   39 +++++++++++++++++++++++++++++++++------
9ae3a8
 1 files changed, 33 insertions(+), 6 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/dmg.c b/block/dmg.c
9ae3a8
index be0ee33..856402e 100644
9ae3a8
--- a/block/dmg.c
9ae3a8
+++ b/block/dmg.c
9ae3a8
@@ -100,6 +100,37 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
9ae3a8
     return 0;
9ae3a8
 }
9ae3a8
 
9ae3a8
+/* Increase max chunk sizes, if necessary.  This function is used to calculate
9ae3a8
+ * the buffer sizes needed for compressed/uncompressed chunk I/O.
9ae3a8
+ */
9ae3a8
+static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
9ae3a8
+                                  uint32_t *max_compressed_size,
9ae3a8
+                                  uint32_t *max_sectors_per_chunk)
9ae3a8
+{
9ae3a8
+    uint32_t compressed_size = 0;
9ae3a8
+    uint32_t uncompressed_sectors = 0;
9ae3a8
+
9ae3a8
+    switch (s->types[chunk]) {
9ae3a8
+    case 0x80000005: /* zlib compressed */
9ae3a8
+        compressed_size = s->lengths[chunk];
9ae3a8
+        uncompressed_sectors = s->sectorcounts[chunk];
9ae3a8
+        break;
9ae3a8
+    case 1: /* copy */
9ae3a8
+        uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
9ae3a8
+        break;
9ae3a8
+    case 2: /* zero */
9ae3a8
+        uncompressed_sectors = s->sectorcounts[chunk];
9ae3a8
+        break;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    if (compressed_size > *max_compressed_size) {
9ae3a8
+        *max_compressed_size = compressed_size;
9ae3a8
+    }
9ae3a8
+    if (uncompressed_sectors > *max_sectors_per_chunk) {
9ae3a8
+        *max_sectors_per_chunk = uncompressed_sectors;
9ae3a8
+    }
9ae3a8
+}
9ae3a8
+
9ae3a8
 static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
                     Error **errp)
9ae3a8
 {
9ae3a8
@@ -245,12 +276,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
                     goto fail;
9ae3a8
                 }
9ae3a8
 
9ae3a8
-                if (s->lengths[i] > max_compressed_size) {
9ae3a8
-                    max_compressed_size = s->lengths[i];
9ae3a8
-                }
9ae3a8
-                if (s->sectorcounts[i] > max_sectors_per_chunk) {
9ae3a8
-                    max_sectors_per_chunk = s->sectorcounts[i];
9ae3a8
-                }
9ae3a8
+                update_max_chunk_size(s, i, &max_compressed_size,
9ae3a8
+                                      &max_sectors_per_chunk);
9ae3a8
             }
9ae3a8
             s->n_chunks += chunk_count;
9ae3a8
         }
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8