2004-08-02 05:59:26 +08:00
|
|
|
/*
|
|
|
|
* Block driver for the QCOW format
|
2007-09-17 05:08:06 +08:00
|
|
|
*
|
2006-08-02 00:21:11 +08:00
|
|
|
* Copyright (c) 2004-2006 Fabrice Bellard
|
2007-09-17 05:08:06 +08:00
|
|
|
*
|
2004-08-02 05:59:26 +08:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2018-02-01 19:18:39 +08:00
|
|
|
|
2016-01-19 02:01:42 +08:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 16:01:28 +08:00
|
|
|
#include "qapi/error.h"
|
2016-03-21 22:11:48 +08:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-18 01:19:44 +08:00
|
|
|
#include "block/block_int.h"
|
2016-03-08 22:57:05 +08:00
|
|
|
#include "sysemu/block-backend.h"
|
2012-12-18 01:20:00 +08:00
|
|
|
#include "qemu/module.h"
|
2018-02-01 19:18:46 +08:00
|
|
|
#include "qemu/option.h"
|
2016-03-16 00:22:36 +08:00
|
|
|
#include "qemu/bswap.h"
|
2004-09-30 05:30:43 +08:00
|
|
|
#include <zlib.h>
|
2018-02-01 19:18:39 +08:00
|
|
|
#include "qapi/qmp/qdict.h"
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
#include "qapi/qmp/qstring.h"
|
2018-03-10 02:53:19 +08:00
|
|
|
#include "qapi/qobject-input-visitor.h"
|
|
|
|
#include "qapi/qapi-visit-block-core.h"
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
#include "crypto/block.h"
|
2017-04-06 18:00:28 +08:00
|
|
|
#include "migration/blocker.h"
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
#include "block/crypto.h"
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
/**************************************************************/
|
|
|
|
/* QEMU COW block driver with compression and encryption support */
|
|
|
|
|
|
|
|
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
|
|
|
|
#define QCOW_VERSION 1
|
|
|
|
|
|
|
|
#define QCOW_CRYPT_NONE 0
|
|
|
|
#define QCOW_CRYPT_AES 1
|
|
|
|
|
|
|
|
#define QCOW_OFLAG_COMPRESSED (1LL << 63)
|
|
|
|
|
|
|
|
typedef struct QCowHeader {
|
|
|
|
uint32_t magic;
|
|
|
|
uint32_t version;
|
|
|
|
uint64_t backing_file_offset;
|
|
|
|
uint32_t backing_file_size;
|
|
|
|
uint32_t mtime;
|
|
|
|
uint64_t size; /* in bytes */
|
|
|
|
uint8_t cluster_bits;
|
|
|
|
uint8_t l2_bits;
|
2014-05-07 22:56:10 +08:00
|
|
|
uint16_t padding;
|
2004-08-02 05:59:26 +08:00
|
|
|
uint32_t crypt_method;
|
|
|
|
uint64_t l1_table_offset;
|
2014-05-07 22:56:10 +08:00
|
|
|
} QEMU_PACKED QCowHeader;
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
#define L2_CACHE_SIZE 16
|
|
|
|
|
|
|
|
typedef struct BDRVQcowState {
|
|
|
|
int cluster_bits;
|
|
|
|
int cluster_size;
|
|
|
|
int cluster_sectors;
|
|
|
|
int l2_bits;
|
|
|
|
int l2_size;
|
2014-05-08 19:08:20 +08:00
|
|
|
unsigned int l1_size;
|
2004-08-02 05:59:26 +08:00
|
|
|
uint64_t cluster_offset_mask;
|
|
|
|
uint64_t l1_table_offset;
|
|
|
|
uint64_t *l1_table;
|
|
|
|
uint64_t *l2_cache;
|
|
|
|
uint64_t l2_cache_offsets[L2_CACHE_SIZE];
|
|
|
|
uint32_t l2_cache_counts[L2_CACHE_SIZE];
|
|
|
|
uint8_t *cluster_cache;
|
|
|
|
uint8_t *cluster_data;
|
|
|
|
uint64_t cluster_cache_offset;
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
QCryptoBlock *crypto; /* Disk encryption format driver */
|
2004-08-02 05:59:26 +08:00
|
|
|
uint32_t crypt_method_header;
|
2011-07-15 22:27:42 +08:00
|
|
|
CoMutex lock;
|
2011-11-22 23:44:45 +08:00
|
|
|
Error *migration_blocker;
|
2004-08-02 05:59:26 +08:00
|
|
|
} BDRVQcowState;
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
static QemuOptsList qcow_create_opts;
|
|
|
|
|
2010-04-14 20:17:38 +08:00
|
|
|
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
|
|
|
|
{
|
|
|
|
const QCowHeader *cow_header = (const void *)buf;
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2005-04-29 05:09:32 +08:00
|
|
|
if (buf_size >= sizeof(QCowHeader) &&
|
|
|
|
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
2007-09-17 05:08:06 +08:00
|
|
|
be32_to_cpu(cow_header->version) == QCOW_VERSION)
|
2004-08-02 05:59:26 +08:00
|
|
|
return 100;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
static QemuOptsList qcow_runtime_opts = {
|
|
|
|
.name = "qcow",
|
|
|
|
.head = QTAILQ_HEAD_INITIALIZER(qcow_runtime_opts.head),
|
|
|
|
.desc = {
|
|
|
|
BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
|
|
|
|
{ /* end of list */ }
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2013-09-05 20:22:29 +08:00
|
|
|
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
|
Error **errp)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2014-05-08 19:35:09 +08:00
|
|
|
unsigned int len, i, shift;
|
|
|
|
int ret;
|
2004-08-02 05:59:26 +08:00
|
|
|
QCowHeader header;
|
2017-01-16 19:31:53 +08:00
|
|
|
Error *local_err = NULL;
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
QCryptoBlockOpenOptions *crypto_opts = NULL;
|
|
|
|
unsigned int cflags = 0;
|
|
|
|
QDict *encryptopts = NULL;
|
|
|
|
const char *encryptfmt;
|
|
|
|
|
|
|
|
qdict_extract_subqdict(options, &encryptopts, "encrypt.");
|
|
|
|
encryptfmt = qdict_get_try_str(encryptopts, "format");
|
2006-08-02 00:21:11 +08:00
|
|
|
|
2016-12-17 01:52:37 +08:00
|
|
|
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
|
|
|
|
false, errp);
|
|
|
|
if (!bs->file) {
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2016-12-17 01:52:37 +08:00
|
|
|
}
|
|
|
|
|
2016-06-21 00:24:02 +08:00
|
|
|
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
2011-12-15 18:14:00 +08:00
|
|
|
if (ret < 0) {
|
2004-08-02 05:59:26 +08:00
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
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);
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2011-12-15 18:14:00 +08:00
|
|
|
if (header.magic != QCOW_MAGIC) {
|
2014-02-17 21:44:06 +08:00
|
|
|
error_setg(errp, "Image not in qcow format");
|
|
|
|
ret = -EINVAL;
|
2011-12-15 18:14:00 +08:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
if (header.version != QCOW_VERSION) {
|
2016-03-17 02:54:33 +08:00
|
|
|
error_setg(errp, "Unsupported qcow version %" PRIu32, header.version);
|
2011-12-15 18:14:00 +08:00
|
|
|
ret = -ENOTSUP;
|
2004-08-02 05:59:26 +08:00
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
|
|
|
|
2014-05-07 23:30:30 +08:00
|
|
|
if (header.size <= 1) {
|
|
|
|
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
2011-12-15 18:14:00 +08:00
|
|
|
ret = -EINVAL;
|
2004-08-02 05:59:26 +08:00
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
2014-05-07 23:30:30 +08:00
|
|
|
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
|
|
|
|
error_setg(errp, "Cluster size must be between 512 and 64k");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2014-05-15 22:10:11 +08:00
|
|
|
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
|
|
|
|
* so bytes = num_entries << 3. */
|
|
|
|
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
|
|
|
|
error_setg(errp, "L2 table size must be between 512 and 64k");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
s->crypt_method_header = header.crypt_method;
|
2011-12-15 18:14:00 +08:00
|
|
|
if (s->crypt_method_header) {
|
2016-03-21 22:11:48 +08:00
|
|
|
if (bdrv_uses_whitelist() &&
|
|
|
|
s->crypt_method_header == QCOW_CRYPT_AES) {
|
block: drop support for using qcow[2] encryption with system emulators
Back in the 2.3.0 release we declared qcow[2] encryption as
deprecated, warning people that it would be removed in a future
release.
commit a1f688f4152e65260b94f37543521ceff8bfebe4
Author: Markus Armbruster <armbru@redhat.com>
Date: Fri Mar 13 21:09:40 2015 +0100
block: Deprecate QCOW/QCOW2 encryption
The code still exists today, but by a (happy?) accident we entirely
broke the ability to use qcow[2] encryption in the system emulators
in the 2.4.0 release due to
commit 8336aafae1451d54c81dd2b187b45f7c45d2428e
Author: Daniel P. Berrange <berrange@redhat.com>
Date: Tue May 12 17:09:18 2015 +0100
qcow2/qcow: protect against uninitialized encryption key
This commit was designed to prevent future coding bugs which
might cause QEMU to read/write data on an encrypted block
device in plain text mode before a decryption key is set.
It turns out this preventative measure was a little too good,
because we already had a long standing bug where QEMU read
encrypted data in plain text mode during system emulator
startup, in order to guess disk geometry:
Thread 10 (Thread 0x7fffd3fff700 (LWP 30373)):
#0 0x00007fffe90b1a28 in raise () at /lib64/libc.so.6
#1 0x00007fffe90b362a in abort () at /lib64/libc.so.6
#2 0x00007fffe90aa227 in __assert_fail_base () at /lib64/libc.so.6
#3 0x00007fffe90aa2d2 in () at /lib64/libc.so.6
#4 0x000055555587ae19 in qcow2_co_readv (bs=0x5555562accb0, sector_num=0, remaining_sectors=1, qiov=0x7fffffffd260) at block/qcow2.c:1229
#5 0x000055555589b60d in bdrv_aligned_preadv (bs=bs@entry=0x5555562accb0, req=req@entry=0x7fffd3ffea50, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=512, qiov=qiov@entry=0x7fffffffd260, flags=0) at block/io.c:908
#6 0x000055555589b8bc in bdrv_co_do_preadv (bs=0x5555562accb0, offset=0, bytes=512, qiov=0x7fffffffd260, flags=<optimized out>) at block/io.c:999
#7 0x000055555589c375 in bdrv_rw_co_entry (opaque=0x7fffffffd210) at block/io.c:544
#8 0x000055555586933b in coroutine_thread (opaque=0x555557876310) at coroutine-gthread.c:134
#9 0x00007ffff64e1835 in g_thread_proxy (data=0x5555562b5590) at gthread.c:778
#10 0x00007ffff6bb760a in start_thread () at /lib64/libpthread.so.0
#11 0x00007fffe917f59d in clone () at /lib64/libc.so.6
Thread 1 (Thread 0x7ffff7ecab40 (LWP 30343)):
#0 0x00007fffe91797a9 in syscall () at /lib64/libc.so.6
#1 0x00007ffff64ff87f in g_cond_wait (cond=cond@entry=0x555555e085f0 <coroutine_cond>, mutex=mutex@entry=0x555555e08600 <coroutine_lock>) at gthread-posix.c:1397
#2 0x00005555558692c3 in qemu_coroutine_switch (co=<optimized out>) at coroutine-gthread.c:117
#3 0x00005555558692c3 in qemu_coroutine_switch (from_=0x5555562b5e30, to_=to_@entry=0x555557876310, action=action@entry=COROUTINE_ENTER) at coroutine-gthread.c:175
#4 0x0000555555868a90 in qemu_coroutine_enter (co=0x555557876310, opaque=0x0) at qemu-coroutine.c:116
#5 0x0000555555859b84 in thread_pool_completion_bh (opaque=0x7fffd40010e0) at thread-pool.c:187
#6 0x0000555555859514 in aio_bh_poll (ctx=ctx@entry=0x5555562953b0) at async.c:85
#7 0x0000555555864d10 in aio_dispatch (ctx=ctx@entry=0x5555562953b0) at aio-posix.c:135
#8 0x0000555555864f75 in aio_poll (ctx=ctx@entry=0x5555562953b0, blocking=blocking@entry=true) at aio-posix.c:291
#9 0x000055555589c40d in bdrv_prwv_co (bs=bs@entry=0x5555562accb0, offset=offset@entry=0, qiov=qiov@entry=0x7fffffffd260, is_write=is_write@entry=false, flags=flags@entry=(unknown: 0)) at block/io.c:591
#10 0x000055555589c503 in bdrv_rw_co (bs=bs@entry=0x5555562accb0, sector_num=sector_num@entry=0, buf=buf@entry=0x7fffffffd2e0 "\321,", nb_sectors=nb_sectors@entry=21845, is_write=is_write@entry=false, flags=flags@entry=(unknown: 0)) at block/io.c:614
#11 0x000055555589c562 in bdrv_read_unthrottled (nb_sectors=21845, buf=0x7fffffffd2e0 "\321,", sector_num=0, bs=0x5555562accb0) at block/io.c:622
#12 0x000055555589c562 in bdrv_read_unthrottled (bs=0x5555562accb0, sector_num=sector_num@entry=0, buf=buf@entry=0x7fffffffd2e0 "\321,", nb_sectors=nb_sectors@entry=21845) at block/io.c:634
nb_sectors@entry=1) at block/block-backend.c:504
#14 0x0000555555752e9f in guess_disk_lchs (blk=blk@entry=0x5555562a5290, pcylinders=pcylinders@entry=0x7fffffffd52c, pheads=pheads@entry=0x7fffffffd530, psectors=psectors@entry=0x7fffffffd534) at hw/block/hd-geometry.c:68
#15 0x0000555555752ff7 in hd_geometry_guess (blk=0x5555562a5290, pcyls=pcyls@entry=0x555557875d1c, pheads=pheads@entry=0x555557875d20, psecs=psecs@entry=0x555557875d24, ptrans=ptrans@entry=0x555557875d28) at hw/block/hd-geometry.c:133
#16 0x0000555555752b87 in blkconf_geometry (conf=conf@entry=0x555557875d00, ptrans=ptrans@entry=0x555557875d28, cyls_max=cyls_max@entry=65536, heads_max=heads_max@entry=16, secs_max=secs_max@entry=255, errp=errp@entry=0x7fffffffd5e0) at hw/block/block.c:71
#17 0x0000555555799bc4 in ide_dev_initfn (dev=0x555557875c80, kind=IDE_HD) at hw/ide/qdev.c:174
#18 0x0000555555768394 in device_realize (dev=0x555557875c80, errp=0x7fffffffd640) at hw/core/qdev.c:247
#19 0x0000555555769a81 in device_set_realized (obj=0x555557875c80, value=<optimized out>, errp=0x7fffffffd730) at hw/core/qdev.c:1058
#20 0x00005555558240ce in property_set_bool (obj=0x555557875c80, v=<optimized out>, opaque=0x555557875de0, name=<optimized out>, errp=0x7fffffffd730)
at qom/object.c:1514
#21 0x0000555555826c87 in object_property_set_qobject (obj=obj@entry=0x555557875c80, value=value@entry=0x55555784bcb0, name=name@entry=0x55555591cb3d "realized", errp=errp@entry=0x7fffffffd730) at qom/qom-qobject.c:24
#22 0x0000555555825760 in object_property_set_bool (obj=obj@entry=0x555557875c80, value=value@entry=true, name=name@entry=0x55555591cb3d "realized", errp=errp@entry=0x7fffffffd730) at qom/object.c:905
#23 0x000055555576897b in qdev_init_nofail (dev=dev@entry=0x555557875c80) at hw/core/qdev.c:380
#24 0x0000555555799ead in ide_create_drive (bus=bus@entry=0x555557629630, unit=unit@entry=0, drive=0x5555562b77e0) at hw/ide/qdev.c:122
#25 0x000055555579a746 in pci_ide_create_devs (dev=dev@entry=0x555557628db0, hd_table=hd_table@entry=0x7fffffffd830) at hw/ide/pci.c:440
#26 0x000055555579b165 in pci_piix3_ide_init (bus=<optimized out>, hd_table=0x7fffffffd830, devfn=<optimized out>) at hw/ide/piix.c:218
#27 0x000055555568ca55 in pc_init1 (machine=0x5555562960a0, pci_enabled=1, kvmclock_enabled=<optimized out>) at /home/berrange/src/virt/qemu/hw/i386/pc_piix.c:256
#28 0x0000555555603ab2 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4249
So the safety net is correctly preventing QEMU reading cipher
text as if it were plain text, during startup and aborting QEMU
to avoid bad usage of this data.
For added fun this bug only happens if the encrypted qcow2
file happens to have data written to the first cluster,
otherwise the cluster won't be allocated and so qcow2 would
not try the decryption routines at all, just return all 0's.
That no one even noticed, let alone reported, this bug that
has shipped in 2.4.0, 2.5.0 and 2.6.0 shows that the number
of actual users of encrypted qcow2 is approximately zero.
So rather than fix the crash, and backport it to stable
releases, just go ahead with what we have warned users about
and disable any use of qcow2 encryption in the system
emulators. qemu-img/qemu-io/qemu-nbd are still able to access
qcow2 encrypted images for the sake of data conversion.
In the future, qcow2 will gain support for the alternative
luks format, but when this happens it'll be using the
'-object secret' infrastructure for getting keys, which
avoids this problematic scenario entirely.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2016-06-13 19:30:09 +08:00
|
|
|
error_setg(errp,
|
|
|
|
"Use of AES-CBC encrypted qcow images is no longer "
|
|
|
|
"supported in system emulators");
|
|
|
|
error_append_hint(errp,
|
|
|
|
"You can use 'qemu-img convert' to convert your "
|
|
|
|
"image to an alternative supported format, such "
|
|
|
|
"as unencrypted qcow, or raw with the LUKS "
|
|
|
|
"format instead.\n");
|
|
|
|
ret = -ENOSYS;
|
|
|
|
goto fail;
|
2016-03-21 22:11:48 +08:00
|
|
|
}
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
if (s->crypt_method_header == QCOW_CRYPT_AES) {
|
|
|
|
if (encryptfmt && !g_str_equal(encryptfmt, "aes")) {
|
|
|
|
error_setg(errp,
|
|
|
|
"Header reported 'aes' encryption format but "
|
|
|
|
"options specify '%s'", encryptfmt);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
qdict_del(encryptopts, "format");
|
|
|
|
crypto_opts = block_crypto_open_opts_init(
|
|
|
|
Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
|
|
|
|
if (!crypto_opts) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-03-21 22:11:48 +08:00
|
|
|
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
if (flags & BDRV_O_NO_IO) {
|
|
|
|
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
|
|
|
}
|
2017-06-24 00:24:17 +08:00
|
|
|
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
|
|
|
|
NULL, NULL, cflags, errp);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
if (!s->crypto) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error_setg(errp, "invalid encryption method in qcow header");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-06-24 06:37:26 +08:00
|
|
|
bs->encrypted = true;
|
2017-06-24 00:24:16 +08:00
|
|
|
} else {
|
|
|
|
if (encryptfmt) {
|
|
|
|
error_setg(errp, "No encryption in image header, but options "
|
|
|
|
"specified format '%s'", encryptfmt);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
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;
|
2014-05-08 19:08:20 +08:00
|
|
|
if (header.size > UINT64_MAX - (1LL << shift)) {
|
|
|
|
error_setg(errp, "Image too large");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
} else {
|
|
|
|
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
|
|
|
if (l1_size > INT_MAX / sizeof(uint64_t)) {
|
|
|
|
error_setg(errp, "Image too large");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
s->l1_size = l1_size;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
s->l1_table_offset = header.l1_table_offset;
|
block: Use g_new() & friends where that makes obvious sense
g_new(T, n) is neater than g_malloc(sizeof(T) * n). It's also safer,
for two reasons. One, it catches multiplication overflowing size_t.
Two, it returns T * rather than void *, which lets the compiler catch
more type errors.
Patch created with Coccinelle, with two manual changes on top:
* Add const to bdrv_iterate_format() to keep the types straight
* Convert the allocation in bdrv_drop_intermediate(), which Coccinelle
inexplicably misses
Coccinelle semantic patch:
@@
type T;
@@
-g_malloc(sizeof(T))
+g_new(T, 1)
@@
type T;
@@
-g_try_malloc(sizeof(T))
+g_try_new(T, 1)
@@
type T;
@@
-g_malloc0(sizeof(T))
+g_new0(T, 1)
@@
type T;
@@
-g_try_malloc0(sizeof(T))
+g_try_new0(T, 1)
@@
type T;
expression n;
@@
-g_malloc(sizeof(T) * (n))
+g_new(T, n)
@@
type T;
expression n;
@@
-g_try_malloc(sizeof(T) * (n))
+g_try_new(T, n)
@@
type T;
expression n;
@@
-g_malloc0(sizeof(T) * (n))
+g_new0(T, n)
@@
type T;
expression n;
@@
-g_try_malloc0(sizeof(T) * (n))
+g_try_new0(T, n)
@@
type T;
expression p, n;
@@
-g_realloc(p, sizeof(T) * (n))
+g_renew(T, p, n)
@@
type T;
expression p, n;
@@
-g_try_realloc(p, sizeof(T) * (n))
+g_try_renew(T, p, n)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-08-19 16:31:08 +08:00
|
|
|
s->l1_table = g_try_new(uint64_t, s->l1_size);
|
2014-05-20 19:36:05 +08:00
|
|
|
if (s->l1_table == NULL) {
|
|
|
|
error_setg(errp, "Could not allocate memory for L1 table");
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-12-15 18:14:00 +08:00
|
|
|
|
2016-06-21 00:24:02 +08:00
|
|
|
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
2011-12-15 18:14:00 +08:00
|
|
|
s->l1_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
2004-08-02 05:59:26 +08:00
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
for(i = 0;i < s->l1_size; i++) {
|
|
|
|
be64_to_cpus(&s->l1_table[i]);
|
|
|
|
}
|
2014-05-20 19:36:05 +08:00
|
|
|
|
|
|
|
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
|
|
|
|
s->l2_cache =
|
2015-06-16 20:19:22 +08:00
|
|
|
qemu_try_blockalign(bs->file->bs,
|
2014-05-20 19:36:05 +08:00
|
|
|
s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
|
|
|
|
if (s->l2_cache == NULL) {
|
|
|
|
error_setg(errp, "Could not allocate L2 table cache");
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-08-21 11:09:37 +08:00
|
|
|
s->cluster_cache = g_malloc(s->cluster_size);
|
|
|
|
s->cluster_data = g_malloc(s->cluster_size);
|
2004-08-02 05:59:26 +08:00
|
|
|
s->cluster_cache_offset = -1;
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
/* read the backing file name */
|
|
|
|
if (header.backing_file_offset != 0) {
|
|
|
|
len = header.backing_file_size;
|
2015-01-27 21:33:55 +08:00
|
|
|
if (len > 1023 || len >= sizeof(bs->backing_file)) {
|
2014-05-08 19:35:09 +08:00
|
|
|
error_setg(errp, "Backing file name too long");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
2016-06-21 00:24:02 +08:00
|
|
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
2011-12-15 18:14:00 +08:00
|
|
|
bs->backing_file, len);
|
|
|
|
if (ret < 0) {
|
2004-08-02 05:59:26 +08:00
|
|
|
goto fail;
|
2011-12-15 18:14:00 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
bs->backing_file[len] = '\0';
|
|
|
|
}
|
2011-08-12 05:27:15 +08:00
|
|
|
|
2011-11-22 23:44:45 +08:00
|
|
|
/* Disable migration when qcow images are used */
|
2015-04-08 17:29:19 +08:00
|
|
|
error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
|
|
|
|
"does not support live migration",
|
|
|
|
bdrv_get_device_or_node_name(bs));
|
2017-01-16 19:31:53 +08:00
|
|
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
error_free(s->migration_blocker);
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-11-22 23:44:45 +08:00
|
|
|
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
QDECREF(encryptopts);
|
|
|
|
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
|
2011-08-12 05:27:15 +08:00
|
|
|
qemu_co_mutex_init(&s->lock);
|
2004-08-02 05:59:26 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
2011-08-21 11:09:37 +08:00
|
|
|
g_free(s->l1_table);
|
2014-05-20 19:36:05 +08:00
|
|
|
qemu_vfree(s->l2_cache);
|
2011-08-21 11:09:37 +08:00
|
|
|
g_free(s->cluster_cache);
|
|
|
|
g_free(s->cluster_data);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
qcrypto_block_free(s->crypto);
|
|
|
|
QDECREF(encryptopts);
|
|
|
|
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
|
2011-12-15 18:14:00 +08:00
|
|
|
return ret;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-21 03:13:29 +08:00
|
|
|
|
|
|
|
/* We have nothing to do for QCOW reopen, stubs just return
|
|
|
|
* success */
|
|
|
|
static int qcow_reopen_prepare(BDRVReopenState *state,
|
|
|
|
BlockReopenQueue *queue, Error **errp)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
/* 'allocate' is:
|
|
|
|
*
|
|
|
|
* 0 to not allocate.
|
|
|
|
*
|
|
|
|
* 1 to allocate a normal cluster (for sector indexes 'n_start' to
|
|
|
|
* 'n_end')
|
|
|
|
*
|
|
|
|
* 2 to allocate a compressed cluster of size
|
|
|
|
* 'compressed_size'. 'compressed_size' must be > 0 and <
|
2007-09-17 05:08:06 +08:00
|
|
|
* cluster_size
|
2004-08-02 05:59:26 +08:00
|
|
|
*
|
2017-08-10 04:38:05 +08:00
|
|
|
* return 0 if not allocated, 1 if *result is assigned, and negative
|
|
|
|
* errno on failure.
|
2004-08-02 05:59:26 +08:00
|
|
|
*/
|
2017-08-10 04:38:05 +08:00
|
|
|
static int get_cluster_offset(BlockDriverState *bs,
|
|
|
|
uint64_t offset, int allocate,
|
|
|
|
int compressed_size,
|
|
|
|
int n_start, int n_end, uint64_t *result)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2017-08-10 04:38:05 +08:00
|
|
|
int min_index, i, j, l1_index, l2_index, ret;
|
2017-08-10 04:38:06 +08:00
|
|
|
int64_t l2_offset;
|
|
|
|
uint64_t *l2_table, cluster_offset, tmp;
|
2004-08-02 05:59:26 +08:00
|
|
|
uint32_t min_count;
|
|
|
|
int new_l2_table;
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2017-08-10 04:38:05 +08:00
|
|
|
*result = 0;
|
2004-08-02 05:59:26 +08:00
|
|
|
l1_index = offset >> (s->l2_bits + s->cluster_bits);
|
|
|
|
l2_offset = s->l1_table[l1_index];
|
|
|
|
new_l2_table = 0;
|
|
|
|
if (!l2_offset) {
|
|
|
|
if (!allocate)
|
|
|
|
return 0;
|
|
|
|
/* allocate a new l2 entry */
|
2015-06-16 20:19:22 +08:00
|
|
|
l2_offset = bdrv_getlength(bs->file->bs);
|
2017-08-10 04:38:06 +08:00
|
|
|
if (l2_offset < 0) {
|
|
|
|
return l2_offset;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
/* round to cluster size */
|
2017-08-10 04:38:06 +08:00
|
|
|
l2_offset = QEMU_ALIGN_UP(l2_offset, s->cluster_size);
|
2004-08-02 05:59:26 +08:00
|
|
|
/* update the L1 entry */
|
|
|
|
s->l1_table[l1_index] = l2_offset;
|
|
|
|
tmp = cpu_to_be64(l2_offset);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pwrite_sync(bs->file,
|
|
|
|
s->l1_table_offset + l1_index * sizeof(tmp),
|
|
|
|
&tmp, sizeof(tmp));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
new_l2_table = 1;
|
|
|
|
}
|
|
|
|
for(i = 0; i < L2_CACHE_SIZE; i++) {
|
|
|
|
if (l2_offset == s->l2_cache_offsets[i]) {
|
|
|
|
/* increment the hit count */
|
|
|
|
if (++s->l2_cache_counts[i] == 0xffffffff) {
|
|
|
|
for(j = 0; j < L2_CACHE_SIZE; j++) {
|
|
|
|
s->l2_cache_counts[j] >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l2_table = s->l2_cache + (i << s->l2_bits);
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* not found: load a new entry in the least used one */
|
|
|
|
min_index = 0;
|
|
|
|
min_count = 0xffffffff;
|
|
|
|
for(i = 0; i < L2_CACHE_SIZE; i++) {
|
|
|
|
if (s->l2_cache_counts[i] < min_count) {
|
|
|
|
min_count = s->l2_cache_counts[i];
|
|
|
|
min_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
2004-08-02 05:59:26 +08:00
|
|
|
if (new_l2_table) {
|
|
|
|
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
|
|
|
s->l2_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
} else {
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pread(bs->file, l2_offset, l2_table,
|
|
|
|
s->l2_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
s->l2_cache_offsets[min_index] = l2_offset;
|
|
|
|
s->l2_cache_counts[min_index] = 1;
|
|
|
|
found:
|
|
|
|
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
|
|
|
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
2007-09-17 05:08:06 +08:00
|
|
|
if (!cluster_offset ||
|
2004-08-02 05:59:26 +08:00
|
|
|
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
|
|
|
|
if (!allocate)
|
|
|
|
return 0;
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
2004-08-02 05:59:26 +08:00
|
|
|
/* allocate a new cluster */
|
|
|
|
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
|
|
|
|
(n_end - n_start) < s->cluster_sectors) {
|
|
|
|
/* if the cluster is already compressed, we must
|
|
|
|
decompress it in the case it is not completely
|
|
|
|
overwritten */
|
2017-08-10 04:38:05 +08:00
|
|
|
if (decompress_cluster(bs, cluster_offset) < 0) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
2015-06-16 20:19:22 +08:00
|
|
|
cluster_offset = bdrv_getlength(bs->file->bs);
|
2017-08-10 04:38:06 +08:00
|
|
|
if ((int64_t) cluster_offset < 0) {
|
|
|
|
return cluster_offset;
|
|
|
|
}
|
|
|
|
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
|
2004-08-02 05:59:26 +08:00
|
|
|
/* write the cluster content */
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
|
|
|
|
s->cluster_size);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
} else {
|
2015-06-16 20:19:22 +08:00
|
|
|
cluster_offset = bdrv_getlength(bs->file->bs);
|
2017-08-10 04:38:06 +08:00
|
|
|
if ((int64_t) cluster_offset < 0) {
|
|
|
|
return cluster_offset;
|
|
|
|
}
|
2009-01-09 03:29:03 +08:00
|
|
|
if (allocate == 1) {
|
|
|
|
/* round to cluster size */
|
2017-08-10 04:38:06 +08:00
|
|
|
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
|
|
|
|
if (cluster_offset + s->cluster_size > INT64_MAX) {
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
|
|
|
|
PREALLOC_MODE_OFF, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-09 03:29:03 +08:00
|
|
|
/* if encrypted, we must initialize the cluster
|
|
|
|
content which won't be written */
|
qcow2/qcow: protect against uninitialized encryption key
When a qcow[2] file is opened, if the header reports an
encryption method, this is used to set the 'crypt_method_header'
field on the BDRVQcow[2]State struct, and the 'encrypted' flag
in the BDRVState struct.
When doing I/O operations, the 'crypt_method' field on the
BDRVQcow[2]State struct is checked to determine if encryption
needs to be applied.
The crypt_method_header value is copied into crypt_method when
the bdrv_set_key() method is called.
The QEMU code which opens a block device is expected to always
do a check
if (bdrv_is_encrypted(bs)) {
bdrv_set_key(bs, ....key...);
}
If code forgets to do this, then 'crypt_method' is never set
and so when I/O is performed, QEMU writes plain text data
into a sector which is expected to contain cipher text, or
when reading, will return cipher text instead of plain
text.
Change the qcow[2] code to consult bs->encrypted when deciding
whether encryption is required, and assert(s->crypt_method)
to protect against cases where the caller forgets to set the
encryption key.
Also put an assert in the set_key methods to protect against
the case where the caller sets an encryption key on a block
device that does not have encryption
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2015-05-13 00:09:18 +08:00
|
|
|
if (bs->encrypted &&
|
2009-01-09 03:29:03 +08:00
|
|
|
(n_end - n_start) < s->cluster_sectors) {
|
|
|
|
uint64_t start_sect;
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
assert(s->crypto);
|
2009-01-09 03:29:03 +08:00
|
|
|
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
|
|
|
|
for(i = 0; i < s->cluster_sectors; i++) {
|
|
|
|
if (i < n_start || i >= n_end) {
|
2017-06-24 00:24:07 +08:00
|
|
|
memset(s->cluster_data, 0x00, 512);
|
2017-09-27 20:53:39 +08:00
|
|
|
if (qcrypto_block_encrypt(s->crypto,
|
|
|
|
(start_sect + i) *
|
|
|
|
BDRV_SECTOR_SIZE,
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
s->cluster_data,
|
|
|
|
BDRV_SECTOR_SIZE,
|
2017-08-29 20:08:36 +08:00
|
|
|
NULL) < 0) {
|
2017-08-10 04:38:05 +08:00
|
|
|
return -EIO;
|
|
|
|
}
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pwrite(bs->file,
|
|
|
|
cluster_offset + i * 512,
|
|
|
|
s->cluster_data, 512);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2015-07-02 01:10:37 +08:00
|
|
|
}
|
2009-01-09 03:29:03 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
}
|
2009-01-09 03:29:03 +08:00
|
|
|
} else if (allocate == 2) {
|
|
|
|
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
|
|
|
(uint64_t)compressed_size << (63 - s->cluster_bits);
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* update L2 table */
|
|
|
|
tmp = cpu_to_be64(cluster_offset);
|
|
|
|
l2_table[l2_index] = tmp;
|
2017-11-23 10:08:18 +08:00
|
|
|
if (allocate == 2) {
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
|
|
|
|
} else {
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
|
|
|
}
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
|
|
|
&tmp, sizeof(tmp));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
2017-08-10 04:38:05 +08:00
|
|
|
*result = cluster_offset;
|
|
|
|
return 1;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
2018-02-14 04:26:51 +08:00
|
|
|
static int coroutine_fn qcow_co_block_status(BlockDriverState *bs,
|
|
|
|
bool want_zero,
|
|
|
|
int64_t offset, int64_t bytes,
|
|
|
|
int64_t *pnum, int64_t *map,
|
|
|
|
BlockDriverState **file)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2018-02-14 04:26:51 +08:00
|
|
|
int index_in_cluster, ret;
|
|
|
|
int64_t n;
|
2004-08-02 05:59:26 +08:00
|
|
|
uint64_t cluster_offset;
|
|
|
|
|
2011-11-14 20:44:21 +08:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2018-02-14 04:26:51 +08:00
|
|
|
ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
|
2011-11-14 20:44:21 +08:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-08-10 04:38:05 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-14 04:26:51 +08:00
|
|
|
index_in_cluster = offset & (s->cluster_size - 1);
|
|
|
|
n = s->cluster_size - index_in_cluster;
|
|
|
|
if (n > bytes) {
|
|
|
|
n = bytes;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
*pnum = n;
|
2013-09-05 01:00:30 +08:00
|
|
|
if (!cluster_offset) {
|
|
|
|
return 0;
|
|
|
|
}
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
|
2013-09-05 01:00:30 +08:00
|
|
|
return BDRV_BLOCK_DATA;
|
|
|
|
}
|
2018-02-14 04:26:51 +08:00
|
|
|
*map = cluster_offset | index_in_cluster;
|
2016-01-26 11:58:49 +08:00
|
|
|
*file = bs->file->bs;
|
2018-02-14 04:26:51 +08:00
|
|
|
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
|
|
|
const uint8_t *buf, int buf_size)
|
|
|
|
{
|
|
|
|
z_stream strm1, *strm = &strm1;
|
|
|
|
int ret, out_len;
|
|
|
|
|
|
|
|
memset(strm, 0, sizeof(*strm));
|
|
|
|
|
|
|
|
strm->next_in = (uint8_t *)buf;
|
|
|
|
strm->avail_in = buf_size;
|
|
|
|
strm->next_out = out_buf;
|
|
|
|
strm->avail_out = out_buf_size;
|
|
|
|
|
|
|
|
ret = inflateInit2(strm, -12);
|
|
|
|
if (ret != Z_OK)
|
|
|
|
return -1;
|
|
|
|
ret = inflate(strm, Z_FINISH);
|
|
|
|
out_len = strm->next_out - out_buf;
|
|
|
|
if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
|
|
|
|
out_len != out_buf_size) {
|
|
|
|
inflateEnd(strm);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
inflateEnd(strm);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2010-04-14 20:17:38 +08:00
|
|
|
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
2010-04-14 20:17:38 +08:00
|
|
|
BDRVQcowState *s = bs->opaque;
|
2004-08-02 05:59:26 +08:00
|
|
|
int ret, csize;
|
|
|
|
uint64_t coffset;
|
|
|
|
|
|
|
|
coffset = cluster_offset & s->cluster_offset_mask;
|
|
|
|
if (s->cluster_cache_offset != coffset) {
|
|
|
|
csize = cluster_offset >> (63 - s->cluster_bits);
|
|
|
|
csize &= (s->cluster_size - 1);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
2016-06-21 00:24:02 +08:00
|
|
|
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
|
2007-09-17 05:08:06 +08:00
|
|
|
if (ret != csize)
|
2004-08-02 05:59:26 +08:00
|
|
|
return -1;
|
|
|
|
if (decompress_buffer(s->cluster_cache, s->cluster_size,
|
|
|
|
s->cluster_data, csize) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s->cluster_cache_offset = coffset;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-10 16:23:22 +08:00
|
|
|
static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
2011-08-23 21:21:11 +08:00
|
|
|
int nb_sectors, QEMUIOVector *qiov)
|
2006-08-02 00:21:11 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
int index_in_cluster;
|
2011-08-23 21:21:11 +08:00
|
|
|
int ret = 0, n;
|
2011-08-23 21:21:10 +08:00
|
|
|
uint64_t cluster_offset;
|
2011-08-23 21:21:09 +08:00
|
|
|
struct iovec hd_iov;
|
|
|
|
QEMUIOVector hd_qiov;
|
2011-08-23 21:21:11 +08:00
|
|
|
uint8_t *buf;
|
|
|
|
void *orig_buf;
|
2006-08-02 00:21:11 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
if (qiov->niov > 1) {
|
2014-05-20 19:36:05 +08:00
|
|
|
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
|
|
|
if (buf == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2011-08-23 21:21:11 +08:00
|
|
|
} else {
|
|
|
|
orig_buf = NULL;
|
|
|
|
buf = (uint8_t *)qiov->iov->iov_base;
|
2006-08-02 00:21:11 +08:00
|
|
|
}
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
|
|
|
|
while (nb_sectors != 0) {
|
|
|
|
/* prepare next request */
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = get_cluster_offset(bs, sector_num << 9,
|
|
|
|
0, 0, 0, 0, &cluster_offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2011-08-23 21:21:11 +08:00
|
|
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
|
|
|
n = s->cluster_sectors - index_in_cluster;
|
|
|
|
if (n > nb_sectors) {
|
|
|
|
n = nb_sectors;
|
|
|
|
}
|
2006-08-07 10:38:06 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
if (!cluster_offset) {
|
2015-06-17 20:55:21 +08:00
|
|
|
if (bs->backing) {
|
2011-08-23 21:21:11 +08:00
|
|
|
/* read from the base image */
|
|
|
|
hd_iov.iov_base = (void *)buf;
|
|
|
|
hd_iov.iov_len = n * 512;
|
|
|
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 10:08:18 +08:00
|
|
|
/* qcow2 emits this on bs->file instead of bs->backing */
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
2016-05-24 23:21:22 +08:00
|
|
|
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
|
2011-08-23 21:21:11 +08:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
2017-08-10 04:38:05 +08:00
|
|
|
break;
|
2011-08-23 21:21:11 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Note: in this case, no need to wait */
|
|
|
|
memset(buf, 0, 512 * n);
|
|
|
|
}
|
|
|
|
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
|
|
|
/* add AIO support for compressed blocks ? */
|
|
|
|
if (decompress_cluster(bs, cluster_offset) < 0) {
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2011-08-23 21:21:11 +08:00
|
|
|
}
|
|
|
|
memcpy(buf,
|
|
|
|
s->cluster_cache + index_in_cluster * 512, 512 * n);
|
|
|
|
} else {
|
|
|
|
if ((cluster_offset & 511) != 0) {
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2011-08-23 21:21:11 +08:00
|
|
|
}
|
|
|
|
hd_iov.iov_base = (void *)buf;
|
2011-08-23 21:21:09 +08:00
|
|
|
hd_iov.iov_len = n * 512;
|
|
|
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
2011-07-15 22:27:42 +08:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
2016-05-24 23:21:22 +08:00
|
|
|
ret = bdrv_co_readv(bs->file,
|
2011-08-23 21:21:11 +08:00
|
|
|
(cluster_offset >> 9) + index_in_cluster,
|
2011-08-23 21:21:09 +08:00
|
|
|
n, &hd_qiov);
|
2011-07-15 22:27:42 +08:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
2011-08-23 21:21:11 +08:00
|
|
|
break;
|
|
|
|
}
|
qcow2/qcow: protect against uninitialized encryption key
When a qcow[2] file is opened, if the header reports an
encryption method, this is used to set the 'crypt_method_header'
field on the BDRVQcow[2]State struct, and the 'encrypted' flag
in the BDRVState struct.
When doing I/O operations, the 'crypt_method' field on the
BDRVQcow[2]State struct is checked to determine if encryption
needs to be applied.
The crypt_method_header value is copied into crypt_method when
the bdrv_set_key() method is called.
The QEMU code which opens a block device is expected to always
do a check
if (bdrv_is_encrypted(bs)) {
bdrv_set_key(bs, ....key...);
}
If code forgets to do this, then 'crypt_method' is never set
and so when I/O is performed, QEMU writes plain text data
into a sector which is expected to contain cipher text, or
when reading, will return cipher text instead of plain
text.
Change the qcow[2] code to consult bs->encrypted when deciding
whether encryption is required, and assert(s->crypt_method)
to protect against cases where the caller forgets to set the
encryption key.
Also put an assert in the set_key methods to protect against
the case where the caller sets an encryption key on a block
device that does not have encryption
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2015-05-13 00:09:18 +08:00
|
|
|
if (bs->encrypted) {
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
assert(s->crypto);
|
2017-09-27 20:53:39 +08:00
|
|
|
if (qcrypto_block_decrypt(s->crypto,
|
|
|
|
sector_num * BDRV_SECTOR_SIZE, buf,
|
2017-08-29 20:08:36 +08:00
|
|
|
n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2015-07-02 01:10:37 +08:00
|
|
|
}
|
2011-02-20 05:18:12 +08:00
|
|
|
}
|
|
|
|
}
|
2011-08-23 21:21:11 +08:00
|
|
|
ret = 0;
|
2009-04-08 02:43:24 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
nb_sectors -= n;
|
|
|
|
sector_num += n;
|
|
|
|
buf += n * 512;
|
2011-08-23 21:21:10 +08:00
|
|
|
}
|
|
|
|
|
2011-07-15 22:27:42 +08:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
if (qiov->niov > 1) {
|
allow qemu_iovec_from_buffer() to specify offset from which to start copying
Similar to
qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
int c, size_t bytes);
the new prototype is:
qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
const void *buf, size_t bytes);
The processing starts at offset bytes within qiov.
This way, we may copy a bounce buffer directly to
a middle of qiov.
This is exactly the same function as iov_from_buf() from
iov.c, so use the existing implementation and rename it
to qemu_iovec_from_buf() to be shorter and to match the
utility function.
As with utility implementation, we now assert that the
offset is inside actual iovec. Nothing changed for
current callers, because `offset' parameter is new.
While at it, stop using "bounce-qiov" in block/qcow2.c
and copy decrypted data directly from cluster_data
instead of recreating a temp qiov for doing that.
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2012-06-08 00:17:55 +08:00
|
|
|
qemu_iovec_from_buf(qiov, 0, orig_buf, qiov->size);
|
2011-08-23 21:21:11 +08:00
|
|
|
qemu_vfree(orig_buf);
|
2011-06-07 21:20:44 +08:00
|
|
|
}
|
|
|
|
|
2011-07-15 22:27:42 +08:00
|
|
|
return ret;
|
2006-08-02 00:21:11 +08:00
|
|
|
}
|
|
|
|
|
2011-11-10 16:23:22 +08:00
|
|
|
static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
2011-08-23 21:21:11 +08:00
|
|
|
int nb_sectors, QEMUIOVector *qiov)
|
2006-08-02 00:21:11 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
int index_in_cluster;
|
|
|
|
uint64_t cluster_offset;
|
2011-08-23 21:21:11 +08:00
|
|
|
int ret = 0, n;
|
2011-08-23 21:21:09 +08:00
|
|
|
struct iovec hd_iov;
|
|
|
|
QEMUIOVector hd_qiov;
|
2011-08-23 21:21:11 +08:00
|
|
|
uint8_t *buf;
|
|
|
|
void *orig_buf;
|
2006-08-07 10:38:06 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
s->cluster_cache_offset = -1; /* disable compressed cache */
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2017-06-24 00:24:07 +08:00
|
|
|
/* We must always copy the iov when encrypting, so we
|
|
|
|
* don't modify the original data buffer during encryption */
|
|
|
|
if (bs->encrypted || qiov->niov > 1) {
|
2014-05-20 19:36:05 +08:00
|
|
|
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
|
|
|
if (buf == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2012-06-08 00:21:06 +08:00
|
|
|
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
|
2006-08-02 00:21:11 +08:00
|
|
|
} else {
|
2011-08-23 21:21:11 +08:00
|
|
|
orig_buf = NULL;
|
|
|
|
buf = (uint8_t *)qiov->iov->iov_base;
|
2006-08-02 00:21:11 +08:00
|
|
|
}
|
2009-04-08 02:43:20 +08:00
|
|
|
|
2011-07-15 22:27:42 +08:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2011-08-23 21:21:10 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
while (nb_sectors != 0) {
|
2006-08-02 00:21:11 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
|
|
|
n = s->cluster_sectors - index_in_cluster;
|
|
|
|
if (n > nb_sectors) {
|
|
|
|
n = nb_sectors;
|
|
|
|
}
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = get_cluster_offset(bs, sector_num << 9, 1, 0,
|
|
|
|
index_in_cluster,
|
|
|
|
index_in_cluster + n, &cluster_offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2011-08-23 21:21:11 +08:00
|
|
|
if (!cluster_offset || (cluster_offset & 511) != 0) {
|
|
|
|
ret = -EIO;
|
|
|
|
break;
|
|
|
|
}
|
qcow2/qcow: protect against uninitialized encryption key
When a qcow[2] file is opened, if the header reports an
encryption method, this is used to set the 'crypt_method_header'
field on the BDRVQcow[2]State struct, and the 'encrypted' flag
in the BDRVState struct.
When doing I/O operations, the 'crypt_method' field on the
BDRVQcow[2]State struct is checked to determine if encryption
needs to be applied.
The crypt_method_header value is copied into crypt_method when
the bdrv_set_key() method is called.
The QEMU code which opens a block device is expected to always
do a check
if (bdrv_is_encrypted(bs)) {
bdrv_set_key(bs, ....key...);
}
If code forgets to do this, then 'crypt_method' is never set
and so when I/O is performed, QEMU writes plain text data
into a sector which is expected to contain cipher text, or
when reading, will return cipher text instead of plain
text.
Change the qcow[2] code to consult bs->encrypted when deciding
whether encryption is required, and assert(s->crypt_method)
to protect against cases where the caller forgets to set the
encryption key.
Also put an assert in the set_key methods to protect against
the case where the caller sets an encryption key on a block
device that does not have encryption
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2015-05-13 00:09:18 +08:00
|
|
|
if (bs->encrypted) {
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
assert(s->crypto);
|
2017-09-27 20:53:39 +08:00
|
|
|
if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
|
|
|
|
buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
2015-07-02 01:10:37 +08:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
|
|
|
}
|
2011-08-23 21:21:11 +08:00
|
|
|
}
|
2006-08-02 00:21:11 +08:00
|
|
|
|
2017-06-24 00:24:07 +08:00
|
|
|
hd_iov.iov_base = (void *)buf;
|
2011-08-23 21:21:11 +08:00
|
|
|
hd_iov.iov_len = n * 512;
|
|
|
|
qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
|
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2016-05-24 23:21:22 +08:00
|
|
|
ret = bdrv_co_writev(bs->file,
|
2011-08-23 21:21:11 +08:00
|
|
|
(cluster_offset >> 9) + index_in_cluster,
|
|
|
|
n, &hd_qiov);
|
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = 0;
|
2009-05-25 21:45:37 +08:00
|
|
|
|
2011-08-23 21:21:11 +08:00
|
|
|
nb_sectors -= n;
|
|
|
|
sector_num += n;
|
|
|
|
buf += n * 512;
|
|
|
|
}
|
2011-07-15 22:27:42 +08:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2017-06-24 00:24:07 +08:00
|
|
|
qemu_vfree(orig_buf);
|
2011-06-07 21:20:44 +08:00
|
|
|
|
2011-07-15 22:27:42 +08:00
|
|
|
return ret;
|
2006-08-02 00:21:11 +08:00
|
|
|
}
|
|
|
|
|
2004-09-19 03:32:11 +08:00
|
|
|
static void qcow_close(BlockDriverState *bs)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2011-11-22 23:44:45 +08:00
|
|
|
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
qcrypto_block_free(s->crypto);
|
|
|
|
s->crypto = NULL;
|
2011-08-21 11:09:37 +08:00
|
|
|
g_free(s->l1_table);
|
2014-05-20 19:36:05 +08:00
|
|
|
qemu_vfree(s->l2_cache);
|
2011-08-21 11:09:37 +08:00
|
|
|
g_free(s->cluster_cache);
|
|
|
|
g_free(s->cluster_data);
|
2011-11-22 23:44:45 +08:00
|
|
|
|
|
|
|
migrate_del_blocker(s->migration_blocker);
|
|
|
|
error_free(s->migration_blocker);
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
|
|
|
|
Error **errp)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
2018-03-10 02:53:19 +08:00
|
|
|
BlockdevCreateOptionsQcow *qcow_opts;
|
2011-11-21 15:40:39 +08:00
|
|
|
int header_size, backing_filename_len, l1_size, shift, i;
|
2004-08-02 05:59:26 +08:00
|
|
|
QCowHeader header;
|
2011-11-21 15:40:39 +08:00
|
|
|
uint8_t *tmp;
|
2009-05-18 22:42:10 +08:00
|
|
|
int64_t total_size = 0;
|
2010-01-20 07:56:12 +08:00
|
|
|
int ret;
|
2018-03-10 02:53:19 +08:00
|
|
|
BlockDriverState *bs;
|
2016-03-08 22:57:05 +08:00
|
|
|
BlockBackend *qcow_blk;
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
QCryptoBlock *crypto = NULL;
|
2009-05-18 22:42:10 +08:00
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
assert(opts->driver == BLOCKDEV_DRIVER_QCOW);
|
|
|
|
qcow_opts = &opts->u.qcow;
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
total_size = qcow_opts->size;
|
2017-06-24 00:24:03 +08:00
|
|
|
if (total_size == 0) {
|
|
|
|
error_setg(errp, "Image size is too small, cannot be zero length");
|
2018-03-10 02:53:19 +08:00
|
|
|
return -EINVAL;
|
2017-06-24 00:24:03 +08:00
|
|
|
}
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
if (qcow_opts->has_encrypt &&
|
|
|
|
qcow_opts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_QCOW)
|
|
|
|
{
|
|
|
|
error_setg(errp, "Unsupported encryption format");
|
|
|
|
return -EINVAL;
|
2009-05-18 22:42:10 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
/* Create BlockBackend to write to the image */
|
|
|
|
bs = bdrv_open_blockdev_ref(qcow_opts->file, errp);
|
|
|
|
if (bs == NULL) {
|
|
|
|
return -EIO;
|
2011-11-21 15:40:39 +08:00
|
|
|
}
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
qcow_blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
|
|
|
|
ret = blk_insert_bs(qcow_blk, bs, errp);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto exit;
|
2011-11-21 15:40:39 +08:00
|
|
|
}
|
2016-03-08 22:57:05 +08:00
|
|
|
blk_set_allow_write_beyond_eof(qcow_blk, true);
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
/* Create image format */
|
2017-06-14 04:20:54 +08:00
|
|
|
ret = blk_truncate(qcow_blk, 0, PREALLOC_MODE_OFF, errp);
|
2011-11-21 15:40:39 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
header.magic = cpu_to_be32(QCOW_MAGIC);
|
|
|
|
header.version = cpu_to_be32(QCOW_VERSION);
|
2014-09-10 17:05:46 +08:00
|
|
|
header.size = cpu_to_be64(total_size);
|
2004-08-02 05:59:26 +08:00
|
|
|
header_size = sizeof(header);
|
|
|
|
backing_filename_len = 0;
|
2018-03-10 02:53:19 +08:00
|
|
|
if (qcow_opts->has_backing_file) {
|
|
|
|
if (strcmp(qcow_opts->backing_file, "fat:")) {
|
2008-03-18 14:52:48 +08:00
|
|
|
header.backing_file_offset = cpu_to_be64(header_size);
|
2018-03-10 02:53:19 +08:00
|
|
|
backing_filename_len = strlen(qcow_opts->backing_file);
|
2008-03-18 14:52:48 +08:00
|
|
|
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
|
|
|
header_size += backing_filename_len;
|
|
|
|
} else {
|
|
|
|
/* special backing file for vvfat */
|
2018-03-10 02:53:19 +08:00
|
|
|
qcow_opts->has_backing_file = false;
|
2008-03-18 14:52:48 +08:00
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
2014-03-24 16:30:17 +08:00
|
|
|
unmodified sectors */
|
2004-08-02 05:59:26 +08:00
|
|
|
header.l2_bits = 12; /* 32 KB L2 tables */
|
|
|
|
} else {
|
|
|
|
header.cluster_bits = 12; /* 4 KB clusters */
|
|
|
|
header.l2_bits = 9; /* 4 KB L2 tables */
|
|
|
|
}
|
|
|
|
header_size = (header_size + 7) & ~7;
|
|
|
|
shift = header.cluster_bits + header.l2_bits;
|
2014-09-10 17:05:46 +08:00
|
|
|
l1_size = (total_size + (1LL << shift) - 1) >> shift;
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
header.l1_table_offset = cpu_to_be64(header_size);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
if (qcow_opts->has_encrypt) {
|
2004-08-02 05:59:26 +08:00
|
|
|
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.",
|
2017-06-24 00:24:17 +08:00
|
|
|
NULL, NULL, NULL, errp);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
if (!crypto) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
} else {
|
|
|
|
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
|
|
|
}
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
/* write all the data */
|
2016-05-07 00:26:27 +08:00
|
|
|
ret = blk_pwrite(qcow_blk, 0, &header, sizeof(header), 0);
|
2010-01-20 07:56:12 +08:00
|
|
|
if (ret != sizeof(header)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2018-03-10 02:53:19 +08:00
|
|
|
if (qcow_opts->has_backing_file) {
|
2016-03-08 22:57:05 +08:00
|
|
|
ret = blk_pwrite(qcow_blk, sizeof(header),
|
2018-03-10 02:53:19 +08:00
|
|
|
qcow_opts->backing_file, backing_filename_len, 0);
|
2010-01-20 07:56:12 +08:00
|
|
|
if (ret != backing_filename_len) {
|
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
2011-11-21 15:40:39 +08:00
|
|
|
|
|
|
|
tmp = g_malloc0(BDRV_SECTOR_SIZE);
|
2016-06-01 00:35:52 +08:00
|
|
|
for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE);
|
|
|
|
i++) {
|
2016-05-07 00:26:27 +08:00
|
|
|
ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
|
|
|
|
tmp, BDRV_SECTOR_SIZE, 0);
|
2011-11-21 15:40:39 +08:00
|
|
|
if (ret != BDRV_SECTOR_SIZE) {
|
|
|
|
g_free(tmp);
|
2010-01-20 07:56:12 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
2010-01-20 07:56:12 +08:00
|
|
|
|
2011-11-21 15:40:39 +08:00
|
|
|
g_free(tmp);
|
2010-01-20 07:56:12 +08:00
|
|
|
ret = 0;
|
|
|
|
exit:
|
2016-03-08 22:57:05 +08:00
|
|
|
blk_unref(qcow_blk);
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
qcrypto_block_free(crypto);
|
2018-03-10 02:53:19 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int coroutine_fn qcow_co_create_opts(const char *filename,
|
|
|
|
QemuOpts *opts, Error **errp)
|
|
|
|
{
|
|
|
|
BlockdevCreateOptions *create_options = NULL;
|
|
|
|
BlockDriverState *bs = NULL;
|
|
|
|
QDict *qdict = NULL;
|
|
|
|
QObject *qobj;
|
|
|
|
Visitor *v;
|
|
|
|
const char *val;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
static const QDictRenames opt_renames[] = {
|
|
|
|
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
|
|
|
|
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Parse options and convert legacy syntax */
|
|
|
|
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qcow_create_opts, true);
|
|
|
|
|
|
|
|
val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
|
|
|
|
if (val && !strcmp(val, "on")) {
|
|
|
|
qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
|
|
|
|
} else if (val && !strcmp(val, "off")) {
|
|
|
|
qdict_del(qdict, BLOCK_OPT_ENCRYPT);
|
|
|
|
}
|
|
|
|
|
|
|
|
val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
|
|
|
|
if (val && !strcmp(val, "aes")) {
|
|
|
|
qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!qdict_rename_keys(qdict, opt_renames, errp)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create and open the file (protocol layer) */
|
|
|
|
ret = bdrv_create_file(filename, opts, &local_err);
|
|
|
|
if (ret < 0) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
bs = bdrv_open(filename, NULL, NULL,
|
|
|
|
BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
|
|
|
|
if (bs == NULL) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now get the QAPI type BlockdevCreateOptions */
|
|
|
|
qdict_put_str(qdict, "driver", "qcow");
|
|
|
|
qdict_put_str(qdict, "file", bs->node_name);
|
|
|
|
|
|
|
|
qobj = qdict_crumple(qdict, errp);
|
|
|
|
QDECREF(qdict);
|
|
|
|
qdict = qobject_to_qdict(qobj);
|
|
|
|
if (qdict == NULL) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
|
|
|
|
visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
|
|
|
|
visit_free(v);
|
|
|
|
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Silently round up size */
|
|
|
|
assert(create_options->driver == BLOCKDEV_DRIVER_QCOW);
|
|
|
|
create_options->u.qcow.size =
|
|
|
|
ROUND_UP(create_options->u.qcow.size, BDRV_SECTOR_SIZE);
|
|
|
|
|
|
|
|
/* Create the qcow image (format layer) */
|
|
|
|
ret = qcow_co_create(create_options, errp);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
fail:
|
|
|
|
QDECREF(qdict);
|
|
|
|
bdrv_unref(bs);
|
|
|
|
qapi_free_BlockdevCreateOptions(create_options);
|
2010-01-20 07:56:12 +08:00
|
|
|
return ret;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
2006-08-06 05:32:10 +08:00
|
|
|
static int qcow_make_empty(BlockDriverState *bs)
|
2005-12-19 02:28:15 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
2006-08-02 00:21:11 +08:00
|
|
|
int ret;
|
2005-12-19 02:28:15 +08:00
|
|
|
|
|
|
|
memset(s->l1_table, 0, l1_length);
|
2016-06-21 02:09:15 +08:00
|
|
|
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
|
2010-06-18 22:11:53 +08:00
|
|
|
l1_length) < 0)
|
|
|
|
return -1;
|
2017-06-14 04:20:53 +08:00
|
|
|
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length,
|
|
|
|
PREALLOC_MODE_OFF, NULL);
|
2006-08-02 00:21:11 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2005-12-19 02:28:15 +08:00
|
|
|
|
|
|
|
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
|
|
|
|
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
|
|
|
|
memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-02 05:59:26 +08:00
|
|
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
|
|
|
tables to avoid losing bytes in alignment */
|
2016-07-22 16:17:46 +08:00
|
|
|
static coroutine_fn int
|
|
|
|
qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
|
|
|
|
uint64_t bytes, QEMUIOVector *qiov)
|
2004-08-02 05:59:26 +08:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2016-07-22 16:17:46 +08:00
|
|
|
QEMUIOVector hd_qiov;
|
|
|
|
struct iovec iov;
|
2004-08-02 05:59:26 +08:00
|
|
|
z_stream strm;
|
|
|
|
int ret, out_len;
|
2016-07-22 16:17:46 +08:00
|
|
|
uint8_t *buf, *out_buf;
|
2004-08-02 05:59:26 +08:00
|
|
|
uint64_t cluster_offset;
|
|
|
|
|
2016-07-22 16:17:47 +08:00
|
|
|
buf = qemu_blockalign(bs, s->cluster_size);
|
2016-07-22 16:17:46 +08:00
|
|
|
if (bytes != s->cluster_size) {
|
2016-07-22 16:17:47 +08:00
|
|
|
if (bytes > s->cluster_size ||
|
|
|
|
offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
2016-07-22 16:17:46 +08:00
|
|
|
{
|
2016-07-22 16:17:47 +08:00
|
|
|
qemu_vfree(buf);
|
|
|
|
return -EINVAL;
|
2013-04-15 23:17:32 +08:00
|
|
|
}
|
2016-07-22 16:17:47 +08:00
|
|
|
/* Zero-pad last write if image size is not cluster aligned */
|
|
|
|
memset(buf + bytes, 0, s->cluster_size - bytes);
|
2013-04-15 23:17:32 +08:00
|
|
|
}
|
2016-07-22 16:17:46 +08:00
|
|
|
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
|
2004-08-02 05:59:26 +08:00
|
|
|
|
2016-07-15 00:59:25 +08:00
|
|
|
out_buf = g_malloc(s->cluster_size);
|
2004-08-02 05:59:26 +08:00
|
|
|
|
|
|
|
/* best compression, small window, no zlib header */
|
|
|
|
memset(&strm, 0, sizeof(strm));
|
|
|
|
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
|
2007-09-17 05:08:06 +08:00
|
|
|
Z_DEFLATED, -12,
|
2004-08-02 05:59:26 +08:00
|
|
|
9, Z_DEFAULT_STRATEGY);
|
|
|
|
if (ret != 0) {
|
2011-10-26 17:21:50 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
strm.avail_in = s->cluster_size;
|
|
|
|
strm.next_in = (uint8_t *)buf;
|
|
|
|
strm.avail_out = s->cluster_size;
|
|
|
|
strm.next_out = out_buf;
|
|
|
|
|
|
|
|
ret = deflate(&strm, Z_FINISH);
|
|
|
|
if (ret != Z_STREAM_END && ret != Z_OK) {
|
|
|
|
deflateEnd(&strm);
|
2011-10-26 17:21:50 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
out_len = strm.next_out - out_buf;
|
|
|
|
|
|
|
|
deflateEnd(&strm);
|
|
|
|
|
|
|
|
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
|
|
|
|
/* could not compress: write normal cluster */
|
2016-07-22 16:17:46 +08:00
|
|
|
ret = qcow_co_writev(bs, offset >> BDRV_SECTOR_BITS,
|
|
|
|
bytes >> BDRV_SECTOR_BITS, qiov);
|
2011-10-26 17:21:50 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
2016-07-22 16:17:46 +08:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2017-08-10 04:38:05 +08:00
|
|
|
ret = get_cluster_offset(bs, offset, 2, out_len, 0, 0, &cluster_offset);
|
2016-07-22 16:17:46 +08:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-08-10 04:38:05 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-07-22 16:17:46 +08:00
|
|
|
if (cluster_offset == 0) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto fail;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
2016-07-22 16:17:46 +08:00
|
|
|
cluster_offset &= s->cluster_offset_mask;
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2016-07-22 16:17:46 +08:00
|
|
|
iov = (struct iovec) {
|
|
|
|
.iov_base = out_buf,
|
|
|
|
.iov_len = out_len,
|
|
|
|
};
|
|
|
|
qemu_iovec_init_external(&hd_qiov, &iov, 1);
|
2017-11-23 10:08:18 +08:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
2016-07-22 16:17:46 +08:00
|
|
|
ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
success:
|
2011-10-26 17:21:50 +08:00
|
|
|
ret = 0;
|
|
|
|
fail:
|
2016-07-22 16:17:46 +08:00
|
|
|
qemu_vfree(buf);
|
2011-08-21 11:09:37 +08:00
|
|
|
g_free(out_buf);
|
2011-10-26 17:21:50 +08:00
|
|
|
return ret;
|
2004-08-02 05:59:26 +08:00
|
|
|
}
|
|
|
|
|
2006-08-06 05:32:10 +08:00
|
|
|
static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
bdi->cluster_size = s->cluster_size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-05 17:20:57 +08:00
|
|
|
static QemuOptsList qcow_create_opts = {
|
|
|
|
.name = "qcow-create-opts",
|
|
|
|
.head = QTAILQ_HEAD_INITIALIZER(qcow_create_opts.head),
|
|
|
|
.desc = {
|
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_SIZE,
|
|
|
|
.type = QEMU_OPT_SIZE,
|
|
|
|
.help = "Virtual disk size"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_BACKING_FILE,
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
.help = "File name of a base image"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_ENCRYPT,
|
|
|
|
.type = QEMU_OPT_BOOL,
|
2017-06-24 00:24:06 +08:00
|
|
|
.help = "Encrypt the image with format 'aes'. (Deprecated "
|
|
|
|
"in favor of " BLOCK_OPT_ENCRYPT_FORMAT "=aes)",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_ENCRYPT_FORMAT,
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
.help = "Encrypt the image, format choices: 'aes'",
|
2014-06-05 17:20:57 +08:00
|
|
|
},
|
qcow: convert QCow to use QCryptoBlock for encryption
This converts the qcow driver to make use of the QCryptoBlock
APIs for encrypting image content. This is only wired up to
permit use of the legacy QCow encryption format. Users who wish
to have the strong LUKS format should switch to qcow2 instead.
With this change it is now required to use the QCryptoSecret
object for providing passwords, instead of the current block
password APIs / interactive prompting.
$QEMU \
-object secret,id=sec0,file=/home/berrange/encrypted.pw \
-drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\
encrypt.key-secret=sec0
Though note that running QEMU system emulators with the AES
encryption is no longer supported, so while the above syntax
is valid, QEMU will refuse to actually run the VM in this
particular example.
Likewise when creating images with the legacy AES-CBC format
qemu-img create -f qcow \
--object secret,id=sec0,file=/home/berrange/encrypted.pw \
-o encrypt.format=aes,encrypt.key-secret=sec0 \
/home/berrange/encrypted.qcow 64M
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 20170623162419.26068-10-berrange@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2017-06-24 00:24:08 +08:00
|
|
|
BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
|
2014-06-05 17:20:57 +08:00
|
|
|
{ /* end of list */ }
|
|
|
|
}
|
2009-05-18 22:42:10 +08:00
|
|
|
};
|
|
|
|
|
2009-05-10 06:03:42 +08:00
|
|
|
static BlockDriver bdrv_qcow = {
|
2009-03-08 06:00:29 +08:00
|
|
|
.format_name = "qcow",
|
|
|
|
.instance_size = sizeof(BDRVQcowState),
|
|
|
|
.bdrv_probe = qcow_probe,
|
|
|
|
.bdrv_open = qcow_open,
|
|
|
|
.bdrv_close = qcow_close,
|
2016-12-19 23:36:02 +08:00
|
|
|
.bdrv_child_perm = bdrv_format_default_perms,
|
2014-06-05 17:20:57 +08:00
|
|
|
.bdrv_reopen_prepare = qcow_reopen_prepare,
|
2018-03-10 02:53:19 +08:00
|
|
|
.bdrv_co_create = qcow_co_create,
|
2018-01-18 20:43:45 +08:00
|
|
|
.bdrv_co_create_opts = qcow_co_create_opts,
|
2013-06-28 18:47:42 +08:00
|
|
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
2014-06-04 21:09:35 +08:00
|
|
|
.supports_backing = true,
|
2011-11-11 00:25:44 +08:00
|
|
|
|
|
|
|
.bdrv_co_readv = qcow_co_readv,
|
|
|
|
.bdrv_co_writev = qcow_co_writev,
|
2018-02-14 04:26:51 +08:00
|
|
|
.bdrv_co_block_status = qcow_co_block_status,
|
2011-11-11 00:25:44 +08:00
|
|
|
|
|
|
|
.bdrv_make_empty = qcow_make_empty,
|
2016-07-22 16:17:46 +08:00
|
|
|
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
|
2011-11-11 00:25:44 +08:00
|
|
|
.bdrv_get_info = qcow_get_info,
|
2009-05-18 22:42:10 +08:00
|
|
|
|
2014-06-05 17:20:57 +08:00
|
|
|
.create_opts = &qcow_create_opts,
|
2004-08-02 05:59:26 +08:00
|
|
|
};
|
2009-05-10 06:03:42 +08:00
|
|
|
|
|
|
|
static void bdrv_qcow_init(void)
|
|
|
|
{
|
|
|
|
bdrv_register(&bdrv_qcow);
|
|
|
|
}
|
|
|
|
|
|
|
|
block_init(bdrv_qcow_init);
|