|
|
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 |
|