From: Kevin Wolf Date: Wed, 26 Mar 2014 13:05:41 +0100 Subject: [PATCH] qcow2: Check header_length (CVE-2014-0144) This fixes an unbounded allocation for s->unknown_header_fields. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Signed-off-by: Stefan Hajnoczi (cherry picked from commit 24342f2cae47d03911e346fe1e520b00dc2818e0) Conflicts: block/qcow2.c tests/qemu-iotests/group --- block/qcow2.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 44161b2..40867a1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -355,6 +355,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) s->qcow_version = header.version; + /* Initialise cluster size */ + if (header.cluster_bits < MIN_CLUSTER_BITS || + header.cluster_bits > MAX_CLUSTER_BITS) { + fprintf(stderr, "Unsupported cluster size: 2^%i", header.cluster_bits); + ret = -EINVAL; + goto fail; + } + + s->cluster_bits = header.cluster_bits; + s->cluster_size = 1 << s->cluster_bits; + s->cluster_sectors = 1 << (s->cluster_bits - 9); + /* Initialise version 3 header fields */ if (header.version == 2) { header.incompatible_features = 0; @@ -368,6 +380,18 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) be64_to_cpus(&header.autoclear_features); be32_to_cpus(&header.refcount_order); be32_to_cpus(&header.header_length); + + if (header.header_length < 104) { + fprintf(stderr, "qcow2 header too short"); + ret = -EINVAL; + goto fail; + } + } + + if (header.header_length > s->cluster_size) { + fprintf(stderr, "qcow2 header exceeds cluster size"); + ret = -EINVAL; + goto fail; } if (header.header_length > sizeof(header)) { @@ -410,11 +434,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) goto fail; } - if (header.cluster_bits < MIN_CLUSTER_BITS || - header.cluster_bits > MAX_CLUSTER_BITS) { - ret = -EINVAL; - goto fail; - } if (header.crypt_method > QCOW_CRYPT_AES) { ret = -EINVAL; goto fail; @@ -423,9 +442,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) if (s->crypt_method_header) { bs->encrypted = 1; } - s->cluster_bits = header.cluster_bits; - s->cluster_size = 1 << s->cluster_bits; - s->cluster_sectors = 1 << (s->cluster_bits - 9); + s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */ s->l2_size = 1 << s->l2_bits; bs->total_sectors = header.size / 512;