diff options
author | Kevin Wolf <kwolf@redhat.com> | 2013-05-14 16:14:33 +0200 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2013-05-14 16:44:33 +0200 |
commit | 2cf7cfa1cde6672b8a35bbed3fbc989f28c05dce (patch) | |
tree | 221828f1201c58fc23331366214972171a64fa0d /block/qcow2.h | |
parent | b087143b4d010451208264b7c841436aafe1cbb1 (diff) | |
download | qemu-2cf7cfa1cde6672b8a35bbed3fbc989f28c05dce.zip qemu-2cf7cfa1cde6672b8a35bbed3fbc989f28c05dce.tar.gz qemu-2cf7cfa1cde6672b8a35bbed3fbc989f28c05dce.tar.bz2 |
qcow2: Catch some L1 table index overflows
This catches the situation that is described in the bug report at
https://bugs.launchpad.net/qemu/+bug/865518 and goes like this:
$ qemu-img create -f qcow2 huge.qcow2 $((1024*1024))T
Formatting 'huge.qcow2', fmt=qcow2 size=1152921504606846976 encryption=off cluster_size=65536 lazy_refcounts=off
$ qemu-io /tmp/huge.qcow2 -c "write $((1024*1024*1024*1024*1024*1024 - 1024)) 512"
Segmentation fault
With this patch applied the segfault will be avoided, however the case
will still fail, though gracefully:
$ qemu-img create -f qcow2 /tmp/huge.qcow2 $((1024*1024))T
Formatting 'huge.qcow2', fmt=qcow2 size=1152921504606846976 encryption=off cluster_size=65536 lazy_refcounts=off
qemu-img: The image size is too large for file format 'qcow2'
Note that even long before these overflow checks kick in, you get
insanely high memory usage (up to INT_MAX * sizeof(uint64_t) = 16 GB for
the L1 table), so with somewhat smaller image sizes you'll probably see
qemu aborting for a failed g_malloc().
If you need huge image sizes, you should increase the cluster size to
the maximum of 2 MB in order to get higher limits.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block/qcow2.h')
-rw-r--r-- | block/qcow2.h | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/block/qcow2.h b/block/qcow2.h index 9421843..6959c6a 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -284,7 +284,7 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size) return (size + (s->cluster_size - 1)) >> s->cluster_bits; } -static inline int size_to_l1(BDRVQcowState *s, int64_t size) +static inline int64_t size_to_l1(BDRVQcowState *s, int64_t size) { int shift = s->cluster_bits + s->l2_bits; return (size + (1ULL << shift) - 1) >> shift; @@ -360,7 +360,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); /* qcow2-cluster.c functions */ -int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size); +int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, + bool exact_size); void qcow2_l2_cache_reset(BlockDriverState *bs); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, |