summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorJeff Cody <jcody@redhat.com>2014-03-28 11:42:24 -0400
committerMichael Roth <mdroth@linux.vnet.ibm.com>2014-07-03 16:18:11 -0500
commit37173f54b7925f02045a93c081deabca1b8a6abd (patch)
tree34e1172eb688912db8f4d2af84cc214b6d17d02c /block
parent76d1eddbe533d828eb866c36b7b13837986c7fc3 (diff)
downloadqemu-37173f54b7925f02045a93c081deabca1b8a6abd.tar.gz
vdi: add bounds checks for blocks_in_image and disk_size header fields (CVE-2014-0144)
The maximum blocks_in_image is 0xffffffff / 4, which also limits the maximum disk_size for a VDI image to 1024TB. Note that this is the maximum size that QEMU will currently support with this driver, not necessarily the maximum size allowed by the image format. This also fixes an incorrect error message, a bug introduced by commit 5b7aa9b56d1bfc79916262f380c3fc7961becb50 (Reported by Stefan Weil) Signed-off-by: Jeff Cody <jcody@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> (cherry picked from commit 63fa06dc978f3669dbfd9443b33cde9e2a7f4b41) Conflicts: block/vdi.c *modified to retain 1.7's usage of logout() over error_setg() Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Diffstat (limited to 'block')
-rw-r--r--block/vdi.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/block/vdi.c b/block/vdi.c
index b6ec0020dc..204a3e5c45 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -120,6 +120,11 @@ typedef unsigned char uuid_t[16];
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
+/* max blocks in image is (0xffffffff / 4) */
+#define VDI_BLOCKS_IN_IMAGE_MAX 0x3fffffff
+#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
+ (uint64_t)DEFAULT_CLUSTER_SIZE)
+
#if !defined(CONFIG_UUID)
static inline void uuid_generate(uuid_t out)
{
@@ -384,6 +389,13 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
vdi_header_print(&header);
#endif
+ if (header.disk_size > VDI_DISK_SIZE_MAX) {
+ logout("disk size is 0x%" PRIx64 ", max supported is 0x%" PRIx64,
+ header.disk_size, VDI_DISK_SIZE_MAX);
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
if (header.disk_size % SECTOR_SIZE != 0) {
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
We accept them but round the disk size to the next multiple of
@@ -416,7 +428,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
logout("unsupported sector size %u B\n", header.sector_size);
ret = -ENOTSUP;
goto fail;
- } else if (header.block_size != 1 * MiB) {
+ } else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
logout("unsupported block size %u B\n", header.block_size);
ret = -ENOTSUP;
goto fail;
@@ -433,6 +445,11 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
logout("parent uuid != 0, unsupported\n");
ret = -ENOTSUP;
goto fail;
+ } else if (header.blocks_in_image > VDI_BLOCKS_IN_IMAGE_MAX) {
+ logout("too many blocks %u, max is %u)",
+ header.blocks_in_image, VDI_BLOCKS_IN_IMAGE_MAX);
+ ret = -ENOTSUP;
+ goto fail;
}
bs->total_sectors = header.disk_size / SECTOR_SIZE;
@@ -681,11 +698,20 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
options++;
}
+ if (bytes > VDI_DISK_SIZE_MAX) {
+ result = -ENOTSUP;
+ logout("image size (size is 0x%" PRIx64
+ ", max supported is 0x%" PRIx64 ")",
+ bytes, VDI_DISK_SIZE_MAX);
+ goto exit;
+ }
+
fd = qemu_open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0) {
- return -errno;
+ result = -errno;
+ goto exit;
}
/* We need enough blocks to store the given disk size,
@@ -746,6 +772,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
result = -errno;
}
+exit:
return result;
}