qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 4/5] qcow1: Validate image size (CVE-2014-022


From: Kevin Wolf
Subject: Re: [Qemu-devel] [PATCH v2 4/5] qcow1: Validate image size (CVE-2014-0223)
Date: Fri, 16 May 2014 12:47:56 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

Am 15.05.2014 um 18:35 hat Benoît Canet geschrieben:
> The Thursday 15 May 2014 à 16:21:56 (+0200), Kevin Wolf wrote :
> > A huge image size could cause s->l1_size to overflow. Make sure that
> > images never require a L1 table larger than what fits in s->l1_size.
> > 
> > This cannot only cause unbounded allocations, but also the allocation of
> > a too small L1 table, resulting in out-of-bounds array accesses (both
> > reads and writes).
> > 
> > Cc: address@hidden
> > Signed-off-by: Kevin Wolf <address@hidden>
> > ---
> >  block/qcow.c               | 16 ++++++++++++++--
> >  tests/qemu-iotests/092     |  9 +++++++++
> >  tests/qemu-iotests/092.out |  7 +++++++
> >  3 files changed, 30 insertions(+), 2 deletions(-)
> > 
> > diff --git a/block/qcow.c b/block/qcow.c
> > index e8038e5..3566c05 100644
> > --- a/block/qcow.c
> > +++ b/block/qcow.c
> > @@ -61,7 +61,7 @@ typedef struct BDRVQcowState {
> >      int cluster_sectors;
> >      int l2_bits;
> >      int l2_size;
> > -    int l1_size;
> > +    unsigned int l1_size;
> >      uint64_t cluster_offset_mask;
> >      uint64_t l1_table_offset;
> >      uint64_t *l1_table;
> > @@ -166,7 +166,19 @@ static int qcow_open(BlockDriverState *bs, QDict 
> > *options, int flags,
> >  
> >      /* read the level 1 table */
> >      shift = s->cluster_bits + s->l2_bits;
> > -    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
> > +    if (header.size > UINT64_MAX - (1LL << shift)) {
> > +        error_setg(errp, "Image too large");
> > +        ret = -EINVAL;
> > +        goto fail;
> > +    } else {
> > +        uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
> > +        if (l1_size > INT_MAX / sizeof(uint64_t)) {
> > +            error_setg(errp, "Image too large");
> > +            ret = -EINVAL;
> > +            goto fail;
> > +        }
> > +        s->l1_size = l1_size;
> > +    }
> >  
> >      s->l1_table_offset = header.l1_table_offset;
> >      s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
> > diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
> > index fb8bacc..ae6ca76 100755
> > --- a/tests/qemu-iotests/092
> > +++ b/tests/qemu-iotests/092
> > @@ -43,6 +43,7 @@ _supported_fmt qcow
> >  _supported_proto generic
> >  _supported_os Linux
> >  
> > +offset_size=24
> >  offset_cluster_bits=32
> >  offset_l2_bits=33
> >  
> > @@ -72,6 +73,14 @@ poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
> >  poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
> >  { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | 
> > _filter_testdir
> >  
> > +echo
> > +echo "== Invalid size =="
> > +_make_test_img 64M
> > +poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
> > +{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | 
> > _filter_testdir
> > +poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
> > +{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | 
> > _filter_testdir
> > +
> >  # success, all done
> >  echo "*** done"
> >  rm -f $seq.full
> > diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out
> > index 73918b3..ac03302 100644
> > --- a/tests/qemu-iotests/092.out
> > +++ b/tests/qemu-iotests/092.out
> > @@ -21,4 +21,11 @@ qemu-io: can't open device TEST_DIR/t.qcow: L2 table 
> > size must be between 512 an
> >  no file open, try 'help open'
> >  qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 
> > 512 and 64k
> >  no file open, try 'help open'
> > +
> > +== Invalid size ==
> > +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
> > +qemu-io: can't open device TEST_DIR/t.qcow: Image too large
> > +no file open, try 'help open'
> > +qemu-io: can't open device TEST_DIR/t.qcow: Image too large
> > +no file open, try 'help open'
> >  *** done
> > -- 
> > 1.8.3.1
> > 
> 
> I still not understand this one :)

I know, and I'm sorry about that, but I can't explain better than I did.

Last attempt: There is this code line in the original source:

    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;

There are two different integer overflows that can happen in this line.
header.size + (1LL << shift) could exceed UINT64_MAX (header.size is
uint64_t), and the whole calculation could exceed INT_MAX (s->l1_size is
int).

My patch checks for these two conditions and leaves everything else as
it is. It has nothing to do with any L2 table sizes or anything.

Kevin



reply via email to

[Prev in Thread] Current Thread [Next in Thread]