0a122b
From 0b7385ddaa538c5995d2f16333a80a0f579a6212 Mon Sep 17 00:00:00 2001
0a122b
From: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Date: Tue, 25 Mar 2014 14:23:46 +0100
0a122b
Subject: [PATCH 39/49] dmg: prevent chunk buffer overflow (CVE-2014-0145)
0a122b
0a122b
RH-Author: Kevin Wolf <kwolf@redhat.com>
0a122b
Message-id: <1395753835-7591-40-git-send-email-kwolf@redhat.com>
0a122b
Patchwork-id: n/a
0a122b
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 39/48] dmg: prevent chunk buffer overflow (CVE-2014-0145)
0a122b
Bugzilla: 1079325
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=1079325
0a122b
Upstream status: Embargoed
0a122b
0a122b
Both compressed and uncompressed I/O is buffered. dmg_open() calculates
0a122b
the maximum buffer size needed from the metadata in the image file.
0a122b
0a122b
There is currently a buffer overflow since ->lengths[] is accounted
0a122b
against the maximum compressed buffer size but actually uses the
0a122b
uncompressed buffer:
0a122b
0a122b
switch (s->types[chunk]) {
0a122b
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/
0a122b
ret = bdrv_pread(bs->file, s->offsets[chunk],
0a122b
s->uncompressed_chunk, s->lengths[chunk]);
0a122b
0a122b
We must account against the maximum uncompressed buffer size for type=1
0a122b
chunks.
0a122b
0a122b
This patch fixes the maximum buffer size calculation to take into
0a122b
account the chunk type. It is critical that we update the correct
0a122b
maximum since there are two buffers ->compressed_chunk and
0a122b
->uncompressed_chunk.
0a122b
0a122b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
0a122b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
0a122b
---
0a122b
 block/dmg.c |   39 +++++++++++++++++++++++++++++++++------
0a122b
 1 files changed, 33 insertions(+), 6 deletions(-)
0a122b
0a122b
diff --git a/block/dmg.c b/block/dmg.c
0a122b
index be0ee33..856402e 100644
0a122b
--- a/block/dmg.c
0a122b
+++ b/block/dmg.c
0a122b
@@ -100,6 +100,37 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
0a122b
     return 0;
0a122b
 }
0a122b
 
0a122b
+/* Increase max chunk sizes, if necessary.  This function is used to calculate
0a122b
+ * the buffer sizes needed for compressed/uncompressed chunk I/O.
0a122b
+ */
0a122b
+static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
0a122b
+                                  uint32_t *max_compressed_size,
0a122b
+                                  uint32_t *max_sectors_per_chunk)
0a122b
+{
0a122b
+    uint32_t compressed_size = 0;
0a122b
+    uint32_t uncompressed_sectors = 0;
0a122b
+
0a122b
+    switch (s->types[chunk]) {
0a122b
+    case 0x80000005: /* zlib compressed */
0a122b
+        compressed_size = s->lengths[chunk];
0a122b
+        uncompressed_sectors = s->sectorcounts[chunk];
0a122b
+        break;
0a122b
+    case 1: /* copy */
0a122b
+        uncompressed_sectors = (s->lengths[chunk] + 511) / 512;
0a122b
+        break;
0a122b
+    case 2: /* zero */
0a122b
+        uncompressed_sectors = s->sectorcounts[chunk];
0a122b
+        break;
0a122b
+    }
0a122b
+
0a122b
+    if (compressed_size > *max_compressed_size) {
0a122b
+        *max_compressed_size = compressed_size;
0a122b
+    }
0a122b
+    if (uncompressed_sectors > *max_sectors_per_chunk) {
0a122b
+        *max_sectors_per_chunk = uncompressed_sectors;
0a122b
+    }
0a122b
+}
0a122b
+
0a122b
 static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
0a122b
                     Error **errp)
0a122b
 {
0a122b
@@ -245,12 +276,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
0a122b
                     goto fail;
0a122b
                 }
0a122b
 
0a122b
-                if (s->lengths[i] > max_compressed_size) {
0a122b
-                    max_compressed_size = s->lengths[i];
0a122b
-                }
0a122b
-                if (s->sectorcounts[i] > max_sectors_per_chunk) {
0a122b
-                    max_sectors_per_chunk = s->sectorcounts[i];
0a122b
-                }
0a122b
+                update_max_chunk_size(s, i, &max_compressed_size,
0a122b
+                                      &max_sectors_per_chunk);
0a122b
             }
0a122b
             s->n_chunks += chunk_count;
0a122b
         }
0a122b
-- 
0a122b
1.7.1
0a122b