Bug 1217351

Summary: Overflow in malloc size calculation in VMDK driver
Product: Red Hat Enterprise Linux 7 Reporter: Richard W.M. Jones <rjones>
Component: qemu-kvmAssignee: Fam Zheng <famz>
Status: CLOSED ERRATA QA Contact: Virtualization Bugs <virt-bugs>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 7.1CC: famz, hhuang, huding, juzhang, mazhang, rbalakri, xfu
Target Milestone: rcKeywords: Reopened
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: qemu-kvm-1.5.3-91.el7 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
: 1218823 1226809 (view as bug list) Environment:
Last Closed: 2015-11-19 05:01:58 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1218823, 1226809    
Attachments:
Description Flags
afl6.img none

Description Richard W.M. Jones 2015-04-30 08:11:49 UTC
Created attachment 1020433 [details]
afl6.img

Description of problem:

The attached image causes an overflow, possible exploitable,
in the VMDK driver in qemu.  Confirmed on upstream qemu and
RHEL 7.

Version-Release number of selected component (if applicable):

qemu-kvm-1.5.3-86.el7

How reproducible:

100%

Steps to Reproduce:
1. qemu-img info afl6.img

Additional info:

What actually happens here is a calculation overflows in block/vmdk.c:

  static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
                              Error **errp)
  {
    int ret;
    int l1_size, i;                                      # 1

    /* read the L1 table */
    l1_size = extent->l1_size * sizeof(uint32_t);        # 2
    extent->l1_table = g_try_malloc(l1_size);            # 3
    if (l1_size && extent->l1_table == NULL) {
        return -ENOMEM;
    }                                                                           

At line 1, l1_size is an int (ie. 32 bits).

At line 2, extent->l1_size == 536870912 and the calculation overflows,
returning l1_size == -2147483648.

At line 3, the allocation fails.

The extent->l1_size field is indirectly under the control of
the attacker, so you can probably make that overflow to a non-negative
number, resulting in some small buffer being allocated, and a
subsequent buffer overflow.  This wouldn't affect 'qemu-img info' but
it might affect other subcommands, eg. 'qemu-img convert'.  Also if
qemu was directly using a VMDK disk.

Comment 2 Fam Zheng 2015-05-05 03:02:37 UTC
l1_size is already checked against 512 * 1024 * 1024. See where is is assigned:

static int vmdk_add_extent(BlockDriverState *bs,
                           BlockDriverState *file, bool flat, int64_t sectors,
                           int64_t l1_offset, int64_t l1_backup_offset,
                           uint32_t l1_size,
                           int l2_size, uint64_t cluster_sectors,
                           VmdkExtent **new_extent,
                           Error **errp)
{
    ...

    if (l1_size > 512 * 1024 * 1024) {
        /* Although with big capacity and small l1_entry_sectors, we can get a
         * big l1_size, we don't want unbounded value to allocate the table.
         * Limit it to 512M, which is 16PB for default cluster and L2 table
         * size */
        error_setg(errp, "L1 size too big");
        return -EFBIG;
    }

    ...
    extent->l1_size = l1_size;

Comment 3 Richard W.M. Jones 2015-05-05 07:43:42 UTC
Did you try the disk image?  It demonstrates the overflow happening.

Comment 4 Fam Zheng 2015-05-05 09:07:58 UTC
Yes, Rich, you're right, the image does cause an overflow.

In fact, that's the only possible value to overflow (extent->l1_size = 0x20000000):

l1_size = extent->l1_size * sizeof(long) => 0x80000000;

g_try_malloc returns NULL because l1_size is interpreted as negative during type casting from 'int' to 'gsize', which yields a very large value. Eventually, by coincidence, we get expected behavior:

qemu-img: Could not open '/tmp/afl6.img': Could not open '/tmp/afl6.img': Cannot allocate memory

Values larger than 0x20000000 will be refused as the code in comment #2 shows.

Values smaller than 0x20000000 will not overflow l1_size.

Because it only happens to work, this is still a valid bug report and we should fix the overflow.

Thanks!

Fam

Comment 5 Richard W.M. Jones 2015-05-05 09:58:21 UTC
Making this bug public since it has been reported upstream and
since it is not exploitable after all.

Patch is:
https://lists.nongnu.org/archive/html/qemu-devel/2015-05/msg00413.html

Comment 6 Miroslav Rezanina 2015-06-15 14:09:20 UTC
Fix included in qemu-kvm-1.5.3-91.el7

Comment 8 mazhang 2015-07-22 03:11:58 UTC
1. Test this bug on qemu-img-1.5.3-90.el7.x86_64
# qemu-img info afl6.img 
qemu-img: Could not open 'afl6.img': Could not open 'afl6.img': Cannot allocate memory

2. Upgrade qemu-img to qemu-img-1.5.3-97.el7.x86_64.

# qemu-img info afl6.img 
tcmalloc: large alloc 2147483648 bytes == 0x7f8252fd6000 @  0x7f824e99ac73 0x7f824e9badb2 0x7f824e49f5ff 0x7f825017b03f 0x7f825017cb42 0x7f825017c318 0x7f825017cf08 0x7f825014c254 0x7f82501516fb 0x7f82501a228d 0x7f82501a26b6 0x7f824ca39af5 0x7f8250148f8d (nil)
qemu-img: Could not open 'afl6.img': Could not read l1 table from extent 'afl6.img': Invalid argument

Fam, is this expected for this bug fix?

Thanks,
Mazhang.

Comment 9 Richard W.M. Jones 2015-07-22 09:44:48 UTC
Yes this is correct.  Without the patch, a calculation in qemu-img
overflows causing it to allocate a negative amount of memory and
you see the error "Cannot allocate memory".  With the patch the
allocation is correct and it fails a bit later with "Invalid argument".

The test image is (deliberately) faulty so it cannot be opened, so
the only question is which error you get.

Comment 10 mazhang 2015-07-22 10:48:03 UTC
(In reply to Richard W.M. Jones from comment #9)
> Yes this is correct.  Without the patch, a calculation in qemu-img
> overflows causing it to allocate a negative amount of memory and
> you see the error "Cannot allocate memory".  With the patch the
> allocation is correct and it fails a bit later with "Invalid argument".
> 
> The test image is (deliberately) faulty so it cannot be opened, so
> the only question is which error you get.

Thanks for your explanation, let's set this bug verified.

Comment 12 errata-xmlrpc 2015-11-19 05:01:58 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHBA-2015-2213.html