From: Stefan Weil <sw@weilnetz.de>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Stefan Weil <sw@weilnetz.de>,
Jeff Cody <jcody@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH 2/2] vdi: add bounds checks for block related header fields (CVE-2014-0144)
Date: Wed, 26 Mar 2014 22:38:05 +0100 [thread overview]
Message-ID: <1395869885-27751-2-git-send-email-sw@weilnetz.de> (raw)
In-Reply-To: <1395869885-27751-1-git-send-email-sw@weilnetz.de>
(1) block_size must not be null.
(2) blocks_in_image * 4 must fit into a size_t.
(3) blocks_in_image * block_size must fit into a uint64_t.
Header field disk_size already has a bounds check which now works
because of modification (1) and (3).
This patch was inspired by Jeff Cody's patch for the same problem.
Cc: Jeff Cody <jcody@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Weil <sw@weilnetz.de>
---
Hello Stefan, hello Jeff,
I tried to improve your previous patch - maybe you want to improve it further
or take parts from it to fix that CVE (of which I have no information).
The patch was compiled on 32 and 64 bit Linux and cross compiled with MinGW-w64,
but not tested otherwise.
Regards
Stefan
block/vdi.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/block/vdi.c b/block/vdi.c
index b832905..8fb59a1 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -420,7 +420,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
header.sector_size, SECTOR_SIZE);
ret = -ENOTSUP;
goto fail;
-#if !defined(CONFIG_VDI_BLOCK_SIZE)
+#if defined(CONFIG_VDI_BLOCK_SIZE)
+ } else if (header.block_size == 0) {
+ error_setg(errp, "unsupported VDI image (block size is null)");
+ ret = -EINVAL;
+ goto fail;
+#else
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
header.block_size, DEFAULT_CLUSTER_SIZE);
@@ -435,6 +440,18 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
(uint64_t)header.blocks_in_image * header.block_size);
ret = -ENOTSUP;
goto fail;
+#if SIZE_MAX <= UINT32_MAX
+ } else if (header.blocks_in_image > SIZE_MAX / sizeof(uint32_t)) {
+ /* blocks_in_image * sizeof(uint32_t) must fit into size_t. */
+ error_setg(errp, "unsupported VDI image (number of blocks %u, "
+ "only %zu are possible)",
+ header.blocks_in_image, SIZE_MAX / sizeof(uint32_t));
+#endif
+ } else if (header.blocks_in_image > UINT64_MAX / header.block_size) {
+ /* blocks_in_image * block_size must fit into uint64_t. */
+ error_setg(errp, "unsupported VDI image (number of blocks %u, "
+ "only %" PRIu64 " are possible)",
+ header.blocks_in_image, UINT64_MAX / header.block_size);
} else if (!uuid_is_null(header.uuid_link)) {
error_setg(errp, "unsupported VDI image (non-NULL link UUID)");
ret = -ENOTSUP;
@@ -691,6 +708,33 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
options++;
}
+#if defined(CONFIG_VDI_BLOCK_SIZE)
+ if (block_size == 0) {
+ return -EINVAL;
+ }
+#endif
+
+ if (bytes > UINT64_MAX - block_size) {
+ /* Overflow in calculation of blocks (see below). */
+ return -ENOTSUP;
+ }
+
+ /* We need enough blocks to store the given disk size,
+ so always round up. */
+ blocks = (bytes + block_size - 1) / block_size;
+
+#if SIZE_MAX <= UINT32_MAX
+ if (blocks > SIZE_MAX / sizeof(uint32_t)) {
+ /* blocks * sizeof(uint32_t) must fit into size_t. */
+ return -ENOTSUP;
+ }
+#endif
+
+ if (blocks > UINT64_MAX / block_size) {
+ /* blocks * block_size must fit into uint64_t. */
+ return -EINVAL;
+ }
+
fd = qemu_open(filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
@@ -698,10 +742,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
return -errno;
}
- /* We need enough blocks to store the given disk size,
- so always round up. */
- blocks = (bytes + block_size - 1) / block_size;
-
bmap_size = blocks * sizeof(uint32_t);
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
--
1.7.10.4
next prev parent reply other threads:[~2014-03-26 21:38 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-26 21:38 [Qemu-devel] [PATCH 1/2] vdi: Fix error message and two more small code improvements Stefan Weil
2014-03-26 21:38 ` Stefan Weil [this message]
2014-03-27 19:49 ` [Qemu-devel] [PATCH 2/2] vdi: add bounds checks for block related header fields (CVE-2014-0144) Jeff Cody
2014-03-27 20:25 ` Stefan Weil
2014-03-28 8:47 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1395869885-27751-2-git-send-email-sw@weilnetz.de \
--to=sw@weilnetz.de \
--cc=jcody@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).