97 lines
3.3 KiB
Diff
97 lines
3.3 KiB
Diff
From: Jeff Cody <jcody@redhat.com>
|
|
Date: Wed, 26 Mar 2014 13:05:36 +0100
|
|
Subject: [PATCH] vpc/vhd: add bounds check for max_table_entries and
|
|
block_size (CVE-2014-0144)
|
|
|
|
This adds checks to make sure that max_table_entries and block_size
|
|
are in sane ranges. Memory is allocated based on max_table_entries,
|
|
and block_size is used to calculate indices into that allocated
|
|
memory, so if these values are incorrect that can lead to potential
|
|
unbounded memory allocation, or invalid memory accesses.
|
|
|
|
Also, the allocation of the pagetable is changed from g_malloc0()
|
|
to qemu_blockalign().
|
|
|
|
Signed-off-by: Jeff Cody <jcody@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>
|
|
(cherry picked from commit 97f1c45c6f456572e5b504b8614e4a69e23b8e3a)
|
|
---
|
|
block/vpc.c | 27 +++++++++++++++++++++++----
|
|
1 file changed, 23 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/block/vpc.c b/block/vpc.c
|
|
index fe4f311..16c5acf 100644
|
|
--- a/block/vpc.c
|
|
+++ b/block/vpc.c
|
|
@@ -45,6 +45,8 @@ enum vhd_type {
|
|
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
|
#define VHD_TIMESTAMP_BASE 946684800
|
|
|
|
+#define VHD_MAX_SECTORS (65535LL * 255 * 255)
|
|
+
|
|
// always big-endian
|
|
struct vhd_footer {
|
|
char creator[8]; // "conectix"
|
|
@@ -163,6 +165,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
|
struct vhd_dyndisk_header* dyndisk_header;
|
|
uint8_t buf[HEADER_SIZE];
|
|
uint32_t checksum;
|
|
+ uint64_t computed_size;
|
|
int disk_type = VHD_DYNAMIC;
|
|
int ret;
|
|
|
|
@@ -211,7 +214,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
|
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
|
|
|
|
/* Allow a maximum disk size of approximately 2 TB */
|
|
- if (bs->total_sectors >= 65535LL * 255 * 255) {
|
|
+ if (bs->total_sectors >= VHD_MAX_SECTORS) {
|
|
ret = -EFBIG;
|
|
goto fail;
|
|
}
|
|
@@ -234,7 +237,23 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
|
s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
|
|
|
|
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
|
- s->pagetable = g_malloc(s->max_table_entries * 4);
|
|
+
|
|
+ if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+ if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) {
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ computed_size = (uint64_t) s->max_table_entries * s->block_size;
|
|
+ if (computed_size < bs->total_sectors * 512) {
|
|
+ ret = -EINVAL;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
|
|
|
|
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
|
|
|
@@ -280,7 +299,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags)
|
|
return 0;
|
|
|
|
fail:
|
|
- g_free(s->pagetable);
|
|
+ qemu_vfree(s->pagetable);
|
|
#ifdef CACHE
|
|
g_free(s->pageentry_u8);
|
|
#endif
|
|
@@ -801,7 +820,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
|
|
static void vpc_close(BlockDriverState *bs)
|
|
{
|
|
BDRVVPCState *s = bs->opaque;
|
|
- g_free(s->pagetable);
|
|
+ qemu_vfree(s->pagetable);
|
|
#ifdef CACHE
|
|
g_free(s->pageentry_u8);
|
|
#endif
|