2004-08-01 23:59:26 +02:00
|
|
|
/*
|
|
|
|
* Block driver for the QCOW format
|
2007-09-16 23:08:06 +02:00
|
|
|
*
|
2006-08-01 18:21:11 +02:00
|
|
|
* Copyright (c) 2004-2006 Fabrice Bellard
|
2007-09-16 23:08:06 +02:00
|
|
|
*
|
2004-08-01 23:59:26 +02: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 12:18:39 +01:00
|
|
|
|
2016-01-18 19:01:42 +01: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 09:01:28 +01:00
|
|
|
#include "qapi/error.h"
|
2016-03-21 15:11:48 +01:00
|
|
|
#include "qemu/error-report.h"
|
2012-12-17 18:19:44 +01:00
|
|
|
#include "block/block_int.h"
|
2018-06-14 21:14:28 +02:00
|
|
|
#include "block/qdict.h"
|
2016-03-08 15:57:05 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/module.h"
|
2018-02-01 12:18:46 +01:00
|
|
|
#include "qemu/option.h"
|
2016-03-15 17:22:36 +01:00
|
|
|
#include "qemu/bswap.h"
|
block: Add BDS.auto_backing_file
If the backing file is overridden, this most probably does change the
guest-visible data of a BDS. Therefore, we will need to consider this
in bdrv_refresh_filename().
To see whether it has been overridden, we might want to compare
bs->backing_file and bs->backing->bs->filename. However,
bs->backing_file is changed by bdrv_set_backing_hd() (which is just used
to change the backing child at runtime, without modifying the image
header), so bs->backing_file most of the time simply contains a copy of
bs->backing->bs->filename anyway, so it is useless for such a
comparison.
This patch adds an auto_backing_file BDS field which contains the
backing file path as indicated by the image header, which is not changed
by bdrv_set_backing_hd().
Because of bdrv_refresh_filename() magic, however, a BDS's filename may
differ from what has been specified during bdrv_open(). Then, the
comparison between bs->auto_backing_file and bs->backing->bs->filename
may fail even though bs->backing was opened from bs->auto_backing_file.
To mitigate this, we can copy the real BDS's filename (after the whole
bdrv_open() and bdrv_refresh_filename() process) into
bs->auto_backing_file, if we know the former has been opened based on
the latter. This is only possible if no options modifying the backing
file's behavior have been specified, though. To simplify things, this
patch only copies the filename from the backing file if no options have
been specified for it at all.
Furthermore, there are cases where an overlay is created by qemu which
already contains a BDS's filename (e.g. in blockdev-snapshot-sync). We
do not need to worry about updating the overlay's bs->auto_backing_file
there, because we actually wrote a post-bdrv_refresh_filename() filename
into the image header.
So all in all, there will be false negatives where (as of a future
patch) bdrv_refresh_filename() will assume that the backing file differs
from what was specified in the image header, even though it really does
not. However, these cases should be limited to where (1) the user
actually did override something in the backing chain (e.g. by specifying
options for the backing file), or (2) the user executed a QMP command to
change some node's backing file (e.g. change-backing-file or
block-commit with @backing-file given) where the given filename does not
happen to coincide with qemu's idea of the backing BDS's filename.
Then again, (1) really is limited to -drive. With -blockdev or
blockdev-add, you have to adhere to the schema, so a user cannot give
partial "unimportant" options (e.g. by just setting backing.node-name
and leaving the rest to the image header). Therefore, trying to fix
this would mean trying to fix something for -drive only.
To improve on (2), we would need a full infrastructure to "canonicalize"
an arbitrary filename (+ options), so it can be compared against
another. That seems a bit over the top, considering that filenames
nowadays are there mostly for the user's entertainment.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-id: 20190201192935.18394-5-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2019-02-01 20:29:08 +01:00
|
|
|
#include "qemu/cutils.h"
|
2004-09-29 23:30:43 +02:00
|
|
|
#include <zlib.h>
|
2018-02-01 12:18:39 +01: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-23 18:24:08 +02:00
|
|
|
#include "qapi/qmp/qstring.h"
|
2018-03-09 19:53:19 +01: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-23 18:24:08 +02:00
|
|
|
#include "crypto/block.h"
|
2017-04-06 12:00:28 +02:00
|
|
|
#include "migration/blocker.h"
|
2018-05-03 21:50:20 +02:00
|
|
|
#include "crypto.h"
|
2004-08-01 23:59:26 +02: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 16:56:10 +02:00
|
|
|
uint16_t padding;
|
2004-08-01 23:59:26 +02:00
|
|
|
uint32_t crypt_method;
|
|
|
|
uint64_t l1_table_offset;
|
2014-05-07 16:56:10 +02:00
|
|
|
} QEMU_PACKED QCowHeader;
|
2004-08-01 23:59:26 +02:00
|
|
|
|
|
|
|
#define L2_CACHE_SIZE 16
|
|
|
|
|
|
|
|
typedef struct BDRVQcowState {
|
|
|
|
int cluster_bits;
|
|
|
|
int cluster_size;
|
|
|
|
int l2_bits;
|
|
|
|
int l2_size;
|
2014-05-08 13:08:20 +02:00
|
|
|
unsigned int l1_size;
|
2004-08-01 23:59:26 +02: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-23 18:24:08 +02:00
|
|
|
QCryptoBlock *crypto; /* Disk encryption format driver */
|
2004-08-01 23:59:26 +02:00
|
|
|
uint32_t crypt_method_header;
|
2011-07-15 16:27:42 +02:00
|
|
|
CoMutex lock;
|
2011-11-22 16:44:45 +01:00
|
|
|
Error *migration_blocker;
|
2004-08-01 23:59:26 +02:00
|
|
|
} BDRVQcowState;
|
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
static QemuOptsList qcow_create_opts;
|
|
|
|
|
2010-04-14 14:17:38 +02:00
|
|
|
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
2004-08-01 23:59:26 +02: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 10:09:54 +02:00
|
|
|
|
2005-04-28 23:09:32 +02:00
|
|
|
if (buf_size >= sizeof(QCowHeader) &&
|
|
|
|
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
|
2007-09-16 23:08:06 +02:00
|
|
|
be32_to_cpu(cow_header->version) == QCOW_VERSION)
|
2004-08-01 23:59:26 +02:00
|
|
|
return 100;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-05 14:22:29 +02:00
|
|
|
static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
|
Error **errp)
|
2004-08-01 23:59:26 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2014-05-08 13:35:09 +02:00
|
|
|
unsigned int len, i, shift;
|
|
|
|
int ret;
|
2004-08-01 23:59:26 +02:00
|
|
|
QCowHeader header;
|
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-23 18:24:08 +02: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-01 18:21:11 +02:00
|
|
|
|
2020-05-13 13:05:35 +02:00
|
|
|
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
|
|
|
|
BDRV_CHILD_IMAGE, false, errp);
|
2016-12-16 18:52:37 +01:00
|
|
|
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-23 18:24:08 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2016-12-16 18:52:37 +01:00
|
|
|
}
|
|
|
|
|
2016-06-20 18:24:02 +02:00
|
|
|
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
2011-12-15 11:14:00 +01:00
|
|
|
if (ret < 0) {
|
2004-08-01 23:59:26 +02:00
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
2018-10-09 19:25:00 +02:00
|
|
|
header.magic = be32_to_cpu(header.magic);
|
|
|
|
header.version = be32_to_cpu(header.version);
|
|
|
|
header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
|
|
|
|
header.backing_file_size = be32_to_cpu(header.backing_file_size);
|
|
|
|
header.mtime = be32_to_cpu(header.mtime);
|
|
|
|
header.size = be64_to_cpu(header.size);
|
|
|
|
header.crypt_method = be32_to_cpu(header.crypt_method);
|
|
|
|
header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2011-12-15 11:14:00 +01:00
|
|
|
if (header.magic != QCOW_MAGIC) {
|
2014-02-17 14:44:06 +01:00
|
|
|
error_setg(errp, "Image not in qcow format");
|
|
|
|
ret = -EINVAL;
|
2011-12-15 11:14:00 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
if (header.version != QCOW_VERSION) {
|
2019-06-26 23:53:01 +02:00
|
|
|
error_setg(errp, "qcow (v%d) does not support qcow version %" PRIu32,
|
|
|
|
QCOW_VERSION, header.version);
|
|
|
|
if (header.version == 2 || header.version == 3) {
|
|
|
|
error_append_hint(errp, "Try the 'qcow2' driver instead.\n");
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:14:00 +01:00
|
|
|
ret = -ENOTSUP;
|
2004-08-01 23:59:26 +02:00
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
|
|
|
|
2014-05-07 17:30:30 +02:00
|
|
|
if (header.size <= 1) {
|
|
|
|
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
2011-12-15 11:14:00 +01:00
|
|
|
ret = -EINVAL;
|
2004-08-01 23:59:26 +02:00
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
2014-05-07 17:30:30 +02: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 16:10:11 +02: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-01 23:59:26 +02:00
|
|
|
s->crypt_method_header = header.crypt_method;
|
2011-12-15 11:14:00 +01:00
|
|
|
if (s->crypt_method_header) {
|
2016-03-21 15:11:48 +01: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 13:30:09 +02: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 15:11:48 +01: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-23 18:24:08 +02: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;
|
|
|
|
}
|
2018-06-26 19:41:19 +02:00
|
|
|
qdict_put_str(encryptopts, "format", "qcow");
|
|
|
|
crypto_opts = block_crypto_open_opts_init(encryptopts, 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-23 18:24:08 +02:00
|
|
|
if (!crypto_opts) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-03-21 15:11:48 +01: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-23 18:24:08 +02:00
|
|
|
if (flags & BDRV_O_NO_IO) {
|
|
|
|
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
|
|
|
|
}
|
2017-06-23 18:24:17 +02:00
|
|
|
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
|
2018-12-07 17:13:51 +01:00
|
|
|
NULL, NULL, cflags, 1, 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-23 18:24:08 +02: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 00:37:26 +02:00
|
|
|
bs->encrypted = true;
|
2017-06-23 18:24:16 +02: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 11:14:00 +01:00
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
s->cluster_bits = header.cluster_bits;
|
|
|
|
s->cluster_size = 1 << s->cluster_bits;
|
|
|
|
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 13:08:20 +02: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-01 23:59:26 +02: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 10:31:08 +02:00
|
|
|
s->l1_table = g_try_new(uint64_t, s->l1_size);
|
2014-05-20 13:36:05 +02:00
|
|
|
if (s->l1_table == NULL) {
|
|
|
|
error_setg(errp, "Could not allocate memory for L1 table");
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-12-15 11:14:00 +01:00
|
|
|
|
2016-06-20 18:24:02 +02:00
|
|
|
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
2011-12-15 11:14:00 +01:00
|
|
|
s->l1_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
2004-08-01 23:59:26 +02:00
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
|
|
|
|
2004-08-01 23:59:26 +02:00
|
|
|
for(i = 0;i < s->l1_size; i++) {
|
2018-10-09 19:25:00 +02:00
|
|
|
s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2014-05-20 13:36:05 +02:00
|
|
|
|
|
|
|
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
|
|
|
|
s->l2_cache =
|
2015-06-16 14:19:22 +02:00
|
|
|
qemu_try_blockalign(bs->file->bs,
|
2014-05-20 13:36:05 +02: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 05:09:37 +02:00
|
|
|
s->cluster_cache = g_malloc(s->cluster_size);
|
|
|
|
s->cluster_data = g_malloc(s->cluster_size);
|
2004-08-01 23:59:26 +02:00
|
|
|
s->cluster_cache_offset = -1;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2004-08-01 23:59:26 +02:00
|
|
|
/* read the backing file name */
|
|
|
|
if (header.backing_file_offset != 0) {
|
|
|
|
len = header.backing_file_size;
|
2015-01-27 14:33:55 +01:00
|
|
|
if (len > 1023 || len >= sizeof(bs->backing_file)) {
|
2014-05-08 13:35:09 +02:00
|
|
|
error_setg(errp, "Backing file name too long");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
2016-06-20 18:24:02 +02:00
|
|
|
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
block: Add BDS.auto_backing_file
If the backing file is overridden, this most probably does change the
guest-visible data of a BDS. Therefore, we will need to consider this
in bdrv_refresh_filename().
To see whether it has been overridden, we might want to compare
bs->backing_file and bs->backing->bs->filename. However,
bs->backing_file is changed by bdrv_set_backing_hd() (which is just used
to change the backing child at runtime, without modifying the image
header), so bs->backing_file most of the time simply contains a copy of
bs->backing->bs->filename anyway, so it is useless for such a
comparison.
This patch adds an auto_backing_file BDS field which contains the
backing file path as indicated by the image header, which is not changed
by bdrv_set_backing_hd().
Because of bdrv_refresh_filename() magic, however, a BDS's filename may
differ from what has been specified during bdrv_open(). Then, the
comparison between bs->auto_backing_file and bs->backing->bs->filename
may fail even though bs->backing was opened from bs->auto_backing_file.
To mitigate this, we can copy the real BDS's filename (after the whole
bdrv_open() and bdrv_refresh_filename() process) into
bs->auto_backing_file, if we know the former has been opened based on
the latter. This is only possible if no options modifying the backing
file's behavior have been specified, though. To simplify things, this
patch only copies the filename from the backing file if no options have
been specified for it at all.
Furthermore, there are cases where an overlay is created by qemu which
already contains a BDS's filename (e.g. in blockdev-snapshot-sync). We
do not need to worry about updating the overlay's bs->auto_backing_file
there, because we actually wrote a post-bdrv_refresh_filename() filename
into the image header.
So all in all, there will be false negatives where (as of a future
patch) bdrv_refresh_filename() will assume that the backing file differs
from what was specified in the image header, even though it really does
not. However, these cases should be limited to where (1) the user
actually did override something in the backing chain (e.g. by specifying
options for the backing file), or (2) the user executed a QMP command to
change some node's backing file (e.g. change-backing-file or
block-commit with @backing-file given) where the given filename does not
happen to coincide with qemu's idea of the backing BDS's filename.
Then again, (1) really is limited to -drive. With -blockdev or
blockdev-add, you have to adhere to the schema, so a user cannot give
partial "unimportant" options (e.g. by just setting backing.node-name
and leaving the rest to the image header). Therefore, trying to fix
this would mean trying to fix something for -drive only.
To improve on (2), we would need a full infrastructure to "canonicalize"
an arbitrary filename (+ options), so it can be compared against
another. That seems a bit over the top, considering that filenames
nowadays are there mostly for the user's entertainment.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-id: 20190201192935.18394-5-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2019-02-01 20:29:08 +01:00
|
|
|
bs->auto_backing_file, len);
|
2011-12-15 11:14:00 +01:00
|
|
|
if (ret < 0) {
|
2004-08-01 23:59:26 +02:00
|
|
|
goto fail;
|
2011-12-15 11:14:00 +01:00
|
|
|
}
|
block: Add BDS.auto_backing_file
If the backing file is overridden, this most probably does change the
guest-visible data of a BDS. Therefore, we will need to consider this
in bdrv_refresh_filename().
To see whether it has been overridden, we might want to compare
bs->backing_file and bs->backing->bs->filename. However,
bs->backing_file is changed by bdrv_set_backing_hd() (which is just used
to change the backing child at runtime, without modifying the image
header), so bs->backing_file most of the time simply contains a copy of
bs->backing->bs->filename anyway, so it is useless for such a
comparison.
This patch adds an auto_backing_file BDS field which contains the
backing file path as indicated by the image header, which is not changed
by bdrv_set_backing_hd().
Because of bdrv_refresh_filename() magic, however, a BDS's filename may
differ from what has been specified during bdrv_open(). Then, the
comparison between bs->auto_backing_file and bs->backing->bs->filename
may fail even though bs->backing was opened from bs->auto_backing_file.
To mitigate this, we can copy the real BDS's filename (after the whole
bdrv_open() and bdrv_refresh_filename() process) into
bs->auto_backing_file, if we know the former has been opened based on
the latter. This is only possible if no options modifying the backing
file's behavior have been specified, though. To simplify things, this
patch only copies the filename from the backing file if no options have
been specified for it at all.
Furthermore, there are cases where an overlay is created by qemu which
already contains a BDS's filename (e.g. in blockdev-snapshot-sync). We
do not need to worry about updating the overlay's bs->auto_backing_file
there, because we actually wrote a post-bdrv_refresh_filename() filename
into the image header.
So all in all, there will be false negatives where (as of a future
patch) bdrv_refresh_filename() will assume that the backing file differs
from what was specified in the image header, even though it really does
not. However, these cases should be limited to where (1) the user
actually did override something in the backing chain (e.g. by specifying
options for the backing file), or (2) the user executed a QMP command to
change some node's backing file (e.g. change-backing-file or
block-commit with @backing-file given) where the given filename does not
happen to coincide with qemu's idea of the backing BDS's filename.
Then again, (1) really is limited to -drive. With -blockdev or
blockdev-add, you have to adhere to the schema, so a user cannot give
partial "unimportant" options (e.g. by just setting backing.node-name
and leaving the rest to the image header). Therefore, trying to fix
this would mean trying to fix something for -drive only.
To improve on (2), we would need a full infrastructure to "canonicalize"
an arbitrary filename (+ options), so it can be compared against
another. That seems a bit over the top, considering that filenames
nowadays are there mostly for the user's entertainment.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Message-id: 20190201192935.18394-5-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
2019-02-01 20:29:08 +01:00
|
|
|
bs->auto_backing_file[len] = '\0';
|
|
|
|
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
|
|
|
|
bs->auto_backing_file);
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2011-08-11 23:27:15 +02:00
|
|
|
|
2011-11-22 16:44:45 +01:00
|
|
|
/* Disable migration when qcow images are used */
|
2015-04-08 11:29:19 +02: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));
|
error: Avoid error_propagate() after migrate_add_blocker()
When migrate_add_blocker(blocker, &errp) is followed by
error_propagate(errp, err), we can often just as well do
migrate_add_blocker(..., errp).
Do that with this Coccinelle script:
@@
expression blocker, err, errp;
expression ret;
@@
- ret = migrate_add_blocker(blocker, &err);
- if (err) {
+ ret = migrate_add_blocker(blocker, errp);
+ if (ret < 0) {
... when != err;
- error_propagate(errp, err);
...
}
@@
expression blocker, err, errp;
@@
- migrate_add_blocker(blocker, &err);
- if (err) {
+ if (migrate_add_blocker(blocker, errp) < 0) {
... when != err;
- error_propagate(errp, err);
...
}
Double-check @err is not used afterwards. Dereferencing it would be
use after free, but checking whether it's null would be legitimate.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200707160613.848843-43-armbru@redhat.com>
2020-07-07 18:06:10 +02:00
|
|
|
ret = migrate_add_blocker(s->migration_blocker, errp);
|
|
|
|
if (ret < 0) {
|
2017-01-16 12:31:53 +01:00
|
|
|
error_free(s->migration_blocker);
|
|
|
|
goto fail;
|
|
|
|
}
|
2011-11-22 16:44:45 +01:00
|
|
|
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(encryptopts);
|
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-23 18:24:08 +02:00
|
|
|
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
|
2011-08-11 23:27:15 +02:00
|
|
|
qemu_co_mutex_init(&s->lock);
|
2004-08-01 23:59:26 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(s->l1_table);
|
2014-05-20 13:36:05 +02:00
|
|
|
qemu_vfree(s->l2_cache);
|
2011-08-21 05:09:37 +02: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-23 18:24:08 +02:00
|
|
|
qcrypto_block_free(s->crypto);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(encryptopts);
|
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-23 18:24:08 +02:00
|
|
|
qapi_free_QCryptoBlockOpenOptions(crypto_opts);
|
2011-12-15 11:14:00 +01:00
|
|
|
return ret;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
|
2012-09-20 21:13:29 +02: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-01 23:59:26 +02:00
|
|
|
|
|
|
|
/* 'allocate' is:
|
|
|
|
*
|
|
|
|
* 0 to not allocate.
|
|
|
|
*
|
2018-06-28 22:15:19 +02:00
|
|
|
* 1 to allocate a normal cluster (for sector-aligned byte offsets 'n_start'
|
|
|
|
* to 'n_end' within the cluster)
|
2004-08-01 23:59:26 +02:00
|
|
|
*
|
|
|
|
* 2 to allocate a compressed cluster of size
|
|
|
|
* 'compressed_size'. 'compressed_size' must be > 0 and <
|
2007-09-16 23:08:06 +02:00
|
|
|
* cluster_size
|
2004-08-01 23:59:26 +02:00
|
|
|
*
|
2017-08-09 22:38:05 +02:00
|
|
|
* return 0 if not allocated, 1 if *result is assigned, and negative
|
|
|
|
* errno on failure.
|
2004-08-01 23:59:26 +02:00
|
|
|
*/
|
2017-08-09 22:38:05 +02: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-01 23:59:26 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2017-08-09 22:38:05 +02:00
|
|
|
int min_index, i, j, l1_index, l2_index, ret;
|
2017-08-09 22:38:06 +02:00
|
|
|
int64_t l2_offset;
|
|
|
|
uint64_t *l2_table, cluster_offset, tmp;
|
2004-08-01 23:59:26 +02:00
|
|
|
uint32_t min_count;
|
|
|
|
int new_l2_table;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2017-08-09 22:38:05 +02:00
|
|
|
*result = 0;
|
2004-08-01 23:59:26 +02: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 14:19:22 +02:00
|
|
|
l2_offset = bdrv_getlength(bs->file->bs);
|
2017-08-09 22:38:06 +02:00
|
|
|
if (l2_offset < 0) {
|
|
|
|
return l2_offset;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
/* round to cluster size */
|
2017-08-09 22:38:06 +02:00
|
|
|
l2_offset = QEMU_ALIGN_UP(l2_offset, s->cluster_size);
|
2004-08-01 23:59:26 +02:00
|
|
|
/* update the L1 entry */
|
|
|
|
s->l1_table[l1_index] = l2_offset;
|
|
|
|
tmp = cpu_to_be64(l2_offset);
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
|
2017-08-09 22:38:05 +02: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-01 23:59:26 +02: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 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
|
2004-08-01 23:59:26 +02:00
|
|
|
if (new_l2_table) {
|
|
|
|
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
|
|
|
|
s->l2_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
} else {
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = bdrv_pread(bs->file, l2_offset, l2_table,
|
|
|
|
s->l2_size * sizeof(uint64_t));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-01 23:59:26 +02: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-16 23:08:06 +02:00
|
|
|
if (!cluster_offset ||
|
2004-08-01 23:59:26 +02:00
|
|
|
((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
|
|
|
|
if (!allocate)
|
|
|
|
return 0;
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC);
|
2018-06-28 22:15:19 +02:00
|
|
|
assert(QEMU_IS_ALIGNED(n_start | n_end, BDRV_SECTOR_SIZE));
|
2004-08-01 23:59:26 +02:00
|
|
|
/* allocate a new cluster */
|
|
|
|
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
|
2018-06-28 22:15:19 +02:00
|
|
|
(n_end - n_start) < s->cluster_size) {
|
2004-08-01 23:59:26 +02:00
|
|
|
/* if the cluster is already compressed, we must
|
|
|
|
decompress it in the case it is not completely
|
|
|
|
overwritten */
|
2017-08-09 22:38:05 +02:00
|
|
|
if (decompress_cluster(bs, cluster_offset) < 0) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
2015-06-16 14:19:22 +02:00
|
|
|
cluster_offset = bdrv_getlength(bs->file->bs);
|
2017-08-09 22:38:06 +02:00
|
|
|
if ((int64_t) cluster_offset < 0) {
|
|
|
|
return cluster_offset;
|
|
|
|
}
|
|
|
|
cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
|
2004-08-01 23:59:26 +02:00
|
|
|
/* write the cluster content */
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
|
|
|
|
s->cluster_size);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
} else {
|
2015-06-16 14:19:22 +02:00
|
|
|
cluster_offset = bdrv_getlength(bs->file->bs);
|
2017-08-09 22:38:06 +02:00
|
|
|
if ((int64_t) cluster_offset < 0) {
|
|
|
|
return cluster_offset;
|
|
|
|
}
|
2009-01-08 20:29:03 +01:00
|
|
|
if (allocate == 1) {
|
|
|
|
/* round to cluster size */
|
2017-08-09 22:38:06 +02: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,
|
2020-04-24 14:54:40 +02:00
|
|
|
false, PREALLOC_MODE_OFF, 0, NULL);
|
2017-08-09 22:38:06 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-08 20:29:03 +01: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-12 18:09:18 +02:00
|
|
|
if (bs->encrypted &&
|
2018-06-28 22:15:19 +02:00
|
|
|
(n_end - n_start) < s->cluster_size) {
|
|
|
|
uint64_t start_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-23 18:24:08 +02:00
|
|
|
assert(s->crypto);
|
2018-06-28 22:15:19 +02:00
|
|
|
start_offset = offset & ~(s->cluster_size - 1);
|
|
|
|
for (i = 0; i < s->cluster_size; i += BDRV_SECTOR_SIZE) {
|
2009-01-08 20:29:03 +01:00
|
|
|
if (i < n_start || i >= n_end) {
|
2018-06-28 22:15:19 +02:00
|
|
|
memset(s->cluster_data, 0x00, BDRV_SECTOR_SIZE);
|
2017-09-27 14:53:39 +02:00
|
|
|
if (qcrypto_block_encrypt(s->crypto,
|
2018-06-28 22:15:19 +02:00
|
|
|
start_offset + i,
|
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-23 18:24:08 +02:00
|
|
|
s->cluster_data,
|
|
|
|
BDRV_SECTOR_SIZE,
|
2017-08-29 14:08:36 +02:00
|
|
|
NULL) < 0) {
|
2017-08-09 22:38:05 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = bdrv_pwrite(bs->file,
|
2018-06-28 22:15:19 +02:00
|
|
|
cluster_offset + i,
|
|
|
|
s->cluster_data,
|
|
|
|
BDRV_SECTOR_SIZE);
|
2017-08-09 22:38:05 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2015-07-01 19:10:37 +02:00
|
|
|
}
|
2009-01-08 20:29:03 +01:00
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
}
|
2009-01-08 20:29:03 +01:00
|
|
|
} else if (allocate == 2) {
|
|
|
|
cluster_offset |= QCOW_OFLAG_COMPRESSED |
|
|
|
|
(uint64_t)compressed_size << (63 - s->cluster_bits);
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* update L2 table */
|
|
|
|
tmp = cpu_to_be64(cluster_offset);
|
|
|
|
l2_table[l2_index] = tmp;
|
2017-11-23 03:08:18 +01:00
|
|
|
if (allocate == 2) {
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
|
|
|
|
} else {
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
|
|
|
|
}
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
|
|
|
|
&tmp, sizeof(tmp));
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2017-08-09 22:38:05 +02:00
|
|
|
*result = cluster_offset;
|
|
|
|
return 1;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
|
2018-02-13 21:26:51 +01: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-01 23:59:26 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2018-02-13 21:26:51 +01:00
|
|
|
int index_in_cluster, ret;
|
|
|
|
int64_t n;
|
2004-08-01 23:59:26 +02:00
|
|
|
uint64_t cluster_offset;
|
|
|
|
|
2011-11-14 13:44:21 +01:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2018-02-13 21:26:51 +01:00
|
|
|
ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
|
2011-11-14 13:44:21 +01:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-08-09 22:38:05 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-13 21:26:51 +01:00
|
|
|
index_in_cluster = offset & (s->cluster_size - 1);
|
|
|
|
n = s->cluster_size - index_in_cluster;
|
|
|
|
if (n > bytes) {
|
|
|
|
n = bytes;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
*pnum = n;
|
2013-09-04 19:00:30 +02: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-23 18:24:08 +02:00
|
|
|
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
|
2013-09-04 19:00:30 +02:00
|
|
|
return BDRV_BLOCK_DATA;
|
|
|
|
}
|
2018-02-13 21:26:51 +01:00
|
|
|
*map = cluster_offset | index_in_cluster;
|
2016-01-26 04:58:49 +01:00
|
|
|
*file = bs->file->bs;
|
2018-02-13 21:26:51 +01:00
|
|
|
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
|
2004-08-01 23:59:26 +02: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 10:09:54 +02:00
|
|
|
|
2010-04-14 14:17:38 +02:00
|
|
|
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
2004-08-01 23:59:26 +02:00
|
|
|
{
|
2010-04-14 14:17:38 +02:00
|
|
|
BDRVQcowState *s = bs->opaque;
|
2004-08-01 23:59:26 +02: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 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
|
2016-06-20 18:24:02 +02:00
|
|
|
ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
|
2007-09-16 23:08:06 +02:00
|
|
|
if (ret != csize)
|
2004-08-01 23:59:26 +02: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;
|
|
|
|
}
|
|
|
|
|
2018-06-28 22:15:22 +02:00
|
|
|
static void qcow_refresh_limits(BlockDriverState *bs, Error **errp)
|
|
|
|
{
|
|
|
|
/* At least encrypted images require 512-byte alignment. Apply the
|
|
|
|
* limit universally, rather than just on encrypted images, as
|
|
|
|
* it's easier to let the block layer handle rounding than to
|
|
|
|
* audit this code further. */
|
|
|
|
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
|
|
|
|
}
|
|
|
|
|
block: use int64_t instead of uint64_t in driver read handlers
We are generally moving to int64_t for both offset and bytes parameters
on all io paths.
Main motivation is realization of 64-bit write_zeroes operation for
fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
So, convert driver read handlers parameters which are already 64bit to
signed type.
While being here, convert also flags parameter to be BdrvRequestFlags.
Now let's consider all callers. Simple
git grep '\->bdrv_\(aio\|co\)_preadv\(_part\)\?'
shows that's there three callers of driver function:
bdrv_driver_preadv() in block/io.c, passes int64_t, checked by
bdrv_check_qiov_request() to be non-negative.
qcow2_load_vmstate() does bdrv_check_qiov_request().
do_perform_cow_read() has uint64_t argument. And a lot of things in
qcow2 driver are uint64_t, so converting it is big job. But we must
not work with requests that don't satisfy bdrv_check_qiov_request(),
so let's just assert it here.
Still, the functions may be called directly, not only by drv->...
Let's check:
git grep '\.bdrv_\(aio\|co\)_preadv\(_part\)\?\s*=' | \
awk '{print $4}' | sed 's/,//' | sed 's/&//' | sort | uniq | \
while read func; do git grep "$func(" | \
grep -v "$func(BlockDriverState"; done
The only one such caller:
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1);
...
ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
in tests/unit/test-bdrv-drain.c, and it's OK obviously.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20210903102807.27127-4-vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: fix typos]
Signed-off-by: Eric Blake <eblake@redhat.com>
2021-09-03 12:27:59 +02:00
|
|
|
static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
|
|
|
|
int64_t bytes, QEMUIOVector *qiov,
|
|
|
|
BdrvRequestFlags flags)
|
2006-08-01 18:21:11 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2018-06-28 22:15:20 +02:00
|
|
|
int offset_in_cluster;
|
2011-08-23 15:21:11 +02:00
|
|
|
int ret = 0, n;
|
2011-08-23 15:21:10 +02:00
|
|
|
uint64_t cluster_offset;
|
2011-08-23 15:21:11 +02:00
|
|
|
uint8_t *buf;
|
|
|
|
void *orig_buf;
|
2006-08-01 18:21:11 +02:00
|
|
|
|
2018-06-28 22:15:22 +02:00
|
|
|
assert(!flags);
|
2011-08-23 15:21:11 +02:00
|
|
|
if (qiov->niov > 1) {
|
2014-05-20 13:36:05 +02:00
|
|
|
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
|
|
|
if (buf == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2011-08-23 15:21:11 +02:00
|
|
|
} else {
|
|
|
|
orig_buf = NULL;
|
|
|
|
buf = (uint8_t *)qiov->iov->iov_base;
|
2006-08-01 18:21:11 +02:00
|
|
|
}
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2011-08-23 15:21:11 +02:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
|
2018-06-28 22:15:20 +02:00
|
|
|
while (bytes != 0) {
|
2011-08-23 15:21:11 +02:00
|
|
|
/* prepare next request */
|
2018-06-28 22:15:20 +02:00
|
|
|
ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
|
2017-08-09 22:38:05 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2018-06-28 22:15:20 +02:00
|
|
|
offset_in_cluster = offset & (s->cluster_size - 1);
|
|
|
|
n = s->cluster_size - offset_in_cluster;
|
|
|
|
if (n > bytes) {
|
|
|
|
n = bytes;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2006-08-07 04:38:06 +02:00
|
|
|
|
2011-08-23 15:21:11 +02:00
|
|
|
if (!cluster_offset) {
|
2015-06-17 14:55:21 +02:00
|
|
|
if (bs->backing) {
|
2011-08-23 15:21:11 +02:00
|
|
|
/* read from the base image */
|
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 03:08:18 +01:00
|
|
|
/* qcow2 emits this on bs->file instead of bs->backing */
|
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
|
2019-04-22 16:58:32 +02:00
|
|
|
ret = bdrv_co_pread(bs->backing, offset, n, buf, 0);
|
2011-08-23 15:21:11 +02:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
2017-08-09 22:38:05 +02:00
|
|
|
break;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Note: in this case, no need to wait */
|
2018-06-28 22:15:20 +02:00
|
|
|
memset(buf, 0, n);
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
|
|
|
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
|
|
|
|
/* add AIO support for compressed blocks ? */
|
|
|
|
if (decompress_cluster(bs, cluster_offset) < 0) {
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2018-06-28 22:15:20 +02:00
|
|
|
memcpy(buf, s->cluster_cache + offset_in_cluster, n);
|
2011-08-23 15:21:11 +02:00
|
|
|
} else {
|
|
|
|
if ((cluster_offset & 511) != 0) {
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2011-07-15 16:27:42 +02:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
|
2019-04-22 16:58:32 +02:00
|
|
|
ret = bdrv_co_pread(bs->file, cluster_offset + offset_in_cluster,
|
|
|
|
n, buf, 0);
|
2011-07-15 16:27:42 +02:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
2011-08-23 15:21:11 +02: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-12 18:09:18 +02: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-23 18:24:08 +02:00
|
|
|
assert(s->crypto);
|
2017-09-27 14:53:39 +02:00
|
|
|
if (qcrypto_block_decrypt(s->crypto,
|
2018-06-28 22:15:20 +02:00
|
|
|
offset, buf, n, NULL) < 0) {
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
2015-07-01 19:10:37 +02:00
|
|
|
}
|
2011-02-19 22:18:12 +01:00
|
|
|
}
|
|
|
|
}
|
2011-08-23 15:21:11 +02:00
|
|
|
ret = 0;
|
2009-04-07 20:43:24 +02:00
|
|
|
|
2018-06-28 22:15:20 +02:00
|
|
|
bytes -= n;
|
|
|
|
offset += n;
|
|
|
|
buf += n;
|
2011-08-23 15:21:10 +02:00
|
|
|
}
|
|
|
|
|
2011-07-15 16:27:42 +02:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
|
|
|
|
2011-08-23 15:21:11 +02: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-07 18:17:55 +02:00
|
|
|
qemu_iovec_from_buf(qiov, 0, orig_buf, qiov->size);
|
2011-08-23 15:21:11 +02:00
|
|
|
qemu_vfree(orig_buf);
|
2011-06-07 15:20:44 +02:00
|
|
|
}
|
|
|
|
|
2011-07-15 16:27:42 +02:00
|
|
|
return ret;
|
2006-08-01 18:21:11 +02:00
|
|
|
}
|
|
|
|
|
block: use int64_t instead of uint64_t in driver write handlers
We are generally moving to int64_t for both offset and bytes parameters
on all io paths.
Main motivation is realization of 64-bit write_zeroes operation for
fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
So, convert driver write handlers parameters which are already 64bit to
signed type.
While being here, convert also flags parameter to be BdrvRequestFlags.
Now let's consider all callers. Simple
git grep '\->bdrv_\(aio\|co\)_pwritev\(_part\)\?'
shows that's there three callers of driver function:
bdrv_driver_pwritev() and bdrv_driver_pwritev_compressed() in
block/io.c, both pass int64_t, checked by bdrv_check_qiov_request() to
be non-negative.
qcow2_save_vmstate() does bdrv_check_qiov_request().
Still, the functions may be called directly, not only by drv->...
Let's check:
git grep '\.bdrv_\(aio\|co\)_pwritev\(_part\)\?\s*=' | \
awk '{print $4}' | sed 's/,//' | sed 's/&//' | sort | uniq | \
while read func; do git grep "$func(" | \
grep -v "$func(BlockDriverState"; done
shows several callers:
qcow2:
qcow2_co_truncate() write at most up to @offset, which is checked in
generic qcow2_co_truncate() by bdrv_check_request().
qcow2_co_pwritev_compressed_task() pass the request (or part of the
request) that already went through normal write path, so it should
be OK
qcow:
qcow_co_pwritev_compressed() pass int64_t, it's updated by this patch
quorum:
quorum_co_pwrite_zeroes() pass int64_t and int - OK
throttle:
throttle_co_pwritev_compressed() pass int64_t, it's updated by this
patch
vmdk:
vmdk_co_pwritev_compressed() pass int64_t, it's updated by this
patch
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20210903102807.27127-5-vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2021-09-03 12:28:00 +02:00
|
|
|
static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset,
|
|
|
|
int64_t bytes, QEMUIOVector *qiov,
|
|
|
|
BdrvRequestFlags flags)
|
2006-08-01 18:21:11 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2018-06-28 22:15:21 +02:00
|
|
|
int offset_in_cluster;
|
2006-08-01 18:21:11 +02:00
|
|
|
uint64_t cluster_offset;
|
2011-08-23 15:21:11 +02:00
|
|
|
int ret = 0, n;
|
|
|
|
uint8_t *buf;
|
|
|
|
void *orig_buf;
|
2006-08-07 04:38:06 +02:00
|
|
|
|
2018-04-25 00:01:57 +02:00
|
|
|
assert(!flags);
|
2011-08-23 15:21:11 +02:00
|
|
|
s->cluster_cache_offset = -1; /* disable compressed cache */
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2017-06-23 18:24:07 +02: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 13:36:05 +02:00
|
|
|
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
|
|
|
|
if (buf == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2012-06-07 18:21:06 +02:00
|
|
|
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
|
2006-08-01 18:21:11 +02:00
|
|
|
} else {
|
2011-08-23 15:21:11 +02:00
|
|
|
orig_buf = NULL;
|
|
|
|
buf = (uint8_t *)qiov->iov->iov_base;
|
2006-08-01 18:21:11 +02:00
|
|
|
}
|
2009-04-07 20:43:20 +02:00
|
|
|
|
2011-07-15 16:27:42 +02:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2011-08-23 15:21:10 +02:00
|
|
|
|
2018-06-28 22:15:21 +02:00
|
|
|
while (bytes != 0) {
|
|
|
|
offset_in_cluster = offset & (s->cluster_size - 1);
|
|
|
|
n = s->cluster_size - offset_in_cluster;
|
|
|
|
if (n > bytes) {
|
|
|
|
n = bytes;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2018-06-28 22:15:21 +02:00
|
|
|
ret = get_cluster_offset(bs, offset, 1, 0, offset_in_cluster,
|
|
|
|
offset_in_cluster + n, &cluster_offset);
|
2017-08-09 22:38:05 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
2011-08-23 15:21:11 +02: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-12 18:09:18 +02: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-23 18:24:08 +02:00
|
|
|
assert(s->crypto);
|
2018-06-28 22:15:21 +02:00
|
|
|
if (qcrypto_block_encrypt(s->crypto, offset, buf, n, NULL) < 0) {
|
2015-07-01 19:10:37 +02:00
|
|
|
ret = -EIO;
|
|
|
|
break;
|
|
|
|
}
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2006-08-01 18:21:11 +02:00
|
|
|
|
2011-08-23 15:21:11 +02:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
|
2019-04-22 16:58:32 +02:00
|
|
|
ret = bdrv_co_pwrite(bs->file, cluster_offset + offset_in_cluster,
|
|
|
|
n, buf, 0);
|
2011-08-23 15:21:11 +02:00
|
|
|
qemu_co_mutex_lock(&s->lock);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = 0;
|
2009-05-25 15:45:37 +02:00
|
|
|
|
2018-06-28 22:15:21 +02:00
|
|
|
bytes -= n;
|
|
|
|
offset += n;
|
|
|
|
buf += n;
|
2011-08-23 15:21:11 +02:00
|
|
|
}
|
2011-07-15 16:27:42 +02:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2017-06-23 18:24:07 +02:00
|
|
|
qemu_vfree(orig_buf);
|
2011-06-07 15:20:44 +02:00
|
|
|
|
2011-07-15 16:27:42 +02:00
|
|
|
return ret;
|
2006-08-01 18:21:11 +02:00
|
|
|
}
|
|
|
|
|
2004-09-18 21:32:11 +02:00
|
|
|
static void qcow_close(BlockDriverState *bs)
|
2004-08-01 23:59:26 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
2011-11-22 16:44:45 +01: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-23 18:24:08 +02:00
|
|
|
qcrypto_block_free(s->crypto);
|
|
|
|
s->crypto = NULL;
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(s->l1_table);
|
2014-05-20 13:36:05 +02:00
|
|
|
qemu_vfree(s->l2_cache);
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(s->cluster_cache);
|
|
|
|
g_free(s->cluster_data);
|
2011-11-22 16:44:45 +01:00
|
|
|
|
|
|
|
migrate_del_blocker(s->migration_blocker);
|
|
|
|
error_free(s->migration_blocker);
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
|
|
|
|
Error **errp)
|
2004-08-01 23:59:26 +02:00
|
|
|
{
|
2018-03-09 19:53:19 +01:00
|
|
|
BlockdevCreateOptionsQcow *qcow_opts;
|
2011-11-21 08:40:39 +01:00
|
|
|
int header_size, backing_filename_len, l1_size, shift, i;
|
2004-08-01 23:59:26 +02:00
|
|
|
QCowHeader header;
|
2011-11-21 08:40:39 +01:00
|
|
|
uint8_t *tmp;
|
2009-05-18 16:42:10 +02:00
|
|
|
int64_t total_size = 0;
|
2010-01-20 00:56:12 +01:00
|
|
|
int ret;
|
2018-03-09 19:53:19 +01:00
|
|
|
BlockDriverState *bs;
|
2016-03-08 15:57:05 +01: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-23 18:24:08 +02:00
|
|
|
QCryptoBlock *crypto = NULL;
|
2009-05-18 16:42:10 +02:00
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
assert(opts->driver == BLOCKDEV_DRIVER_QCOW);
|
|
|
|
qcow_opts = &opts->u.qcow;
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
total_size = qcow_opts->size;
|
2017-06-23 18:24:03 +02:00
|
|
|
if (total_size == 0) {
|
|
|
|
error_setg(errp, "Image size is too small, cannot be zero length");
|
2018-03-09 19:53:19 +01:00
|
|
|
return -EINVAL;
|
2017-06-23 18:24:03 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 19:53:19 +01: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 16:42:10 +02:00
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
|
2018-03-09 19:53:19 +01: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 08:40:39 +01:00
|
|
|
}
|
|
|
|
|
2020-04-28 21:26:46 +02:00
|
|
|
qcow_blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE,
|
|
|
|
BLK_PERM_ALL, errp);
|
|
|
|
if (!qcow_blk) {
|
|
|
|
ret = -EPERM;
|
2018-03-09 19:53:19 +01:00
|
|
|
goto exit;
|
2011-11-21 08:40:39 +01:00
|
|
|
}
|
2016-03-08 15:57:05 +01:00
|
|
|
blk_set_allow_write_beyond_eof(qcow_blk, true);
|
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
/* Create image format */
|
2004-08-01 23:59:26 +02:00
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
header.magic = cpu_to_be32(QCOW_MAGIC);
|
|
|
|
header.version = cpu_to_be32(QCOW_VERSION);
|
2014-09-10 11:05:46 +02:00
|
|
|
header.size = cpu_to_be64(total_size);
|
2004-08-01 23:59:26 +02:00
|
|
|
header_size = sizeof(header);
|
|
|
|
backing_filename_len = 0;
|
2018-03-09 19:53:19 +01:00
|
|
|
if (qcow_opts->has_backing_file) {
|
|
|
|
if (strcmp(qcow_opts->backing_file, "fat:")) {
|
2008-03-18 07:52:48 +01:00
|
|
|
header.backing_file_offset = cpu_to_be64(header_size);
|
2018-03-09 19:53:19 +01:00
|
|
|
backing_filename_len = strlen(qcow_opts->backing_file);
|
2008-03-18 07:52:48 +01:00
|
|
|
header.backing_file_size = cpu_to_be32(backing_filename_len);
|
|
|
|
header_size += backing_filename_len;
|
|
|
|
} else {
|
|
|
|
/* special backing file for vvfat */
|
2018-03-09 19:53:19 +01:00
|
|
|
qcow_opts->has_backing_file = false;
|
2008-03-18 07:52:48 +01:00
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
|
2014-03-24 09:30:17 +01:00
|
|
|
unmodified sectors */
|
2004-08-01 23:59:26 +02: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 11:05:46 +02:00
|
|
|
l1_size = (total_size + (1LL << shift) - 1) >> shift;
|
2004-08-01 23:59:26 +02: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-23 18:24:08 +02:00
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
if (qcow_opts->has_encrypt) {
|
2004-08-01 23:59:26 +02: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-23 18:24:08 +02:00
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.",
|
2017-06-23 18:24:17 +02: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-23 18:24:08 +02:00
|
|
|
if (!crypto) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
} else {
|
|
|
|
header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
|
|
|
|
}
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2004-08-01 23:59:26 +02:00
|
|
|
/* write all the data */
|
2016-05-06 18:26:27 +02:00
|
|
|
ret = blk_pwrite(qcow_blk, 0, &header, sizeof(header), 0);
|
2010-01-20 00:56:12 +01:00
|
|
|
if (ret != sizeof(header)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
if (qcow_opts->has_backing_file) {
|
2016-03-08 15:57:05 +01:00
|
|
|
ret = blk_pwrite(qcow_blk, sizeof(header),
|
2018-03-09 19:53:19 +01:00
|
|
|
qcow_opts->backing_file, backing_filename_len, 0);
|
2010-01-20 00:56:12 +01:00
|
|
|
if (ret != backing_filename_len) {
|
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2011-11-21 08:40:39 +01:00
|
|
|
|
|
|
|
tmp = g_malloc0(BDRV_SECTOR_SIZE);
|
2016-05-31 18:35:52 +02:00
|
|
|
for (i = 0; i < DIV_ROUND_UP(sizeof(uint64_t) * l1_size, BDRV_SECTOR_SIZE);
|
|
|
|
i++) {
|
2016-05-06 18:26:27 +02:00
|
|
|
ret = blk_pwrite(qcow_blk, header_size + BDRV_SECTOR_SIZE * i,
|
|
|
|
tmp, BDRV_SECTOR_SIZE, 0);
|
2011-11-21 08:40:39 +01:00
|
|
|
if (ret != BDRV_SECTOR_SIZE) {
|
|
|
|
g_free(tmp);
|
2010-01-20 00:56:12 +01:00
|
|
|
goto exit;
|
|
|
|
}
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2010-01-20 00:56:12 +01:00
|
|
|
|
2011-11-21 08:40:39 +01:00
|
|
|
g_free(tmp);
|
2010-01-20 00:56:12 +01:00
|
|
|
ret = 0;
|
|
|
|
exit:
|
2016-03-08 15:57:05 +01:00
|
|
|
blk_unref(qcow_blk);
|
2018-07-25 20:07:29 +02:00
|
|
|
bdrv_unref(bs);
|
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-23 18:24:08 +02:00
|
|
|
qcrypto_block_free(crypto);
|
2018-03-09 19:53:19 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-26 02:12:17 +01:00
|
|
|
static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
|
|
|
|
const char *filename,
|
2018-03-09 19:53:19 +01:00
|
|
|
QemuOpts *opts, Error **errp)
|
|
|
|
{
|
|
|
|
BlockdevCreateOptions *create_options = NULL;
|
|
|
|
BlockDriverState *bs = NULL;
|
qcow: Tolerate backing_fmt=
qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference. On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).
Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing. This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe. With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.
Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.
Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 22:39:49 +02:00
|
|
|
QDict *qdict = NULL;
|
2018-03-09 19:53:19 +01:00
|
|
|
Visitor *v;
|
|
|
|
const char *val;
|
|
|
|
int ret;
|
qcow: Tolerate backing_fmt=
qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference. On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).
Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing. This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe. With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.
Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.
Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 22:39:49 +02:00
|
|
|
char *backing_fmt;
|
2018-03-09 19:53:19 +01:00
|
|
|
|
|
|
|
static const QDictRenames opt_renames[] = {
|
|
|
|
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
|
|
|
|
{ BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
|
qcow: Tolerate backing_fmt=
qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference. On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).
Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing. This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe. With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.
Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.
Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 22:39:49 +02:00
|
|
|
/*
|
|
|
|
* We can't actually store a backing format, but can check that
|
|
|
|
* the user's request made sense.
|
|
|
|
*/
|
|
|
|
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
|
|
|
|
if (backing_fmt && !bdrv_find_format(backing_fmt)) {
|
|
|
|
error_setg(errp, "unrecognized backing format '%s'", backing_fmt);
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2018-03-09 19:53:19 +01:00
|
|
|
/* 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) */
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 18:06:02 +02:00
|
|
|
ret = bdrv_create_file(filename, opts, errp);
|
2018-03-09 19:53:19 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
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);
|
|
|
|
|
2018-06-14 21:14:33 +02:00
|
|
|
v = qobject_input_visitor_new_flat_confused(qdict, errp);
|
|
|
|
if (!v) {
|
2018-03-09 19:53:19 +01:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:06:07 +02:00
|
|
|
visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp);
|
2018-03-09 19:53:19 +01:00
|
|
|
visit_free(v);
|
2020-07-07 18:06:07 +02:00
|
|
|
if (!create_options) {
|
2018-03-09 19:53:19 +01:00
|
|
|
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:
|
qcow: Tolerate backing_fmt=
qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference. On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).
Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing. This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe. With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.
Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.
Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 22:39:49 +02:00
|
|
|
g_free(backing_fmt);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(qdict);
|
2018-03-09 19:53:19 +01:00
|
|
|
bdrv_unref(bs);
|
|
|
|
qapi_free_BlockdevCreateOptions(create_options);
|
2010-01-20 00:56:12 +01:00
|
|
|
return ret;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
|
2006-08-05 23:32:10 +02:00
|
|
|
static int qcow_make_empty(BlockDriverState *bs)
|
2005-12-18 19:28:15 +01:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
|
2006-08-01 18:21:11 +02:00
|
|
|
int ret;
|
2005-12-18 19:28:15 +01:00
|
|
|
|
|
|
|
memset(s->l1_table, 0, l1_length);
|
2016-06-20 20:09:15 +02:00
|
|
|
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
|
2010-06-18 16:11:53 +02:00
|
|
|
l1_length) < 0)
|
|
|
|
return -1;
|
2019-09-18 11:51:40 +02:00
|
|
|
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
|
2020-04-24 14:54:40 +02:00
|
|
|
PREALLOC_MODE_OFF, 0, NULL);
|
2006-08-01 18:21:11 +02:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2005-12-18 19:28:15 +01: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-01 23:59:26 +02:00
|
|
|
/* XXX: put compressed sectors first, then all the cluster aligned
|
|
|
|
tables to avoid losing bytes in alignment */
|
2016-07-22 10:17:46 +02:00
|
|
|
static coroutine_fn int
|
block: use int64_t instead of uint64_t in driver write handlers
We are generally moving to int64_t for both offset and bytes parameters
on all io paths.
Main motivation is realization of 64-bit write_zeroes operation for
fast zeroing large disk chunks, up to the whole disk.
We chose signed type, to be consistent with off_t (which is signed) and
with possibility for signed return type (where negative value means
error).
So, convert driver write handlers parameters which are already 64bit to
signed type.
While being here, convert also flags parameter to be BdrvRequestFlags.
Now let's consider all callers. Simple
git grep '\->bdrv_\(aio\|co\)_pwritev\(_part\)\?'
shows that's there three callers of driver function:
bdrv_driver_pwritev() and bdrv_driver_pwritev_compressed() in
block/io.c, both pass int64_t, checked by bdrv_check_qiov_request() to
be non-negative.
qcow2_save_vmstate() does bdrv_check_qiov_request().
Still, the functions may be called directly, not only by drv->...
Let's check:
git grep '\.bdrv_\(aio\|co\)_pwritev\(_part\)\?\s*=' | \
awk '{print $4}' | sed 's/,//' | sed 's/&//' | sort | uniq | \
while read func; do git grep "$func(" | \
grep -v "$func(BlockDriverState"; done
shows several callers:
qcow2:
qcow2_co_truncate() write at most up to @offset, which is checked in
generic qcow2_co_truncate() by bdrv_check_request().
qcow2_co_pwritev_compressed_task() pass the request (or part of the
request) that already went through normal write path, so it should
be OK
qcow:
qcow_co_pwritev_compressed() pass int64_t, it's updated by this patch
quorum:
quorum_co_pwrite_zeroes() pass int64_t and int - OK
throttle:
throttle_co_pwritev_compressed() pass int64_t, it's updated by this
patch
vmdk:
vmdk_co_pwritev_compressed() pass int64_t, it's updated by this
patch
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20210903102807.27127-5-vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2021-09-03 12:28:00 +02:00
|
|
|
qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
|
|
|
QEMUIOVector *qiov)
|
2004-08-01 23:59:26 +02:00
|
|
|
{
|
|
|
|
BDRVQcowState *s = bs->opaque;
|
|
|
|
z_stream strm;
|
|
|
|
int ret, out_len;
|
2016-07-22 10:17:46 +02:00
|
|
|
uint8_t *buf, *out_buf;
|
2004-08-01 23:59:26 +02:00
|
|
|
uint64_t cluster_offset;
|
|
|
|
|
2016-07-22 10:17:47 +02:00
|
|
|
buf = qemu_blockalign(bs, s->cluster_size);
|
2016-07-22 10:17:46 +02:00
|
|
|
if (bytes != s->cluster_size) {
|
2016-07-22 10:17:47 +02:00
|
|
|
if (bytes > s->cluster_size ||
|
|
|
|
offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
|
2016-07-22 10:17:46 +02:00
|
|
|
{
|
2016-07-22 10:17:47 +02:00
|
|
|
qemu_vfree(buf);
|
|
|
|
return -EINVAL;
|
2013-04-15 17:17:32 +02:00
|
|
|
}
|
2016-07-22 10:17:47 +02:00
|
|
|
/* Zero-pad last write if image size is not cluster aligned */
|
|
|
|
memset(buf + bytes, 0, s->cluster_size - bytes);
|
2013-04-15 17:17:32 +02:00
|
|
|
}
|
2016-07-22 10:17:46 +02:00
|
|
|
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
|
2004-08-01 23:59:26 +02:00
|
|
|
|
2016-07-14 18:59:25 +02:00
|
|
|
out_buf = g_malloc(s->cluster_size);
|
2004-08-01 23:59:26 +02:00
|
|
|
|
|
|
|
/* best compression, small window, no zlib header */
|
|
|
|
memset(&strm, 0, sizeof(strm));
|
|
|
|
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
|
2007-09-16 23:08:06 +02:00
|
|
|
Z_DEFLATED, -12,
|
2004-08-01 23:59:26 +02:00
|
|
|
9, Z_DEFAULT_STRATEGY);
|
|
|
|
if (ret != 0) {
|
2011-10-26 11:21:50 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2004-08-01 23:59:26 +02: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 11:21:50 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto fail;
|
2004-08-01 23:59:26 +02: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 */
|
2018-06-28 22:15:22 +02:00
|
|
|
ret = qcow_co_pwritev(bs, offset, bytes, qiov, 0);
|
2011-10-26 11:21:50 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2016-07-22 10:17:46 +02:00
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
qemu_co_mutex_lock(&s->lock);
|
2017-08-09 22:38:05 +02:00
|
|
|
ret = get_cluster_offset(bs, offset, 2, out_len, 0, 0, &cluster_offset);
|
2016-07-22 10:17:46 +02:00
|
|
|
qemu_co_mutex_unlock(&s->lock);
|
2017-08-09 22:38:05 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-07-22 10:17:46 +02:00
|
|
|
if (cluster_offset == 0) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto fail;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
2016-07-22 10:17:46 +02:00
|
|
|
cluster_offset &= s->cluster_offset_mask;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2017-11-23 03:08:18 +01:00
|
|
|
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
|
2019-04-22 16:58:32 +02:00
|
|
|
ret = bdrv_co_pwrite(bs->file, cluster_offset, out_len, out_buf, 0);
|
2016-07-22 10:17:46 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
success:
|
2011-10-26 11:21:50 +02:00
|
|
|
ret = 0;
|
|
|
|
fail:
|
2016-07-22 10:17:46 +02:00
|
|
|
qemu_vfree(buf);
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(out_buf);
|
2011-10-26 11:21:50 +02:00
|
|
|
return ret;
|
2004-08-01 23:59:26 +02:00
|
|
|
}
|
|
|
|
|
2006-08-05 23:32:10 +02: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 11:20:57 +02: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"
|
|
|
|
},
|
qcow: Tolerate backing_fmt=
qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference. On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).
Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing. This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe. With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.
Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.
Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-07-06 22:39:49 +02:00
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_BACKING_FMT,
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
.help = "Format of the backing image",
|
|
|
|
},
|
2014-06-05 11:20:57 +02:00
|
|
|
{
|
|
|
|
.name = BLOCK_OPT_ENCRYPT,
|
|
|
|
.type = QEMU_OPT_BOOL,
|
2017-06-23 18:24:06 +02: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 11:20:57 +02: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-23 18:24:08 +02:00
|
|
|
BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."),
|
2014-06-05 11:20:57 +02:00
|
|
|
{ /* end of list */ }
|
|
|
|
}
|
2009-05-18 16:42:10 +02:00
|
|
|
};
|
|
|
|
|
2019-02-01 20:29:25 +01:00
|
|
|
static const char *const qcow_strong_runtime_opts[] = {
|
|
|
|
"encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET,
|
|
|
|
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2009-05-10 00:03:42 +02:00
|
|
|
static BlockDriver bdrv_qcow = {
|
2009-03-07 23:00:29 +01:00
|
|
|
.format_name = "qcow",
|
|
|
|
.instance_size = sizeof(BDRVQcowState),
|
|
|
|
.bdrv_probe = qcow_probe,
|
|
|
|
.bdrv_open = qcow_open,
|
|
|
|
.bdrv_close = qcow_close,
|
2020-05-13 13:05:39 +02:00
|
|
|
.bdrv_child_perm = bdrv_default_perms,
|
2014-06-05 11:20:57 +02:00
|
|
|
.bdrv_reopen_prepare = qcow_reopen_prepare,
|
2018-03-09 19:53:19 +01:00
|
|
|
.bdrv_co_create = qcow_co_create,
|
2018-01-18 13:43:45 +01:00
|
|
|
.bdrv_co_create_opts = qcow_co_create_opts,
|
2013-06-28 12:47:42 +02:00
|
|
|
.bdrv_has_zero_init = bdrv_has_zero_init_1,
|
2020-05-13 13:05:12 +02:00
|
|
|
.is_format = true,
|
2014-06-04 15:09:35 +02:00
|
|
|
.supports_backing = true,
|
2018-06-28 22:15:22 +02:00
|
|
|
.bdrv_refresh_limits = qcow_refresh_limits,
|
2011-11-10 17:25:44 +01:00
|
|
|
|
2018-06-28 22:15:22 +02:00
|
|
|
.bdrv_co_preadv = qcow_co_preadv,
|
|
|
|
.bdrv_co_pwritev = qcow_co_pwritev,
|
2018-02-13 21:26:51 +01:00
|
|
|
.bdrv_co_block_status = qcow_co_block_status,
|
2011-11-10 17:25:44 +01:00
|
|
|
|
|
|
|
.bdrv_make_empty = qcow_make_empty,
|
2016-07-22 10:17:46 +02:00
|
|
|
.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,
|
2011-11-10 17:25:44 +01:00
|
|
|
.bdrv_get_info = qcow_get_info,
|
2009-05-18 16:42:10 +02:00
|
|
|
|
2014-06-05 11:20:57 +02:00
|
|
|
.create_opts = &qcow_create_opts,
|
2019-02-01 20:29:25 +01:00
|
|
|
.strong_runtime_opts = qcow_strong_runtime_opts,
|
2004-08-01 23:59:26 +02:00
|
|
|
};
|
2009-05-10 00:03:42 +02:00
|
|
|
|
|
|
|
static void bdrv_qcow_init(void)
|
|
|
|
{
|
|
|
|
bdrv_register(&bdrv_qcow);
|
|
|
|
}
|
|
|
|
|
|
|
|
block_init(bdrv_qcow_init);
|