diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-02-05 16:29:01 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-02-05 16:29:01 +0000 |
commit | e5d3df6deb664a31e6c69b36e07f1701fee7cbf5 (patch) | |
tree | 841b8c96776663e62b563cb99c6574278ca90560 | |
parent | 2b2449f7e467957778ca006904471b231dc0ac8e (diff) | |
parent | 1b7650ef2f63d53cf89af25a9f323323cf2423a7 (diff) |
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
Block pull request
# gpg: Signature made Fri 31 Jan 2014 21:16:43 GMT using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35 775A 9CA4 ABB3 81AB 73C8
* remotes/stefanha/tags/block-pull-request:
qemu-iotests: only run 071 on qcow2
dataplane: Comment fix
block/vhdx: Error checking fixes
qemu-iotests: Drop assert_no_active_commit in case 040
block/vmdk: add basic .bdrv_check support
block: remove qcow2 .bdrv_make_empty implementation
block: remove QED .bdrv_make_empty implementation
Describe flaws in qcow/qcow2 encryption in the docs
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | block/qcow2.c | 21 | ||||
-rw-r--r-- | block/qed.c | 6 | ||||
-rw-r--r-- | block/vhdx-log.c | 4 | ||||
-rw-r--r-- | block/vhdx.c | 8 | ||||
-rw-r--r-- | block/vmdk.c | 48 | ||||
-rw-r--r-- | hw/block/dataplane/virtio-blk.c | 2 | ||||
-rw-r--r-- | qemu-doc.texi | 23 | ||||
-rw-r--r-- | qemu-img.texi | 23 | ||||
-rwxr-xr-x | tests/qemu-iotests/040 | 28 | ||||
-rwxr-xr-x | tests/qemu-iotests/071 | 2 |
10 files changed, 108 insertions, 57 deletions
diff --git a/block/qcow2.c b/block/qcow2.c index 2da62b8a90..99a1ad13e6 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1689,26 +1689,6 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, return ret; } -static int qcow2_make_empty(BlockDriverState *bs) -{ -#if 0 - /* XXX: not correct */ - BDRVQcowState *s = bs->opaque; - uint32_t l1_length = s->l1_size * sizeof(uint64_t); - int ret; - - memset(s->l1_table, 0, l1_length); - if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0) - return -1; - ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length); - if (ret < 0) - return ret; - - l2_cache_reset(bs); -#endif - return 0; -} - static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, BdrvRequestFlags flags) { @@ -2252,7 +2232,6 @@ static BlockDriver bdrv_qcow2 = { .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = qcow2_co_get_block_status, .bdrv_set_key = qcow2_set_key, - .bdrv_make_empty = qcow2_make_empty, .bdrv_co_readv = qcow2_co_readv, .bdrv_co_writev = qcow2_co_writev, diff --git a/block/qed.c b/block/qed.c index 694e6e2ee0..b9ca7ac0da 100644 --- a/block/qed.c +++ b/block/qed.c @@ -731,11 +731,6 @@ static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs, return cb.status; } -static int bdrv_qed_make_empty(BlockDriverState *bs) -{ - return -ENOTSUP; -} - static BDRVQEDState *acb_to_s(QEDAIOCB *acb) { return acb->common.bs->opaque; @@ -1617,7 +1612,6 @@ static BlockDriver bdrv_qed = { .bdrv_create = bdrv_qed_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = bdrv_qed_co_get_block_status, - .bdrv_make_empty = bdrv_qed_make_empty, .bdrv_aio_readv = bdrv_qed_aio_readv, .bdrv_aio_writev = bdrv_qed_aio_writev, .bdrv_co_write_zeroes = bdrv_qed_co_write_zeroes, diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 8c9ae0d8e7..02755b8ded 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -965,8 +965,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s, cpu_to_le32s((uint32_t *)(buffer + 4)); /* now write to the log */ - vhdx_log_write_sectors(bs, &s->log, §ors_written, buffer, - desc_sectors + sectors); + ret = vhdx_log_write_sectors(bs, &s->log, §ors_written, buffer, + desc_sectors + sectors); if (ret < 0) { goto exit; } diff --git a/block/vhdx.c b/block/vhdx.c index 9ee0a612ff..55689cf641 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -374,7 +374,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s, inactive_header->log_guid = *log_guid; } - vhdx_write_header(bs->file, inactive_header, header_offset, true); + ret = vhdx_write_header(bs->file, inactive_header, header_offset, true); if (ret < 0) { goto exit; } @@ -1810,13 +1810,13 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, creator = g_utf8_to_utf16("QEMU v" QEMU_VERSION, -1, NULL, &creator_items, NULL); signature = cpu_to_le64(VHDX_FILE_SIGNATURE); - bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature)); + ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature)); if (ret < 0) { goto delete_and_exit; } if (creator) { - bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature), creator, - creator_items * sizeof(gunichar2)); + ret = bdrv_pwrite(bs, VHDX_FILE_ID_OFFSET + sizeof(signature), + creator, creator_items * sizeof(gunichar2)); if (ret < 0) { goto delete_and_exit; } diff --git a/block/vmdk.c b/block/vmdk.c index 99ca60fdb9..e809e2ef46 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1942,6 +1942,53 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) return info; } +static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result, + BdrvCheckMode fix) +{ + BDRVVmdkState *s = bs->opaque; + VmdkExtent *extent = NULL; + int64_t sector_num = 0; + int64_t total_sectors = bdrv_getlength(bs) / BDRV_SECTOR_SIZE; + int ret; + uint64_t cluster_offset; + + if (fix) { + return -ENOTSUP; + } + + for (;;) { + if (sector_num >= total_sectors) { + return 0; + } + extent = find_extent(s, sector_num, extent); + if (!extent) { + fprintf(stderr, + "ERROR: could not find extent for sector %" PRId64 "\n", + sector_num); + break; + } + ret = get_cluster_offset(bs, extent, NULL, + sector_num << BDRV_SECTOR_BITS, + 0, &cluster_offset); + if (ret == VMDK_ERROR) { + fprintf(stderr, + "ERROR: could not get cluster_offset for sector %" + PRId64 "\n", sector_num); + break; + } + if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) { + fprintf(stderr, + "ERROR: cluster offset for sector %" + PRId64 " points after EOF\n", sector_num); + break; + } + sector_num += extent->cluster_sectors; + } + + result->corruptions++; + return 0; +} + static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) { int i; @@ -2015,6 +2062,7 @@ static BlockDriver bdrv_vmdk = { .instance_size = sizeof(BDRVVmdkState), .bdrv_probe = vmdk_probe, .bdrv_open = vmdk_open, + .bdrv_check = vmdk_check, .bdrv_reopen_prepare = vmdk_reopen_prepare, .bdrv_read = vmdk_co_read, .bdrv_write = vmdk_co_write, diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 456d437ac3..2237edb4eb 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -145,7 +145,7 @@ static void do_get_id_cmd(VirtIOBlockDataPlane *s, { char id[VIRTIO_BLK_ID_BYTES]; - /* Serial number not NUL-terminated when shorter than buffer */ + /* Serial number not NUL-terminated when longer than buffer */ strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id)); iov_from_buf(iov, iov_cnt, 0, id, sizeof(id)); complete_request_early(s, elem, inhdr, VIRTIO_BLK_S_OK); diff --git a/qemu-doc.texi b/qemu-doc.texi index ce61f30d6e..ad31f2d2d0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -547,10 +547,27 @@ File name of a base image (see @option{create} subcommand) @item backing_fmt Image format of the base image @item encryption -If this option is set to @code{on}, the image is encrypted. +If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC. + +The use of encryption in qcow and qcow2 images is considered to be flawed by +modern cryptography standards, suffering from a number of design problems: + +@itemize @minus +@item The AES-CBC cipher is used with predictable initialization vectors based +on the sector number. This makes it vulnerable to chosen plaintext attacks +which can reveal the existence of encrypted data. +@item The user passphrase is directly used as the encryption key. A poorly +chosen or short passphrase will compromise the security of the encryption. +@item In the event of the passphrase being compromised there is no way to +change the passphrase to protect data in any qcow images. The files must +be cloned, using a different encryption passphrase in the new file. The +original file must then be securely erased using a program like shred, +though even this is ineffective with many modern storage technologies. +@end itemize -Encryption uses the AES format which is very secure (128 bit keys). Use -a long password (16 characters) to get maximum protection. +Use of qcow / qcow2 encryption is thus strongly discouraged. Users are +recommended to use an alternative encryption technology such as the +Linux dm-crypt / LUKS system. @item cluster_size Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster diff --git a/qemu-img.texi b/qemu-img.texi index 526d56a458..f84590ebf0 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -409,10 +409,27 @@ File name of a base image (see @option{create} subcommand) @item backing_fmt Image format of the base image @item encryption -If this option is set to @code{on}, the image is encrypted. +If this option is set to @code{on}, the image is encrypted with 128-bit AES-CBC. -Encryption uses the AES format which is very secure (128 bit keys). Use -a long password (16 characters) to get maximum protection. +The use of encryption in qcow and qcow2 images is considered to be flawed by +modern cryptography standards, suffering from a number of design problems: + +@itemize @minus +@item The AES-CBC cipher is used with predictable initialization vectors based +on the sector number. This makes it vulnerable to chosen plaintext attacks +which can reveal the existence of encrypted data. +@item The user passphrase is directly used as the encryption key. A poorly +chosen or short passphrase will compromise the security of the encryption. +@item In the event of the passphrase being compromised there is no way to +change the passphrase to protect data in any qcow images. The files must +be cloned, using a different encryption passphrase in the new file. The +original file must then be securely erased using a program like shred, +though even this is ineffective with many modern storage technologies. +@end itemize + +Use of qcow / qcow2 encryption is thus strongly discouraged. Users are +recommended to use an alternative encryption technology such as the +Linux dm-crypt / LUKS system. @item cluster_size Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 72eaad5b08..734b6a6bb4 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -35,12 +35,8 @@ test_img = os.path.join(iotests.test_dir, 'test.img') class ImageCommitTestCase(iotests.QMPTestCase): '''Abstract base class for image commit test cases''' - def assert_no_active_commit(self): - result = self.vm.qmp('query-block-jobs') - self.assert_qmp(result, 'return', []) - def run_commit_test(self, top, base): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) self.assert_qmp(result, 'return', {}) @@ -59,7 +55,7 @@ class ImageCommitTestCase(iotests.QMPTestCase): self.assert_qmp(event, 'data/len', self.image_len) self.vm.qmp('block-job-complete', device='drive0') - self.assert_no_active_commit() + self.assert_no_active_block_jobs() self.vm.shutdown() class TestSingleDrive(ImageCommitTestCase): @@ -91,19 +87,19 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_qmp(result, 'error/class', 'DeviceNotFound') def test_top_same_base(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % backing_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % backing_img) def test_top_invalid(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % backing_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Top image file badfile not found') def test_base_invalid(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img, base='badfile') self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') @@ -114,13 +110,13 @@ class TestSingleDrive(ImageCommitTestCase): self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) def test_top_and_base_reversed(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img) def test_top_omitted(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0') self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing") @@ -181,19 +177,19 @@ class TestRelativePaths(ImageCommitTestCase): self.assert_qmp(result, 'error/class', 'DeviceNotFound') def test_top_same_base(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='%s' % self.mid_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img) def test_top_invalid(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % self.backing_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Top image file badfile not found') def test_base_invalid(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='badfile') self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') @@ -204,7 +200,7 @@ class TestRelativePaths(ImageCommitTestCase): self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) def test_top_and_base_reversed(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.backing_img, base='%s' % self.mid_img) self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % self.mid_img) @@ -229,7 +225,7 @@ class TestSetSpeed(ImageCommitTestCase): os.remove(backing_img) def test_set_speed(self): - self.assert_no_active_commit() + self.assert_no_active_block_jobs() self.vm.pause_drive('drive0') result = self.vm.qmp('block-commit', device='drive0', top=mid_img, speed=1024 * 1024) diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index 2a22546e1a..dbc07c6c4f 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter -_supported_fmt generic +_supported_fmt qcow2 _supported_proto generic _supported_os Linux |