X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block%2Fbochs.c;h=af8b7abdfdaf760a4d5d3b30269fc385bf40ca8b;hb=4113b0532da6c448f8e458b413ebde035234d0ea;hp=4d6403f9040f19ad03d02ec74869e28e14779973;hpb=05fd3bf2a1c9fc26414d3cf608732c40d0d9eb23;p=mirror_qemu.git diff --git a/block/bochs.c b/block/bochs.c index 4d6403f904..af8b7abdfd 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -22,6 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu-common.h" #include "block/block_int.h" #include "qemu/module.h" @@ -38,57 +40,42 @@ // not allocated: 0xffffffff -// always little-endian -struct bochs_header_v1 { - char magic[32]; // "Bochs Virtual HD Image" - char type[16]; // "Redolog" - char subtype[16]; // "Undoable" / "Volatile" / "Growing" - uint32_t version; - uint32_t header; // size of header - - union { - struct { - uint32_t catalog; // num of entries - uint32_t bitmap; // bitmap size - uint32_t extent; // extent size - uint64_t disk; // disk size - char padding[HEADER_SIZE - 64 - 8 - 20]; - } redolog; - char padding[HEADER_SIZE - 64 - 8]; - } extra; -}; - // always little-endian struct bochs_header { - char magic[32]; // "Bochs Virtual HD Image" - char type[16]; // "Redolog" - char subtype[16]; // "Undoable" / "Volatile" / "Growing" + char magic[32]; /* "Bochs Virtual HD Image" */ + char type[16]; /* "Redolog" */ + char subtype[16]; /* "Undoable" / "Volatile" / "Growing" */ uint32_t version; - uint32_t header; // size of header + uint32_t header; /* size of header */ + + uint32_t catalog; /* num of entries */ + uint32_t bitmap; /* bitmap size */ + uint32_t extent; /* extent size */ union { - struct { - uint32_t catalog; // num of entries - uint32_t bitmap; // bitmap size - uint32_t extent; // extent size - uint32_t reserved; // for ??? - uint64_t disk; // disk size - char padding[HEADER_SIZE - 64 - 8 - 24]; - } redolog; - char padding[HEADER_SIZE - 64 - 8]; + struct { + uint32_t reserved; /* for ??? */ + uint64_t disk; /* disk size */ + char padding[HEADER_SIZE - 64 - 20 - 12]; + } QEMU_PACKED redolog; + struct { + uint64_t disk; /* disk size */ + char padding[HEADER_SIZE - 64 - 20 - 8]; + } QEMU_PACKED redolog_v1; + char padding[HEADER_SIZE - 64 - 20]; } extra; -}; +} QEMU_PACKED; typedef struct BDRVBochsState { CoMutex lock; uint32_t *catalog_bitmap; - int catalog_size; + uint32_t catalog_size; - int data_offset; + uint32_t data_offset; - int bitmap_blocks; - int extent_blocks; - int extent_size; + uint32_t bitmap_blocks; + uint32_t extent_blocks; + uint32_t extent_size; } BDRVBochsState; static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) @@ -112,14 +99,13 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVBochsState *s = bs->opaque; - int i; + uint32_t i; struct bochs_header bochs; - struct bochs_header_v1 header_v1; int ret; bs->read_only = 1; // no write support yet - ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)); + ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs)); if (ret < 0) { return ret; } @@ -134,16 +120,26 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, } if (le32_to_cpu(bochs.version) == HEADER_V1) { - memcpy(&header_v1, &bochs, sizeof(bochs)); - bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512; + bs->total_sectors = le64_to_cpu(bochs.extra.redolog_v1.disk) / 512; } else { - bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; + bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; + } + + /* Limit to 1M entries to avoid unbounded allocation. This is what is + * needed for the largest image that bximage can create (~8 TB). */ + s->catalog_size = le32_to_cpu(bochs.catalog); + if (s->catalog_size > 0x100000) { + error_setg(errp, "Catalog size is too large"); + return -EFBIG; } - s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); - s->catalog_bitmap = g_malloc(s->catalog_size * 4); + s->catalog_bitmap = g_try_new(uint32_t, s->catalog_size); + if (s->catalog_size && s->catalog_bitmap == NULL) { + error_setg(errp, "Could not allocate memory for catalog"); + return -ENOMEM; + } - ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, + ret = bdrv_pread(bs->file->bs, le32_to_cpu(bochs.header), s->catalog_bitmap, s->catalog_size * 4); if (ret < 0) { goto fail; @@ -154,10 +150,34 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags, s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4); - s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512; - s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512; + s->bitmap_blocks = 1 + (le32_to_cpu(bochs.bitmap) - 1) / 512; + s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512; - s->extent_size = le32_to_cpu(bochs.extra.redolog.extent); + s->extent_size = le32_to_cpu(bochs.extent); + if (s->extent_size < BDRV_SECTOR_SIZE) { + /* bximage actually never creates extents smaller than 4k */ + error_setg(errp, "Extent size must be at least 512"); + ret = -EINVAL; + goto fail; + } else if (!is_power_of_2(s->extent_size)) { + error_setg(errp, "Extent size %" PRIu32 " is not a power of two", + s->extent_size); + ret = -EINVAL; + goto fail; + } else if (s->extent_size > 0x800000) { + error_setg(errp, "Extent size %" PRIu32 " is too large", + s->extent_size); + ret = -EINVAL; + goto fail; + } + + if (s->catalog_size < DIV_ROUND_UP(bs->total_sectors, + s->extent_size / BDRV_SECTOR_SIZE)) + { + error_setg(errp, "Catalog size is too small for this disk size"); + ret = -EINVAL; + goto fail; + } qemu_co_mutex_init(&s->lock); return 0; @@ -170,29 +190,32 @@ fail: static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) { BDRVBochsState *s = bs->opaque; - int64_t offset = sector_num * 512; - int64_t extent_index, extent_offset, bitmap_offset; + uint64_t offset = sector_num * 512; + uint64_t extent_index, extent_offset, bitmap_offset; char bitmap_entry; + int ret; // seek to sector extent_index = offset / s->extent_size; extent_offset = (offset % s->extent_size) / 512; if (s->catalog_bitmap[extent_index] == 0xffffffff) { - return -1; /* not allocated */ + return 0; /* not allocated */ } - bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] * - (s->extent_blocks + s->bitmap_blocks)); + bitmap_offset = s->data_offset + + (512 * (uint64_t) s->catalog_bitmap[extent_index] * + (s->extent_blocks + s->bitmap_blocks)); /* read in bitmap for current extent */ - if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8), - &bitmap_entry, 1) != 1) { - return -1; + ret = bdrv_pread(bs->file->bs, bitmap_offset + (extent_offset / 8), + &bitmap_entry, 1); + if (ret < 0) { + return ret; } if (!((bitmap_entry >> (extent_offset % 8)) & 1)) { - return -1; /* not allocated */ + return 0; /* not allocated */ } return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); @@ -205,13 +228,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num, while (nb_sectors > 0) { int64_t block_offset = seek_to_sector(bs, sector_num); - if (block_offset >= 0) { - ret = bdrv_pread(bs->file, block_offset, buf, 512); - if (ret != 512) { - return -1; + if (block_offset < 0) { + return block_offset; + } else if (block_offset > 0) { + ret = bdrv_pread(bs->file->bs, block_offset, buf, 512); + if (ret < 0) { + return ret; } - } else + } else { memset(buf, 0, 512); + } nb_sectors--; sector_num++; buf += 512;