From 39d486fbbcbb4ff167d76f20a153d5809afd316a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 25 Mar 2014 11:45:40 +0100 Subject: [PATCH 22/48] block/cloop: refuse images with bogus offsets (CVE-2014-0144) RH-Author: Kevin Wolf Message-id: <1395744364-16049-22-git-send-email-kwolf@redhat.com> Patchwork-id: n/a O-Subject: [EMBARGOED RHEL-6.6/6.5.z qemu-kvm PATCH v2 21/45] block/cloop: refuse images with bogus offsets (CVE-2014-0144) Bugzilla: 1079453 RH-Acked-by: Max Reitz RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Jeff Cody Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079453 Upstream status: Embargoed The offsets[] array allows efficient seeking and tells us the maximum compressed data size. If the offsets are bogus the maximum compressed data size will be unrealistic. This could cause g_malloc() to abort and bogus offsets mean the image is broken anyway. Therefore we should refuse such images. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf Conflicts: tests/qemu-iotests/075 tests/qemu-iotests/075.out Signed-off-by: Kevin Wolf --- block/cloop.c | 36 +++++++++++++++++++++++++++++++----- 1 files changed, 31 insertions(+), 5 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index cc364ce..1fecad7 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -119,12 +119,38 @@ static int cloop_open(BlockDriverState *bs, int flags) } for(i=0;in_blocks;i++) { + uint64_t size; + s->offsets[i] = be64_to_cpu(s->offsets[i]); - if (i > 0) { - uint32_t size = s->offsets[i] - s->offsets[i - 1]; - if (size > max_compressed_block_size) { - max_compressed_block_size = size; - } + if (i == 0) { + continue; + } + + if (s->offsets[i] < s->offsets[i - 1]) { + qerror_report(QERR_GENERIC_ERROR, + "offsets not monotonically increasing, " + "image file is corrupt"); + ret = -EINVAL; + goto fail; + } + + size = s->offsets[i] - s->offsets[i - 1]; + + /* Compressed blocks should be smaller than the uncompressed block size + * but maybe compression performed poorly so the compressed block is + * actually bigger. Clamp down on unrealistic values to prevent + * ridiculous s->compressed_block allocation. + */ + if (size > 2 * MAX_BLOCK_SIZE) { + qerror_report(QERR_GENERIC_ERROR, + "invalid compressed block size, " + "image file is corrupt"); + ret = -EINVAL; + goto fail; + } + + if (size > max_compressed_block_size) { + max_compressed_block_size = size; } } -- 1.7.1