]> xenbits.xensource.com Git - qemu-upstream-4.3-testing.git/commitdiff
dmg: sanitize chunk length and sectorcount (CVE-2014-0145)
authorStefan Hajnoczi <stefanha@redhat.com>
Thu, 5 Mar 2015 11:27:26 +0000 (11:27 +0000)
committerStefano Stabellini <stefano.stabellini@eu.citrix.com>
Thu, 5 Mar 2015 17:24:49 +0000 (17:24 +0000)
Chunk length and sectorcount are used for decompression buffers as well
as the bdrv_pread() count argument.  Ensure that they have reasonable
values so neither memory allocation nor conversion from uint64_t to int
will cause problems.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
block/dmg.c

index dc3b507544190643c161a3b30177e5961f5effa6..1311f6ba6425a41fa595dcc14983c8df3fa3a1c3 100644 (file)
 #include "module.h"
 #include <zlib.h>
 
+enum {
+    /* Limit chunk sizes to prevent unreasonable amounts of memory being used
+     * or truncating when converting to 32-bit types
+     */
+    DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */
+    DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
+};
+
 typedef struct BDRVDMGState {
     CoMutex lock;
     /* each chunk contains a certain number of sectors,
@@ -186,12 +194,26 @@ static int dmg_open(BlockDriverState *bs, int flags)
                s->sectorcounts[i] = read_off(bs, offset);
                offset += 8;
 
+        if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
+            error_report("sector count %" PRIu64 " for chunk %u is "
+                    "larger than max (%u)",
+                    s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
+            goto fail;
+        }
+
                s->offsets[i] = last_in_offset+read_off(bs, offset);
                offset += 8;
 
                s->lengths[i] = read_off(bs, offset);
                offset += 8;
 
+        if (s->lengths[i] > DMG_LENGTHS_MAX) {
+            error_report("length %" PRIu64 " for chunk %u is larger "
+                    "than max (%u)",
+                    s->lengths[i], i, DMG_LENGTHS_MAX);
+            goto fail;
+        }
+
         update_max_chunk_size(s, i, &max_compressed_size,
                 &max_sectors_per_chunk);
            }