Blame SOURCES/kvm-block-vpc-prevent-overflow-if-max_table_entries-0x40.patch

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