Blob Blame History Raw
From af26019bf167d71fc3a8e5d46865a4c53d58e976 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Wed, 26 Mar 2014 13:05:29 +0100
Subject: [PATCH] block/cloop: fix offsets[] size off-by-one

cloop stores the number of compressed blocks in the n_blocks header
field.  The file actually contains n_blocks + 1 offsets, where the extra
offset is the end-of-file offset.

The following line in cloop_read_block() results in an out-of-bounds
offsets[] access:

    uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];

This patch allocates and loads the extra offset so that
cloop_read_block() works correctly when the last block is accessed.

Notice that we must free s->offsets[] unconditionally now since there is
always an end-of-file offset.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 42d43d35d907579179a39c924d169da924786f65)

Conflicts:
	tests/qemu-iotests/075
	tests/qemu-iotests/075.out
---
 block/cloop.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/block/cloop.c b/block/cloop.c
index 5c9c085..b28aae1 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -98,14 +98,14 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
     s->n_blocks = be32_to_cpu(s->n_blocks);
 
     /* read offsets */
-    if (s->n_blocks > UINT32_MAX / sizeof(uint64_t)) {
+    if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) {
         /* Prevent integer overflow */
         fprintf(stderr, "n_blocks %u must be %zu or less",
                    s->n_blocks,
-                   UINT32_MAX / sizeof(uint64_t));
+                   (UINT32_MAX - 1) / sizeof(uint64_t));
         return -EINVAL;
     }
-    offsets_size = s->n_blocks * sizeof(uint64_t);
+    offsets_size = (s->n_blocks + 1) * sizeof(uint64_t);
     if (offsets_size > 512 * 1024 * 1024) {
         /* Prevent ridiculous offsets_size which causes memory allocation to
          * fail or overflows bdrv_pread() size.  In practice the 512 MB
@@ -122,7 +122,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags)
         goto fail;
     }
 
-    for(i=0;i<s->n_blocks;i++) {
+    for (i = 0; i < s->n_blocks + 1; i++) {
         uint64_t size;
 
         s->offsets[i] = be64_to_cpu(s->offsets[i]);
@@ -242,9 +242,7 @@ static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num,
 static void cloop_close(BlockDriverState *bs)
 {
     BDRVCloopState *s = bs->opaque;
-    if (s->n_blocks > 0) {
-        g_free(s->offsets);
-    }
+    g_free(s->offsets);
     g_free(s->compressed_block);
     g_free(s->uncompressed_block);
     inflateEnd(&s->zstream);