From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, qemu-block@nongnu.org
Subject: [Qemu-devel] [PATCH 1/5] qcow2/qcow: protect against uninitialized encryption key
Date: Tue, 12 May 2015 17:09:18 +0100 [thread overview]
Message-ID: <1431446962-9860-2-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1431446962-9860-1-git-send-email-berrange@redhat.com>
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 todo 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>
---
block/qcow.c | 10 +++++++---
block/qcow2-cluster.c | 3 ++-
block/qcow2.c | 18 ++++++++++++------
3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/block/qcow.c b/block/qcow.c
index ab89328..911e59f 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -269,6 +269,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
+ assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
@@ -411,9 +412,10 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
/* if encrypted, we must initialize the cluster
content which won't be written */
- if (s->crypt_method &&
+ if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
+ assert(s->crypt_method);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
@@ -590,7 +592,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
if (ret < 0) {
break;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
encrypt_sectors(s, sector_num, buf, buf,
n, 0,
&s->aes_decrypt_key);
@@ -661,7 +664,8 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
ret = -EIO;
break;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
if (!cluster_data) {
cluster_data = g_malloc0(s->cluster_size);
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index ed2b44d..2d7777d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -403,7 +403,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
goto out;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
qcow2_encrypt_sectors(s, start_sect + n_start,
iov.iov_base, iov.iov_base, n, 1,
&s->aes_encrypt_key);
diff --git a/block/qcow2.c b/block/qcow2.c
index b9a72e3..f7b4cc6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1037,6 +1037,7 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
for(i = 0;i < len;i++) {
keybuf[i] = key[i];
}
+ assert(bs->encrypted);
s->crypt_method = s->crypt_method_header;
if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
@@ -1224,7 +1225,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
goto fail;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
+
/*
* For encrypted images, read everything into a temporary
* contiguous buffer on which the AES functions can work.
@@ -1255,7 +1258,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
if (ret < 0) {
goto fail;
}
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
qcow2_encrypt_sectors(s, sector_num, cluster_data,
cluster_data, cur_nr_sectors, 0, &s->aes_decrypt_key);
qemu_iovec_from_buf(qiov, bytes_done,
@@ -1315,7 +1319,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
trace_qcow2_writev_start_part(qemu_coroutine_self());
index_in_cluster = sector_num & (s->cluster_sectors - 1);
cur_nr_sectors = remaining_sectors;
- if (s->crypt_method &&
+ if (bs->encrypted &&
cur_nr_sectors >
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) {
cur_nr_sectors =
@@ -1334,7 +1338,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
qemu_iovec_concat(&hd_qiov, qiov, bytes_done,
cur_nr_sectors * 512);
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
if (!cluster_data) {
cluster_data = qemu_try_blockalign(bs->file,
QCOW_MAX_CRYPT_CLUSTERS
@@ -1484,7 +1489,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
* that means we don't have to worry about reopening them here.
*/
- if (s->crypt_method) {
+ if (bs->encrypted) {
+ assert(s->crypt_method);
crypt_method = s->crypt_method;
memcpy(&aes_encrypt_key, &s->aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&aes_decrypt_key, &s->aes_decrypt_key, sizeof(aes_decrypt_key));
@@ -1513,7 +1519,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
- if (crypt_method) {
+ if (bs->encrypted) {
s->crypt_method = crypt_method;
memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
memcpy(&s->aes_decrypt_key, &aes_decrypt_key, sizeof(aes_decrypt_key));
--
2.1.0
next prev parent reply other threads:[~2015-05-12 16:09 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-12 16:09 [Qemu-devel] [PATCH 0/5] Misc fixes and testing of qcow[2] encryption Daniel P. Berrange
2015-05-12 16:09 ` Daniel P. Berrange [this message]
2015-05-12 18:06 ` [Qemu-devel] [PATCH 1/5] qcow2/qcow: protect against uninitialized encryption key Eric Blake
2015-05-12 16:09 ` [Qemu-devel] [PATCH 2/5] util: move read_password method out of qemu-img into osdep/oslib Daniel P. Berrange
2015-05-12 18:22 ` Eric Blake
2015-05-12 16:09 ` [Qemu-devel] [PATCH 3/5] util: allow \n to terminate password input Daniel P. Berrange
2015-05-12 18:23 ` Eric Blake
2015-05-12 16:09 ` [Qemu-devel] [PATCH 4/5] qemu-io: prompt for encryption keys when required Daniel P. Berrange
2015-05-12 18:32 ` Eric Blake
2015-05-13 8:09 ` Daniel P. Berrange
2015-05-13 10:50 ` Markus Armbruster
2015-05-12 16:09 ` [Qemu-devel] [PATCH 5/5] tests: add test case for encrypted qcow2 read/write Daniel P. Berrange
2015-05-12 18:35 ` Eric Blake
2015-05-12 19:06 ` [Qemu-devel] [Qemu-block] " John Snow
2015-05-12 19:52 ` Eric Blake
2015-05-12 19:54 ` John Snow
2015-05-18 15:38 ` [Qemu-devel] [PATCH 0/5] Misc fixes and testing of qcow[2] encryption Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1431446962-9860-2-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.