aboutsummaryrefslogtreecommitdiff
path: root/block/qcow.c
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2015-05-12 17:09:18 +0100
committerKevin Wolf <kwolf@redhat.com>2015-05-22 17:08:01 +0200
commit8336aafae1451d54c81dd2b187b45f7c45d2428e (patch)
tree9522e81e80c456021576ad40e1e96b49d9284303 /block/qcow.c
parentaa4f592a1dd9aea5f5c36f6ff4b22b5bd208162a (diff)
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>
Diffstat (limited to 'block/qcow.c')
-rw-r--r--block/qcow.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/block/qcow.c b/block/qcow.c
index ab893284d2..911e59fd0b 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);
}