From patchwork Wed Mar 26 12:05:36 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 333942 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 7BCDB14008B for ; Thu, 27 Mar 2014 01:03:48 +1100 (EST) Received: from localhost ([::1]:47496 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmju-0001j8-8y for incoming@patchwork.ozlabs.org; Wed, 26 Mar 2014 08:15:26 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49973) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmbU-0000um-Ae for qemu-devel@nongnu.org; Wed, 26 Mar 2014 08:06:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WSmbO-0003xl-1Q for qemu-devel@nongnu.org; Wed, 26 Mar 2014 08:06:44 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48024) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSmbN-0003xU-Qi; Wed, 26 Mar 2014 08:06:37 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s2QC6b7O017157 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 26 Mar 2014 08:06:37 -0400 Received: from localhost (dhcp-64-106.muc.redhat.com [10.32.64.106]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s2QC6aGc029752; Wed, 26 Mar 2014 08:06:36 -0400 From: Stefan Hajnoczi To: Date: Wed, 26 Mar 2014 13:05:36 +0100 Message-Id: <1395835569-21193-15-git-send-email-stefanha@redhat.com> In-Reply-To: <1395835569-21193-1-git-send-email-stefanha@redhat.com> References: <1395835569-21193-1-git-send-email-stefanha@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , Jeff Cody , pmatouse@redhat.com, qemu-stable@nongnu.org Subject: [Qemu-devel] [PATCH for-2.0 14/47] vpc/vhd: add bounds check for max_table_entries and block_size (CVE-2014-0144) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Jeff Cody This adds checks to make sure that max_table_entries and block_size are in sane ranges. Memory is allocated based on max_table_entries, and block_size is used to calculate indices into that allocated memory, so if these values are incorrect that can lead to potential unbounded memory allocation, or invalid memory accesses. Also, the allocation of the pagetable is changed from g_malloc0() to qemu_blockalign(). Signed-off-by: Jeff Cody Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/vpc.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 82bf248..ba82d48 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -45,6 +45,8 @@ enum vhd_type { // Seconds since Jan 1, 2000 0:00:00 (UTC) #define VHD_TIMESTAMP_BASE 946684800 +#define VHD_MAX_SECTORS (65535LL * 255 * 255) + // always big-endian typedef struct vhd_footer { char creator[8]; // "conectix" @@ -164,6 +166,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, VHDDynDiskHeader *dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; + uint64_t computed_size; int disk_type = VHD_DYNAMIC; int ret; @@ -222,7 +225,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, } /* Allow a maximum disk size of approximately 2 TB */ - if (bs->total_sectors >= 65535LL * 255 * 255) { + if (bs->total_sectors >= VHD_MAX_SECTORS) { ret = -EFBIG; goto fail; } @@ -245,7 +248,23 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511; s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries); - s->pagetable = g_malloc(s->max_table_entries * 4); + + if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) { + ret = -EINVAL; + goto fail; + } + if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) { + ret = -EINVAL; + goto fail; + } + + computed_size = (uint64_t) s->max_table_entries * s->block_size; + if (computed_size < bs->total_sectors * 512) { + ret = -EINVAL; + goto fail; + } + + s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4); s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); @@ -298,7 +317,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags, return 0; fail: - g_free(s->pagetable); + qemu_vfree(s->pagetable); #ifdef CACHE g_free(s->pageentry_u8); #endif @@ -833,7 +852,7 @@ static int vpc_has_zero_init(BlockDriverState *bs) static void vpc_close(BlockDriverState *bs) { BDRVVPCState *s = bs->opaque; - g_free(s->pagetable); + qemu_vfree(s->pagetable); #ifdef CACHE g_free(s->pageentry_u8); #endif