From 7f49d52c38d0e6ffcb6a5085622f967f6fe0cefe Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 25 Mar 2014 11:45:59 +0100 Subject: [PATCH 41/48] dmg: sanitize chunk length and sectorcount (CVE-2014-0145) RH-Author: Kevin Wolf Message-id: <1395744364-16049-41-git-send-email-kwolf@redhat.com> Patchwork-id: n/a O-Subject: [EMBARGOED RHEL-6.6/6.5.z qemu-kvm PATCH v2 40/45] dmg: sanitize chunk length and sectorcount (CVE-2014-0145) Bugzilla: 1079324 RH-Acked-by: Max Reitz RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Laszlo Ersek Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079324 Upstream status: Embargoed Chunk length and sectorcount are used for decompression buffers as well as the bdrv_pread() count argument. Ensure that they have reasonable values so neither memory allocation nor conversion from uint64_t to int will cause problems. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/dmg.c | 24 ++++++++++++++++++++++++ 1 files changed, 24 insertions(+), 0 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index ab001b3..eb1717d 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -27,6 +27,14 @@ #include "module.h" #include +enum { + /* Limit chunk sizes to prevent unreasonable amounts of memory being used + * or truncating when converting to 32-bit types + */ + DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */ + DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512, +}; + typedef struct BDRVDMGState { CoMutex lock; /* each chunk contains a certain number of sectors, @@ -200,6 +208,14 @@ static int dmg_open(BlockDriverState *bs, int flags) } offset += 8; + if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) { + error_report("sector count %" PRIu64 " for chunk %u is " + "larger than max (%u)", + s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX); + ret = -EINVAL; + goto fail; + } + ret = read_uint64(bs, offset, &s->offsets[i]); if (ret < 0) { goto fail; @@ -213,6 +229,14 @@ static int dmg_open(BlockDriverState *bs, int flags) } offset += 8; + if (s->lengths[i] > DMG_LENGTHS_MAX) { + error_report("length %" PRIu64 " for chunk %u is larger " + "than max (%u)", + s->lengths[i], i, DMG_LENGTHS_MAX); + ret = -EINVAL; + goto fail; + } + if (s->lengths[i] > max_compressed_size) { max_compressed_size = s->lengths[i]; } -- 1.7.1