9ae3a8
From 714a0140fd0061b44d63bd538a2d6a7de6f59be6 Mon Sep 17 00:00:00 2001
9ae3a8
From: Jeff Cody <jcody@redhat.com>
9ae3a8
Date: Tue, 25 Mar 2014 14:23:22 +0100
9ae3a8
Subject: [PATCH 15/49] vpc/vhd: add bounds check for max_table_entries and block_size (CVE-2014-0144)
9ae3a8
9ae3a8
RH-Author: Kevin Wolf <kwolf@redhat.com>
9ae3a8
Message-id: <1395753835-7591-16-git-send-email-kwolf@redhat.com>
9ae3a8
Patchwork-id: n/a
9ae3a8
O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 15/48] vpc/vhd: add bounds check for max_table_entries and block_size (CVE-2014-0144)
9ae3a8
Bugzilla: 1079455
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: Jeff Cody <jcody@redhat.com>
9ae3a8
9ae3a8
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079455
9ae3a8
Upstream status: Embargoed
9ae3a8
9ae3a8
This adds checks to make sure that max_table_entries and block_size
9ae3a8
are in sane ranges. Memory is allocated based on max_table_entries,
9ae3a8
and block_size is used to calculate indices into that allocated
9ae3a8
memory, so if these values are incorrect that can lead to potential
9ae3a8
unbounded memory allocation, or invalid memory accesses.
9ae3a8
9ae3a8
Also, the allocation of the pagetable is changed from g_malloc0()
9ae3a8
to qemu_blockalign().
9ae3a8
9ae3a8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
---
9ae3a8
 block/vpc.c |   27 +++++++++++++++++++++++----
9ae3a8
 1 files changed, 23 insertions(+), 4 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/vpc.c b/block/vpc.c
9ae3a8
index 059069f..de5bc22 100644
9ae3a8
--- a/block/vpc.c
9ae3a8
+++ b/block/vpc.c
9ae3a8
@@ -45,6 +45,8 @@ enum vhd_type {
9ae3a8
 // Seconds since Jan 1, 2000 0:00:00 (UTC)
9ae3a8
 #define VHD_TIMESTAMP_BASE 946684800
9ae3a8
 
9ae3a8
+#define VHD_MAX_SECTORS       (65535LL * 255 * 255)
9ae3a8
+
9ae3a8
 // always big-endian
9ae3a8
 struct vhd_footer {
9ae3a8
     char        creator[8]; // "conectix"
9ae3a8
@@ -164,6 +166,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
     struct vhd_dyndisk_header* dyndisk_header;
9ae3a8
     uint8_t buf[HEADER_SIZE];
9ae3a8
     uint32_t checksum;
9ae3a8
+    uint64_t computed_size;
9ae3a8
     int disk_type = VHD_DYNAMIC;
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
@@ -212,7 +215,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
9ae3a8
 
9ae3a8
     /* Allow a maximum disk size of approximately 2 TB */
9ae3a8
-    if (bs->total_sectors >= 65535LL * 255 * 255) {
9ae3a8
+    if (bs->total_sectors >= VHD_MAX_SECTORS) {
9ae3a8
         ret = -EFBIG;
9ae3a8
         goto fail;
9ae3a8
     }
9ae3a8
@@ -235,7 +238,23 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
         s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
9ae3a8
 
9ae3a8
         s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
9ae3a8
-        s->pagetable = g_malloc(s->max_table_entries * 4);
9ae3a8
+
9ae3a8
+        if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
9ae3a8
+            ret = -EINVAL;
9ae3a8
+            goto fail;
9ae3a8
+        }
9ae3a8
+        if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
9ae3a8
+            ret = -EINVAL;
9ae3a8
+            goto fail;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        computed_size = (uint64_t) s->max_table_entries * s->block_size;
9ae3a8
+        if (computed_size < bs->total_sectors * 512) {
9ae3a8
+            ret = -EINVAL;
9ae3a8
+            goto fail;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
9ae3a8
 
9ae3a8
         s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
9ae3a8
 
9ae3a8
@@ -281,7 +300,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
     return 0;
9ae3a8
 
9ae3a8
 fail:
9ae3a8
-    g_free(s->pagetable);
9ae3a8
+    qemu_vfree(s->pagetable);
9ae3a8
 #ifdef CACHE
9ae3a8
     g_free(s->pageentry_u8);
9ae3a8
 #endif
9ae3a8
@@ -804,7 +823,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options,
9ae3a8
 static void vpc_close(BlockDriverState *bs)
9ae3a8
 {
9ae3a8
     BDRVVPCState *s = bs->opaque;
9ae3a8
-    g_free(s->pagetable);
9ae3a8
+    qemu_vfree(s->pagetable);
9ae3a8
 #ifdef CACHE
9ae3a8
     g_free(s->pageentry_u8);
9ae3a8
 #endif
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8