static void nbd_teardown_connection(NbdClientSession *client) { struct nbd_request request = { .type = NBD_CMD_DISC, .from = 0, .len = 0 }; nbd_send_request(client->sock, &request); /* finish any pending coroutines */ shutdown(client->sock, 2); nbd_recv_coroutines_enter_all(client); qemu_aio_set_fd_handler(client->sock, NULL, NULL, NULL); closesocket(client->sock); client->sock = -1; } void nbd_client_session_close(NbdClientSession *client) { if (!client->bs) { return; } nbd_teardown_connection(client); client->bs = NULL; } int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs, int sock, const char *export) { int ret; /* NBD handshake */ logout("session init %s\n", export); qemu_set_block(sock); ret = nbd_receive_negotiate(sock, export, &client->nbdflags, &client->size, &client->blocksize); if (ret < 0) { logout("Failed to negotiate with the NBD server\n"); closesocket(sock); return ret; } qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->free_sema); client->bs = bs; client->sock = sock; /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qemu_set_nonblock(sock); qemu_aio_set_fd_handler(sock, nbd_reply_ready, NULL, client); logout("Established connection with NBD server\n"); return 0; }
void nbd_client_close(BlockDriverState *bs) { NbdClientSession *client = nbd_get_client_session(bs); struct nbd_request request = { .type = NBD_CMD_DISC, .from = 0, .len = 0 }; if (client->sock == -1) { return; } nbd_send_request(client->sock, &request); nbd_teardown_connection(bs); } int nbd_client_init(BlockDriverState *bs, int sock, const char *export, Error **errp) { NbdClientSession *client = nbd_get_client_session(bs); int ret; /* NBD handshake */ logout("session init %s\n", export); qemu_set_block(sock); ret = nbd_receive_negotiate(sock, export, &client->nbdflags, &client->size, &client->blocksize, errp); if (ret < 0) { logout("Failed to negotiate with the NBD server\n"); closesocket(sock); return ret; } qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->free_sema); client->sock = sock; /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qemu_set_nonblock(sock); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); return 0; }
static void ssh_state_init(BDRVSSHState *s) { memset(s, 0, sizeof *s); s->sock = -1; s->offset = -1; qemu_co_mutex_init(&s->lock); }
static void test_co_mutex(void) { CoMutex m; qemu_co_mutex_init(&m); do_test_co_mutex(mutex_fn, &m); }
static int parallels_open(BlockDriverState *bs, int flags) { BDRVParallelsState *s = bs->opaque; int i; struct parallels_header ph; bs->read_only = 1; // no write support yet if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph)) goto fail; if (memcmp(ph.magic, HEADER_MAGIC, 16) || (le32_to_cpu(ph.version) != HEADER_VERSION)) { goto fail; } bs->total_sectors = le32_to_cpu(ph.nb_sectors); s->tracks = le32_to_cpu(ph.tracks); s->catalog_size = le32_to_cpu(ph.catalog_entries); s->catalog_bitmap = g_malloc(s->catalog_size * 4); if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) != s->catalog_size * 4) goto fail; for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); qemu_co_mutex_init(&s->lock); return 0; fail: if (s->catalog_bitmap) g_free(s->catalog_bitmap); return -1; }
static int vmdk_open(BlockDriverState *bs, int flags) { int ret; BDRVVmdkState *s = bs->opaque; if (vmdk_open_sparse(bs, bs->file, flags) == 0) { s->desc_offset = 0x200; } else { ret = vmdk_open_desc_file(bs, flags, 0); if (ret) { goto fail; } } /* try to open parent images, if exist */ ret = vmdk_parent_open(bs); if (ret) { goto fail; } s->parent_cid = vmdk_read_cid(bs, 1); qemu_co_mutex_init(&s->lock); /* Disable migration when VMDK images are used */ error_set(&s->migration_blocker, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, "vmdk", bs->device_name, "live migration"); migrate_add_blocker(s->migration_blocker); return 0; fail: vmdk_free_extents(bs); return ret; }
static int parallels_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVParallelsState *s = bs->opaque; int i; struct parallels_header ph; int ret; bs->read_only = 1; // no write support yet ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph)); if (ret < 0) { goto fail; } if (memcmp(ph.magic, HEADER_MAGIC, 16) || (le32_to_cpu(ph.version) != HEADER_VERSION)) { error_setg(errp, "Image not in Parallels format"); ret = -EINVAL; goto fail; } bs->total_sectors = le32_to_cpu(ph.nb_sectors); s->tracks = le32_to_cpu(ph.tracks); if (s->tracks == 0) { error_setg(errp, "Invalid image: Zero sectors per track"); ret = -EINVAL; goto fail; } s->catalog_size = le32_to_cpu(ph.catalog_entries); if (s->catalog_size > INT_MAX / 4) { error_setg(errp, "Catalog too large"); ret = -EFBIG; goto fail; } s->catalog_bitmap = g_try_malloc(s->catalog_size * 4); if (s->catalog_size && s->catalog_bitmap == NULL) { ret = -ENOMEM; goto fail; } ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4); if (ret < 0) { goto fail; } for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->catalog_bitmap); return ret; }
static void test_co_mutex_lockable(void) { CoMutex m; CoMutex *null_pointer = NULL; qemu_co_mutex_init(&m); do_test_co_mutex(lockable_fn, QEMU_MAKE_LOCKABLE(&m)); g_assert(QEMU_MAKE_LOCKABLE(null_pointer) == NULL); }
static int nbd_open(BlockDriverState *bs, const char* filename, int flags) { BDRVNBDState *s = bs->opaque; int result; qemu_co_mutex_init(&s->send_mutex); qemu_co_mutex_init(&s->free_sema); /* Pop the config into our state object. Exit if invalid. */ result = nbd_config(s, filename, flags); if (result != 0) { return result; } /* establish TCP connection, return error if it fails * TODO: Configurable retry-until-timeout behaviour. */ result = nbd_establish_connection(bs); return result; }
static int cloop_open(BlockDriverState *bs, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; bs->read_only = 1; /* read header */ if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) { goto cloop_close; } s->block_size = be32_to_cpu(s->block_size); if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) { goto cloop_close; } 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); if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < offsets_size) { goto cloop_close; } for(i=0;i<s->n_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; } } } /* 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) { goto cloop_close; } s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; cloop_close: return -1; }
NBDClient *nbd_client_new(NBDExport *exp, int csock, void (*close)(NBDClient *)) { NBDClient *client; if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) < 0) { return NULL; } client = g_malloc0(sizeof(NBDClient)); client->refcount = 1; client->exp = exp; client->sock = csock; client->close = close; qemu_co_mutex_init(&client->send_lock); qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); return client; }
static int dmg_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVDMGState *s = bs->opaque; DmgHeaderState ds; uint64_t rsrc_fork_offset, rsrc_fork_length; uint64_t plist_xml_offset, plist_xml_length; int64_t offset; int ret; block_module_load_one("dmg-bz2"); bs->read_only = true; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; /* used by dmg_read_mish_block to keep track of the current I/O position */ ds.data_fork_offset = 0; ds.max_compressed_size = 1; ds.max_sectors_per_chunk = 1; /* locate the UDIF trailer */ offset = dmg_find_koly_offset(bs->file, errp); if (offset < 0) { ret = offset; goto fail; } /* offset of data fork (DataForkOffset) */ ret = read_uint64(bs, offset + 0x18, &ds.data_fork_offset); if (ret < 0) { goto fail; } else if (ds.data_fork_offset > offset) { ret = -EINVAL; goto fail; } /* offset of resource fork (RsrcForkOffset) */ ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset); if (ret < 0) { goto fail; } ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length); if (ret < 0) { goto fail; } if (rsrc_fork_offset >= offset || rsrc_fork_length > offset - rsrc_fork_offset) { ret = -EINVAL; goto fail; } /* offset of property list (XMLOffset) */ ret = read_uint64(bs, offset + 0xd8, &plist_xml_offset); if (ret < 0) { goto fail; } ret = read_uint64(bs, offset + 0xe0, &plist_xml_length); if (ret < 0) { goto fail; } if (plist_xml_offset >= offset || plist_xml_length > offset - plist_xml_offset) { ret = -EINVAL; goto fail; } ret = read_uint64(bs, offset + 0x1ec, (uint64_t *)&bs->total_sectors); if (ret < 0) { goto fail; } if (bs->total_sectors < 0) { ret = -EINVAL; goto fail; } if (rsrc_fork_length != 0) { ret = dmg_read_resource_fork(bs, &ds, rsrc_fork_offset, rsrc_fork_length); if (ret < 0) { goto fail; } } else if (plist_xml_length != 0) { ret = dmg_read_plist_xml(bs, &ds, plist_xml_offset, plist_xml_length); if (ret < 0) { goto fail; } } else { ret = -EINVAL; goto fail; } /* initialize zlib engine */ s->compressed_chunk = qemu_try_blockalign(bs->file->bs, ds.max_compressed_size + 1); s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs, 512 * ds.max_sectors_per_chunk); if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { ret = -ENOMEM; goto fail; } if (inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_chunk = s->n_chunks; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->types); g_free(s->offsets); g_free(s->lengths); g_free(s->sectors); g_free(s->sectorcounts); qemu_vfree(s->compressed_chunk); qemu_vfree(s->uncompressed_chunk); return ret; }
void nbd_client_close(BlockDriverState *bs) { NbdClientSession *client = nbd_get_client_session(bs); struct nbd_request request = { .type = NBD_CMD_DISC, .from = 0, .len = 0 }; if (client->ioc == NULL) { return; } nbd_send_request(client->ioc, &request); nbd_teardown_connection(bs); } int nbd_client_init(BlockDriverState *bs, QIOChannelSocket *sioc, const char *export, QCryptoTLSCreds *tlscreds, const char *hostname, Error **errp) { NbdClientSession *client = nbd_get_client_session(bs); int ret; /* NBD handshake */ logout("session init %s\n", export); qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, &client->nbdflags, tlscreds, hostname, &client->ioc, &client->size, errp); if (ret < 0) { logout("Failed to negotiate with the NBD server\n"); return ret; } qemu_co_mutex_init(&client->send_mutex); qemu_co_mutex_init(&client->free_sema); client->sioc = sioc; object_ref(OBJECT(client->sioc)); if (!client->ioc) { client->ioc = QIO_CHANNEL(sioc); object_ref(OBJECT(client->ioc)); } /* Now that we're connected, set the socket to be non-blocking and * kick the reply mechanism. */ qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); return 0; }
static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVVHDXState *s = bs->opaque; int ret = 0; uint32_t i; uint64_t signature; uint32_t data_blocks_cnt, bitmap_blocks_cnt; s->bat = NULL; qemu_co_mutex_init(&s->lock); /* validate the file signature */ ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t)); if (ret < 0) { goto fail; } if (memcmp(&signature, "vhdxfile", 8)) { ret = -EINVAL; goto fail; } ret = vhdx_parse_header(bs, s); if (ret) { goto fail; } ret = vhdx_parse_log(bs, s); if (ret) { goto fail; } ret = vhdx_open_region_tables(bs, s); if (ret) { goto fail; } ret = vhdx_parse_metadata(bs, s); if (ret) { goto fail; } s->block_size = s->params.block_size; /* the VHDX spec dictates that virtual_disk_size is always a multiple of * logical_sector_size */ bs->total_sectors = s->virtual_disk_size >> s->logical_sector_size_bits; data_blocks_cnt = s->virtual_disk_size >> s->block_size_bits; if (s->virtual_disk_size - (data_blocks_cnt << s->block_size_bits)) { data_blocks_cnt++; } bitmap_blocks_cnt = data_blocks_cnt >> s->chunk_ratio_bits; if (data_blocks_cnt - (bitmap_blocks_cnt << s->chunk_ratio_bits)) { bitmap_blocks_cnt++; } if (s->parent_entries) { s->bat_entries = bitmap_blocks_cnt * (s->chunk_ratio + 1); } else { s->bat_entries = data_blocks_cnt + ((data_blocks_cnt - 1) >> s->chunk_ratio_bits); } s->bat_offset = s->bat_rt.file_offset; if (s->bat_entries > s->bat_rt.length / sizeof(VHDXBatEntry)) { /* BAT allocation is not large enough for all entries */ ret = -EINVAL; goto fail; } s->bat = qemu_blockalign(bs, s->bat_rt.length); ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length); if (ret < 0) { goto fail; } for (i = 0; i < s->bat_entries; i++) { le64_to_cpus(&s->bat[i]); } if (flags & BDRV_O_RDWR) { ret = -ENOTSUP; goto fail; } /* TODO: differencing files, write */ /* Disable migration when VHDX images are used */ error_set(&s->migration_blocker, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, "vhdx", bs->device_name, "live migration"); migrate_add_blocker(s->migration_blocker); return 0; fail: qemu_vfree(s->headers[0]); qemu_vfree(s->headers[1]); qemu_vfree(s->bat); qemu_vfree(s->parent_entries); return ret; }
static int cloop_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; int ret; bs->read_only = 1; bs->request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O supported */ /* read header */ ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4); if (ret < 0) { return ret; } s->block_size = be32_to_cpu(s->block_size); if (s->block_size % 512) { error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512", s->block_size); return -EINVAL; } if (s->block_size == 0) { error_setg(errp, "block_size cannot be zero"); return -EINVAL; } /* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but * we can accept more. Prevent ridiculous values like 4 GB - 1 since we * need a buffer this big. */ if (s->block_size > MAX_BLOCK_SIZE) { error_setg(errp, "block_size %" PRIu32 " must be %u MB or less", s->block_size, MAX_BLOCK_SIZE / (1024 * 1024)); return -EINVAL; } ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4); if (ret < 0) { return ret; } s->n_blocks = be32_to_cpu(s->n_blocks); /* read offsets */ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) { /* Prevent integer overflow */ error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less", s->n_blocks, (UINT32_MAX - 1) / sizeof(uint64_t)); return -EINVAL; } 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_try_malloc(offsets_size); if (s->offsets == NULL) { error_setg(errp, "Could not allocate offsets table"); return -ENOMEM; } ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size); if (ret < 0) { goto fail; } for (i = 0; i < s->n_blocks + 1; i++) { uint64_t size; s->offsets[i] = be64_to_cpu(s->offsets[i]); if (i == 0) { continue; } if (s->offsets[i] < s->offsets[i - 1]) { error_setg(errp, "offsets not monotonically increasing at " "index %" PRIu32 ", 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 %" PRIu32 ", image file is corrupt", i); ret = -EINVAL; goto fail; } if (size > max_compressed_block_size) { max_compressed_block_size = size; } } /* initialize zlib engine */ s->compressed_block = g_try_malloc(max_compressed_block_size + 1); if (s->compressed_block == NULL) { error_setg(errp, "Could not allocate compressed_block"); ret = -ENOMEM; goto fail; } s->uncompressed_block = g_try_malloc(s->block_size); if (s->uncompressed_block == NULL) { error_setg(errp, "Could not allocate uncompressed_block"); ret = -ENOMEM; goto fail; } if (inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->offsets); g_free(s->compressed_block); g_free(s->uncompressed_block); return ret; }
static int vpc_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVVPCState *s = bs->opaque; int i; VHDFooter *footer; VHDDynDiskHeader *dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; uint64_t computed_size; uint64_t pagetable_size; int disk_type = VHD_DYNAMIC; int ret; ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; } footer = (VHDFooter *) s->footer_buf; if (strncmp(footer->creator, "conectix", 8)) { int64_t offset = bdrv_getlength(bs->file->bs); if (offset < 0) { ret = offset; goto fail; } else if (offset < HEADER_SIZE) { ret = -EINVAL; goto fail; } /* If a fixed disk, the footer is found only at the end of the file */ ret = bdrv_pread(bs->file->bs, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE); if (ret < 0) { goto fail; } if (strncmp(footer->creator, "conectix", 8)) { error_setg(errp, "invalid VPC image"); ret = -EINVAL; goto fail; } disk_type = VHD_FIXED; } checksum = be32_to_cpu(footer->checksum); footer->checksum = 0; if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum) fprintf(stderr, "block-vpc: The header checksum of '%s' is " "incorrect.\n", bs->filename); /* Write 'checksum' back to footer, or else will leave it with zero. */ footer->checksum = cpu_to_be32(checksum); // The visible size of a image in Virtual PC depends on the geometry // rather than on the size stored in the footer (the size in the footer // is too large usually) bs->total_sectors = (int64_t) be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; /* Images that have exactly the maximum geometry are probably bigger and * would be truncated if we adhered to the geometry for them. Rely on * footer->current_size for them. */ if (bs->total_sectors == VHD_MAX_GEOMETRY) { bs->total_sectors = be64_to_cpu(footer->current_size) / BDRV_SECTOR_SIZE; } /* Allow a maximum disk size of approximately 2 TB */ if (bs->total_sectors >= VHD_MAX_SECTORS) { ret = -EFBIG; goto fail; } if (disk_type == VHD_DYNAMIC) { ret = bdrv_pread(bs->file->bs, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE); if (ret < 0) { goto fail; } dyndisk_header = (VHDDynDiskHeader *) buf; if (strncmp(dyndisk_header->magic, "cxsparse", 8)) { ret = -EINVAL; goto fail; } s->block_size = be32_to_cpu(dyndisk_header->block_size); if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) { error_setg(errp, "Invalid block size %" PRIu32, s->block_size); ret = -EINVAL; goto fail; } s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511; s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries); if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) { ret = -EINVAL; goto fail; } if (s->max_table_entries > (VHD_MAX_SECTORS * 512) / s->block_size) { ret = -EINVAL; goto fail; } computed_size = (uint64_t) s->max_table_entries * s->block_size; if (computed_size < bs->total_sectors * 512) { ret = -EINVAL; goto fail; } if (s->max_table_entries > SIZE_MAX / 4 || s->max_table_entries > (int) INT_MAX / 4) { error_setg(errp, "Max Table Entries too large (%" PRId32 ")", s->max_table_entries); ret = -EINVAL; goto fail; } pagetable_size = (uint64_t) s->max_table_entries * 4; s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size); if (s->pagetable == NULL) { ret = -ENOMEM; goto fail; } s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); ret = bdrv_pread(bs->file->bs, s->bat_offset, s->pagetable, pagetable_size); if (ret < 0) { goto fail; } s->free_data_block_offset = ROUND_UP(s->bat_offset + pagetable_size, 512); for (i = 0; i < s->max_table_entries; i++) { be32_to_cpus(&s->pagetable[i]); if (s->pagetable[i] != 0xFFFFFFFF) { int64_t next = (512 * (int64_t) s->pagetable[i]) + s->bitmap_size + s->block_size; if (next > s->free_data_block_offset) { s->free_data_block_offset = next; } } } if (s->free_data_block_offset > bdrv_getlength(bs->file->bs)) { error_setg(errp, "block-vpc: free_data_block_offset points after " "the end of file. The image has been truncated."); ret = -EINVAL; goto fail; } s->last_bitmap_offset = (int64_t) -1; #ifdef CACHE s->pageentry_u8 = g_malloc(512); s->pageentry_u32 = s->pageentry_u8; s->pageentry_u16 = s->pageentry_u8; s->last_pagetable = -1; #endif } qemu_co_mutex_init(&s->lock); /* Disable migration when VHD images are used */ error_setg(&s->migration_blocker, "The vpc format used by node '%s' " "does not support live migration", bdrv_get_device_or_node_name(bs)); migrate_add_blocker(s->migration_blocker); return 0; fail: qemu_vfree(s->pagetable); #ifdef CACHE g_free(s->pageentry_u8); #endif return ret; }
static int dmg_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVDMGState *s = bs->opaque; uint64_t info_begin, info_end, last_in_offset, last_out_offset; uint32_t count, tmp; uint32_t max_compressed_size = 1, max_sectors_per_chunk = 1, i; int64_t offset; int ret; bs->read_only = 1; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; /* read offset of info blocks */ offset = bdrv_getlength(bs->file); if (offset < 0) { ret = offset; goto fail; } offset -= 0x1d8; ret = read_uint64(bs, offset, &info_begin); if (ret < 0) { goto fail; } else if (info_begin == 0) { ret = -EINVAL; goto fail; } ret = read_uint32(bs, info_begin, &tmp); if (ret < 0) { goto fail; } else if (tmp != 0x100) { ret = -EINVAL; goto fail; } ret = read_uint32(bs, info_begin + 4, &count); if (ret < 0) { goto fail; } else if (count == 0) { ret = -EINVAL; goto fail; } info_end = info_begin + count; offset = info_begin + 0x100; /* read offsets */ last_in_offset = last_out_offset = 0; while (offset < info_end) { uint32_t type; ret = read_uint32(bs, offset, &count); if (ret < 0) { goto fail; } else if (count == 0) { ret = -EINVAL; goto fail; } offset += 4; ret = read_uint32(bs, offset, &type); if (ret < 0) { goto fail; } if (type == 0x6d697368 && count >= 244) { size_t new_size; uint32_t chunk_count; offset += 4; offset += 200; chunk_count = (count - 204) / 40; new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); s->types = g_realloc(s->types, new_size / 2); s->offsets = g_realloc(s->offsets, new_size); s->lengths = g_realloc(s->lengths, new_size); s->sectors = g_realloc(s->sectors, new_size); s->sectorcounts = g_realloc(s->sectorcounts, new_size); for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { ret = read_uint32(bs, offset, &s->types[i]); if (ret < 0) { goto fail; } offset += 4; if (s->types[i] != 0x80000005 && s->types[i] != 1 && s->types[i] != 2) { if (s->types[i] == 0xffffffff && i > 0) { last_in_offset = s->offsets[i - 1] + s->lengths[i - 1]; last_out_offset = s->sectors[i - 1] + s->sectorcounts[i - 1]; } chunk_count--; i--; offset += 36; continue; } offset += 4; ret = read_uint64(bs, offset, &s->sectors[i]); if (ret < 0) { goto fail; } s->sectors[i] += last_out_offset; offset += 8; ret = read_uint64(bs, offset, &s->sectorcounts[i]); if (ret < 0) { goto fail; } offset += 8; if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) { error_report("sector count %" PRIu64 " for chunk %" PRIu32 " is larger than max (%u)", s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX); ret = -EINVAL; goto fail; } ret = read_uint64(bs, offset, &s->offsets[i]); if (ret < 0) { goto fail; } s->offsets[i] += last_in_offset; offset += 8; ret = read_uint64(bs, offset, &s->lengths[i]); if (ret < 0) { goto fail; } offset += 8; if (s->lengths[i] > DMG_LENGTHS_MAX) { error_report("length %" PRIu64 " for chunk %" PRIu32 " is larger than max (%u)", s->lengths[i], i, DMG_LENGTHS_MAX); ret = -EINVAL; goto fail; } update_max_chunk_size(s, i, &max_compressed_size, &max_sectors_per_chunk); } s->n_chunks += chunk_count; } } /* initialize zlib engine */ s->compressed_chunk = qemu_try_blockalign(bs->file, max_compressed_size + 1); s->uncompressed_chunk = qemu_try_blockalign(bs->file, 512 * max_sectors_per_chunk); if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { ret = -ENOMEM; goto fail; } if (inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_chunk = s->n_chunks; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->types); g_free(s->offsets); g_free(s->lengths); g_free(s->sectors); g_free(s->sectorcounts); qemu_vfree(s->compressed_chunk); qemu_vfree(s->uncompressed_chunk); return ret; }
static int dmg_open(BlockDriverState *bs, int flags) { BDRVDMGState *s = bs->opaque; uint64_t info_begin,info_end,last_in_offset,last_out_offset; uint32_t count, tmp; uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; int64_t offset; int ret; bs->read_only = 1; s->n_chunks = 0; s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; /* read offset of info blocks */ offset = bdrv_getlength(bs->file); if (offset < 0) { ret = offset; goto fail; } offset -= 0x1d8; ret = read_uint64(bs, offset, &info_begin); if (ret < 0) { goto fail; } else if (info_begin == 0) { ret = -EINVAL; goto fail; } ret = read_uint32(bs, info_begin, &tmp); if (ret < 0) { goto fail; } else if (tmp != 0x100) { ret = -EINVAL; goto fail; } ret = read_uint32(bs, info_begin + 4, &count); if (ret < 0) { goto fail; } else if (count == 0) { ret = -EINVAL; goto fail; } info_end = info_begin + count; offset = info_begin + 0x100; /* read offsets */ last_in_offset = last_out_offset = 0; while (offset < info_end) { uint32_t type; ret = read_uint32(bs, offset, &count); if (ret < 0) { goto fail; } else if (count == 0) { ret = -EINVAL; goto fail; } offset += 4; ret = read_uint32(bs, offset, &type); if (ret < 0) { goto fail; } if (type == 0x6d697368 && count >= 244) { int new_size, chunk_count; offset += 4; offset += 200; chunk_count = (count-204)/40; new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); s->types = g_realloc(s->types, new_size/2); s->offsets = g_realloc(s->offsets, new_size); s->lengths = g_realloc(s->lengths, new_size); s->sectors = g_realloc(s->sectors, new_size); s->sectorcounts = g_realloc(s->sectorcounts, new_size); for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { ret = read_uint32(bs, offset, &s->types[i]); if (ret < 0) { goto fail; } offset += 4; if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { if(s->types[i]==0xffffffff) { last_in_offset = s->offsets[i-1]+s->lengths[i-1]; last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1]; } chunk_count--; i--; offset += 36; continue; } offset += 4; ret = read_uint64(bs, offset, &s->sectors[i]); if (ret < 0) { goto fail; } s->sectors[i] += last_out_offset; offset += 8; ret = read_uint64(bs, offset, &s->sectorcounts[i]); if (ret < 0) { goto fail; } offset += 8; ret = read_uint64(bs, offset, &s->offsets[i]); if (ret < 0) { goto fail; } s->offsets[i] += last_in_offset; offset += 8; ret = read_uint64(bs, offset, &s->lengths[i]); if (ret < 0) { goto fail; } offset += 8; if(s->lengths[i]>max_compressed_size) max_compressed_size = s->lengths[i]; if(s->sectorcounts[i]>max_sectors_per_chunk) max_sectors_per_chunk = s->sectorcounts[i]; } s->n_chunks+=chunk_count; } } /* initialize zlib engine */ s->compressed_chunk = g_malloc(max_compressed_size+1); s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk); if(inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_chunk = s->n_chunks; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->types); g_free(s->offsets); g_free(s->lengths); g_free(s->sectors); g_free(s->sectorcounts); g_free(s->compressed_chunk); g_free(s->uncompressed_chunk); return ret; }
static int CVE_2014_0223_qemu1_0_qcow_open(BlockDriverState *bs, int flags) { BDRVQcowState *s = bs->opaque; int len, i, shift; QCowHeader header; if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header)) goto fail; be32_to_cpus(&header.magic); be32_to_cpus(&header.version); be64_to_cpus(&header.backing_file_offset); be32_to_cpus(&header.backing_file_size); be32_to_cpus(&header.mtime); be64_to_cpus(&header.size); be32_to_cpus(&header.crypt_method); be64_to_cpus(&header.l1_table_offset); if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) goto fail; if (header.size <= 1 || header.cluster_bits < 9) goto fail; if (header.crypt_method > QCOW_CRYPT_AES) goto fail; s->crypt_method_header = header.crypt_method; if (s->crypt_method_header) bs->encrypted = 1; s->cluster_bits = header.cluster_bits; s->cluster_size = 1 << s->cluster_bits; s->cluster_sectors = 1 << (s->cluster_bits - 9); s->l2_bits = header.l2_bits; s->l2_size = 1 << s->l2_bits; bs->total_sectors = header.size / 512; s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1; /* read the level 1 table */ shift = s->cluster_bits + s->l2_bits; s->l1_size = (header.size + (1LL << shift) - 1) >> shift; s->l1_table_offset = header.l1_table_offset; s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t)); if (!s->l1_table) goto fail; if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != s->l1_size * sizeof(uint64_t)) goto fail; for(i = 0;i < s->l1_size; i++) { be64_to_cpus(&s->l1_table[i]); } /* alloc L2 cache */ s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); if (!s->l2_cache) goto fail; s->cluster_cache = g_malloc(s->cluster_size); if (!s->cluster_cache) goto fail; s->cluster_data = g_malloc(s->cluster_size); if (!s->cluster_data) goto fail; s->cluster_cache_offset = -1; /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; if (len > 1023) len = 1023; if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len) goto fail; bs->backing_file[len] = '\0'; } /* Disable migration when qcow images are used */ error_set(&s->migration_blocker, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, "qcow", bs->device_name, "live migration"); migrate_add_blocker(s->migration_blocker); qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->l1_table); g_free(s->l2_cache); g_free(s->cluster_cache); g_free(s->cluster_data); return -1; }