# HG changeset patch # User Pascal Bellard # Date 1429788618 -7200 # Node ID 9c8ef3fd3dcff0da89e9b3c5edc1431b4fda377d # Parent c73f683146cfdf6dff0a8d34e059dfb56f216328 qemu: apply cloop.u diff -r c73f683146cf -r 9c8ef3fd3dcf qemu/receipt --- a/qemu/receipt Thu Apr 23 01:34:37 2015 +0300 +++ b/qemu/receipt Thu Apr 23 13:30:18 2015 +0200 @@ -20,7 +20,7 @@ # Rules to configure and make the package. compile_rules() { -# patch -p0 < $stuff/cloop.u + patch -p0 < $stuff/cloop.u TARGET="i386-softmmu, x86_64-softmmu, \ arm-softmmu, ppc-softmmu, mips-softmmu" diff -r c73f683146cf -r 9c8ef3fd3dcf qemu/stuff/cloop.u --- a/qemu/stuff/cloop.u Thu Apr 23 01:34:37 2015 +0300 +++ b/qemu/stuff/cloop.u Thu Apr 23 13:30:18 2015 +0200 @@ -1,8 +1,8 @@ --- block/cloop.c +++ block/cloop.c -@@ -26,11 +26,78 @@ - #include "qemu/module.h" - #include +@@ -29,11 +29,85 @@ + /* Maximum compressed block size */ + #define MAX_BLOCK_SIZE (64 * 1024 * 1024) +typedef struct cloop_tail { + uint32_t table_size; @@ -16,7 +16,7 @@ + uint32_t optidx; /* 32-bit index number */ +} block_info; + -+static inline void build_index(block_info *offsets, unsigned long n) ++static inline int build_index(block_info *offsets, unsigned long n) +{ + uint32_t *ofs32 = (uint32_t *) offsets; + uint64_t *ofs64 = (uint64_t *) offsets; @@ -26,17 +26,19 @@ + while (n--) { + offsets[n].offset = be64_to_cpu(offsets[n].offset); + offsets[n].size = ntohl(offsets[n].size); ++ if (offsets[n].size > 2 * MAX_BLOCK_SIZE) ++ return n+1; + } -+ // return (char *) "128BE accelerated knoppix 1.0"; + } + else { /* V2.0 */ + uint64_t last = be64_to_cpu(ofs64[n - 1]); + while (n--) { + offsets[n].size = last - + (offsets[n].offset = be64_to_cpu(ofs64[n])); ++ if (offsets[n].size > 2 * MAX_BLOCK_SIZE) ++ return n+1; + last = offsets[n].offset; + } -+ // return (char *) "64BE v2.0"; + } + } + else if (ofs32[1] == 0) { /* V1.0 */ @@ -44,31 +46,36 @@ + while (n--) { + offsets[n].size = last - + (offsets[n].offset = le64_to_cpu(ofs64[n])); ++ if (offsets[n].size > 2 * MAX_BLOCK_SIZE) ++ return n+1; + last = offsets[n].offset; + } -+ // return (char *) "64LE v1.0"; + } + else if (ntohl(ofs32[0]) == (4*n) + 0x8C) { /* V0.68 */ + uint64_t last = ntohl(ofs32[n - 1]); + while (n--) { + offsets[n].size = last - + (offsets[n].offset = ntohl(ofs32[n])); ++ if (offsets[n].size > 2 * MAX_BLOCK_SIZE) ++ return n+1; + last = offsets[n].offset; + } -+ // return (char *) "32BE v0.68"; + } + else { /* V3.0 */ + unsigned long i; + uint64_t j; + -+ for (i = n; i-- > 0; ) ++ for (i = n; i-- > 0; ) { + offsets[i].size = ntohl(ofs32[i]); ++ if (offsets[i].size > 2 * MAX_BLOCK_SIZE) ++ return i+1; ++ } + for (i = 0, j = 128 + 4 + 4; i < n; i++) { + offsets[i].offset = j; + j += offsets[i].size; + } -+ // return (char *) "32BE v3.0"; + } ++ return 0; +} + typedef struct BDRVCloopState { @@ -80,7 +87,7 @@ uint32_t sectors_per_block; uint32_t current_block; uint8_t *compressed_block; -@@ -40,17 +107,21 @@ +@@ -43,17 +117,21 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -109,50 +116,87 @@ + return ret; } - static int cloop_open(BlockDriverState *bs, QDict *options, int flags) -@@ -74,32 +145,67 @@ + static int cloop_open(BlockDriverState *bs, QDict *options, int flags, +@@ -91,79 +169,104 @@ + MAX_BLOCK_SIZE / (1024 * 1024)); + return -EINVAL; + } +- + ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); + if (ret < 0) { + return ret; } s->n_blocks = be32_to_cpu(s->n_blocks); -- /* read offsets */ -- offsets_size = s->n_blocks * sizeof(uint64_t); -- s->offsets = g_malloc(offsets_size); + /* initialize zlib engine */ + max_compressed_block_size = s->block_size + s->block_size/1000 + 12 + 4; + s->compressed_block = g_malloc(max_compressed_block_size + 1); + s->uncompressed_block = g_malloc(s->block_size); - -- ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); -- if (ret < 0) { ++ + if (inflateInit(&s->zstream) != Z_OK) { + ret = -EINVAL; - goto fail; ++ goto fail; ++ } ++ + /* read offsets */ +- if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) { ++ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(block_info)) { + /* Prevent integer overflow */ + error_setg(errp, "n_blocks %u must be %zu or less", + s->n_blocks, +- (UINT32_MAX - 1) / sizeof(uint64_t)); ++ (UINT32_MAX - 1) / sizeof(block_info)); + return -EINVAL; } - -- for(i=0;in_blocks;i++) { -- 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; -- } -+ /* read offsets */ +- 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 +- * offsets[] limit supports 16 TB images at 256 KB block size. +- */ +- error_setg(errp, "image requires too many offsets, " +- "try increasing block size"); +- return -EINVAL; +- } +- s->offsets = g_malloc(offsets_size); + if (s->n_blocks + 1 == 0) { + cloop_tail tail; + int64_t end = bdrv_getlength(bs->file); + void *p; + uint32_t toclen, len; -+ + +- ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); +- if (ret < 0) { +- goto fail; +- } +- +- for (i = 0; i < s->n_blocks + 1; i++) { +- uint64_t size; + ret = bdrv_pread(bs->file, end - sizeof(tail), &tail, sizeof(tail)); + if (ret < 0) { + goto fail; - } -+ ++ } + +- s->offsets[i] = be64_to_cpu(s->offsets[i]); +- if (i == 0) { +- continue; + s->n_blocks = be32_to_cpu(tail.num_blocks); + offsets_size = s->n_blocks * sizeof(block_info); ++ 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 ++ * offsets[] limit supports 16 TB images at 256 KB block size. ++ */ ++ error_setg(errp, "image requires too many offsets, " ++ "try increasing block size"); ++ return -EINVAL; + } + len = be32_to_cpu(tail.table_size); + toclen = (be32_to_cpu(tail.index_size) & 255) * s->n_blocks; -+ + +- if (s->offsets[i] < s->offsets[i - 1]) { +- error_setg(errp, "offsets not monotonically increasing at " +- "index %u, image file is corrupt", i); + s->offsets = g_malloc(offsets_size); + p = g_malloc(len); + @@ -166,37 +210,64 @@ + s->zstream.avail_out = toclen; + ret = inflateReset(&s->zstream); + if (ret != Z_OK) { -+ ret = -EINVAL; -+ goto fail; -+ } + 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 = inflate(&s->zstream, Z_FINISH); + if (ret != Z_STREAM_END || s->zstream.total_out != toclen) { -+ ret = -EINVAL; -+ goto fail; -+ } + ret = -EINVAL; + goto fail; + } + g_free(p); - } ++ } + else { + offsets_size = s->n_blocks * sizeof(block_info); ++ 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 ++ * offsets[] limit supports 16 TB images at 256 KB block size. ++ */ ++ error_setg(errp, "image requires too many offsets, " ++ "try increasing block size"); ++ return -EINVAL; ++ } + s->offsets = g_malloc(offsets_size); +- if (size > max_compressed_block_size) { +- max_compressed_block_size = size; ++ ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); ++ if (ret < 0) { ++ goto fail; + } + } +- - /* initialize zlib engine */ - s->compressed_block = g_malloc(max_compressed_block_size + 1); - s->uncompressed_block = g_malloc(s->block_size); - if (inflateInit(&s->zstream) != Z_OK) { -- ret = -EINVAL; -- goto fail; -+ ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); -+ if (ret < 0) { -+ goto fail; -+ } ++ ret = build_index(s->offsets, s->n_blocks); ++ if (ret) { ++ error_setg(errp, "invalid compressed block size at index %u, " ++ "image file is corrupt", ret-1); + ret = -EINVAL; + goto fail; } -+ build_index(s->offsets, s->n_blocks); + s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; -@@ -120,10 +226,10 @@ +@@ -184,10 +287,10 @@ if (s->current_block != block_num) { int ret;