9ae3a8
From aab4d4ef24bf36c65e4d33cf817903118061ad85 Mon Sep 17 00:00:00 2001
9ae3a8
From: Jeffrey Cody <jcody@redhat.com>
9ae3a8
Date: Wed, 29 Jul 2015 16:59:54 +0200
9ae3a8
Subject: [PATCH 03/13] block: vpc - prevent overflow if max_table_entries >=
9ae3a8
 0x40000000
9ae3a8
9ae3a8
Message-id: <6ed83012cdee022f7015ed8fc7bc93abc3a8ef76.1438188988.git.jcody@redhat.com>
9ae3a8
Patchwork-id: 67199
9ae3a8
O-Subject: [RHEL-7.2 qemu-kvm PATCH 2/3] block: vpc - prevent overflow if max_table_entries >= 0x40000000
9ae3a8
Bugzilla: 1217349
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9ae3a8
RH-Acked-by: Max Reitz <mreitz@redhat.com>
9ae3a8
9ae3a8
When we allocate the pagetable based on max_table_entries, we multiply
9ae3a8
the max table entry value by 4 to accomodate a table of 32-bit integers.
9ae3a8
However, max_table_entries is a uint32_t, and the VPC driver accepts
9ae3a8
ranges for that entry over 0x40000000.  So during this allocation:
9ae3a8
9ae3a8
s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
9ae3a8
9ae3a8
The size arg overflows, allocating significantly less memory than
9ae3a8
expected.
9ae3a8
9ae3a8
Since qemu_try_blockalign() size argument is size_t, cast the
9ae3a8
multiplication correctly to prevent overflow.
9ae3a8
9ae3a8
The value of "max_table_entries * 4" is used elsewhere in the code as
9ae3a8
well, so store the correct value for use in all those cases.
9ae3a8
9ae3a8
We also check the Max Tables Entries value, to make sure that it is <
9ae3a8
SIZE_MAX / 4, so we know the pagetable size will fit in size_t.
9ae3a8
9ae3a8
Cc: qemu-stable@nongnu.org
9ae3a8
Reported-by: Richard W.M. Jones <rjones@redhat.com>
9ae3a8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9ae3a8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9ae3a8
(cherry picked from commit b15deac79530d818092cb49a8021bcce83d71b5b)
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 block/vpc.c | 18 ++++++++++++++----
9ae3a8
 1 file changed, 14 insertions(+), 4 deletions(-)
9ae3a8
9ae3a8
diff --git a/block/vpc.c b/block/vpc.c
9ae3a8
index 6fdce40..1ded510 100644
9ae3a8
--- a/block/vpc.c
9ae3a8
+++ b/block/vpc.c
9ae3a8
@@ -167,6 +167,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
     uint8_t buf[HEADER_SIZE];
9ae3a8
     uint32_t checksum;
9ae3a8
     uint64_t computed_size;
9ae3a8
+    uint64_t pagetable_size;
9ae3a8
     int disk_type = VHD_DYNAMIC;
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
@@ -260,7 +261,17 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
             goto fail;
9ae3a8
         }
9ae3a8
 
9ae3a8
-        s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
9ae3a8
+        if (s->max_table_entries > SIZE_MAX / 4 ||
9ae3a8
+            s->max_table_entries > (int) INT_MAX / 4) {
9ae3a8
+            error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
9ae3a8
+                        s->max_table_entries);
9ae3a8
+            ret = -EINVAL;
9ae3a8
+            goto fail;
9ae3a8
+        }
9ae3a8
+
9ae3a8
+        pagetable_size = (uint64_t) s->max_table_entries * 4;
9ae3a8
+
9ae3a8
+        s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
9ae3a8
         if (s->pagetable == NULL) {
9ae3a8
             ret = -ENOMEM;
9ae3a8
             goto fail;
9ae3a8
@@ -268,14 +279,13 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
9ae3a8
 
9ae3a8
         s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
9ae3a8
 
9ae3a8
-        ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
9ae3a8
-                         s->max_table_entries * 4);
9ae3a8
+        ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
9ae3a8
         if (ret < 0) {
9ae3a8
             goto fail;
9ae3a8
         }
9ae3a8
 
9ae3a8
         s->free_data_block_offset =
9ae3a8
-            (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
9ae3a8
+            ROUND_UP(s->bat_offset + pagetable_size, 512);
9ae3a8
 
9ae3a8
         for (i = 0; i < s->max_table_entries; i++) {
9ae3a8
             be32_to_cpus(&s->pagetable[i]);
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8