Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into…
Browse files Browse the repository at this point in the history
… staging

Bugfixes and Daniel Berrange's crypto library.

# gpg: Signature made Wed Jul  8 12:12:29 2015 BST using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream:
  ossaudio: fix memory leak
  ui: convert VNC to use generic cipher API
  block: convert qcow/qcow2 to use generic cipher API
  ui: convert VNC websockets to use crypto APIs
  block: convert quorum blockdrv to use crypto APIs
  crypto: add a nettle cipher implementation
  crypto: add a gcrypt cipher implementation
  crypto: introduce generic cipher API & built-in implementation
  crypto: move built-in D3DES implementation into crypto/
  crypto: move built-in AES implementation into crypto/
  crypto: introduce new module for computing hash digests
  vl: move rom_load_all after machine init done

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jul 8, 2015
2 parents c8e8428 + 2828a30 commit acf7b7f
Show file tree
Hide file tree
Showing 41 changed files with 2,546 additions and 279 deletions.
7 changes: 7 additions & 0 deletions MAINTAINERS
Expand Up @@ -1052,6 +1052,13 @@ S: Supported
F: qemu-seccomp.c
F: include/sysemu/seccomp.h

Cryptography
M: Daniel P. Berrange <berrange@redhat.com>
S: Maintained
F: crypto/
F: include/crypto/
F: tests/test-crypto-*

Usermode Emulation
------------------
Overall
Expand Down
1 change: 1 addition & 0 deletions Makefile.objs
Expand Up @@ -2,6 +2,7 @@
# Common libraries for tools and emulators
stub-obj-y = stubs/
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
util-obj-y += crypto/

#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
Expand Down
1 change: 1 addition & 0 deletions audio/ossaudio.c
Expand Up @@ -853,6 +853,7 @@ static void *oss_audio_init (void)

if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
access(conf->devpath_out, R_OK | W_OK) < 0) {
g_free(conf);
return NULL;
}
return conf;
Expand Down
2 changes: 1 addition & 1 deletion block/Makefile.objs
Expand Up @@ -3,7 +3,7 @@ block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-c
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-$(CONFIG_QUORUM) += quorum.o
block-obj-y += quorum.o
block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
Expand Down
102 changes: 75 additions & 27 deletions block/qcow.c
Expand Up @@ -26,7 +26,7 @@
#include "qemu/module.h"
#include <zlib.h>
#include "qapi/qmp/qerror.h"
#include "qemu/aes.h"
#include "crypto/cipher.h"
#include "migration/migration.h"

/**************************************************************/
Expand Down Expand Up @@ -72,10 +72,8 @@ typedef struct BDRVQcowState {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
uint32_t crypt_method; /* current crypt method, 0 if no key yet */
QCryptoCipher *cipher; /* NULL if no key yet */
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
CoMutex lock;
Error *migration_blocker;
} BDRVQcowState;
Expand Down Expand Up @@ -154,6 +152,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL;
goto fail;
}
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
error_setg(errp, "AES cipher not available");
ret = -EINVAL;
goto fail;
}
s->crypt_method_header = header.crypt_method;
if (s->crypt_method_header) {
bs->encrypted = 1;
Expand Down Expand Up @@ -260,6 +263,7 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
BDRVQcowState *s = bs->opaque;
uint8_t keybuf[16];
int len, i;
Error *err;

memset(keybuf, 0, 16);
len = strlen(key);
Expand All @@ -271,38 +275,67 @@ static int qcow_set_key(BlockDriverState *bs, const char *key)
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)
return -1;
if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
qcrypto_cipher_free(s->cipher);
s->cipher = qcrypto_cipher_new(
QCRYPTO_CIPHER_ALG_AES_128,
QCRYPTO_CIPHER_MODE_CBC,
keybuf, G_N_ELEMENTS(keybuf),
&err);

if (!s->cipher) {
/* XXX would be nice if errors in this method could
* be properly propagate to the caller. Would need
* the bdrv_set_key() API signature to be fixed. */
error_free(err);
return -1;
}
return 0;
}

/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;

for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}

/* 'allocate' is:
Expand Down Expand Up @@ -416,15 +449,20 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
if (bs->encrypted &&
(n_end - n_start) < s->cluster_sectors) {
uint64_t start_sect;
assert(s->crypt_method);
assert(s->cipher);
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
memset(s->cluster_data + 512, 0x00, 512);
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1, 1,
&s->aes_encrypt_key);
Error *err = NULL;
if (encrypt_sectors(s, start_sect + i,
s->cluster_data,
s->cluster_data + 512, 1,
true, &err) < 0) {
error_free(err);
errno = EIO;
return -1;
}
if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
s->cluster_data, 512) != 512)
return -1;
Expand Down Expand Up @@ -464,7 +502,7 @@ static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
if (!cluster_offset) {
return 0;
}
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypt_method) {
if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->cipher) {
return BDRV_BLOCK_DATA;
}
cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS);
Expand Down Expand Up @@ -531,6 +569,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector hd_qiov;
uint8_t *buf;
void *orig_buf;
Error *err = NULL;

if (qiov->niov > 1) {
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
Expand Down Expand Up @@ -594,10 +633,11 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
assert(s->crypt_method);
encrypt_sectors(s, sector_num, buf, buf,
n, 0,
&s->aes_decrypt_key);
assert(s->cipher);
if (encrypt_sectors(s, sector_num, buf, buf,
n, false, &err) < 0) {
goto fail;
}
}
}
ret = 0;
Expand All @@ -618,6 +658,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
return ret;

fail:
error_free(err);
ret = -EIO;
goto done;
}
Expand Down Expand Up @@ -666,12 +707,17 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
break;
}
if (bs->encrypted) {
assert(s->crypt_method);
Error *err = NULL;
assert(s->cipher);
if (!cluster_data) {
cluster_data = g_malloc0(s->cluster_size);
}
encrypt_sectors(s, sector_num, cluster_data, buf,
n, 1, &s->aes_encrypt_key);
if (encrypt_sectors(s, sector_num, cluster_data, buf,
n, true, &err) < 0) {
error_free(err);
ret = -EIO;
break;
}
src_buf = cluster_data;
} else {
src_buf = buf;
Expand Down Expand Up @@ -708,6 +754,8 @@ static void qcow_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;

qcrypto_cipher_free(s->cipher);
s->cipher = NULL;
g_free(s->l1_table);
qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
Expand Down
46 changes: 36 additions & 10 deletions block/qcow2-cluster.c
Expand Up @@ -339,26 +339,47 @@ static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_tab
/* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, int enc,
const AES_KEY *key)
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc,
Error **errp)
{
union {
uint64_t ll[2];
uint8_t b[16];
} ivec;
int i;
int ret;

for(i = 0; i < nb_sectors; i++) {
ivec.ll[0] = cpu_to_le64(sector_num);
ivec.ll[1] = 0;
AES_cbc_encrypt(in_buf, out_buf, 512, key,
ivec.b, enc);
if (qcrypto_cipher_setiv(s->cipher,
ivec.b, G_N_ELEMENTS(ivec.b),
errp) < 0) {
return -1;
}
if (enc) {
ret = qcrypto_cipher_encrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
} else {
ret = qcrypto_cipher_decrypt(s->cipher,
in_buf,
out_buf,
512,
errp);
}
if (ret < 0) {
return -1;
}
sector_num++;
in_buf += 512;
out_buf += 512;
}
return 0;
}

static int coroutine_fn copy_sectors(BlockDriverState *bs,
Expand Down Expand Up @@ -401,10 +422,15 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
}

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);
Error *err = NULL;
assert(s->cipher);
if (qcow2_encrypt_sectors(s, start_sect + n_start,
iov.iov_base, iov.iov_base, n,
true, &err) < 0) {
ret = -EIO;
error_free(err);
goto out;
}
}

ret = qcow2_pre_write_overlap_check(bs, 0,
Expand Down

0 comments on commit acf7b7f

Please sign in to comment.