Skip to content

Commit

Permalink
vdi: add bounds checks for blocks_in_image and disk_size header fields (
Browse files Browse the repository at this point in the history
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
5b7aa9b (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 63fa06d)

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>
  • Loading branch information
codyprime authored and mdroth committed Jul 3, 2014
1 parent 76d1edd commit 37173f5
Showing 1 changed file with 29 additions and 2 deletions.
31 changes: 29 additions & 2 deletions block/vdi.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -746,6 +772,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
result = -errno;
}

exit:
return result;
}

Expand Down

0 comments on commit 37173f5

Please sign in to comment.