| From cba6c4e21a8dce857af0ed08d26801ebd5d5598a Mon Sep 17 00:00:00 2001 |
| From: Stefan Hajnoczi <stefanha@redhat.com> |
| Date: Tue, 25 Mar 2014 14:23:14 +0100 |
| Subject: [PATCH 07/49] block/cloop: refuse images with bogus offsets (CVE-2014-0144) |
| |
| RH-Author: Kevin Wolf <kwolf@redhat.com> |
| Message-id: <1395753835-7591-8-git-send-email-kwolf@redhat.com> |
| Patchwork-id: n/a |
| O-Subject: [virt-devel] [EMBARGOED RHEL-7.0 qemu-kvm PATCH 07/48] block/cloop: refuse images with bogus offsets (CVE-2014-0144) |
| Bugzilla: 1079455 |
| RH-Acked-by: Jeff Cody <jcody@redhat.com> |
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com> |
| |
| From: Stefan Hajnoczi <stefanha@redhat.com> |
| |
| Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1079455 |
| Upstream status: Embargoed |
| |
| The offsets[] array allows efficient seeking and tells us the maximum |
| compressed data size. If the offsets are bogus the maximum compressed |
| data size will be unrealistic. |
| |
| This could cause g_malloc() to abort and bogus offsets mean the image is |
| broken anyway. Therefore we should refuse such images. |
| |
| Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
| Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
| |
| block/cloop.c | 34 +++++++++++++++++++++++++++++----- |
| tests/qemu-iotests/075 | 15 +++++++++++++++ |
| tests/qemu-iotests/075.out | 8 ++++++++ |
| 3 files changed, 52 insertions(+), 5 deletions(-) |
| |
| diff --git a/block/cloop.c b/block/cloop.c |
| index 844665e..55a804f 100644 |
| |
| |
| @@ -124,12 +124,36 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags, |
| } |
| |
| for(i=0;i<s->n_blocks;i++) { |
| + uint64_t size; |
| + |
| s->offsets[i] = be64_to_cpu(s->offsets[i]); |
| - if (i > 0) { |
| - uint32_t size = s->offsets[i] - s->offsets[i - 1]; |
| - if (size > max_compressed_block_size) { |
| - max_compressed_block_size = size; |
| - } |
| + if (i == 0) { |
| + continue; |
| + } |
| + |
| + if (s->offsets[i] < s->offsets[i - 1]) { |
| + error_setg(errp, "offsets not monotonically increasing at " |
| + "index %u, image file is corrupt", i); |
| + ret = -EINVAL; |
| + goto fail; |
| + } |
| + |
| + size = s->offsets[i] - s->offsets[i - 1]; |
| + |
| + /* Compressed blocks should be smaller than the uncompressed block size |
| + * but maybe compression performed poorly so the compressed block is |
| + * actually bigger. Clamp down on unrealistic values to prevent |
| + * ridiculous s->compressed_block allocation. |
| + */ |
| + if (size > 2 * MAX_BLOCK_SIZE) { |
| + error_setg(errp, "invalid compressed block size at index %u, " |
| + "image file is corrupt", i); |
| + ret = -EINVAL; |
| + goto fail; |
| + } |
| + |
| + if (size > max_compressed_block_size) { |
| + max_compressed_block_size = size; |
| } |
| } |
| |
| diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075 |
| index 9c00fa8..d74fb33 100755 |
| |
| |
| @@ -44,6 +44,7 @@ _supported_os Linux |
| |
| block_size_offset=128 |
| n_blocks_offset=132 |
| +offsets_offset=136 |
| |
| echo |
| echo "== check that the first sector can be read ==" |
| @@ -80,6 +81,20 @@ _use_sample_img simple-pattern.cloop.bz2 |
| poke_file "$TEST_IMG" "$n_blocks_offset" "\x04\x00\x00\x01" |
| $QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir |
| |
| +echo |
| +echo "== refuse images with non-monotonically increasing offsets ==" |
| +_use_sample_img simple-pattern.cloop.bz2 |
| +poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\xff\xff\xff\xff" |
| +poke_file "$TEST_IMG" $((offsets_offset + 8)) "\x00\x00\x00\x00\xff\xfe\x00\x00" |
| +$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir |
| + |
| +echo |
| +echo "== refuse images with invalid compressed block size ==" |
| +_use_sample_img simple-pattern.cloop.bz2 |
| +poke_file "$TEST_IMG" "$offsets_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" |
| +poke_file "$TEST_IMG" $((offsets_offset + 8)) "\xff\xff\xff\xff\xff\xff\xff\xff" |
| +$QEMU_IO -c "read 0 512" $TEST_IMG 2>&1 | _filter_qemu_io | _filter_testdir |
| + |
| # success, all done |
| echo "*** done" |
| rm -f $seq.full |
| diff --git a/tests/qemu-iotests/075.out b/tests/qemu-iotests/075.out |
| index 7cdaee1..911cd3b 100644 |
| |
| |
| @@ -23,4 +23,12 @@ no file open, try 'help open' |
| == refuse images that require too many offsets |
| qemu-io: can't open device TEST_DIR/simple-pattern.cloop: image requires too many offsets, try increasing block size |
| no file open, try 'help open' |
| + |
| +== refuse images with non-monotonically increasing offsets == |
| +qemu-io: can't open device TEST_DIR/simple-pattern.cloop: offsets not monotonically increasing at index 1, image file is corrupt |
| +no file open, try 'help open' |
| + |
| +== refuse images with invalid compressed block size == |
| +qemu-io: can't open device TEST_DIR/simple-pattern.cloop: invalid compressed block size at index 1, image file is corrupt |
| +no file open, try 'help open' |
| *** done |
| -- |
| 1.7.1 |
| |