Compare commits
128 Commits
machine-pu
...
pull-ui-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
569a93cbbe | ||
|
|
81b00c968a | ||
|
|
0e066b2cc5 | ||
|
|
2538039f2c | ||
|
|
ffa6564c9b | ||
|
|
ae6296342a | ||
|
|
8ff98f1ed2 | ||
|
|
e89fdafb58 | ||
|
|
459621ac1a | ||
|
|
ac0d25e843 | ||
|
|
a335c6f204 | ||
|
|
62a830b688 | ||
|
|
13fd2cb689 | ||
|
|
ddc8528443 | ||
|
|
5400c02b90 | ||
|
|
2a845da736 | ||
|
|
55e8a15435 | ||
|
|
8baeb22bfc | ||
|
|
c2d8019cd7 | ||
|
|
5503e28504 | ||
|
|
08183c20b8 | ||
|
|
ee276391a3 | ||
|
|
ba5970a178 | ||
|
|
a3feb08639 | ||
|
|
1309cf448a | ||
|
|
3a55fc0f24 | ||
|
|
9db51b4d64 | ||
|
|
ca0b7566cc | ||
|
|
cd9953f720 | ||
|
|
3c27969b3e | ||
|
|
2d1d422d11 | ||
|
|
082751e82b | ||
|
|
434ad76db5 | ||
|
|
d855e27565 | ||
|
|
9cf70c5225 | ||
|
|
71c265816d | ||
|
|
c20fc0c3ee | ||
|
|
e64befe929 | ||
|
|
a4fa93bf20 | ||
|
|
97553976dd | ||
|
|
fdee2025dd | ||
|
|
41b65e5eda | ||
|
|
14c5d49ab3 | ||
|
|
4958fe5d3c | ||
|
|
998261726a | ||
|
|
330b58368c | ||
|
|
9fa570d57e | ||
|
|
f7ac78cfe1 | ||
|
|
621e6ae657 | ||
|
|
a284974dee | ||
|
|
4829e0378d | ||
|
|
ad4929384b | ||
|
|
3625c739ea | ||
|
|
e3ad72965a | ||
|
|
3be5cc2324 | ||
|
|
dff0367cf6 | ||
|
|
983bff3530 | ||
|
|
f34d57d359 | ||
|
|
e3d60bc7c6 | ||
|
|
182b391e79 | ||
|
|
0ab6d12ffd | ||
|
|
3666a97f78 | ||
|
|
ac4338f8eb | ||
|
|
bd59adce69 | ||
|
|
32bafa8fdd | ||
|
|
861877a0dd | ||
|
|
12f254fd5f | ||
|
|
c1ff0e6c85 | ||
|
|
386230a249 | ||
|
|
0949e95b48 | ||
|
|
8df59565d2 | ||
|
|
7ce106a96f | ||
|
|
7599697c66 | ||
|
|
4040d995e4 | ||
|
|
972a110162 | ||
|
|
29f6bd15eb | ||
|
|
879c26fb9f | ||
|
|
3e308f20ed | ||
|
|
6741d38ad0 | ||
|
|
361dca7a5a | ||
|
|
509565f36f | ||
|
|
6049490df4 | ||
|
|
8896e08814 | ||
|
|
57d6a42883 | ||
|
|
a55d3fba99 | ||
|
|
fc1453cdfc | ||
|
|
5bd5119667 | ||
|
|
a8823a3bfd | ||
|
|
1bf1cbc91f | ||
|
|
f21d96d04b | ||
|
|
9aaf28c61d | ||
|
|
79720af640 | ||
|
|
2626058034 | ||
|
|
981f4f578e | ||
|
|
262b4e8f74 | ||
|
|
fe1a9cbc33 | ||
|
|
7c735873d9 | ||
|
|
efaa7c4eeb | ||
|
|
e5e785500b | ||
|
|
2cf22d6a1a | ||
|
|
9492b0b928 | ||
|
|
d0e46a5577 | ||
|
|
a55448b368 | ||
|
|
da31d594cf | ||
|
|
1393f21270 | ||
|
|
74d1b8fc27 | ||
|
|
da27a00e27 | ||
|
|
f8746fb804 | ||
|
|
23f7fcb295 | ||
|
|
7d9690148a | ||
|
|
eaec903c5b | ||
|
|
e3ba0b6701 | ||
|
|
84f7f180b0 | ||
|
|
50f6753e27 | ||
|
|
94318522ed | ||
|
|
084a85eedd | ||
|
|
aa41363598 | ||
|
|
5a95e0fccd | ||
|
|
cb730894ae | ||
|
|
37788f253a | ||
|
|
331ac65963 | ||
|
|
1f3ddfcb25 | ||
|
|
147dfab747 | ||
|
|
b917da4cbd | ||
|
|
8c45754724 | ||
|
|
33616ace9f | ||
|
|
773460256b | ||
|
|
03c698f0a2 |
@@ -1016,7 +1016,7 @@ F: blockjob.c
|
||||
F: include/block/blockjob.h
|
||||
F: block/backup.c
|
||||
F: block/commit.c
|
||||
F: block/stream.h
|
||||
F: block/stream.c
|
||||
F: block/mirror.c
|
||||
T: git git://github.com/codyprime/qemu-kvm-jtc.git block
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
stub-obj-y = stubs/
|
||||
stub-obj-y = stubs/ crypto/
|
||||
util-obj-y = util/ qobject/ qapi/
|
||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "block/block.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/sockets.h"
|
||||
#ifdef CONFIG_EPOLL
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
@@ -33,7 +33,7 @@ struct AioHandler
|
||||
QLIST_ENTRY(AioHandler) node;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EPOLL
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
|
||||
/* The fd number threashold to switch to epoll */
|
||||
#define EPOLL_ENABLE_THRESHOLD 64
|
||||
@@ -483,7 +483,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
|
||||
|
||||
void aio_context_setup(AioContext *ctx, Error **errp)
|
||||
{
|
||||
#ifdef CONFIG_EPOLL
|
||||
#ifdef CONFIG_EPOLL_CREATE1
|
||||
assert(!ctx->epollfd);
|
||||
ctx->epollfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (ctx->epollfd == -1) {
|
||||
|
||||
@@ -567,7 +567,7 @@ static CharDriverState *chr_baum_init(const char *id,
|
||||
ChardevReturn *ret,
|
||||
Error **errp)
|
||||
{
|
||||
ChardevCommon *common = backend->u.braille;
|
||||
ChardevCommon *common = backend->u.braille.data;
|
||||
BaumDriverState *baum;
|
||||
CharDriverState *chr;
|
||||
brlapi_handle_t *handle;
|
||||
|
||||
@@ -68,7 +68,7 @@ static CharDriverState *qemu_chr_open_msmouse(const char *id,
|
||||
ChardevReturn *ret,
|
||||
Error **errp)
|
||||
{
|
||||
ChardevCommon *common = backend->u.msmouse;
|
||||
ChardevCommon *common = backend->u.msmouse.data;
|
||||
CharDriverState *chr;
|
||||
|
||||
chr = qemu_chr_alloc(common, errp);
|
||||
|
||||
133
block.c
133
block.c
@@ -55,8 +55,6 @@
|
||||
|
||||
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||
|
||||
struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
|
||||
|
||||
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
|
||||
QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);
|
||||
|
||||
@@ -226,10 +224,7 @@ void bdrv_register(BlockDriver *bdrv)
|
||||
|
||||
BlockDriverState *bdrv_new_root(void)
|
||||
{
|
||||
BlockDriverState *bs = bdrv_new();
|
||||
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
return bs;
|
||||
return bdrv_new();
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_new(void)
|
||||
@@ -1180,10 +1175,9 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role)
|
||||
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role)
|
||||
{
|
||||
BdrvChild *child = g_new(BdrvChild, 1);
|
||||
*child = (BdrvChild) {
|
||||
@@ -1192,24 +1186,43 @@ static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
.role = child_role,
|
||||
};
|
||||
|
||||
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
||||
QLIST_INSERT_HEAD(&child_bs->parents, child, next_parent);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role)
|
||||
{
|
||||
BdrvChild *child = bdrv_root_attach_child(child_bs, child_name, child_role);
|
||||
QLIST_INSERT_HEAD(&parent_bs->children, child, next);
|
||||
return child;
|
||||
}
|
||||
|
||||
static void bdrv_detach_child(BdrvChild *child)
|
||||
{
|
||||
QLIST_REMOVE(child, next);
|
||||
if (child->next.le_prev) {
|
||||
QLIST_REMOVE(child, next);
|
||||
child->next.le_prev = NULL;
|
||||
}
|
||||
QLIST_REMOVE(child, next_parent);
|
||||
g_free(child->name);
|
||||
g_free(child);
|
||||
}
|
||||
|
||||
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
|
||||
void bdrv_root_unref_child(BdrvChild *child)
|
||||
{
|
||||
BlockDriverState *child_bs;
|
||||
|
||||
child_bs = child->bs;
|
||||
bdrv_detach_child(child);
|
||||
bdrv_unref(child_bs);
|
||||
}
|
||||
|
||||
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
|
||||
{
|
||||
if (child == NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -1218,9 +1231,7 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
|
||||
child->bs->inherits_from = NULL;
|
||||
}
|
||||
|
||||
child_bs = child->bs;
|
||||
bdrv_detach_child(child);
|
||||
bdrv_unref(child_bs);
|
||||
bdrv_root_unref_child(child);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1671,9 +1682,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
|
||||
error_setg(errp, "Block protocol '%s' doesn't support the option "
|
||||
"'%s'", drv->format_name, entry->key);
|
||||
} else {
|
||||
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
|
||||
"support the option '%s'", drv->format_name,
|
||||
bdrv_get_device_name(bs), entry->key);
|
||||
error_setg(errp,
|
||||
"Block format '%s' does not support the option '%s'",
|
||||
drv->format_name, entry->key);
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
@@ -2230,26 +2241,10 @@ void bdrv_close_all(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove. */
|
||||
void bdrv_device_remove(BlockDriverState *bs)
|
||||
{
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
}
|
||||
|
||||
/* make a BlockDriverState anonymous by removing from bdrv_state and
|
||||
* graph_bdrv_state list.
|
||||
Also, NULL terminate the device_name to prevent double remove */
|
||||
/* make a BlockDriverState anonymous by removing from graph_bdrv_state list.
|
||||
* Also, NULL terminate the device_name to prevent double remove */
|
||||
void bdrv_make_anon(BlockDriverState *bs)
|
||||
{
|
||||
/* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
}
|
||||
@@ -2276,6 +2271,14 @@ static void change_parent_backing_link(BlockDriverState *from,
|
||||
{
|
||||
BdrvChild *c, *next;
|
||||
|
||||
if (from->blk) {
|
||||
/* FIXME We bypass blk_set_bs(), so we need to make these updates
|
||||
* manually. The root problem is not in this change function, but the
|
||||
* existence of BlockDriverState.blk. */
|
||||
to->blk = from->blk;
|
||||
from->blk = NULL;
|
||||
}
|
||||
|
||||
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
|
||||
assert(c->role != &child_backing);
|
||||
c->bs = to;
|
||||
@@ -2284,13 +2287,6 @@ static void change_parent_backing_link(BlockDriverState *from,
|
||||
bdrv_ref(to);
|
||||
bdrv_unref(from);
|
||||
}
|
||||
if (from->blk) {
|
||||
blk_set_bs(from->blk, to);
|
||||
if (!to->device_list.tqe_prev) {
|
||||
QTAILQ_INSERT_BEFORE(from, to, device_list);
|
||||
}
|
||||
bdrv_device_remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_feature_fields(BlockDriverState *bs_top,
|
||||
@@ -2521,26 +2517,6 @@ ro_cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bdrv_commit_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
if (bs->drv && bs->backing) {
|
||||
int ret = bdrv_commit(bs);
|
||||
if (ret < 0) {
|
||||
aio_context_release(aio_context);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return values:
|
||||
* 0 - success
|
||||
@@ -2989,12 +2965,23 @@ BlockDriverState *bdrv_next_node(BlockDriverState *bs)
|
||||
return QTAILQ_NEXT(bs, node_list);
|
||||
}
|
||||
|
||||
/* Iterates over all top-level BlockDriverStates, i.e. BDSs that are owned by
|
||||
* the monitor or attached to a BlockBackend */
|
||||
BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||
{
|
||||
if (!bs) {
|
||||
return QTAILQ_FIRST(&bdrv_states);
|
||||
if (!bs || bs->blk) {
|
||||
bs = blk_next_root_bs(bs);
|
||||
if (bs) {
|
||||
return bs;
|
||||
}
|
||||
}
|
||||
return QTAILQ_NEXT(bs, device_list);
|
||||
|
||||
/* Ignore all BDSs that are attached to a BlockBackend here; they have been
|
||||
* handled by the above block already */
|
||||
do {
|
||||
bs = bdrv_next_monitor_owned(bs);
|
||||
} while (bs && bs->blk);
|
||||
return bs;
|
||||
}
|
||||
|
||||
const char *bdrv_get_node_name(const BlockDriverState *bs)
|
||||
@@ -3302,10 +3289,10 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
|
||||
void bdrv_invalidate_cache_all(Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
while ((bs = bdrv_next(bs)) != NULL) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
@@ -3335,10 +3322,10 @@ static int bdrv_inactivate(BlockDriverState *bs)
|
||||
|
||||
int bdrv_inactivate_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *bs = NULL;
|
||||
int ret;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
while ((bs = bdrv_next(bs)) != NULL) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
@@ -3844,10 +3831,10 @@ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
*/
|
||||
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *bs = NULL;
|
||||
|
||||
/* walk down the bs forest recursively */
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
while ((bs = bdrv_next(bs)) != NULL) {
|
||||
bool perm;
|
||||
|
||||
/* try to recurse in this top level bs */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
44
block/io.c
44
block/io.c
@@ -44,12 +44,6 @@ static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
|
||||
static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov);
|
||||
static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags);
|
||||
static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags);
|
||||
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
@@ -621,20 +615,6 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false, 0);
|
||||
}
|
||||
|
||||
/* Just like bdrv_read(), but with I/O throttling temporarily disabled */
|
||||
int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
bool enabled;
|
||||
int ret;
|
||||
|
||||
enabled = bs->io_limits_enabled;
|
||||
bs->io_limits_enabled = false;
|
||||
ret = bdrv_read(bs, sector_num, buf, nb_sectors);
|
||||
bs->io_limits_enabled = enabled;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return < 0 if error. Important errors are:
|
||||
-EIO generic I/O error (may happen for all errors)
|
||||
-ENOMEDIUM No media inserted.
|
||||
@@ -939,7 +919,7 @@ out:
|
||||
/*
|
||||
* Handle a read request in coroutine context
|
||||
*/
|
||||
static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@@ -1284,7 +1264,7 @@ fail:
|
||||
/*
|
||||
* Handle a write request in coroutine context
|
||||
*/
|
||||
static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
@@ -1445,26 +1425,6 @@ int coroutine_fn bdrv_co_write_zeroes(BlockDriverState *bs,
|
||||
BDRV_REQ_ZERO_WRITE | flags);
|
||||
}
|
||||
|
||||
int bdrv_flush_all(void)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
int result = 0;
|
||||
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
int ret;
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
ret = bdrv_flush(bs);
|
||||
if (ret < 0 && !result) {
|
||||
result = ret;
|
||||
}
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct BdrvCoGetBlockStatusData {
|
||||
BlockDriverState *bs;
|
||||
BlockDriverState *base;
|
||||
|
||||
@@ -206,13 +206,13 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, char **export,
|
||||
if (qdict_haskey(options, "path")) {
|
||||
UnixSocketAddress *q_unix;
|
||||
saddr->type = SOCKET_ADDRESS_KIND_UNIX;
|
||||
q_unix = saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
|
||||
q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
|
||||
q_unix->path = g_strdup(qdict_get_str(options, "path"));
|
||||
qdict_del(options, "path");
|
||||
} else {
|
||||
InetSocketAddress *inet;
|
||||
saddr->type = SOCKET_ADDRESS_KIND_INET;
|
||||
inet = saddr->u.inet = g_new0(InetSocketAddress, 1);
|
||||
inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
|
||||
inet->host = g_strdup(qdict_get_str(options, "host"));
|
||||
if (!qdict_get_try_str(options, "port")) {
|
||||
inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
|
||||
@@ -321,7 +321,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
error_setg(errp, "TLS only supported over IP sockets");
|
||||
goto error;
|
||||
}
|
||||
hostname = saddr->u.inet->host;
|
||||
hostname = saddr->u.inet.data->host;
|
||||
}
|
||||
|
||||
/* establish TCP connection, return error if it fails
|
||||
|
||||
@@ -478,7 +478,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
file = blk_new_open("image", filename, NULL, NULL,
|
||||
file = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (file == NULL) {
|
||||
|
||||
@@ -121,11 +121,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
if (header.version != QCOW_VERSION) {
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||
header.version);
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "qcow", version);
|
||||
error_setg(errp, "Unsupported qcow version %" PRIu32, header.version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -797,7 +793,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qcow_blk = blk_new_open("image", filename, NULL, NULL,
|
||||
qcow_blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (qcow_blk == NULL) {
|
||||
|
||||
@@ -198,22 +198,8 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
|
||||
Error **errp, const char *fmt, ...)
|
||||
{
|
||||
char msg[64];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "qcow2", msg);
|
||||
}
|
||||
|
||||
static void report_unsupported_feature(BlockDriverState *bs,
|
||||
Error **errp, Qcow2Feature *table, uint64_t mask)
|
||||
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
|
||||
uint64_t mask)
|
||||
{
|
||||
char *features = g_strdup("");
|
||||
char *old;
|
||||
@@ -238,7 +224,7 @@ static void report_unsupported_feature(BlockDriverState *bs,
|
||||
g_free(old);
|
||||
}
|
||||
|
||||
report_unsupported(bs, errp, "%s", features);
|
||||
error_setg(errp, "Unsupported qcow2 feature(s): %s", features);
|
||||
g_free(features);
|
||||
}
|
||||
|
||||
@@ -855,7 +841,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
if (header.version < 2 || header.version > 3) {
|
||||
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||
error_setg(errp, "Unsupported qcow2 version %" PRIu32, header.version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -935,7 +921,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
void *feature_table = NULL;
|
||||
qcow2_read_extensions(bs, header.header_length, ext_end,
|
||||
&feature_table, NULL);
|
||||
report_unsupported_feature(bs, errp, feature_table,
|
||||
report_unsupported_feature(errp, feature_table,
|
||||
s->incompatible_features &
|
||||
~QCOW2_INCOMPAT_MASK);
|
||||
ret = -ENOTSUP;
|
||||
@@ -2173,7 +2159,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
blk = blk_new_open("image", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -2238,7 +2224,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
*/
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
blk = blk_new_open("image-qcow2", filename, NULL, options,
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -2300,7 +2286,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
|
||||
options = qdict_new();
|
||||
qdict_put(options, "driver", qstring_from_str("qcow2"));
|
||||
blk = blk_new_open("image-flush", filename, NULL, options,
|
||||
blk = blk_new_open(filename, NULL, options,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -2814,15 +2800,15 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
|
||||
|
||||
*spec_info = (ImageInfoSpecific){
|
||||
.type = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
|
||||
.u.qcow2 = g_new(ImageInfoSpecificQCow2, 1),
|
||||
.u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
|
||||
};
|
||||
if (s->qcow_version == 2) {
|
||||
*spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
|
||||
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
|
||||
.compat = g_strdup("0.10"),
|
||||
.refcount_bits = s->refcount_bits,
|
||||
};
|
||||
} else if (s->qcow_version == 3) {
|
||||
*spec_info->u.qcow2 = (ImageInfoSpecificQCow2){
|
||||
*spec_info->u.qcow2.data = (ImageInfoSpecificQCow2){
|
||||
.compat = g_strdup("1.1"),
|
||||
.lazy_refcounts = s->compatible_features &
|
||||
QCOW2_COMPAT_LAZY_REFCOUNTS,
|
||||
|
||||
22
block/qed.c
22
block/qed.c
@@ -377,18 +377,6 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_qed_drain(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
|
||||
/* Cancel timer and start doing I/O that were meant to happen as if it
|
||||
* fired, that way we get bdrv_drain() taking care of the ongoing requests
|
||||
* correctly. */
|
||||
qed_cancel_need_check_timer(s);
|
||||
qed_plug_allocating_write_reqs(s);
|
||||
bdrv_aio_flush(s->bs, qed_clear_need_check, s);
|
||||
}
|
||||
|
||||
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -412,11 +400,8 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
if (s->header.features & ~QED_FEATURE_MASK) {
|
||||
/* image uses unsupported feature bits */
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%" PRIx64,
|
||||
s->header.features & ~QED_FEATURE_MASK);
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "QED", buf);
|
||||
error_setg(errp, "Unsupported QED features: %" PRIx64,
|
||||
s->header.features & ~QED_FEATURE_MASK);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
|
||||
@@ -589,7 +574,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
blk = blk_new_open("image", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -1694,7 +1679,6 @@ static BlockDriver bdrv_qed = {
|
||||
.bdrv_check = bdrv_qed_check,
|
||||
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
||||
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
||||
.bdrv_drain = bdrv_qed_drain,
|
||||
};
|
||||
|
||||
static void bdrv_qed_init(void)
|
||||
|
||||
@@ -284,9 +284,17 @@ static void quorum_aio_cb(void *opaque, int ret)
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
QuorumOpType type;
|
||||
bool rewrite = false;
|
||||
|
||||
if (ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
QuorumOpType type;
|
||||
type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE;
|
||||
quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
|
||||
sacb->aiocb->bs->node_name, ret);
|
||||
}
|
||||
|
||||
if (acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO) {
|
||||
/* We try to read next child in FIFO order if we fail to read */
|
||||
if (ret < 0 && (acb->child_iter + 1) < s->num_children) {
|
||||
@@ -303,15 +311,8 @@ static void quorum_aio_cb(void *opaque, int ret)
|
||||
return;
|
||||
}
|
||||
|
||||
type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE;
|
||||
sacb->ret = ret;
|
||||
acb->count++;
|
||||
if (ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
|
||||
sacb->aiocb->bs->node_name, ret);
|
||||
}
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
if (acb->count < s->num_children) {
|
||||
|
||||
@@ -1646,7 +1646,7 @@ static int sd_prealloc(const char *filename, Error **errp)
|
||||
void *buf = NULL;
|
||||
int ret;
|
||||
|
||||
blk = blk_new_open("image-prealloc", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
errp);
|
||||
if (blk == NULL) {
|
||||
@@ -1843,7 +1843,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk = blk_new_open("backing", backing_file, NULL, NULL,
|
||||
blk = blk_new_open(backing_file, NULL, NULL,
|
||||
BDRV_O_PROTOCOL | BDRV_O_CACHE_WB, errp);
|
||||
if (blk == NULL) {
|
||||
ret = -EIO;
|
||||
@@ -2549,7 +2549,7 @@ static int sd_snapshot_delete(BlockDriverState *bs,
|
||||
const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
uint32_t snap_id = 0;
|
||||
unsigned long snap_id = 0;
|
||||
char snap_tag[SD_MAX_VDI_TAG_LEN];
|
||||
Error *local_err = NULL;
|
||||
int fd, ret;
|
||||
@@ -2571,12 +2571,15 @@ static int sd_snapshot_delete(BlockDriverState *bs,
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memset(snap_tag, 0, sizeof(snap_tag));
|
||||
pstrcpy(buf, SD_MAX_VDI_LEN, s->name);
|
||||
if (qemu_strtoul(snapshot_id, NULL, 10, (unsigned long *)&snap_id)) {
|
||||
return -1;
|
||||
ret = qemu_strtoul(snapshot_id, NULL, 10, &snap_id);
|
||||
if (ret || snap_id > UINT32_MAX) {
|
||||
error_setg(errp, "Invalid snapshot ID: %s",
|
||||
snapshot_id ? snapshot_id : "<null>");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (snap_id) {
|
||||
hdr.snapid = snap_id;
|
||||
hdr.snapid = (uint32_t) snap_id;
|
||||
} else {
|
||||
pstrcpy(snap_tag, sizeof(snap_tag), snapshot_id);
|
||||
pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, snap_tag);
|
||||
|
||||
@@ -768,7 +768,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
blk = blk_new_open("image", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
|
||||
@@ -1838,7 +1838,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
blk = blk_new_open("image", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
|
||||
21
block/vmdk.c
21
block/vmdk.c
@@ -661,11 +661,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
compressed =
|
||||
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
||||
if (le32_to_cpu(header.version) > 3) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
le32_to_cpu(header.version));
|
||||
error_setg(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_or_node_name(bs), "vmdk", buf);
|
||||
error_setg(errp, "Unsupported VMDK version %" PRIu32,
|
||||
le32_to_cpu(header.version));
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) &&
|
||||
!compressed) {
|
||||
@@ -1664,7 +1661,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
blk = blk_new_open("extent", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
@@ -1949,7 +1946,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
blk = blk_new_open("backing", full_backing, NULL, NULL,
|
||||
blk = blk_new_open(full_backing, NULL, NULL,
|
||||
BDRV_O_NO_BACKING | BDRV_O_CACHE_WB, errp);
|
||||
g_free(full_backing);
|
||||
if (blk == NULL) {
|
||||
@@ -2021,7 +2018,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
new_blk = blk_new_open("descriptor", filename, NULL, NULL,
|
||||
new_blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (new_blk == NULL) {
|
||||
@@ -2206,18 +2203,18 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs)
|
||||
|
||||
*spec_info = (ImageInfoSpecific){
|
||||
.type = IMAGE_INFO_SPECIFIC_KIND_VMDK,
|
||||
{
|
||||
.vmdk = g_new0(ImageInfoSpecificVmdk, 1),
|
||||
.u = {
|
||||
.vmdk.data = g_new0(ImageInfoSpecificVmdk, 1),
|
||||
},
|
||||
};
|
||||
|
||||
*spec_info->u.vmdk = (ImageInfoSpecificVmdk) {
|
||||
*spec_info->u.vmdk.data = (ImageInfoSpecificVmdk) {
|
||||
.create_type = g_strdup(s->create_type),
|
||||
.cid = s->cid,
|
||||
.parent_cid = s->parent_cid,
|
||||
};
|
||||
|
||||
next = &spec_info->u.vmdk->extents;
|
||||
next = &spec_info->u.vmdk.data->extents;
|
||||
for (i = 0; i < s->num_extents; i++) {
|
||||
*next = g_new0(ImageInfoList, 1);
|
||||
(*next)->value = vmdk_get_extent_info(&s->extents[i]);
|
||||
|
||||
@@ -888,7 +888,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk = blk_new_open("image", filename, NULL, NULL,
|
||||
blk = blk_new_open(filename, NULL, NULL,
|
||||
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
|
||||
&local_err);
|
||||
if (blk == NULL) {
|
||||
|
||||
71
blockdev.c
71
blockdev.c
@@ -147,6 +147,7 @@ void blockdev_auto_del(BlockBackend *blk)
|
||||
DriveInfo *dinfo = blk_legacy_dinfo(blk);
|
||||
|
||||
if (dinfo && dinfo->auto_del) {
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
@@ -561,7 +562,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
if ((!file || !*file) && !qdict_size(bs_opts)) {
|
||||
BlockBackendRootState *blk_rs;
|
||||
|
||||
blk = blk_new(qemu_opts_id(opts), errp);
|
||||
blk = blk_new(errp);
|
||||
if (!blk) {
|
||||
goto early_err;
|
||||
}
|
||||
@@ -597,8 +598,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
bdrv_flags |= BDRV_O_INACTIVE;
|
||||
}
|
||||
|
||||
blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
|
||||
errp);
|
||||
blk = blk_new_open(file, NULL, bs_opts, bdrv_flags, errp);
|
||||
if (!blk) {
|
||||
goto err_no_bs_opts;
|
||||
}
|
||||
@@ -630,6 +630,12 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
|
||||
blk_set_on_error(blk, on_read_error, on_write_error);
|
||||
|
||||
if (!monitor_add_blk(blk, qemu_opts_id(opts), errp)) {
|
||||
blk_unref(blk);
|
||||
blk = NULL;
|
||||
goto err_no_bs_opts;
|
||||
}
|
||||
|
||||
err_no_bs_opts:
|
||||
qemu_opts_del(opts);
|
||||
QDECREF(interval_dict);
|
||||
@@ -717,6 +723,13 @@ void blockdev_close_all_bdrv_states(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterates over the list of monitor-owned BlockDriverStates */
|
||||
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs)
|
||||
{
|
||||
return bs ? QTAILQ_NEXT(bs, monitor_list)
|
||||
: QTAILQ_FIRST(&monitor_bdrv_states);
|
||||
}
|
||||
|
||||
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1173,7 +1186,7 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
|
||||
int ret;
|
||||
|
||||
if (!strcmp(device, "all")) {
|
||||
ret = bdrv_commit_all();
|
||||
ret = blk_commit_all();
|
||||
} else {
|
||||
BlockDriverState *bs;
|
||||
AioContext *aio_context;
|
||||
@@ -1234,7 +1247,7 @@ void qmp_blockdev_snapshot_sync(bool has_device, const char *device,
|
||||
};
|
||||
TransactionAction action = {
|
||||
.type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC,
|
||||
.u.blockdev_snapshot_sync = &snapshot,
|
||||
.u.blockdev_snapshot_sync.data = &snapshot,
|
||||
};
|
||||
blockdev_do_action(&action, errp);
|
||||
}
|
||||
@@ -1248,7 +1261,7 @@ void qmp_blockdev_snapshot(const char *node, const char *overlay,
|
||||
};
|
||||
TransactionAction action = {
|
||||
.type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT,
|
||||
.u.blockdev_snapshot = &snapshot_data,
|
||||
.u.blockdev_snapshot.data = &snapshot_data,
|
||||
};
|
||||
blockdev_do_action(&action, errp);
|
||||
}
|
||||
@@ -1263,7 +1276,7 @@ void qmp_blockdev_snapshot_internal_sync(const char *device,
|
||||
};
|
||||
TransactionAction action = {
|
||||
.type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC,
|
||||
.u.blockdev_snapshot_internal_sync = &snapshot,
|
||||
.u.blockdev_snapshot_internal_sync.data = &snapshot,
|
||||
};
|
||||
blockdev_do_action(&action, errp);
|
||||
}
|
||||
@@ -1502,7 +1515,7 @@ static void internal_snapshot_prepare(BlkActionState *common,
|
||||
|
||||
g_assert(common->action->type ==
|
||||
TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC);
|
||||
internal = common->action->u.blockdev_snapshot_internal_sync;
|
||||
internal = common->action->u.blockdev_snapshot_internal_sync.data;
|
||||
state = DO_UPCAST(InternalSnapshotState, common, common);
|
||||
|
||||
/* 1. parse input */
|
||||
@@ -1652,7 +1665,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
switch (action->type) {
|
||||
case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT:
|
||||
{
|
||||
BlockdevSnapshot *s = action->u.blockdev_snapshot;
|
||||
BlockdevSnapshot *s = action->u.blockdev_snapshot.data;
|
||||
device = s->node;
|
||||
node_name = s->node;
|
||||
new_image_file = NULL;
|
||||
@@ -1661,7 +1674,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
break;
|
||||
case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
|
||||
{
|
||||
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync;
|
||||
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
|
||||
device = s->has_device ? s->device : NULL;
|
||||
node_name = s->has_node_name ? s->node_name : NULL;
|
||||
new_image_file = s->snapshot_file;
|
||||
@@ -1710,7 +1723,7 @@ static void external_snapshot_prepare(BlkActionState *common,
|
||||
}
|
||||
|
||||
if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
|
||||
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync;
|
||||
BlockdevSnapshotSync *s = action->u.blockdev_snapshot_sync.data;
|
||||
const char *format = s->has_format ? s->format : "qcow2";
|
||||
enum NewImageMode mode;
|
||||
const char *snapshot_node_name =
|
||||
@@ -1848,7 +1861,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
|
||||
backup = common->action->u.drive_backup;
|
||||
backup = common->action->u.drive_backup.data;
|
||||
|
||||
blk = blk_by_name(backup->device);
|
||||
if (!blk) {
|
||||
@@ -1930,7 +1943,7 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
|
||||
Error *local_err = NULL;
|
||||
|
||||
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
|
||||
backup = common->action->u.blockdev_backup;
|
||||
backup = common->action->u.blockdev_backup.data;
|
||||
|
||||
blk = blk_by_name(backup->device);
|
||||
if (!blk) {
|
||||
@@ -2016,7 +2029,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
action = common->action->u.block_dirty_bitmap_add;
|
||||
action = common->action->u.block_dirty_bitmap_add.data;
|
||||
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
|
||||
qmp_block_dirty_bitmap_add(action->node, action->name,
|
||||
action->has_granularity, action->granularity,
|
||||
@@ -2035,7 +2048,7 @@ static void block_dirty_bitmap_add_abort(BlkActionState *common)
|
||||
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
||||
common, common);
|
||||
|
||||
action = common->action->u.block_dirty_bitmap_add;
|
||||
action = common->action->u.block_dirty_bitmap_add.data;
|
||||
/* Should not be able to fail: IF the bitmap was added via .prepare(),
|
||||
* then the node reference and bitmap name must have been valid.
|
||||
*/
|
||||
@@ -2055,7 +2068,7 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
|
||||
return;
|
||||
}
|
||||
|
||||
action = common->action->u.block_dirty_bitmap_clear;
|
||||
action = common->action->u.block_dirty_bitmap_clear.data;
|
||||
state->bitmap = block_dirty_bitmap_lookup(action->node,
|
||||
action->name,
|
||||
&state->bs,
|
||||
@@ -2413,11 +2426,6 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* This follows the convention established by bdrv_make_anon() */
|
||||
if (bs->device_list.tqe_prev) {
|
||||
bdrv_device_remove(bs);
|
||||
}
|
||||
|
||||
blk_remove_bs(blk);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
@@ -2465,8 +2473,6 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
|
||||
|
||||
blk_insert_bs(blk, bs);
|
||||
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
|
||||
if (!blk_dev_has_tray(blk)) {
|
||||
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
|
||||
* called at all); therefore, the medium needs to be pushed into the
|
||||
@@ -2859,13 +2865,16 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
|
||||
blk_remove_bs(blk);
|
||||
}
|
||||
|
||||
/* if we have a device attached to this BlockDriverState
|
||||
* then we need to make the drive anonymous until the device
|
||||
* can be removed. If this is a drive with no device backing
|
||||
* then we can just get rid of the block driver state right here.
|
||||
/* Make the BlockBackend and the attached BlockDriverState anonymous */
|
||||
monitor_remove_blk(blk);
|
||||
if (blk_bs(blk)) {
|
||||
bdrv_make_anon(blk_bs(blk));
|
||||
}
|
||||
|
||||
/* If this BlockBackend has a device attached to it, its refcount will be
|
||||
* decremented when the device is removed; otherwise we have to do so here.
|
||||
*/
|
||||
if (blk_get_attached_dev(blk)) {
|
||||
blk_hide_on_behalf_of_hmp_drive_del(blk);
|
||||
/* Further I/O must not pause the guest */
|
||||
blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
|
||||
BLOCKDEV_ON_ERROR_REPORT);
|
||||
@@ -3898,6 +3907,7 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr)
|
||||
qdict = qemu_opts_to_qdict(opts, NULL);
|
||||
|
||||
if (!qdict_get_try_str(qdict, "node-name")) {
|
||||
QDECREF(qdict);
|
||||
error_report("'node-name' needs to be specified");
|
||||
goto out;
|
||||
}
|
||||
@@ -3975,6 +3985,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
|
||||
if (bs && bdrv_key_required(bs)) {
|
||||
if (blk) {
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
} else {
|
||||
QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
|
||||
@@ -4004,6 +4015,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
}
|
||||
|
||||
if (has_id) {
|
||||
/* blk_by_name() never returns a BB that is not owned by the monitor */
|
||||
blk = blk_by_name(id);
|
||||
if (!blk) {
|
||||
error_setg(errp, "Cannot find block backend %s", id);
|
||||
@@ -4051,6 +4063,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
}
|
||||
|
||||
if (blk) {
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
} else {
|
||||
QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
|
||||
@@ -4221,7 +4234,7 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
|
||||
static QemuOptsList qemu_root_bds_opts = {
|
||||
.name = "root-bds",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_root_bds_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "discard",
|
||||
|
||||
34
configure
vendored
34
configure
vendored
@@ -306,8 +306,10 @@ gtkabi=""
|
||||
gtk_gl="no"
|
||||
gnutls=""
|
||||
gnutls_hash=""
|
||||
gnutls_rnd=""
|
||||
nettle=""
|
||||
gcrypt=""
|
||||
gcrypt_kdf="no"
|
||||
vte=""
|
||||
virglrenderer=""
|
||||
tpm="yes"
|
||||
@@ -2201,6 +2203,13 @@ if test "$gnutls" != "no"; then
|
||||
gnutls_hash="no"
|
||||
fi
|
||||
|
||||
# gnutls_rnd requires >= 2.11.0
|
||||
if $pkg_config --exists "gnutls >= 2.11.0"; then
|
||||
gnutls_rnd="yes"
|
||||
else
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
if $pkg_config --exists 'gnutls >= 3.0'; then
|
||||
gnutls_gcrypt=no
|
||||
gnutls_nettle=yes
|
||||
@@ -2228,9 +2237,11 @@ if test "$gnutls" != "no"; then
|
||||
else
|
||||
gnutls="no"
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
else
|
||||
gnutls_hash="no"
|
||||
gnutls_rnd="no"
|
||||
fi
|
||||
|
||||
|
||||
@@ -2292,6 +2303,19 @@ if test "$gcrypt" != "no"; then
|
||||
if test -z "$nettle"; then
|
||||
nettle="no"
|
||||
fi
|
||||
|
||||
cat > $TMPC << EOF
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_kdf_derive(NULL, 0, GCRY_KDF_PBKDF2,
|
||||
GCRY_MD_SHA256,
|
||||
NULL, 0, 0, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then
|
||||
gcrypt_kdf=yes
|
||||
fi
|
||||
else
|
||||
if test "$gcrypt" = "yes"; then
|
||||
feature_not_found "gcrypt" "Install gcrypt devel"
|
||||
@@ -2812,7 +2836,7 @@ fi
|
||||
# curses probe
|
||||
if test "$curses" != "no" ; then
|
||||
if test "$mingw32" = "yes" ; then
|
||||
curses_list="-lpdcurses"
|
||||
curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lpdcurses"
|
||||
else
|
||||
curses_list="$($pkg_config --libs ncurses 2>/dev/null):-lncurses:-lcurses"
|
||||
fi
|
||||
@@ -4714,7 +4738,9 @@ echo "GTK support $gtk"
|
||||
echo "GTK GL support $gtk_gl"
|
||||
echo "GNUTLS support $gnutls"
|
||||
echo "GNUTLS hash $gnutls_hash"
|
||||
echo "GNUTLS rnd $gnutls_rnd"
|
||||
echo "libgcrypt $gcrypt"
|
||||
echo "libgcrypt kdf $gcrypt_kdf"
|
||||
if test "$nettle" = "yes"; then
|
||||
echo "nettle $nettle ($nettle_version)"
|
||||
else
|
||||
@@ -5092,8 +5118,14 @@ fi
|
||||
if test "$gnutls_hash" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_HASH=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gnutls_rnd" = "yes" ; then
|
||||
echo "CONFIG_GNUTLS_RND=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$gcrypt" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT=y" >> $config_host_mak
|
||||
if test "$gcrypt_kdf" = "yes" ; then
|
||||
echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak
|
||||
fi
|
||||
fi
|
||||
if test "$nettle" = "yes" ; then
|
||||
echo "CONFIG_NETTLE=y" >> $config_host_mak
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
|
||||
#include "ivshmem-server.h"
|
||||
|
||||
@@ -257,7 +254,8 @@ ivshmem_server_ftruncate(int fd, unsigned shmsize)
|
||||
/* Init a new ivshmem server */
|
||||
int
|
||||
ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
|
||||
const char *shm_path, size_t shm_size, unsigned n_vectors,
|
||||
const char *shm_path, bool use_shm_open,
|
||||
size_t shm_size, unsigned n_vectors,
|
||||
bool verbose)
|
||||
{
|
||||
int ret;
|
||||
@@ -278,6 +276,7 @@ ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
server->use_shm_open = use_shm_open;
|
||||
server->shm_size = shm_size;
|
||||
server->n_vectors = n_vectors;
|
||||
|
||||
@@ -286,31 +285,6 @@ ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
|
||||
#define HUGETLBFS_MAGIC 0x958458f6
|
||||
|
||||
static long gethugepagesize(const char *path)
|
||||
{
|
||||
struct statfs fs;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = statfs(path, &fs);
|
||||
} while (ret != 0 && errno == EINTR);
|
||||
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs.f_type != HUGETLBFS_MAGIC) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fs.f_bsize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* open shm, create and bind to the unix socket */
|
||||
int
|
||||
ivshmem_server_start(IvshmemServer *server)
|
||||
@@ -319,27 +293,17 @@ ivshmem_server_start(IvshmemServer *server)
|
||||
int shm_fd, sock_fd, ret;
|
||||
|
||||
/* open shm file */
|
||||
#ifdef CONFIG_LINUX
|
||||
long hpagesize;
|
||||
|
||||
hpagesize = gethugepagesize(server->shm_path);
|
||||
if (hpagesize < 0 && errno != ENOENT) {
|
||||
IVSHMEM_SERVER_DEBUG(server, "cannot stat shm file %s: %s\n",
|
||||
server->shm_path, strerror(errno));
|
||||
}
|
||||
|
||||
if (hpagesize > 0) {
|
||||
if (server->use_shm_open) {
|
||||
IVSHMEM_SERVER_DEBUG(server, "Using POSIX shared memory: %s\n",
|
||||
server->shm_path);
|
||||
shm_fd = shm_open(server->shm_path, O_CREAT | O_RDWR, S_IRWXU);
|
||||
} else {
|
||||
gchar *filename = g_strdup_printf("%s/ivshmem.XXXXXX", server->shm_path);
|
||||
IVSHMEM_SERVER_DEBUG(server, "Using hugepages: %s\n", server->shm_path);
|
||||
IVSHMEM_SERVER_DEBUG(server, "Using file-backed shared memory: %s\n",
|
||||
server->shm_path);
|
||||
shm_fd = mkstemp(filename);
|
||||
unlink(filename);
|
||||
g_free(filename);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
IVSHMEM_SERVER_DEBUG(server, "Using POSIX shared memory: %s\n",
|
||||
server->shm_path);
|
||||
shm_fd = shm_open(server->shm_path, O_CREAT|O_RDWR, S_IRWXU);
|
||||
}
|
||||
|
||||
if (shm_fd < 0) {
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef struct IvshmemServer {
|
||||
char unix_sock_path[PATH_MAX]; /**< path to unix socket */
|
||||
int sock_fd; /**< unix sock file descriptor */
|
||||
char shm_path[PATH_MAX]; /**< path to shm */
|
||||
bool use_shm_open;
|
||||
size_t shm_size; /**< size of shm */
|
||||
int shm_fd; /**< shm file descriptor */
|
||||
unsigned n_vectors; /**< number of vectors */
|
||||
@@ -89,7 +90,8 @@ typedef struct IvshmemServer {
|
||||
*/
|
||||
int
|
||||
ivshmem_server_init(IvshmemServer *server, const char *unix_sock_path,
|
||||
const char *shm_path, size_t shm_size, unsigned n_vectors,
|
||||
const char *shm_path, bool use_shm_open,
|
||||
size_t shm_size, unsigned n_vectors,
|
||||
bool verbose);
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,35 +29,38 @@ typedef struct IvshmemServerArgs {
|
||||
const char *pid_file;
|
||||
const char *unix_socket_path;
|
||||
const char *shm_path;
|
||||
bool use_shm_open;
|
||||
uint64_t shm_size;
|
||||
unsigned n_vectors;
|
||||
} IvshmemServerArgs;
|
||||
|
||||
/* show ivshmem_server_usage and exit with given error code */
|
||||
static void
|
||||
ivshmem_server_usage(const char *name, int code)
|
||||
ivshmem_server_usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "%s [opts]\n", name);
|
||||
fprintf(stderr, " -h: show this help\n");
|
||||
fprintf(stderr, " -v: verbose mode\n");
|
||||
fprintf(stderr, " -F: foreground mode (default is to daemonize)\n");
|
||||
fprintf(stderr, " -p <pid_file>: path to the PID file (used in daemon\n"
|
||||
" mode only).\n"
|
||||
" Default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
|
||||
fprintf(stderr, " -S <unix_socket_path>: path to the unix socket\n"
|
||||
" to listen to.\n"
|
||||
" Default=%s\n", IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH);
|
||||
fprintf(stderr, " -m <shm_path>: path to the shared memory.\n"
|
||||
" The path corresponds to a POSIX shm name or a\n"
|
||||
" hugetlbfs mount point.\n"
|
||||
" default=%s\n", IVSHMEM_SERVER_DEFAULT_SHM_PATH);
|
||||
fprintf(stderr, " -l <size>: size of shared memory in bytes. The suffix\n"
|
||||
" K, M and G can be used (ex: 1K means 1024).\n"
|
||||
" default=%u\n", IVSHMEM_SERVER_DEFAULT_SHM_SIZE);
|
||||
fprintf(stderr, " -n <n_vects>: number of vectors.\n"
|
||||
" default=%u\n", IVSHMEM_SERVER_DEFAULT_N_VECTORS);
|
||||
printf("Usage: %s [OPTION]...\n"
|
||||
" -h: show this help\n"
|
||||
" -v: verbose mode\n"
|
||||
" -F: foreground mode (default is to daemonize)\n"
|
||||
" -p <pid-file>: path to the PID file (used in daemon mode only)\n"
|
||||
" default " IVSHMEM_SERVER_DEFAULT_PID_FILE "\n"
|
||||
" -S <unix-socket-path>: path to the unix socket to listen to\n"
|
||||
" default " IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH "\n"
|
||||
" -M <shm-name>: POSIX shared memory object to use\n"
|
||||
" default " IVSHMEM_SERVER_DEFAULT_SHM_PATH "\n"
|
||||
" -m <dir-name>: where to create shared memory\n"
|
||||
" -l <size>: size of shared memory in bytes\n"
|
||||
" suffixes K, M and G can be used, e.g. 1K means 1024\n"
|
||||
" default %u\n"
|
||||
" -n <nvectors>: number of vectors\n"
|
||||
" default %u\n",
|
||||
progname, IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
|
||||
IVSHMEM_SERVER_DEFAULT_N_VECTORS);
|
||||
}
|
||||
|
||||
exit(code);
|
||||
static void
|
||||
ivshmem_server_help(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "Try '%s -h' for more information.\n", progname);
|
||||
}
|
||||
|
||||
/* parse the program arguments, exit on error */
|
||||
@@ -68,20 +71,12 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
|
||||
unsigned long long v;
|
||||
Error *err = NULL;
|
||||
|
||||
while ((c = getopt(argc, argv,
|
||||
"h" /* help */
|
||||
"v" /* verbose */
|
||||
"F" /* foreground */
|
||||
"p:" /* pid_file */
|
||||
"S:" /* unix_socket_path */
|
||||
"m:" /* shm_path */
|
||||
"l:" /* shm_size */
|
||||
"n:" /* n_vectors */
|
||||
)) != -1) {
|
||||
while ((c = getopt(argc, argv, "hvFp:S:m:M:l:n:")) != -1) {
|
||||
|
||||
switch (c) {
|
||||
case 'h': /* help */
|
||||
ivshmem_server_usage(argv[0], 0);
|
||||
ivshmem_server_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
@@ -92,36 +87,41 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
|
||||
args->foreground = 1;
|
||||
break;
|
||||
|
||||
case 'p': /* pid_file */
|
||||
case 'p': /* pid file */
|
||||
args->pid_file = optarg;
|
||||
break;
|
||||
|
||||
case 'S': /* unix_socket_path */
|
||||
case 'S': /* unix socket path */
|
||||
args->unix_socket_path = optarg;
|
||||
break;
|
||||
|
||||
case 'm': /* shm_path */
|
||||
case 'M': /* shm name */
|
||||
case 'm': /* dir name */
|
||||
args->shm_path = optarg;
|
||||
args->use_shm_open = c == 'M';
|
||||
break;
|
||||
|
||||
case 'l': /* shm_size */
|
||||
case 'l': /* shm size */
|
||||
parse_option_size("shm_size", optarg, &args->shm_size, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
ivshmem_server_usage(argv[0], 1);
|
||||
ivshmem_server_help(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n': /* n_vectors */
|
||||
case 'n': /* number of vectors */
|
||||
if (parse_uint_full(optarg, &v, 0) < 0) {
|
||||
fprintf(stderr, "cannot parse n_vectors\n");
|
||||
ivshmem_server_usage(argv[0], 1);
|
||||
ivshmem_server_help(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
args->n_vectors = v;
|
||||
break;
|
||||
|
||||
default:
|
||||
ivshmem_server_usage(argv[0], 1);
|
||||
ivshmem_server_usage(argv[0]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -129,12 +129,14 @@ ivshmem_server_parse_args(IvshmemServerArgs *args, int argc, char *argv[])
|
||||
if (args->n_vectors > IVSHMEM_SERVER_MAX_VECTORS) {
|
||||
fprintf(stderr, "too many requested vectors (max is %d)\n",
|
||||
IVSHMEM_SERVER_MAX_VECTORS);
|
||||
ivshmem_server_usage(argv[0], 1);
|
||||
ivshmem_server_help(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (args->verbose == 1 && args->foreground == 0) {
|
||||
fprintf(stderr, "cannot use verbose in daemon mode\n");
|
||||
ivshmem_server_usage(argv[0], 1);
|
||||
ivshmem_server_help(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,11 +194,18 @@ main(int argc, char *argv[])
|
||||
.pid_file = IVSHMEM_SERVER_DEFAULT_PID_FILE,
|
||||
.unix_socket_path = IVSHMEM_SERVER_DEFAULT_UNIX_SOCK_PATH,
|
||||
.shm_path = IVSHMEM_SERVER_DEFAULT_SHM_PATH,
|
||||
.use_shm_open = true,
|
||||
.shm_size = IVSHMEM_SERVER_DEFAULT_SHM_SIZE,
|
||||
.n_vectors = IVSHMEM_SERVER_DEFAULT_N_VECTORS,
|
||||
};
|
||||
int ret = 1;
|
||||
|
||||
/*
|
||||
* Do not remove this notice without adding proper error handling!
|
||||
* Start with handling ivshmem_server_send_one_msg() failure.
|
||||
*/
|
||||
printf("*** Example code, do not use in production ***\n");
|
||||
|
||||
/* parse arguments, will exit on error */
|
||||
ivshmem_server_parse_args(&args, argc, argv);
|
||||
|
||||
@@ -219,7 +228,8 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* init the ivshms structure */
|
||||
if (ivshmem_server_init(&server, args.unix_socket_path, args.shm_path,
|
||||
if (ivshmem_server_init(&server, args.unix_socket_path,
|
||||
args.shm_path, args.use_shm_open,
|
||||
args.shm_size, args.n_vectors, args.verbose) < 0) {
|
||||
fprintf(stderr, "cannot init server\n");
|
||||
goto err;
|
||||
|
||||
5
cpus.c
5
cpus.c
@@ -29,6 +29,7 @@
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/kvm.h"
|
||||
@@ -734,7 +735,7 @@ static int do_vm_stop(RunState state)
|
||||
}
|
||||
|
||||
bdrv_drain_all();
|
||||
ret = bdrv_flush_all();
|
||||
ret = blk_flush_all();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1433,7 +1434,7 @@ int vm_stop_force_state(RunState state)
|
||||
bdrv_drain_all();
|
||||
/* Make sure to return an error if the flush in a previous vm_stop()
|
||||
* failed. */
|
||||
return bdrv_flush_all();
|
||||
return blk_flush_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,23 @@ crypto-obj-y += tlscredsanon.o
|
||||
crypto-obj-y += tlscredsx509.o
|
||||
crypto-obj-y += tlssession.o
|
||||
crypto-obj-y += secret.o
|
||||
crypto-obj-$(CONFIG_GCRYPT) += random-gcrypt.o
|
||||
crypto-obj-$(if $(CONFIG_GCRYPT),n,$(CONFIG_GNUTLS_RND)) += random-gnutls.o
|
||||
crypto-obj-y += pbkdf.o
|
||||
crypto-obj-$(CONFIG_NETTLE) += pbkdf-nettle.o
|
||||
crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT_KDF)) += pbkdf-gcrypt.o
|
||||
crypto-obj-y += ivgen.o
|
||||
crypto-obj-y += ivgen-essiv.o
|
||||
crypto-obj-y += ivgen-plain.o
|
||||
crypto-obj-y += ivgen-plain64.o
|
||||
crypto-obj-y += afsplit.o
|
||||
crypto-obj-y += xts.o
|
||||
crypto-obj-y += block.o
|
||||
crypto-obj-y += block-qcow.o
|
||||
crypto-obj-y += block-luks.o
|
||||
|
||||
# Let the userspace emulators avoid linking gnutls/etc
|
||||
crypto-aes-obj-y = aes.o
|
||||
|
||||
stub-obj-y += random-stub.o
|
||||
stub-obj-y += pbkdf-stub.o
|
||||
|
||||
158
crypto/afsplit.c
Normal file
158
crypto/afsplit.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* QEMU Crypto anti forensic information splitter
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* Derived from cryptsetup package lib/luks1/af.c
|
||||
*
|
||||
* Copyright (C) 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
* Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/afsplit.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
|
||||
static void qcrypto_afsplit_xor(size_t blocklen,
|
||||
const uint8_t *in1,
|
||||
const uint8_t *in2,
|
||||
uint8_t *out)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < blocklen; i++) {
|
||||
out[i] = in1[i] ^ in2[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint8_t *block,
|
||||
Error **errp)
|
||||
{
|
||||
size_t digestlen = qcrypto_hash_digest_len(hash);
|
||||
|
||||
size_t hashcount = blocklen / digestlen;
|
||||
size_t finallen = blocklen % digestlen;
|
||||
uint32_t i;
|
||||
|
||||
if (finallen) {
|
||||
hashcount++;
|
||||
} else {
|
||||
finallen = digestlen;
|
||||
}
|
||||
|
||||
for (i = 0; i < hashcount; i++) {
|
||||
uint8_t *out = NULL;
|
||||
size_t outlen = 0;
|
||||
uint32_t iv = cpu_to_be32(i);
|
||||
struct iovec in[] = {
|
||||
{ .iov_base = &iv,
|
||||
.iov_len = sizeof(iv) },
|
||||
{ .iov_base = block + (i * digestlen),
|
||||
.iov_len = (i == (hashcount - 1)) ? finallen : digestlen },
|
||||
};
|
||||
|
||||
if (qcrypto_hash_bytesv(hash,
|
||||
in,
|
||||
G_N_ELEMENTS(in),
|
||||
&out, &outlen,
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(outlen == digestlen);
|
||||
memcpy(block + (i * digestlen), out,
|
||||
(i == (hashcount - 1)) ? finallen : digestlen);
|
||||
g_free(out);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
if (qcrypto_random_bytes(out + (i * blocklen), blocklen, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
out + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in,
|
||||
block,
|
||||
out + (i * blocklen));
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *block = g_new0(uint8_t, blocklen);
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
for (i = 0; i < (stripes - 1); i++) {
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
block);
|
||||
if (qcrypto_afsplit_hash(hash, blocklen, block,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
qcrypto_afsplit_xor(blocklen,
|
||||
in + (i * blocklen),
|
||||
block,
|
||||
out);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
g_free(block);
|
||||
return ret;
|
||||
}
|
||||
1328
crypto/block-luks.c
Normal file
1328
crypto/block-luks.c
Normal file
File diff suppressed because it is too large
Load Diff
28
crypto/block-luks.h
Normal file
28
crypto/block-luks.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption LUKS format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_LUKS_H__
|
||||
#define QCRYPTO_BLOCK_LUKS_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_luks;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_LUKS_H__ */
|
||||
173
crypto/block-qcow.c
Normal file
173
crypto/block-qcow.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that the block encryption implemented in this file is broken
|
||||
* by design. This exists only to allow data to be liberated from
|
||||
* existing qcow[2] images and should not be used in any new areas.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/secret.h"
|
||||
|
||||
#define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
|
||||
|
||||
|
||||
static bool
|
||||
qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
|
||||
size_t buf_size G_GNUC_UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_init(QCryptoBlock *block,
|
||||
const char *keysecret,
|
||||
Error **errp)
|
||||
{
|
||||
char *password;
|
||||
int ret;
|
||||
uint8_t keybuf[16];
|
||||
int len;
|
||||
|
||||
memset(keybuf, 0, 16);
|
||||
|
||||
password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
|
||||
if (!password) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(password);
|
||||
memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
|
||||
g_free(password);
|
||||
|
||||
block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC);
|
||||
block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
|
||||
0, 0, NULL, 0, errp);
|
||||
if (!block->ivgen) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC,
|
||||
keybuf, G_N_ELEMENTS(keybuf),
|
||||
errp);
|
||||
if (!block->cipher) {
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block->payload_offset = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_open(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
|
||||
return 0;
|
||||
} else {
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp,
|
||||
"Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
return qcrypto_block_qcow_init(block,
|
||||
options->u.qcow.key_secret, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_create(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
|
||||
QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
|
||||
void *opaque G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
if (!options->u.qcow.key_secret) {
|
||||
error_setg(errp, "Parameter 'key-secret' is required for cipher");
|
||||
return -1;
|
||||
}
|
||||
/* QCow2 has no special header, since everything is hardwired */
|
||||
return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_block_qcow_cleanup(QCryptoBlock *block)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_decrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_block_encrypt_helper(block->cipher,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
const QCryptoBlockDriver qcrypto_block_driver_qcow = {
|
||||
.open = qcrypto_block_qcow_open,
|
||||
.create = qcrypto_block_qcow_create,
|
||||
.cleanup = qcrypto_block_qcow_cleanup,
|
||||
.decrypt = qcrypto_block_qcow_decrypt,
|
||||
.encrypt = qcrypto_block_qcow_encrypt,
|
||||
.has_format = qcrypto_block_qcow_has_format,
|
||||
};
|
||||
28
crypto/block-qcow.h
Normal file
28
crypto/block-qcow.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_QCOW_H__
|
||||
#define QCRYPTO_BLOCK_QCOW_H__
|
||||
|
||||
#include "crypto/blockpriv.h"
|
||||
|
||||
extern const QCryptoBlockDriver qcrypto_block_driver_qcow;
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_QCOW_H__ */
|
||||
260
crypto/block.c
Normal file
260
crypto/block.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/blockpriv.h"
|
||||
#include "crypto/block-qcow.h"
|
||||
#include "crypto/block-luks.h"
|
||||
|
||||
static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
|
||||
[Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
|
||||
[Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
|
||||
};
|
||||
|
||||
|
||||
bool qcrypto_block_has_format(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
const QCryptoBlockDriver *driver;
|
||||
|
||||
if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[format]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
driver = qcrypto_block_drivers[format];
|
||||
|
||||
return driver->has_format(buf, len);
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->open(block, options,
|
||||
readfunc, opaque, flags, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
|
||||
|
||||
block->format = options->format;
|
||||
|
||||
if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
|
||||
!qcrypto_block_drivers[options->format]) {
|
||||
error_setg(errp, "Unsupported block driver %d", options->format);
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->driver = qcrypto_block_drivers[options->format];
|
||||
|
||||
if (block->driver->create(block, options, initfunc,
|
||||
writefunc, opaque, errp) < 0) {
|
||||
g_free(block);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->decrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
return block->driver->encrypt(block, startsector, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
|
||||
{
|
||||
return block->cipher;
|
||||
}
|
||||
|
||||
|
||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
|
||||
{
|
||||
return block->ivgen;
|
||||
}
|
||||
|
||||
|
||||
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
|
||||
{
|
||||
return block->kdfhash;
|
||||
}
|
||||
|
||||
|
||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
|
||||
{
|
||||
return block->payload_offset;
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_block_free(QCryptoBlock *block)
|
||||
{
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->driver->cleanup(block);
|
||||
|
||||
qcrypto_cipher_free(block->cipher);
|
||||
qcrypto_ivgen_free(block->ivgen);
|
||||
g_free(block);
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
while (len > 0) {
|
||||
size_t nbytes;
|
||||
if (niv) {
|
||||
if (qcrypto_ivgen_calculate(ivgen,
|
||||
startsector,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_setiv(cipher,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = len > sectorsize ? sectorsize : len;
|
||||
if (qcrypto_cipher_decrypt(cipher, buf, buf,
|
||||
nbytes, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
startsector++;
|
||||
buf += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
g_free(iv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
int ret = -1;
|
||||
|
||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||
|
||||
while (len > 0) {
|
||||
size_t nbytes;
|
||||
if (niv) {
|
||||
if (qcrypto_ivgen_calculate(ivgen,
|
||||
startsector,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_setiv(cipher,
|
||||
iv, niv,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
nbytes = len > sectorsize ? sectorsize : len;
|
||||
if (qcrypto_cipher_encrypt(cipher, buf, buf,
|
||||
nbytes, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
startsector++;
|
||||
buf += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
g_free(iv);
|
||||
return ret;
|
||||
}
|
||||
92
crypto/blockpriv.h
Normal file
92
crypto/blockpriv.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_PRIV_H__
|
||||
#define QCRYPTO_BLOCK_PRIV_H__
|
||||
|
||||
#include "crypto/block.h"
|
||||
|
||||
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
|
||||
|
||||
struct QCryptoBlock {
|
||||
QCryptoBlockFormat format;
|
||||
|
||||
const QCryptoBlockDriver *driver;
|
||||
void *opaque;
|
||||
|
||||
QCryptoCipher *cipher;
|
||||
QCryptoIVGen *ivgen;
|
||||
QCryptoHashAlgorithm kdfhash;
|
||||
size_t niv;
|
||||
uint64_t payload_offset; /* In bytes */
|
||||
};
|
||||
|
||||
struct QCryptoBlockDriver {
|
||||
int (*open)(QCryptoBlock *block,
|
||||
QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp);
|
||||
|
||||
int (*create)(QCryptoBlock *block,
|
||||
QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
void (*cleanup)(QCryptoBlock *block);
|
||||
|
||||
int (*encrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
int (*decrypt)(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
bool (*has_format)(const uint8_t *buf,
|
||||
size_t buflen);
|
||||
};
|
||||
|
||||
|
||||
int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_PRIV_H__ */
|
||||
@@ -21,11 +21,17 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/desrfb.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
|
||||
struct QCryptoCipherBuiltinAESContext {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||
struct QCryptoCipherBuiltinAES {
|
||||
AES_KEY encrypt_key;
|
||||
AES_KEY decrypt_key;
|
||||
QCryptoCipherBuiltinAESContext key;
|
||||
QCryptoCipherBuiltinAESContext key_tweak;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
|
||||
@@ -67,6 +73,82 @@ static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
|
||||
const void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_cipher_aes_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *aesctx = ctx;
|
||||
|
||||
qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec,
|
||||
src, dst, length);
|
||||
}
|
||||
|
||||
|
||||
static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
@@ -75,29 +157,26 @@ static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
|
||||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_encrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_encrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.encrypt_key,
|
||||
&ctxt->state.aes.key.enc,
|
||||
ctxt->state.aes.iv, 1);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -112,29 +191,26 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||
{
|
||||
QCryptoCipherBuiltin *ctxt = cipher->opaque;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_ECB) {
|
||||
const uint8_t *inptr = in;
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
} else {
|
||||
uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.decrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
|
||||
in, out, len);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.decrypt_key,
|
||||
&ctxt->state.aes.key.dec,
|
||||
ctxt->state.aes.iv, 0);
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_decrypt(&ctxt->state.aes.key,
|
||||
&ctxt->state.aes.key_tweak,
|
||||
qcrypto_cipher_aes_xts_encrypt,
|
||||
qcrypto_cipher_aes_xts_decrypt,
|
||||
ctxt->state.aes.iv,
|
||||
len, out, in);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -166,21 +242,46 @@ static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
|
||||
QCryptoCipherBuiltin *ctxt;
|
||||
|
||||
if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
|
||||
cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
|
||||
error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctxt = g_new0(QCryptoCipherBuiltin, 1);
|
||||
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.encrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.decrypt_key) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4,
|
||||
&ctxt->state.aes.key_tweak.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ctxt->blocksize = AES_BLOCK_SIZE;
|
||||
@@ -322,7 +423,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
cipher->alg = alg;
|
||||
cipher->mode = mode;
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
|
||||
@@ -29,6 +31,12 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -38,7 +46,9 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
|
||||
struct QCryptoCipherGcrypt {
|
||||
gcry_cipher_hd_t handle;
|
||||
gcry_cipher_hd_t tweakhandle;
|
||||
size_t blocksize;
|
||||
uint8_t *iv;
|
||||
};
|
||||
|
||||
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
@@ -53,6 +63,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
gcrymode = GCRY_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
@@ -63,7 +74,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -84,6 +95,30 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcryalg = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
gcryalg = GCRY_CIPHER_CAST5;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
gcryalg = GCRY_CIPHER_SERPENT128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
gcryalg = GCRY_CIPHER_SERPENT192;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
gcryalg = GCRY_CIPHER_SERPENT256;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH128;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
gcryalg = GCRY_CIPHER_TWOFISH;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
return NULL;
|
||||
@@ -101,6 +136,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot initialize cipher: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
/* We're using standard DES cipher from gcrypt, so we need
|
||||
@@ -112,13 +155,44 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
g_free(rfbkey);
|
||||
ctx->blocksize = 8;
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
ctx->blocksize = 16;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
nkey /= 2;
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
|
||||
} else {
|
||||
err = gcry_cipher_setkey(ctx->handle, key, nkey);
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
switch (cipher->alg) {
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->blocksize = 16;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->blocksize = 8;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set key: %s",
|
||||
gcry_strerror(err));
|
||||
goto error;
|
||||
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->iv = g_new0(uint8_t, ctx->blocksize);
|
||||
}
|
||||
|
||||
cipher->opaque = ctx;
|
||||
@@ -126,6 +200,9 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
error:
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
return NULL;
|
||||
@@ -140,11 +217,35 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||
}
|
||||
ctx = cipher->opaque;
|
||||
gcry_cipher_close(ctx->handle);
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
gcry_cipher_close(ctx->tweakhandle);
|
||||
}
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
|
||||
|
||||
static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
gcry_error_t err;
|
||||
err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
|
||||
g_assert(err == 0);
|
||||
}
|
||||
|
||||
int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
const void *in,
|
||||
void *out,
|
||||
@@ -160,13 +261,20 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_encrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_encrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot encrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -188,13 +296,20 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
xts_decrypt(ctx->handle, ctx->tweakhandle,
|
||||
qcrypto_gcrypt_xts_encrypt,
|
||||
qcrypto_gcrypt_xts_decrypt,
|
||||
ctx->iv, len, out, in);
|
||||
} else {
|
||||
err = gcry_cipher_decrypt(ctx->handle,
|
||||
out, len,
|
||||
in, len);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot decrypt data: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -213,12 +328,16 @@ int qcrypto_cipher_setiv(QCryptoCipher *cipher,
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
if (ctx->iv) {
|
||||
memcpy(ctx->iv, iv, niv);
|
||||
} else {
|
||||
gcry_cipher_reset(ctx->handle);
|
||||
err = gcry_cipher_setiv(ctx->handle, iv, niv);
|
||||
if (err != 0) {
|
||||
error_setg(errp, "Cannot set IV: %s",
|
||||
gcry_strerror(err));
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -19,56 +19,174 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
#include <nettle/nettle-types.h>
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/des.h>
|
||||
#include <nettle/cbc.h>
|
||||
#include <nettle/cast128.h>
|
||||
#include <nettle/serpent.h>
|
||||
#include <nettle/twofish.h>
|
||||
|
||||
typedef void (*QCryptoCipherNettleFuncWrapper)(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
#if CONFIG_NETTLE_VERSION_MAJOR < 3
|
||||
typedef nettle_crypt_func nettle_cipher_func;
|
||||
|
||||
typedef nettle_crypt_func * QCryptoCipherNettleFuncNative;
|
||||
typedef void * cipher_ctx_t;
|
||||
typedef unsigned cipher_length_t;
|
||||
|
||||
#define cast5_set_key cast128_set_key
|
||||
#else
|
||||
typedef nettle_cipher_func * QCryptoCipherNettleFuncNative;
|
||||
typedef const void * cipher_ctx_t;
|
||||
typedef size_t cipher_length_t;
|
||||
#endif
|
||||
|
||||
static nettle_cipher_func aes_encrypt_wrapper;
|
||||
static nettle_cipher_func aes_decrypt_wrapper;
|
||||
static nettle_cipher_func des_encrypt_wrapper;
|
||||
static nettle_cipher_func des_decrypt_wrapper;
|
||||
typedef struct QCryptoNettleAES {
|
||||
struct aes_ctx enc;
|
||||
struct aes_ctx dec;
|
||||
} QCryptoNettleAES;
|
||||
|
||||
static void aes_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
static void aes_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_encrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_encrypt(&aesctx->enc, length, dst, src);
|
||||
}
|
||||
|
||||
static void aes_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
static void aes_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
aes_decrypt(ctx, length, dst, src);
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_decrypt(&aesctx->dec, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
static void des_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_encrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_decrypt_native(cipher_ctx_t ctx, cipher_length_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void aes_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_encrypt(&aesctx->enc, length, dst, src);
|
||||
}
|
||||
|
||||
static void aes_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
const QCryptoNettleAES *aesctx = ctx;
|
||||
aes_decrypt(&aesctx->dec, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void des_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
|
||||
static void des_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
des_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void cast128_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
cast128_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void serpent_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
serpent_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_encrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_encrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
static void twofish_decrypt_wrapper(const void *ctx, size_t length,
|
||||
uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
twofish_decrypt(ctx, length, dst, src);
|
||||
}
|
||||
|
||||
typedef struct QCryptoCipherNettle QCryptoCipherNettle;
|
||||
struct QCryptoCipherNettle {
|
||||
void *ctx_encrypt;
|
||||
void *ctx_decrypt;
|
||||
nettle_cipher_func *alg_encrypt;
|
||||
nettle_cipher_func *alg_decrypt;
|
||||
/* Primary cipher context for all modes */
|
||||
void *ctx;
|
||||
/* Second cipher context for XTS mode only */
|
||||
void *ctx_tweak;
|
||||
/* Cipher callbacks for both contexts */
|
||||
QCryptoCipherNettleFuncNative alg_encrypt_native;
|
||||
QCryptoCipherNettleFuncNative alg_decrypt_native;
|
||||
QCryptoCipherNettleFuncWrapper alg_encrypt_wrapper;
|
||||
QCryptoCipherNettleFuncWrapper alg_decrypt_wrapper;
|
||||
|
||||
uint8_t *iv;
|
||||
size_t blocksize;
|
||||
};
|
||||
@@ -80,6 +198,13 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -99,13 +224,14 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher mode %d", mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -117,14 +243,15 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALG_DES_RFB:
|
||||
ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
|
||||
ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
|
||||
ctx->ctx = g_new0(struct des_ctx, 1);
|
||||
rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
|
||||
des_set_key(ctx->ctx_encrypt, rfbkey);
|
||||
des_set_key(ctx->ctx, rfbkey);
|
||||
g_free(rfbkey);
|
||||
|
||||
ctx->alg_encrypt = des_encrypt_wrapper;
|
||||
ctx->alg_decrypt = des_decrypt_wrapper;
|
||||
ctx->alg_encrypt_native = des_encrypt_native;
|
||||
ctx->alg_decrypt_native = des_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = des_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = des_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = DES_BLOCK_SIZE;
|
||||
break;
|
||||
@@ -132,17 +259,103 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
|
||||
case QCRYPTO_CIPHER_ALG_AES_128:
|
||||
case QCRYPTO_CIPHER_ALG_AES_192:
|
||||
case QCRYPTO_CIPHER_ALG_AES_256:
|
||||
ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
|
||||
ctx->ctx = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
|
||||
aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(QCryptoNettleAES, 1);
|
||||
|
||||
ctx->alg_encrypt = aes_encrypt_wrapper;
|
||||
ctx->alg_decrypt = aes_decrypt_wrapper;
|
||||
nkey /= 2;
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->enc,
|
||||
nkey, key + nkey);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx_tweak)->dec,
|
||||
nkey, key + nkey);
|
||||
} else {
|
||||
aes_set_encrypt_key(&((QCryptoNettleAES *)ctx->ctx)->enc,
|
||||
nkey, key);
|
||||
aes_set_decrypt_key(&((QCryptoNettleAES *)ctx->ctx)->dec,
|
||||
nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt_native = aes_encrypt_native;
|
||||
ctx->alg_decrypt_native = aes_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = aes_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = aes_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = AES_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_CAST5_128:
|
||||
ctx->ctx = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct cast128_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
cast5_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
cast5_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt_native = cast128_encrypt_native;
|
||||
ctx->alg_decrypt_native = cast128_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = cast128_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = cast128_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = CAST128_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_128:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_192:
|
||||
case QCRYPTO_CIPHER_ALG_SERPENT_256:
|
||||
ctx->ctx = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct serpent_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
serpent_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
serpent_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt_native = serpent_encrypt_native;
|
||||
ctx->alg_decrypt_native = serpent_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = serpent_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = serpent_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = SERPENT_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_128:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_192:
|
||||
case QCRYPTO_CIPHER_ALG_TWOFISH_256:
|
||||
ctx->ctx = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
ctx->ctx_tweak = g_new0(struct twofish_ctx, 1);
|
||||
|
||||
nkey /= 2;
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
twofish_set_key(ctx->ctx_tweak, nkey, key + nkey);
|
||||
} else {
|
||||
twofish_set_key(ctx->ctx, nkey, key);
|
||||
}
|
||||
|
||||
ctx->alg_encrypt_native = twofish_encrypt_native;
|
||||
ctx->alg_decrypt_native = twofish_decrypt_native;
|
||||
ctx->alg_encrypt_wrapper = twofish_encrypt_wrapper;
|
||||
ctx->alg_decrypt_wrapper = twofish_decrypt_wrapper;
|
||||
|
||||
ctx->blocksize = TWOFISH_BLOCK_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d", alg);
|
||||
goto error;
|
||||
@@ -170,8 +383,8 @@ void qcrypto_cipher_free(QCryptoCipher *cipher)
|
||||
|
||||
ctx = cipher->opaque;
|
||||
g_free(ctx->iv);
|
||||
g_free(ctx->ctx_encrypt);
|
||||
g_free(ctx->ctx_decrypt);
|
||||
g_free(ctx->ctx);
|
||||
g_free(ctx->ctx_tweak);
|
||||
g_free(ctx);
|
||||
g_free(cipher);
|
||||
}
|
||||
@@ -193,14 +406,21 @@ int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
|
||||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
|
||||
ctx->alg_encrypt_wrapper(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
|
||||
cbc_encrypt(ctx->ctx, ctx->alg_encrypt_native,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
xts_encrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt_wrapper, ctx->alg_encrypt_wrapper,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
@@ -226,15 +446,26 @@ int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
|
||||
|
||||
switch (cipher->mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
len, out, in);
|
||||
ctx->alg_decrypt_wrapper(ctx->ctx, len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
|
||||
ctx->alg_decrypt, ctx->blocksize, ctx->iv,
|
||||
cbc_decrypt(ctx->ctx, ctx->alg_decrypt_native,
|
||||
ctx->blocksize, ctx->iv,
|
||||
len, out, in);
|
||||
break;
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
if (ctx->blocksize != XTS_BLOCK_SIZE) {
|
||||
error_setg(errp, "Block size must be %d not %zu",
|
||||
XTS_BLOCK_SIZE, ctx->blocksize);
|
||||
return -1;
|
||||
}
|
||||
xts_decrypt(ctx->ctx, ctx->ctx_tweak,
|
||||
ctx->alg_encrypt_wrapper, ctx->alg_decrypt_wrapper,
|
||||
ctx->iv, len, out, in);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher algorithm %d",
|
||||
cipher->alg);
|
||||
|
||||
@@ -27,6 +27,13 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 32,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
|
||||
};
|
||||
|
||||
static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
@@ -34,11 +41,19 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
|
||||
[QCRYPTO_CIPHER_ALG_AES_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_AES_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_SERPENT_256] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16,
|
||||
[QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
|
||||
};
|
||||
|
||||
static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
|
||||
[QCRYPTO_CIPHER_MODE_ECB] = false,
|
||||
[QCRYPTO_CIPHER_MODE_CBC] = true,
|
||||
[QCRYPTO_CIPHER_MODE_XTS] = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -79,6 +94,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
|
||||
|
||||
static bool
|
||||
qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
QCryptoCipherMode mode,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -88,10 +104,27 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
|
||||
error_setg(errp, "XTS mode not compatible with DES-RFB");
|
||||
return false;
|
||||
}
|
||||
if (nkey % 2) {
|
||||
error_setg(errp, "XTS cipher key length should be a multiple of 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alg_key_len[alg] != (nkey / 2)) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg] * 2);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (alg_key_len[alg] != nkey) {
|
||||
error_setg(errp, "Cipher key length %zu should be %zu",
|
||||
nkey, alg_key_len[alg]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
118
crypto/ivgen-essiv.c
Normal file
118
crypto/ivgen-essiv.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - essiv
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-essiv.h"
|
||||
|
||||
typedef struct QCryptoIVGenESSIV QCryptoIVGenESSIV;
|
||||
struct QCryptoIVGenESSIV {
|
||||
QCryptoCipher *cipher;
|
||||
};
|
||||
|
||||
static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *salt;
|
||||
size_t nhash;
|
||||
size_t nsalt;
|
||||
QCryptoIVGenESSIV *essiv = g_new0(QCryptoIVGenESSIV, 1);
|
||||
|
||||
/* Not necessarily the same as nkey */
|
||||
nsalt = qcrypto_cipher_get_key_len(ivgen->cipher);
|
||||
|
||||
nhash = qcrypto_hash_digest_len(ivgen->hash);
|
||||
/* Salt must be larger of hash size or key size */
|
||||
salt = g_new0(uint8_t, MAX(nhash, nsalt));
|
||||
|
||||
if (qcrypto_hash_bytes(ivgen->hash, (const gchar *)key, nkey,
|
||||
&salt, &nhash,
|
||||
errp) < 0) {
|
||||
g_free(essiv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now potentially truncate salt to match cipher key len */
|
||||
essiv->cipher = qcrypto_cipher_new(ivgen->cipher,
|
||||
QCRYPTO_CIPHER_MODE_ECB,
|
||||
salt, MIN(nhash, nsalt),
|
||||
errp);
|
||||
if (!essiv->cipher) {
|
||||
g_free(essiv);
|
||||
g_free(salt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_free(salt);
|
||||
ivgen->private = essiv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_essiv_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||
size_t ndata = qcrypto_cipher_get_block_len(ivgen->cipher);
|
||||
uint8_t *data = g_new(uint8_t, ndata);
|
||||
|
||||
sector = cpu_to_le64(sector);
|
||||
memcpy(data, (uint8_t *)§or, ndata);
|
||||
if (sizeof(sector) < ndata) {
|
||||
memset(data + sizeof(sector), 0, ndata - sizeof(sector));
|
||||
}
|
||||
|
||||
if (qcrypto_cipher_encrypt(essiv->cipher,
|
||||
data,
|
||||
data,
|
||||
ndata,
|
||||
errp) < 0) {
|
||||
g_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ndata > niv) {
|
||||
ndata = niv;
|
||||
}
|
||||
memcpy(iv, data, ndata);
|
||||
if (ndata < niv) {
|
||||
memset(iv + ndata, 0, niv - ndata);
|
||||
}
|
||||
g_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_essiv_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
QCryptoIVGenESSIV *essiv = ivgen->private;
|
||||
|
||||
qcrypto_cipher_free(essiv->cipher);
|
||||
g_free(essiv);
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_essiv = {
|
||||
.init = qcrypto_ivgen_essiv_init,
|
||||
.calculate = qcrypto_ivgen_essiv_calculate,
|
||||
.cleanup = qcrypto_ivgen_essiv_cleanup,
|
||||
};
|
||||
|
||||
28
crypto/ivgen-essiv.h
Normal file
28
crypto/ivgen-essiv.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - essiv
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_ESSIV_H__
|
||||
#define QCRYPTO_IVGEN_ESSIV_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_essiv;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_ESSIV_H__ */
|
||||
59
crypto/ivgen-plain.c
Normal file
59
crypto/ivgen-plain.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-plain.h"
|
||||
|
||||
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
size_t ivprefix;
|
||||
uint32_t shortsector = cpu_to_le32((sector & 0xffffffff));
|
||||
ivprefix = sizeof(shortsector);
|
||||
if (ivprefix > niv) {
|
||||
ivprefix = niv;
|
||||
}
|
||||
memcpy(iv, &shortsector, ivprefix);
|
||||
if (ivprefix < niv) {
|
||||
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_plain = {
|
||||
.init = qcrypto_ivgen_plain_init,
|
||||
.calculate = qcrypto_ivgen_plain_calculate,
|
||||
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||
};
|
||||
|
||||
28
crypto/ivgen-plain.h
Normal file
28
crypto/ivgen-plain.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_PLAIN_H__
|
||||
#define QCRYPTO_IVGEN_PLAIN_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_PLAIN_H__ */
|
||||
59
crypto/ivgen-plain64.c
Normal file
59
crypto/ivgen-plain64.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgen-plain.h"
|
||||
|
||||
static int qcrypto_ivgen_plain_init(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_ivgen_plain_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
size_t ivprefix;
|
||||
ivprefix = sizeof(sector);
|
||||
sector = cpu_to_le64(sector);
|
||||
if (ivprefix > niv) {
|
||||
ivprefix = niv;
|
||||
}
|
||||
memcpy(iv, §or, ivprefix);
|
||||
if (ivprefix < niv) {
|
||||
memset(iv + ivprefix, 0, niv - ivprefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcrypto_ivgen_plain_cleanup(QCryptoIVGen *ivgen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
struct QCryptoIVGenDriver qcrypto_ivgen_plain64 = {
|
||||
.init = qcrypto_ivgen_plain_init,
|
||||
.calculate = qcrypto_ivgen_plain_calculate,
|
||||
.cleanup = qcrypto_ivgen_plain_cleanup,
|
||||
};
|
||||
|
||||
28
crypto/ivgen-plain64.h
Normal file
28
crypto/ivgen-plain64.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator - plain64
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crypto/ivgenpriv.h"
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_PLAIN64_H__
|
||||
#define QCRYPTO_IVGEN_PLAIN64_H__
|
||||
|
||||
extern struct QCryptoIVGenDriver qcrypto_ivgen_plain64;
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_PLAIN64_H__ */
|
||||
99
crypto/ivgen.c
Normal file
99
crypto/ivgen.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/ivgenpriv.h"
|
||||
#include "crypto/ivgen-plain.h"
|
||||
#include "crypto/ivgen-plain64.h"
|
||||
#include "crypto/ivgen-essiv.h"
|
||||
|
||||
|
||||
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
|
||||
QCryptoCipherAlgorithm cipheralg,
|
||||
QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoIVGen *ivgen = g_new0(QCryptoIVGen, 1);
|
||||
|
||||
ivgen->algorithm = alg;
|
||||
ivgen->cipher = cipheralg;
|
||||
ivgen->hash = hash;
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_IVGEN_ALG_PLAIN:
|
||||
ivgen->driver = &qcrypto_ivgen_plain;
|
||||
break;
|
||||
case QCRYPTO_IVGEN_ALG_PLAIN64:
|
||||
ivgen->driver = &qcrypto_ivgen_plain64;
|
||||
break;
|
||||
case QCRYPTO_IVGEN_ALG_ESSIV:
|
||||
ivgen->driver = &qcrypto_ivgen_essiv;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unknown block IV generator algorithm %d", alg);
|
||||
g_free(ivgen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ivgen->driver->init(ivgen, key, nkey, errp) < 0) {
|
||||
g_free(ivgen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ivgen;
|
||||
}
|
||||
|
||||
|
||||
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
return ivgen->driver->calculate(ivgen, sector, iv, niv, errp);
|
||||
}
|
||||
|
||||
|
||||
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen)
|
||||
{
|
||||
return ivgen->algorithm;
|
||||
}
|
||||
|
||||
|
||||
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen)
|
||||
{
|
||||
return ivgen->cipher;
|
||||
}
|
||||
|
||||
|
||||
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen)
|
||||
{
|
||||
return ivgen->hash;
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_ivgen_free(QCryptoIVGen *ivgen)
|
||||
{
|
||||
if (!ivgen) {
|
||||
return;
|
||||
}
|
||||
ivgen->driver->cleanup(ivgen);
|
||||
g_free(ivgen);
|
||||
}
|
||||
49
crypto/ivgenpriv.h
Normal file
49
crypto/ivgenpriv.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_PRIV_H__
|
||||
#define QCRYPTO_IVGEN_PRIV_H__
|
||||
|
||||
#include "crypto/ivgen.h"
|
||||
|
||||
typedef struct QCryptoIVGenDriver QCryptoIVGenDriver;
|
||||
|
||||
struct QCryptoIVGenDriver {
|
||||
int (*init)(QCryptoIVGen *ivgen,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp);
|
||||
int (*calculate)(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp);
|
||||
void (*cleanup)(QCryptoIVGen *ivgen);
|
||||
};
|
||||
|
||||
struct QCryptoIVGen {
|
||||
QCryptoIVGenDriver *driver;
|
||||
void *private;
|
||||
|
||||
QCryptoIVGenAlgorithm algorithm;
|
||||
QCryptoCipherAlgorithm cipher;
|
||||
QCryptoHashAlgorithm hash;
|
||||
};
|
||||
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_PRIV_H__ */
|
||||
68
crypto/pbkdf-gcrypt.c
Normal file
68
crypto/pbkdf-gcrypt.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/pbkdf.h"
|
||||
#include "gcrypt.h"
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_MD5:
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
|
||||
[QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
|
||||
[QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
|
||||
[QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (hash >= G_N_ELEMENTS(hash_map) ||
|
||||
hash_map[hash] == GCRY_MD_NONE) {
|
||||
error_setg(errp, "Unexpected hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gcry_kdf_derive(key, nkey, GCRY_KDF_PBKDF2,
|
||||
hash_map[hash],
|
||||
salt, nsalt, iterations,
|
||||
nout, out);
|
||||
if (ret != 0) {
|
||||
error_setg(errp, "Cannot derive password: %s",
|
||||
gcry_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
65
crypto/pbkdf-nettle.c
Normal file
65
crypto/pbkdf-nettle.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/pbkdf.h"
|
||||
#include "nettle/pbkdf2.h"
|
||||
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp)
|
||||
{
|
||||
switch (hash) {
|
||||
case QCRYPTO_HASH_ALG_SHA1:
|
||||
pbkdf2_hmac_sha1(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
case QCRYPTO_HASH_ALG_SHA256:
|
||||
pbkdf2_hmac_sha256(nkey, key,
|
||||
iterations,
|
||||
nsalt, salt,
|
||||
nout, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"PBKDF does not support hash algorithm %d", hash);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
42
crypto/pbkdf-stub.c
Normal file
42
crypto/pbkdf-stub.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/pbkdf.h"
|
||||
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash G_GNUC_UNUSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
|
||||
const uint8_t *key G_GNUC_UNUSED,
|
||||
size_t nkey G_GNUC_UNUSED,
|
||||
const uint8_t *salt G_GNUC_UNUSED,
|
||||
size_t nsalt G_GNUC_UNUSED,
|
||||
unsigned int iterations G_GNUC_UNUSED,
|
||||
uint8_t *out G_GNUC_UNUSED,
|
||||
size_t nout G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg_errno(errp, ENOSYS,
|
||||
"No crypto library supporting PBKDF in this build");
|
||||
return -1;
|
||||
}
|
||||
109
crypto/pbkdf.c
Normal file
109
crypto/pbkdf.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/pbkdf.h"
|
||||
#ifndef _WIN32
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
|
||||
static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
|
||||
Error **errp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FILETIME creation_time, exit_time, kernel_time, user_time;
|
||||
ULARGE_INTEGER thread_time;
|
||||
|
||||
if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time,
|
||||
&kernel_time, &user_time)) {
|
||||
error_setg(errp, "Unable to get thread CPU usage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread_time.LowPart = user_time.dwLowDateTime;
|
||||
thread_time.HighPart = user_time.dwHighDateTime;
|
||||
|
||||
/* QuadPart is units of 100ns and we want ms as unit */
|
||||
*val_ms = thread_time.QuadPart / 10000ll;
|
||||
return 0;
|
||||
#elif defined(RUSAGE_THREAD)
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_THREAD, &ru) < 0) {
|
||||
error_setg_errno(errp, errno, "Unable to get thread CPU usage");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*val_ms = ((ru.ru_utime.tv_sec * 1000ll) +
|
||||
(ru.ru_utime.tv_usec / 1000));
|
||||
return 0;
|
||||
#else
|
||||
*val_ms = 0;
|
||||
error_setg(errp, "Unable to calculate thread CPU usage on this platform");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t out[32];
|
||||
long long int iterations = (1 << 15);
|
||||
unsigned long long delta_ms, start_ms, end_ms;
|
||||
|
||||
while (1) {
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2(hash,
|
||||
key, nkey,
|
||||
salt, nsalt,
|
||||
iterations,
|
||||
out, sizeof(out),
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
delta_ms = end_ms - start_ms;
|
||||
|
||||
if (delta_ms > 500) {
|
||||
break;
|
||||
} else if (delta_ms < 100) {
|
||||
iterations = iterations * 10;
|
||||
} else {
|
||||
iterations = (iterations * 1000 / delta_ms);
|
||||
}
|
||||
}
|
||||
|
||||
iterations = iterations * 1000 / delta_ms;
|
||||
|
||||
if (iterations > INT32_MAX) {
|
||||
error_setg(errp, "Iterations %lld too large for a 32-bit int",
|
||||
iterations);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return iterations;
|
||||
}
|
||||
33
crypto/random-gcrypt.c
Normal file
33
crypto/random-gcrypt.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/random.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
{
|
||||
gcry_randomize(buf, buflen, GCRY_STRONG_RANDOM);
|
||||
return 0;
|
||||
}
|
||||
43
crypto/random-gnutls.c
Normal file
43
crypto/random-gnutls.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/random.h"
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gnutls_rnd(GNUTLS_RND_RANDOM, buf, buflen);
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot get random bytes: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
crypto/random-stub.c
Normal file
31
crypto/random-stub.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "crypto/random.h"
|
||||
|
||||
int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
|
||||
size_t buflen G_GNUC_UNUSED,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "No random byte source provided in this build");
|
||||
return -1;
|
||||
}
|
||||
230
crypto/xts.c
Normal file
230
crypto/xts.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
static void xts_mult_x(uint8_t *I)
|
||||
{
|
||||
int x;
|
||||
uint8_t t, tt;
|
||||
|
||||
for (x = t = 0; x < 16; x++) {
|
||||
tt = I[x] >> 7;
|
||||
I[x] = ((I[x] << 1) | t) & 0xFF;
|
||||
t = tt;
|
||||
}
|
||||
if (tt) {
|
||||
I[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xts_tweak_uncrypt:
|
||||
* @param ctxt: the cipher context
|
||||
* @param func: the cipher function
|
||||
* @src: buffer providing the cipher text of XTS_BLOCK_SIZE bytes
|
||||
* @dst: buffer to output the plain text of XTS_BLOCK_SIZE bytes
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
*
|
||||
* Decrypt data with a tweak
|
||||
*/
|
||||
static void xts_tweak_decrypt(const void *ctx,
|
||||
xts_cipher_func *func,
|
||||
const uint8_t *src,
|
||||
uint8_t *dst,
|
||||
uint8_t *iv)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
/* tweak encrypt block i */
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = src[x] ^ iv[x];
|
||||
}
|
||||
|
||||
func(ctx, XTS_BLOCK_SIZE, dst, dst);
|
||||
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = dst[x] ^ iv[x];
|
||||
}
|
||||
|
||||
/* LFSR the tweak */
|
||||
xts_mult_x(iv);
|
||||
}
|
||||
|
||||
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE];
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv);
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
xts_tweak_decrypt(datactx, decfunc, src, dst, T);
|
||||
|
||||
src += XTS_BLOCK_SIZE;
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
memcpy(CC, T, XTS_BLOCK_SIZE);
|
||||
xts_mult_x(CC);
|
||||
|
||||
/* PP = tweak decrypt block m-1 */
|
||||
xts_tweak_decrypt(datactx, decfunc, src, PP, CC);
|
||||
|
||||
/* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
|
||||
for (i = 0; i < mo; i++) {
|
||||
CC[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = PP[i];
|
||||
}
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
CC[i] = PP[i];
|
||||
}
|
||||
|
||||
/* Pm-1 = Tweak uncrypt CC */
|
||||
xts_tweak_decrypt(datactx, decfunc, CC, dst, T);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xts_tweak_crypt:
|
||||
* @param ctxt: the cipher context
|
||||
* @param func: the cipher function
|
||||
* @src: buffer providing the plain text of XTS_BLOCK_SIZE bytes
|
||||
* @dst: buffer to output the cipher text of XTS_BLOCK_SIZE bytes
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
*
|
||||
* Encrypt data with a tweak
|
||||
*/
|
||||
static void xts_tweak_encrypt(const void *ctx,
|
||||
xts_cipher_func *func,
|
||||
const uint8_t *src,
|
||||
uint8_t *dst,
|
||||
uint8_t *iv)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
/* tweak encrypt block i */
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = src[x] ^ iv[x];
|
||||
}
|
||||
|
||||
func(ctx, XTS_BLOCK_SIZE, dst, dst);
|
||||
|
||||
for (x = 0; x < XTS_BLOCK_SIZE; x++) {
|
||||
dst[x] = dst[x] ^ iv[x];
|
||||
}
|
||||
|
||||
/* LFSR the tweak */
|
||||
xts_mult_x(iv);
|
||||
}
|
||||
|
||||
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
uint8_t PP[XTS_BLOCK_SIZE], CC[XTS_BLOCK_SIZE], T[XTS_BLOCK_SIZE];
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T, iv);
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
xts_tweak_encrypt(datactx, encfunc, src, dst, T);
|
||||
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
src += XTS_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
/* CC = tweak encrypt block m-1 */
|
||||
xts_tweak_encrypt(datactx, encfunc, src, CC, T);
|
||||
|
||||
/* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
|
||||
for (i = 0; i < mo; i++) {
|
||||
PP[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = CC[i];
|
||||
}
|
||||
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
PP[i] = CC[i];
|
||||
}
|
||||
|
||||
/* Cm-1 = Tweak encrypt PP */
|
||||
xts_tweak_encrypt(datactx, encfunc, PP, dst, T);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T);
|
||||
}
|
||||
@@ -36,5 +36,5 @@ CONFIG_SDHCI=y
|
||||
CONFIG_EDU=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_IVSHMEM=$(CONFIG_POSIX)
|
||||
CONFIG_IVSHMEM=$(CONFIG_EVENTFD)
|
||||
CONFIG_ROCKER=y
|
||||
|
||||
@@ -84,6 +84,8 @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
|
||||
|
||||
err:
|
||||
if (dinfo) {
|
||||
blk_unref(blk_by_legacy_dinfo(dinfo));
|
||||
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||
monitor_remove_blk(blk);
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,8 +153,6 @@
|
||||
/* opcodes/i386-dis.c r1.126 */
|
||||
#include "qemu-common.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
static int fetch_data2(struct disassemble_info *, bfd_byte *);
|
||||
static int fetch_data(struct disassemble_info *, bfd_byte *);
|
||||
static void ckprefix (void);
|
||||
|
||||
@@ -615,8 +615,6 @@ static const char *const reg_half_names[] =
|
||||
/* Maximum length of an instruction. */
|
||||
#define MAXLEN 22
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
struct private
|
||||
{
|
||||
/* Points to first byte not fetched. */
|
||||
|
||||
@@ -284,7 +284,7 @@ better than open-coding the member to be type 'str'.
|
||||
=== Union types ===
|
||||
|
||||
Usage: { 'union': STRING, 'data': DICT }
|
||||
or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
|
||||
or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME-OR-DICT,
|
||||
'discriminator': ENUM-MEMBER-OF-BASE }
|
||||
|
||||
Union types are used to let the user choose between several different
|
||||
@@ -297,22 +297,22 @@ be empty.
|
||||
A simple union type defines a mapping from automatic discriminator
|
||||
values to data types like in this example:
|
||||
|
||||
{ 'struct': 'FileOptions', 'data': { 'filename': 'str' } }
|
||||
{ 'struct': 'Qcow2Options',
|
||||
'data': { 'backing-file': 'str', 'lazy-refcounts': 'bool' } }
|
||||
{ 'struct': 'BlockdevOptionsFile', 'data': { 'filename': 'str' } }
|
||||
{ 'struct': 'BlockdevOptionsQcow2',
|
||||
'data': { 'backing': 'str', '*lazy-refcounts': 'bool' } }
|
||||
|
||||
{ 'union': 'BlockdevOptions',
|
||||
'data': { 'file': 'FileOptions',
|
||||
'qcow2': 'Qcow2Options' } }
|
||||
{ 'union': 'BlockdevOptionsSimple',
|
||||
'data': { 'file': 'BlockdevOptionsFile',
|
||||
'qcow2': 'BlockdevOptionsQcow2' } }
|
||||
|
||||
In the Client JSON Protocol, a simple union is represented by a
|
||||
dictionary that contains the 'type' member as a discriminator, and a
|
||||
'data' member that is of the specified data type corresponding to the
|
||||
discriminator value, as in these examples:
|
||||
|
||||
{ "type": "file", "data" : { "filename": "/some/place/my-image" } }
|
||||
{ "type": "qcow2", "data" : { "backing-file": "/some/place/my-image",
|
||||
"lazy-refcounts": true } }
|
||||
{ "type": "file", "data": { "filename": "/some/place/my-image" } }
|
||||
{ "type": "qcow2", "data": { "backing": "/some/place/my-image",
|
||||
"lazy-refcounts": true } }
|
||||
|
||||
The generated C code uses a struct containing a union. Additionally,
|
||||
an implicit C enum 'NameKind' is created, corresponding to the union
|
||||
@@ -320,34 +320,35 @@ an implicit C enum 'NameKind' is created, corresponding to the union
|
||||
the union can be named 'max', as this would collide with the implicit
|
||||
enum. The value for each branch can be of any type.
|
||||
|
||||
A flat union definition specifies a struct as its base, and
|
||||
avoids nesting on the wire. All branches of the union must be
|
||||
complex types, and the top-level members of the union dictionary on
|
||||
the wire will be combination of members from both the base type and the
|
||||
appropriate branch type (when merging two dictionaries, there must be
|
||||
no keys in common). The 'discriminator' member must be the name of an
|
||||
enum-typed member of the base struct.
|
||||
A flat union definition avoids nesting on the wire, and specifies a
|
||||
set of common members that occur in all variants of the union. The
|
||||
'base' key must specifiy either a type name (the type must be a
|
||||
struct, not a union), or a dictionary representing an anonymous type.
|
||||
All branches of the union must be complex types, and the top-level
|
||||
members of the union dictionary on the wire will be combination of
|
||||
members from both the base type and the appropriate branch type (when
|
||||
merging two dictionaries, there must be no keys in common). The
|
||||
'discriminator' member must be the name of a non-optional enum-typed
|
||||
member of the base struct.
|
||||
|
||||
The following example enhances the above simple union example by
|
||||
adding a common member 'readonly', renaming the discriminator to
|
||||
something more applicable, and reducing the number of {} required on
|
||||
the wire:
|
||||
adding an optional common member 'read-only', renaming the
|
||||
discriminator to something more applicable than the simple union's
|
||||
default of 'type', and reducing the number of {} required on the wire:
|
||||
|
||||
{ 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
|
||||
{ 'struct': 'BlockdevCommonOptions',
|
||||
'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
|
||||
{ 'union': 'BlockdevOptions',
|
||||
'base': 'BlockdevCommonOptions',
|
||||
'base': { 'driver': 'BlockdevDriver', '*read-only': 'bool' },
|
||||
'discriminator': 'driver',
|
||||
'data': { 'file': 'FileOptions',
|
||||
'qcow2': 'Qcow2Options' } }
|
||||
'data': { 'file': 'BlockdevOptionsFile',
|
||||
'qcow2': 'BlockdevOptionsQcow2' } }
|
||||
|
||||
Resulting in these JSON objects:
|
||||
|
||||
{ "driver": "file", "readonly": true,
|
||||
{ "driver": "file", "read-only": true,
|
||||
"filename": "/some/place/my-image" }
|
||||
{ "driver": "qcow2", "readonly": false,
|
||||
"backing-file": "/some/place/my-image", "lazy-refcounts": true }
|
||||
{ "driver": "qcow2", "read-only": false,
|
||||
"backing": "/some/place/my-image", "lazy-refcounts": true }
|
||||
|
||||
Notice that in a flat union, the discriminator name is controlled by
|
||||
the user, but because it must map to a base member with enum type, the
|
||||
@@ -366,10 +367,9 @@ union has a struct with a single member named 'data'. That is,
|
||||
is identical on the wire to:
|
||||
|
||||
{ 'enum': 'Enum', 'data': ['one', 'two'] }
|
||||
{ 'struct': 'Base', 'data': { 'type': 'Enum' } }
|
||||
{ 'struct': 'Branch1', 'data': { 'data': 'str' } }
|
||||
{ 'struct': 'Branch2', 'data': { 'data': 'int' } }
|
||||
{ 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
|
||||
{ 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type',
|
||||
'data': { 'one': 'Branch1', 'two': 'Branch2' } }
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@ data types (string, integer, number, or object, but currently not
|
||||
array) on the wire. The definition is similar to a simple union type,
|
||||
where each branch of the union names a QAPI type. For example:
|
||||
|
||||
{ 'alternate': 'BlockRef',
|
||||
{ 'alternate': 'BlockdevRef',
|
||||
'data': { 'definition': 'BlockdevOptions',
|
||||
'reference': 'str' } }
|
||||
|
||||
@@ -403,7 +403,7 @@ following example objects:
|
||||
|
||||
{ "file": "my_existing_block_device_id" }
|
||||
{ "file": { "driver": "file",
|
||||
"readonly": false,
|
||||
"read-only": false,
|
||||
"filename": "/tmp/mydisk.qcow2" } }
|
||||
|
||||
|
||||
@@ -575,9 +575,9 @@ names an object type without members.
|
||||
Example: the SchemaInfo for command query-qmp-schema
|
||||
|
||||
{ "name": "query-qmp-schema", "meta-type": "command",
|
||||
"arg-type": ":empty", "ret-type": "SchemaInfoList" }
|
||||
"arg-type": "q_empty", "ret-type": "SchemaInfoList" }
|
||||
|
||||
Type ":empty" is an object type without members, and type
|
||||
Type "q_empty" is an automatic object type without members, and type
|
||||
"SchemaInfoList" is the array of SchemaInfo type.
|
||||
|
||||
The SchemaInfo for an event has meta-type "event", and variant member
|
||||
@@ -594,9 +594,9 @@ QAPI schema implicitly defines an object type.
|
||||
Example: the SchemaInfo for EVENT_C from section Events
|
||||
|
||||
{ "name": "EVENT_C", "meta-type": "event",
|
||||
"arg-type": ":obj-EVENT_C-arg" }
|
||||
"arg-type": "q_obj-EVENT_C-arg" }
|
||||
|
||||
Type ":obj-EVENT_C-arg" is an implicitly defined object type with
|
||||
Type "q_obj-EVENT_C-arg" is an implicitly defined object type with
|
||||
the two members from the event's definition.
|
||||
|
||||
The SchemaInfo for struct and union types has meta-type "object".
|
||||
@@ -637,11 +637,11 @@ Union types
|
||||
{ "name": "BlockdevOptions", "meta-type": "object",
|
||||
"members": [
|
||||
{ "name": "driver", "type": "BlockdevDriver" },
|
||||
{ "name": "readonly", "type": "bool"} ],
|
||||
{ "name": "read-only", "type": "bool", "default": null } ],
|
||||
"tag": "driver",
|
||||
"variants": [
|
||||
{ "case": "file", "type": "FileOptions" },
|
||||
{ "case": "qcow2", "type": "Qcow2Options" } ] }
|
||||
{ "case": "file", "type": "BlockdevOptionsFile" },
|
||||
{ "case": "qcow2", "type": "BlockdevOptionsQcow2" } ] }
|
||||
|
||||
Note that base types are "flattened": its members are included in the
|
||||
"members" array.
|
||||
@@ -652,20 +652,20 @@ discriminator (called "type" on the wire, see section Union types).
|
||||
A simple union implicitly defines an object type for each of its
|
||||
variants.
|
||||
|
||||
Example: the SchemaInfo for simple union BlockdevOptions from section
|
||||
Example: the SchemaInfo for simple union BlockdevOptionsSimple from section
|
||||
Union types
|
||||
|
||||
{ "name": "BlockdevOptions", "meta-type": "object",
|
||||
{ "name": "BlockdevOptionsSimple", "meta-type": "object",
|
||||
"members": [
|
||||
{ "name": "type", "type": "BlockdevOptionsKind" } ],
|
||||
{ "name": "type", "type": "BlockdevOptionsSimpleKind" } ],
|
||||
"tag": "type",
|
||||
"variants": [
|
||||
{ "case": "file", "type": ":obj-FileOptions-wrapper" },
|
||||
{ "case": "qcow2", "type": ":obj-Qcow2Options-wrapper" } ] }
|
||||
{ "case": "file", "type": "q_obj-BlockdevOptionsFile-wrapper" },
|
||||
{ "case": "qcow2", "type": "q_obj-BlockdevOptionsQcow2-wrapper" } ] }
|
||||
|
||||
Enumeration type "BlockdevOptionsKind" and the object types
|
||||
":obj-FileOptions-wrapper", ":obj-Qcow2Options-wrapper" are
|
||||
implicitly defined.
|
||||
Enumeration type "BlockdevOptionsSimpleKind" and the object types
|
||||
"q_obj-BlockdevOptionsFile-wrapper", "q_obj-BlockdevOptionsQcow2-wrapper"
|
||||
are implicitly defined.
|
||||
|
||||
The SchemaInfo for an alternate type has meta-type "alternate", and
|
||||
variant member "members". "members" is a JSON array. Each element is
|
||||
@@ -673,9 +673,9 @@ a JSON object with member "type", which names a type. Values of the
|
||||
alternate type conform to exactly one of its member types. There is
|
||||
no guarantee on the order in which "members" will be listed.
|
||||
|
||||
Example: the SchemaInfo for BlockRef from section Alternate types
|
||||
Example: the SchemaInfo for BlockdevRef from section Alternate types
|
||||
|
||||
{ "name": "BlockRef", "meta-type": "alternate",
|
||||
{ "name": "BlockdevRef", "meta-type": "alternate",
|
||||
"members": [
|
||||
{ "type": "BlockdevOptions" },
|
||||
{ "type": "str" } ] }
|
||||
|
||||
254
docs/specs/ivshmem-spec.txt
Normal file
254
docs/specs/ivshmem-spec.txt
Normal file
@@ -0,0 +1,254 @@
|
||||
= Device Specification for Inter-VM shared memory device =
|
||||
|
||||
The Inter-VM shared memory device (ivshmem) is designed to share a
|
||||
memory region between multiple QEMU processes running different guests
|
||||
and the host. In order for all guests to be able to pick up the
|
||||
shared memory area, it is modeled by QEMU as a PCI device exposing
|
||||
said memory to the guest as a PCI BAR.
|
||||
|
||||
The device can use a shared memory object on the host directly, or it
|
||||
can obtain one from an ivshmem server.
|
||||
|
||||
In the latter case, the device can additionally interrupt its peers, and
|
||||
get interrupted by its peers.
|
||||
|
||||
|
||||
== Configuring the ivshmem PCI device ==
|
||||
|
||||
There are two basic configurations:
|
||||
|
||||
- Just shared memory: -device ivshmem-plain,memdev=HMB,...
|
||||
|
||||
This uses host memory backend HMB. It should have option "share"
|
||||
set.
|
||||
|
||||
- Shared memory plus interrupts: -device ivshmem,chardev=CHR,vectors=N,...
|
||||
|
||||
An ivshmem server must already be running on the host. The device
|
||||
connects to the server's UNIX domain socket via character device
|
||||
CHR.
|
||||
|
||||
Each peer gets assigned a unique ID by the server. IDs must be
|
||||
between 0 and 65535.
|
||||
|
||||
Interrupts are message-signaled (MSI-X). vectors=N configures the
|
||||
number of vectors to use.
|
||||
|
||||
For more details on ivshmem device properties, see The QEMU Emulator
|
||||
User Documentation (qemu-doc.*).
|
||||
|
||||
|
||||
== The ivshmem PCI device's guest interface ==
|
||||
|
||||
The device has vendor ID 1af4, device ID 1110, revision 1. Before
|
||||
QEMU 2.6.0, it had revision 0.
|
||||
|
||||
=== PCI BARs ===
|
||||
|
||||
The ivshmem PCI device has two or three BARs:
|
||||
|
||||
- BAR0 holds device registers (256 Byte MMIO)
|
||||
- BAR1 holds MSI-X table and PBA (only ivshmem-doorbell)
|
||||
- BAR2 maps the shared memory object
|
||||
|
||||
There are two ways to use this device:
|
||||
|
||||
- If you only need the shared memory part, BAR2 suffices. This way,
|
||||
you have access to the shared memory in the guest and can use it as
|
||||
you see fit. Memnic, for example, uses ivshmem this way from guest
|
||||
user space (see http://dpdk.org/browse/memnic).
|
||||
|
||||
- If you additionally need the capability for peers to interrupt each
|
||||
other, you need BAR0 and BAR1. You will most likely want to write a
|
||||
kernel driver to handle interrupts. Requires the device to be
|
||||
configured for interrupts, obviously.
|
||||
|
||||
Before QEMU 2.6.0, BAR2 can initially be invalid if the device is
|
||||
configured for interrupts. It becomes safely accessible only after
|
||||
the ivshmem server provided the shared memory. These devices have PCI
|
||||
revision 0 rather than 1. Guest software should wait for the
|
||||
IVPosition register (described below) to become non-negative before
|
||||
accessing BAR2.
|
||||
|
||||
Revision 0 of the device is not capable to tell guest software whether
|
||||
it is configured for interrupts.
|
||||
|
||||
=== PCI device registers ===
|
||||
|
||||
BAR 0 contains the following registers:
|
||||
|
||||
Offset Size Access On reset Function
|
||||
0 4 read/write 0 Interrupt Mask
|
||||
bit 0: peer interrupt (rev 0)
|
||||
reserved (rev 1)
|
||||
bit 1..31: reserved
|
||||
4 4 read/write 0 Interrupt Status
|
||||
bit 0: peer interrupt (rev 0)
|
||||
reserved (rev 1)
|
||||
bit 1..31: reserved
|
||||
8 4 read-only 0 or ID IVPosition
|
||||
12 4 write-only N/A Doorbell
|
||||
bit 0..15: vector
|
||||
bit 16..31: peer ID
|
||||
16 240 none N/A reserved
|
||||
|
||||
Software should only access the registers as specified in column
|
||||
"Access". Reserved bits should be ignored on read, and preserved on
|
||||
write.
|
||||
|
||||
In revision 0 of the device, Interrupt Status and Mask Register
|
||||
together control the legacy INTx interrupt when the device has no
|
||||
MSI-X capability: INTx is asserted when the bit-wise AND of Status and
|
||||
Mask is non-zero and the device has no MSI-X capability. Interrupt
|
||||
Status Register bit 0 becomes 1 when an interrupt request from a peer
|
||||
is received. Reading the register clears it.
|
||||
|
||||
IVPosition Register: if the device is not configured for interrupts,
|
||||
this is zero. Else, it is the device's ID (between 0 and 65535).
|
||||
|
||||
Before QEMU 2.6.0, the register may read -1 for a short while after
|
||||
reset. These devices have PCI revision 0 rather than 1.
|
||||
|
||||
There is no good way for software to find out whether the device is
|
||||
configured for interrupts. A positive IVPosition means interrupts,
|
||||
but zero could be either.
|
||||
|
||||
Doorbell Register: writing this register requests to interrupt a peer.
|
||||
The written value's high 16 bits are the ID of the peer to interrupt,
|
||||
and its low 16 bits select an interrupt vector.
|
||||
|
||||
If the device is not configured for interrupts, the write is ignored.
|
||||
|
||||
If the interrupt hasn't completed setup, the write is ignored. The
|
||||
device is not capable to tell guest software whether setup is
|
||||
complete. Interrupts can regress to this state on migration.
|
||||
|
||||
If the peer with the requested ID isn't connected, or it has fewer
|
||||
interrupt vectors connected, the write is ignored. The device is not
|
||||
capable to tell guest software what peers are connected, or how many
|
||||
interrupt vectors are connected.
|
||||
|
||||
The peer's interrupt for this vector then becomes pending. There is
|
||||
no way for software to clear the pending bit, and a polling mode of
|
||||
operation is therefore impossible.
|
||||
|
||||
If the peer is a revision 0 device without MSI-X capability, its
|
||||
Interrupt Status register is set to 1. This asserts INTx unless
|
||||
masked by the Interrupt Mask register. The device is not capable to
|
||||
communicate the interrupt vector to guest software then.
|
||||
|
||||
With multiple MSI-X vectors, different vectors can be used to indicate
|
||||
different events have occurred. The semantics of interrupt vectors
|
||||
are left to the application.
|
||||
|
||||
|
||||
== Interrupt infrastructure ==
|
||||
|
||||
When configured for interrupts, the peers share eventfd objects in
|
||||
addition to shared memory. The shared resources are managed by an
|
||||
ivshmem server.
|
||||
|
||||
=== The ivshmem server ===
|
||||
|
||||
The server listens on a UNIX domain socket.
|
||||
|
||||
For each new client that connects to the server, the server
|
||||
- picks an ID,
|
||||
- creates eventfd file descriptors for the interrupt vectors,
|
||||
- sends the ID and the file descriptor for the shared memory to the
|
||||
new client,
|
||||
- sends connect notifications for the new client to the other clients
|
||||
(these contain file descriptors for sending interrupts),
|
||||
- sends connect notifications for the other clients to the new client,
|
||||
and
|
||||
- sends interrupt setup messages to the new client (these contain file
|
||||
descriptors for receiving interrupts).
|
||||
|
||||
The first client to connect to the server receives ID zero.
|
||||
|
||||
When a client disconnects from the server, the server sends disconnect
|
||||
notifications to the other clients.
|
||||
|
||||
The next section describes the protocol in detail.
|
||||
|
||||
If the server terminates without sending disconnect notifications for
|
||||
its connected clients, the clients can elect to continue. They can
|
||||
communicate with each other normally, but won't receive disconnect
|
||||
notification on disconnect, and no new clients can connect. There is
|
||||
no way for the clients to connect to a restarted server. The device
|
||||
is not capable to tell guest software whether the server is still up.
|
||||
|
||||
Example server code is in contrib/ivshmem-server/. Not to be used in
|
||||
production. It assumes all clients use the same number of interrupt
|
||||
vectors.
|
||||
|
||||
A standalone client is in contrib/ivshmem-client/. It can be useful
|
||||
for debugging.
|
||||
|
||||
=== The ivshmem Client-Server Protocol ===
|
||||
|
||||
An ivshmem device configured for interrupts connects to an ivshmem
|
||||
server. This section details the protocol between the two.
|
||||
|
||||
The connection is one-way: the server sends messages to the client.
|
||||
Each message consists of a single 8 byte little-endian signed number,
|
||||
and may be accompanied by a file descriptor via SCM_RIGHTS. Both
|
||||
client and server close the connection on error.
|
||||
|
||||
Note: QEMU currently doesn't close the connection right on error, but
|
||||
only when the character device is destroyed.
|
||||
|
||||
On connect, the server sends the following messages in order:
|
||||
|
||||
1. The protocol version number, currently zero. The client should
|
||||
close the connection on receipt of versions it can't handle.
|
||||
|
||||
2. The client's ID. This is unique among all clients of this server.
|
||||
IDs must be between 0 and 65535, because the Doorbell register
|
||||
provides only 16 bits for them.
|
||||
|
||||
3. The number -1, accompanied by the file descriptor for the shared
|
||||
memory.
|
||||
|
||||
4. Connect notifications for existing other clients, if any. This is
|
||||
a peer ID (number between 0 and 65535 other than the client's ID),
|
||||
repeated N times. Each repetition is accompanied by one file
|
||||
descriptor. These are for interrupting the peer with that ID using
|
||||
vector 0,..,N-1, in order. If the client is configured for fewer
|
||||
vectors, it closes the extra file descriptors. If it is configured
|
||||
for more, the extra vectors remain unconnected.
|
||||
|
||||
5. Interrupt setup. This is the client's own ID, repeated N times.
|
||||
Each repetition is accompanied by one file descriptor. These are
|
||||
for receiving interrupts from peers using vector 0,..,N-1, in
|
||||
order. If the client is configured for fewer vectors, it closes
|
||||
the extra file descriptors. If it is configured for more, the
|
||||
extra vectors remain unconnected.
|
||||
|
||||
From then on, the server sends these kinds of messages:
|
||||
|
||||
6. Connection / disconnection notification. This is a peer ID.
|
||||
|
||||
- If the number comes with a file descriptor, it's a connection
|
||||
notification, exactly like in step 4.
|
||||
|
||||
- Else, it's a disconnection notification for the peer with that ID.
|
||||
|
||||
Known bugs:
|
||||
|
||||
* The protocol changed incompatibly in QEMU 2.5. Before, messages
|
||||
were native endian long, and there was no version number.
|
||||
|
||||
* The protocol is poorly designed.
|
||||
|
||||
=== The ivshmem Client-Client Protocol ===
|
||||
|
||||
An ivshmem device configured for interrupts receives eventfd file
|
||||
descriptors for interrupting peers and getting interrupted by peers
|
||||
from the server, as explained in the previous section.
|
||||
|
||||
To interrupt a peer, the device writes the 8-byte integer 1 in native
|
||||
byte order to the respective file descriptor.
|
||||
|
||||
To receive an interrupt, the device reads and discards as many 8-byte
|
||||
integers as it can.
|
||||
@@ -1,161 +0,0 @@
|
||||
|
||||
Device Specification for Inter-VM shared memory device
|
||||
------------------------------------------------------
|
||||
|
||||
The Inter-VM shared memory device is designed to share a memory region (created
|
||||
on the host via the POSIX shared memory API) between multiple QEMU processes
|
||||
running different guests. In order for all guests to be able to pick up the
|
||||
shared memory area, it is modeled by QEMU as a PCI device exposing said memory
|
||||
to the guest as a PCI BAR.
|
||||
The memory region does not belong to any guest, but is a POSIX memory object on
|
||||
the host. The host can access this shared memory if needed.
|
||||
|
||||
The device also provides an optional communication mechanism between guests
|
||||
sharing the same memory object. More details about that in the section 'Guest to
|
||||
guest communication' section.
|
||||
|
||||
|
||||
The Inter-VM PCI device
|
||||
-----------------------
|
||||
|
||||
From the VM point of view, the ivshmem PCI device supports three BARs.
|
||||
|
||||
- BAR0 is a 1 Kbyte MMIO region to support registers and interrupts when MSI is
|
||||
not used.
|
||||
- BAR1 is used for MSI-X when it is enabled in the device.
|
||||
- BAR2 is used to access the shared memory object.
|
||||
|
||||
It is your choice how to use the device but you must choose between two
|
||||
behaviors :
|
||||
|
||||
- basically, if you only need the shared memory part, you will map BAR2.
|
||||
This way, you have access to the shared memory in guest and can use it as you
|
||||
see fit (memnic, for example, uses it in userland
|
||||
http://dpdk.org/browse/memnic).
|
||||
|
||||
- BAR0 and BAR1 are used to implement an optional communication mechanism
|
||||
through interrupts in the guests. If you need an event mechanism between the
|
||||
guests accessing the shared memory, you will most likely want to write a
|
||||
kernel driver that will handle interrupts. See details in the section 'Guest
|
||||
to guest communication' section.
|
||||
|
||||
The behavior is chosen when starting your QEMU processes:
|
||||
- no communication mechanism needed, the first QEMU to start creates the shared
|
||||
memory on the host, subsequent QEMU processes will use it.
|
||||
|
||||
- communication mechanism needed, an ivshmem server must be started before any
|
||||
QEMU processes, then each QEMU process connects to the server unix socket.
|
||||
|
||||
For more details on the QEMU ivshmem parameters, see qemu-doc documentation.
|
||||
|
||||
|
||||
Guest to guest communication
|
||||
----------------------------
|
||||
|
||||
This section details the communication mechanism between the guests accessing
|
||||
the ivhsmem shared memory.
|
||||
|
||||
*ivshmem server*
|
||||
|
||||
This server code is available in qemu.git/contrib/ivshmem-server.
|
||||
|
||||
The server must be started on the host before any guest.
|
||||
It creates a shared memory object then waits for clients to connect on a unix
|
||||
socket. All the messages are little-endian int64_t integer.
|
||||
|
||||
For each client (QEMU process) that connects to the server:
|
||||
- the server sends a protocol version, if client does not support it, the client
|
||||
closes the communication,
|
||||
- the server assigns an ID for this client and sends this ID to him as the first
|
||||
message,
|
||||
- the server sends a fd to the shared memory object to this client,
|
||||
- the server creates a new set of host eventfds associated to the new client and
|
||||
sends this set to all already connected clients,
|
||||
- finally, the server sends all the eventfds sets for all clients to the new
|
||||
client.
|
||||
|
||||
The server signals all clients when one of them disconnects.
|
||||
|
||||
The client IDs are limited to 16 bits because of the current implementation (see
|
||||
Doorbell register in 'PCI device registers' subsection). Hence only 65536
|
||||
clients are supported.
|
||||
|
||||
All the file descriptors (fd to the shared memory, eventfds for each client)
|
||||
are passed to clients using SCM_RIGHTS over the server unix socket.
|
||||
|
||||
Apart from the current ivshmem implementation in QEMU, an ivshmem client has
|
||||
been provided in qemu.git/contrib/ivshmem-client for debug.
|
||||
|
||||
*QEMU as an ivshmem client*
|
||||
|
||||
At initialisation, when creating the ivshmem device, QEMU first receives a
|
||||
protocol version and closes communication with server if it does not match.
|
||||
Then, QEMU gets its ID from the server then makes it available through BAR0
|
||||
IVPosition register for the VM to use (see 'PCI device registers' subsection).
|
||||
QEMU then uses the fd to the shared memory to map it to BAR2.
|
||||
eventfds for all other clients received from the server are stored to implement
|
||||
BAR0 Doorbell register (see 'PCI device registers' subsection).
|
||||
Finally, eventfds assigned to this QEMU process are used to send interrupts in
|
||||
this VM.
|
||||
|
||||
*PCI device registers*
|
||||
|
||||
From the VM point of view, the ivshmem PCI device supports 4 registers of
|
||||
32-bits each.
|
||||
|
||||
enum ivshmem_registers {
|
||||
IntrMask = 0,
|
||||
IntrStatus = 4,
|
||||
IVPosition = 8,
|
||||
Doorbell = 12
|
||||
};
|
||||
|
||||
The first two registers are the interrupt mask and status registers. Mask and
|
||||
status are only used with pin-based interrupts. They are unused with MSI
|
||||
interrupts.
|
||||
|
||||
Status Register: The status register is set to 1 when an interrupt occurs.
|
||||
|
||||
Mask Register: The mask register is bitwise ANDed with the interrupt status
|
||||
and the result will raise an interrupt if it is non-zero. However, since 1 is
|
||||
the only value the status will be set to, it is only the first bit of the mask
|
||||
that has any effect. Therefore interrupts can be masked by setting the first
|
||||
bit to 0 and unmasked by setting the first bit to 1.
|
||||
|
||||
IVPosition Register: The IVPosition register is read-only and reports the
|
||||
guest's ID number. The guest IDs are non-negative integers. When using the
|
||||
server, since the server is a separate process, the VM ID will only be set when
|
||||
the device is ready (shared memory is received from the server and accessible
|
||||
via the device). If the device is not ready, the IVPosition will return -1.
|
||||
Applications should ensure that they have a valid VM ID before accessing the
|
||||
shared memory.
|
||||
|
||||
Doorbell Register: To interrupt another guest, a guest must write to the
|
||||
Doorbell register. The doorbell register is 32-bits, logically divided into
|
||||
two 16-bit fields. The high 16-bits are the guest ID to interrupt and the low
|
||||
16-bits are the interrupt vector to trigger. The semantics of the value
|
||||
written to the doorbell depends on whether the device is using MSI or a regular
|
||||
pin-based interrupt. In short, MSI uses vectors while regular interrupts set
|
||||
the status register.
|
||||
|
||||
Regular Interrupts
|
||||
|
||||
If regular interrupts are used (due to either a guest not supporting MSI or the
|
||||
user specifying not to use them on startup) then the value written to the lower
|
||||
16-bits of the Doorbell register results is arbitrary and will trigger an
|
||||
interrupt in the destination guest.
|
||||
|
||||
Message Signalled Interrupts
|
||||
|
||||
An ivshmem device may support multiple MSI vectors. If so, the lower 16-bits
|
||||
written to the Doorbell register must be between 0 and the maximum number of
|
||||
vectors the guest supports. The lower 16 bits written to the doorbell is the
|
||||
MSI vector that will be raised in the destination guest. The number of MSI
|
||||
vectors is configurable but it is set when the VM is started.
|
||||
|
||||
The important thing to remember with MSI is that it is only a signal, no status
|
||||
is set (since MSI interrupts are not shared). All information other than the
|
||||
interrupt itself should be communicated via the shared memory region. Devices
|
||||
supporting multiple MSI vectors can use different vectors to indicate different
|
||||
events have occurred. The semantics of interrupt vectors are left to the
|
||||
user's discretion.
|
||||
8
hmp.c
8
hmp.c
@@ -857,7 +857,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
|
||||
|
||||
switch (ti->options->type) {
|
||||
case TPM_TYPE_OPTIONS_KIND_PASSTHROUGH:
|
||||
tpo = ti->options->u.passthrough;
|
||||
tpo = ti->options->u.passthrough.data;
|
||||
monitor_printf(mon, "%s%s%s%s",
|
||||
tpo->has_path ? ",path=" : "",
|
||||
tpo->has_path ? tpo->path : "",
|
||||
@@ -1753,14 +1753,14 @@ void hmp_sendkey(Monitor *mon, const QDict *qdict)
|
||||
goto err_out;
|
||||
}
|
||||
keylist->value->type = KEY_VALUE_KIND_NUMBER;
|
||||
keylist->value->u.number = value;
|
||||
keylist->value->u.number.data = value;
|
||||
} else {
|
||||
int idx = index_from_key(keys, keyname_len);
|
||||
if (idx == Q_KEY_CODE__MAX) {
|
||||
goto err_out;
|
||||
}
|
||||
keylist->value->type = KEY_VALUE_KIND_QCODE;
|
||||
keylist->value->u.qcode = idx;
|
||||
keylist->value->u.qcode.data = idx;
|
||||
}
|
||||
|
||||
if (!separator) {
|
||||
@@ -1977,7 +1977,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
|
||||
if (value) {
|
||||
switch (value->type) {
|
||||
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
||||
di = value->u.dimm;
|
||||
di = value->u.dimm.data;
|
||||
|
||||
monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
|
||||
MemoryDeviceInfoKind_lookup[value->type],
|
||||
|
||||
@@ -917,7 +917,7 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
|
||||
/* setup via xenbus -> create new block driver instance */
|
||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||
blkdev->blk = blk_new_open(blkdev->dev, blkdev->filename, NULL, options,
|
||||
blkdev->blk = blk_new_open(blkdev->filename, NULL, options,
|
||||
qflags, &local_err);
|
||||
if (!blkdev->blk) {
|
||||
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
|
||||
|
||||
@@ -845,7 +845,7 @@ static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
|
||||
InputKeyEvent *key;
|
||||
|
||||
assert(evt->type == INPUT_EVENT_KIND_KEY);
|
||||
key = evt->u.key;
|
||||
key = evt->u.key.data;
|
||||
qcode = qemu_input_key_value_to_qcode(key->key);
|
||||
trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
|
||||
key->down);
|
||||
|
||||
@@ -516,6 +516,16 @@ PropertyInfo qdev_prop_macaddr = {
|
||||
.set = set_mac,
|
||||
};
|
||||
|
||||
/* --- on/off/auto --- */
|
||||
|
||||
PropertyInfo qdev_prop_on_off_auto = {
|
||||
.name = "OnOffAuto",
|
||||
.description = "on/off/auto",
|
||||
.enum_table = OnOffAuto_lookup,
|
||||
.get = get_enum,
|
||||
.set = set_enum,
|
||||
};
|
||||
|
||||
/* --- lost tick policy --- */
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
|
||||
|
||||
@@ -124,7 +124,7 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
move = evt->u.rel;
|
||||
move = evt->u.rel.data;
|
||||
if (move->axis == INPUT_AXIS_X) {
|
||||
e->xdx += move->value;
|
||||
} else if (move->axis == INPUT_AXIS_Y) {
|
||||
@@ -133,7 +133,7 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
move = evt->u.abs;
|
||||
move = evt->u.abs.data;
|
||||
if (move->axis == INPUT_AXIS_X) {
|
||||
e->xdx = move->value;
|
||||
} else if (move->axis == INPUT_AXIS_Y) {
|
||||
@@ -142,7 +142,7 @@ static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
btn = evt->u.btn;
|
||||
btn = evt->u.btn.data;
|
||||
if (btn->down) {
|
||||
e->buttons_state |= bmap[btn->button];
|
||||
if (btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
@@ -228,7 +228,7 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
int scancodes[3], i, count;
|
||||
int slot;
|
||||
InputKeyEvent *key = evt->u.key;
|
||||
InputKeyEvent *key = evt->u.key.data;
|
||||
|
||||
count = qemu_input_key_value_to_scancode(key->key,
|
||||
key->down,
|
||||
|
||||
@@ -182,7 +182,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState *)dev;
|
||||
int scancodes[3], i, count;
|
||||
InputKeyEvent *key = evt->u.key;
|
||||
InputKeyEvent *key = evt->u.key.data;
|
||||
|
||||
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
|
||||
count = qemu_input_key_value_to_scancode(key->key,
|
||||
@@ -399,7 +399,7 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
move = evt->u.rel;
|
||||
move = evt->u.rel.data;
|
||||
if (move->axis == INPUT_AXIS_X) {
|
||||
s->mouse_dx += move->value;
|
||||
} else if (move->axis == INPUT_AXIS_Y) {
|
||||
@@ -408,7 +408,7 @@ static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
btn = evt->u.btn;
|
||||
btn = evt->u.btn.data;
|
||||
if (btn->down) {
|
||||
s->mouse_buttons |= bmap[btn->button];
|
||||
if (btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
|
||||
@@ -197,7 +197,7 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EVENT_KIND_KEY:
|
||||
key = evt->u.key;
|
||||
key = evt->u.key.data;
|
||||
qcode = qemu_input_key_value_to_qcode(key->key);
|
||||
if (qcode && keymap_qcode[qcode]) {
|
||||
event.type = cpu_to_le16(EV_KEY);
|
||||
@@ -212,7 +212,7 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
|
||||
}
|
||||
break;
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
btn = evt->u.btn;
|
||||
btn = evt->u.btn.data;
|
||||
if (keymap_button[btn->button]) {
|
||||
event.type = cpu_to_le16(EV_KEY);
|
||||
event.code = cpu_to_le16(keymap_button[btn->button]);
|
||||
@@ -227,14 +227,14 @@ static void virtio_input_handle_event(DeviceState *dev, QemuConsole *src,
|
||||
}
|
||||
break;
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
move = evt->u.rel;
|
||||
move = evt->u.rel.data;
|
||||
event.type = cpu_to_le16(EV_REL);
|
||||
event.code = cpu_to_le16(axismap_rel[move->axis]);
|
||||
event.value = cpu_to_le32(move->value);
|
||||
virtio_input_send(vinput, &event);
|
||||
break;
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
move = evt->u.abs;
|
||||
move = evt->u.abs.data;
|
||||
event.type = cpu_to_le16(EV_ABS);
|
||||
event.code = cpu_to_le16(axismap_abs[move->axis]);
|
||||
event.value = cpu_to_le32(move->value);
|
||||
|
||||
@@ -180,7 +180,7 @@ int qmp_pc_dimm_device_list(Object *obj, void *opaque)
|
||||
NULL);
|
||||
di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
|
||||
|
||||
info->u.dimm = di;
|
||||
info->u.dimm.data = di;
|
||||
elem->value = info;
|
||||
elem->next = NULL;
|
||||
**prev = elem;
|
||||
|
||||
1152
hw/misc/ivshmem.c
1152
hw/misc/ivshmem.c
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
#include <sys/inotify.h>
|
||||
#include "qemu/main-loop.h"
|
||||
#endif
|
||||
@@ -92,7 +92,7 @@ enum {
|
||||
EP_EVENT,
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
typedef struct MTPMonEntry MTPMonEntry;
|
||||
|
||||
struct MTPMonEntry {
|
||||
@@ -127,7 +127,7 @@ struct MTPObject {
|
||||
char *name;
|
||||
char *path;
|
||||
struct stat stat;
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
/* inotify watch cookie */
|
||||
int watchfd;
|
||||
#endif
|
||||
@@ -152,7 +152,7 @@ struct MTPState {
|
||||
uint32_t next_handle;
|
||||
|
||||
QTAILQ_HEAD(, MTPObject) objects;
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
/* inotify descriptor */
|
||||
int inotifyfd;
|
||||
QTAILQ_HEAD(events, MTPMonEntry) events;
|
||||
@@ -400,7 +400,7 @@ static MTPObject *usb_mtp_add_child(MTPState *s, MTPObject *o,
|
||||
return child;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
static MTPObject *usb_mtp_object_lookup_name(MTPObject *parent,
|
||||
char *name, int len)
|
||||
{
|
||||
@@ -433,12 +433,11 @@ static void inotify_watchfn(void *arg)
|
||||
MTPState *s = arg;
|
||||
ssize_t bytes;
|
||||
/* From the man page: atleast one event can be read */
|
||||
int len = sizeof(struct inotify_event) + NAME_MAX + 1;
|
||||
int pos;
|
||||
char buf[len];
|
||||
char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
|
||||
|
||||
for (;;) {
|
||||
bytes = read(s->inotifyfd, buf, len);
|
||||
bytes = read(s->inotifyfd, buf, sizeof(buf));
|
||||
pos = 0;
|
||||
|
||||
if (bytes <= 0) {
|
||||
@@ -593,7 +592,7 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
|
||||
if (!dir) {
|
||||
return;
|
||||
}
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
int watchfd = usb_mtp_add_watch(s->inotifyfd, o->path);
|
||||
if (watchfd == -1) {
|
||||
fprintf(stderr, "usb-mtp: failed to add watch for %s\n", o->path);
|
||||
@@ -718,7 +717,7 @@ static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
|
||||
static void usb_mtp_add_str(MTPData *data, const char *str)
|
||||
{
|
||||
uint32_t len = strlen(str)+1;
|
||||
wchar_t wstr[len];
|
||||
wchar_t *wstr = g_new(wchar_t, len);
|
||||
size_t ret;
|
||||
|
||||
ret = mbstowcs(wstr, str, len);
|
||||
@@ -727,6 +726,8 @@ static void usb_mtp_add_str(MTPData *data, const char *str)
|
||||
} else {
|
||||
usb_mtp_add_wstr(data, wstr);
|
||||
}
|
||||
|
||||
g_free(wstr);
|
||||
}
|
||||
|
||||
static void usb_mtp_add_time(MTPData *data, time_t time)
|
||||
@@ -995,7 +996,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
||||
trace_usb_mtp_op_open_session(s->dev.addr);
|
||||
s->session = c->argv[0];
|
||||
usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
if (usb_mtp_inotify_init(s)) {
|
||||
fprintf(stderr, "usb-mtp: file monitoring init failed\n");
|
||||
}
|
||||
@@ -1005,7 +1006,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
|
||||
trace_usb_mtp_op_close_session(s->dev.addr);
|
||||
s->session = 0;
|
||||
s->next_handle = 0;
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
usb_mtp_inotify_cleanup(s);
|
||||
#endif
|
||||
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
|
||||
@@ -1133,7 +1134,7 @@ static void usb_mtp_handle_reset(USBDevice *dev)
|
||||
|
||||
trace_usb_mtp_reset(s->dev.addr);
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
usb_mtp_inotify_cleanup(s);
|
||||
#endif
|
||||
usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
|
||||
@@ -1296,7 +1297,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
|
||||
}
|
||||
break;
|
||||
case EP_EVENT:
|
||||
#ifdef __linux__
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
if (!QTAILQ_EMPTY(&s->events)) {
|
||||
struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
|
||||
uint32_t handle;
|
||||
|
||||
@@ -895,6 +895,11 @@ static uint64_t ehci_caps_read(void *ptr, hwaddr addr,
|
||||
return s->caps[addr];
|
||||
}
|
||||
|
||||
static void ehci_caps_write(void *ptr, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
}
|
||||
|
||||
static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -2315,6 +2320,7 @@ static void ehci_frame_timer(void *opaque)
|
||||
|
||||
static const MemoryRegionOps ehci_mmio_caps_ops = {
|
||||
.read = ehci_caps_read,
|
||||
.write = ehci_caps_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 1,
|
||||
|
||||
@@ -698,11 +698,13 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
|
||||
uint32_t *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
uint32_t tmp[len / sizeof(uint32_t)];
|
||||
uint32_t tmp[5];
|
||||
uint32_t n = len / sizeof(uint32_t);
|
||||
|
||||
assert((len % sizeof(uint32_t)) == 0);
|
||||
assert(n <= ARRAY_SIZE(tmp));
|
||||
|
||||
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
|
||||
for (i = 0; i < n; i++) {
|
||||
tmp[i] = cpu_to_le32(buf[i]);
|
||||
}
|
||||
pci_dma_write(PCI_DEVICE(xhci), addr, tmp, len);
|
||||
|
||||
@@ -34,12 +34,14 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "sysemu/char.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <usbredirparser.h>
|
||||
#include <usbredirfilter.h>
|
||||
|
||||
#include "hw/usb.h"
|
||||
|
||||
/* ERROR is defined below. Remove any previous definition. */
|
||||
#undef ERROR
|
||||
|
||||
#define MAX_ENDPOINTS 32
|
||||
#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */
|
||||
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
|
||||
|
||||
@@ -201,7 +201,6 @@ int bdrv_create(BlockDriver *drv, const char* filename,
|
||||
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
|
||||
BlockDriverState *bdrv_new_root(void);
|
||||
BlockDriverState *bdrv_new(void);
|
||||
void bdrv_device_remove(BlockDriverState *bs);
|
||||
void bdrv_make_anon(BlockDriverState *bs);
|
||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||
void bdrv_replace_in_backing_chain(BlockDriverState *old,
|
||||
@@ -230,8 +229,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state);
|
||||
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
@@ -274,7 +271,6 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
int bdrv_commit_all(void);
|
||||
int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt);
|
||||
void bdrv_register(BlockDriver *bdrv);
|
||||
@@ -373,7 +369,6 @@ int bdrv_inactivate_all(void);
|
||||
/* Ensure contents are flushed to disk. */
|
||||
int bdrv_flush(BlockDriverState *bs);
|
||||
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
|
||||
int bdrv_flush_all(void);
|
||||
void bdrv_close_all(void);
|
||||
void bdrv_drain(BlockDriverState *bs);
|
||||
void bdrv_drain_all(void);
|
||||
@@ -414,6 +409,7 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
|
||||
bool bdrv_chain_contains(BlockDriverState *top, BlockDriverState *base);
|
||||
BlockDriverState *bdrv_next_node(BlockDriverState *bs);
|
||||
BlockDriverState *bdrv_next(BlockDriverState *bs);
|
||||
BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs);
|
||||
int bdrv_is_encrypted(BlockDriverState *bs);
|
||||
int bdrv_key_required(BlockDriverState *bs);
|
||||
int bdrv_set_key(BlockDriverState *bs, const char *key);
|
||||
|
||||
@@ -442,8 +442,6 @@ struct BlockDriverState {
|
||||
char node_name[32];
|
||||
/* element of the list of named nodes building the graph */
|
||||
QTAILQ_ENTRY(BlockDriverState) node_list;
|
||||
/* element of the list of "drives" the guest sees */
|
||||
QTAILQ_ENTRY(BlockDriverState) device_list;
|
||||
/* element of the list of all BlockDriverStates (all_bdrv_states) */
|
||||
QTAILQ_ENTRY(BlockDriverState) bs_list;
|
||||
/* element of the list of monitor-owned BDS */
|
||||
@@ -501,8 +499,6 @@ extern BlockDriver bdrv_file;
|
||||
extern BlockDriver bdrv_raw;
|
||||
extern BlockDriver bdrv_qcow2;
|
||||
|
||||
extern QTAILQ_HEAD(BdrvStates, BlockDriverState) bdrv_states;
|
||||
|
||||
/**
|
||||
* bdrv_setup_io_funcs:
|
||||
*
|
||||
@@ -512,6 +508,13 @@ extern QTAILQ_HEAD(BdrvStates, BlockDriverState) bdrv_states;
|
||||
*/
|
||||
void bdrv_setup_io_funcs(BlockDriver *bdrv);
|
||||
|
||||
int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags);
|
||||
int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags);
|
||||
|
||||
int get_tmp_filename(char *filename, int size);
|
||||
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
|
||||
const char *filename);
|
||||
@@ -696,6 +699,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
|
||||
void hmp_drive_add_node(Monitor *mon, const char *optstr);
|
||||
|
||||
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role);
|
||||
void bdrv_root_unref_child(BdrvChild *child);
|
||||
|
||||
void blk_set_bs(BlockBackend *blk, BlockDriverState *bs);
|
||||
|
||||
void blk_dev_change_media_cb(BlockBackend *blk, bool load);
|
||||
|
||||
135
include/crypto/afsplit.h
Normal file
135
include/crypto/afsplit.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* QEMU Crypto anti forensic information splitter
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_AFSPLIT_H__
|
||||
#define QCRYPTO_AFSPLIT_H__
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/**
|
||||
* This module implements the anti-forensic splitter that is specified
|
||||
* as part of the LUKS format:
|
||||
*
|
||||
* http://clemens.endorphin.org/cryptography
|
||||
* http://clemens.endorphin.org/TKS1-draft.pdf
|
||||
*
|
||||
* The core idea is to take a short piece of data (key material)
|
||||
* and process it to expand it to a much larger piece of data.
|
||||
* The expansion process is reversible, to obtain the original
|
||||
* short data. The key property of the expansion is that if any
|
||||
* byte in the larger data set is changed / missing, it should be
|
||||
* impossible to recreate the original short data.
|
||||
*
|
||||
* <example>
|
||||
* <title>Creating a large split key for storage</title>
|
||||
* <programlisting>
|
||||
* size_t nkey = 32;
|
||||
* uint32_t stripes = 32768; // To produce a 1 MB split key
|
||||
* uint8_t *masterkey = ....a 32-byte AES key...
|
||||
* uint8_t *splitkey;
|
||||
*
|
||||
* splitkey = g_new0(uint8_t, nkey * stripes);
|
||||
*
|
||||
* if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALG_SHA256,
|
||||
* nkey, stripes,
|
||||
* masterkey, splitkey, errp) < 0) {
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* ...store splitkey somewhere...
|
||||
*
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* <example>
|
||||
* <title>Retrieving a master key from storage</title>
|
||||
* <programlisting>
|
||||
* size_t nkey = 32;
|
||||
* uint32_t stripes = 32768; // To produce a 1 MB split key
|
||||
* uint8_t *masterkey;
|
||||
* uint8_t *splitkey = .... read in 1 MB of data...
|
||||
*
|
||||
* masterkey = g_new0(uint8_t, nkey);
|
||||
*
|
||||
* if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALG_SHA256,
|
||||
* nkey, stripes,
|
||||
* splitkey, masterkey, errp) < 0) {
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* ..decrypt data with masterkey...
|
||||
*
|
||||
* g_free(splitkey);
|
||||
* g_free(masterkey);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* qcrypto_afsplit_encode:
|
||||
* @hash: the hash algorithm to use for data expansion
|
||||
* @blocklen: the size of @in in bytes
|
||||
* @stripes: the number of times to expand @in in size
|
||||
* @in: the master key to be expanded in size
|
||||
* @out: preallocated buffer to hold the split key
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Split the data in @in, which is @blocklen bytes in
|
||||
* size, to form a larger piece of data @out, which is
|
||||
* @blocklen * @stripes bytes in size.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error;
|
||||
*/
|
||||
int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_afsplit_decode:
|
||||
* @hash: the hash algorithm to use for data compression
|
||||
* @blocklen: the size of @out in bytes
|
||||
* @stripes: the number of times to decrease @in in size
|
||||
* @in: the split key to be recombined
|
||||
* @out: preallocated buffer to hold the master key
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Join the data in @in, which is @blocklen * @stripes
|
||||
* bytes in size, to form the original small piece of
|
||||
* data @out, which is @blocklen bytes in size.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error;
|
||||
*/
|
||||
int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
|
||||
size_t blocklen,
|
||||
uint32_t stripes,
|
||||
const uint8_t *in,
|
||||
uint8_t *out,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_AFSPLIT_H__ */
|
||||
232
include/crypto/block.h
Normal file
232
include/crypto/block.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* QEMU Crypto block device encryption
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_BLOCK_H__
|
||||
#define QCRYPTO_BLOCK_H__
|
||||
|
||||
#include "crypto/cipher.h"
|
||||
#include "crypto/ivgen.h"
|
||||
|
||||
typedef struct QCryptoBlock QCryptoBlock;
|
||||
|
||||
/* See also QCryptoBlockFormat, QCryptoBlockCreateOptions
|
||||
* and QCryptoBlockOpenOptions in qapi/crypto.json */
|
||||
|
||||
typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block,
|
||||
size_t headerlen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block,
|
||||
size_t offset,
|
||||
const uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp,
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* qcrypto_block_has_format:
|
||||
* @format: the encryption format
|
||||
* @buf: the data from head of the volume
|
||||
* @len: the length of @buf in bytes
|
||||
*
|
||||
* Given @len bytes of data from the head of a storage volume
|
||||
* in @buf, probe to determine if the volume has the encryption
|
||||
* format specified in @format.
|
||||
*
|
||||
* Returns: true if the data in @buf matches @format
|
||||
*/
|
||||
bool qcrypto_block_has_format(QCryptoBlockFormat format,
|
||||
const uint8_t *buf,
|
||||
size_t buflen);
|
||||
|
||||
typedef enum {
|
||||
QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0),
|
||||
} QCryptoBlockOpenFlags;
|
||||
|
||||
/**
|
||||
* qcrypto_block_open:
|
||||
* @options: the encryption options
|
||||
* @readfunc: callback for reading data from the volume
|
||||
* @opaque: data to pass to @readfunc
|
||||
* @flags: bitmask of QCryptoBlockOpenFlags values
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Create a new block encryption object for an existing
|
||||
* storage volume encrypted with format identified by
|
||||
* the parameters in @options.
|
||||
*
|
||||
* This will use @readfunc to initialize the encryption
|
||||
* context based on the volume header(s), extracting the
|
||||
* master key(s) as required.
|
||||
*
|
||||
* If @flags contains QCRYPTO_BLOCK_OPEN_NO_IO then
|
||||
* the open process will be optimized to skip any parts
|
||||
* that are only required to perform I/O. In particular
|
||||
* this would usually avoid the need to decrypt any
|
||||
* master keys. The only thing that can be done with
|
||||
* the resulting QCryptoBlock object would be to query
|
||||
* metadata such as the payload offset. There will be
|
||||
* no cipher or ivgen objects available.
|
||||
*
|
||||
* If any part of initializing the encryption context
|
||||
* fails an error will be returned. This could be due
|
||||
* to the volume being in the wrong format, a cipher
|
||||
* or IV generator algorithm that is not supported,
|
||||
* or incorrect passphrases.
|
||||
*
|
||||
* Returns: a block encryption format, or NULL on error
|
||||
*/
|
||||
QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
|
||||
QCryptoBlockReadFunc readfunc,
|
||||
void *opaque,
|
||||
unsigned int flags,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_block_create:
|
||||
* @format: the encryption format
|
||||
* @initfunc: callback for initializing volume header
|
||||
* @writefunc: callback for writing data to the volume header
|
||||
* @opaque: data to pass to @initfunc and @writefunc
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Create a new block encryption object for initializing
|
||||
* a storage volume to be encrypted with format identified
|
||||
* by the parameters in @options.
|
||||
*
|
||||
* This method will allocate space for a new volume header
|
||||
* using @initfunc and then write header data using @writefunc,
|
||||
* generating new master keys, etc as required. Any existing
|
||||
* data present on the volume will be irrevocably destroyed.
|
||||
*
|
||||
* If any part of initializing the encryption context
|
||||
* fails an error will be returned. This could be due
|
||||
* to the volume being in the wrong format, a cipher
|
||||
* or IV generator algorithm that is not supported,
|
||||
* or incorrect passphrases.
|
||||
*
|
||||
* Returns: a block encryption format, or NULL on error
|
||||
*/
|
||||
QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
|
||||
QCryptoBlockInitFunc initfunc,
|
||||
QCryptoBlockWriteFunc writefunc,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* @qcrypto_block_decrypt:
|
||||
* @block: the block encryption object
|
||||
* @startsector: the sector from which @buf was read
|
||||
* @buf: the buffer to decrypt
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Decrypt @len bytes of cipher text in @buf, writing
|
||||
* plain text back into @buf
|
||||
*
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* @qcrypto_block_encrypt:
|
||||
* @block: the block encryption object
|
||||
* @startsector: the sector to which @buf will be written
|
||||
* @buf: the buffer to decrypt
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Encrypt @len bytes of plain text in @buf, writing
|
||||
* cipher text back into @buf
|
||||
*
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_cipher:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the cipher to use for payload encryption
|
||||
*
|
||||
* Returns: the cipher object
|
||||
*/
|
||||
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_ivgen:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the initialization vector generator to use for
|
||||
* payload encryption
|
||||
*
|
||||
* Returns: the IV generator object
|
||||
*/
|
||||
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_kdf_hash:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the hash algorithm used with the key derivation
|
||||
* function
|
||||
*
|
||||
* Returns: the hash algorithm
|
||||
*/
|
||||
QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_get_payload_offset:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Get the offset to the payload indicated by the
|
||||
* encryption header, in bytes.
|
||||
*
|
||||
* Returns: the payload offset in bytes
|
||||
*/
|
||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
|
||||
|
||||
/**
|
||||
* qcrypto_block_free:
|
||||
* @block: the block encryption object
|
||||
*
|
||||
* Release all resources associated with the encryption
|
||||
* object
|
||||
*/
|
||||
void qcrypto_block_free(QCryptoBlock *block);
|
||||
|
||||
#endif /* QCRYPTO_BLOCK_H__ */
|
||||
206
include/crypto/ivgen.h
Normal file
206
include/crypto/ivgen.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* QEMU Crypto block IV generator
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_IVGEN_H__
|
||||
#define QCRYPTO_IVGEN_H__
|
||||
|
||||
#include "crypto/cipher.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/**
|
||||
* This module provides a framework for generating initialization
|
||||
* vectors for block encryption schemes using chained cipher modes
|
||||
* CBC. The principle is that each disk sector is assigned a unique
|
||||
* initialization vector for use for encryption of data in that
|
||||
* sector.
|
||||
*
|
||||
* <example>
|
||||
* <title>Encrypting block data with initialiation vectors</title>
|
||||
* <programlisting>
|
||||
* uint8_t *data = ....data to encrypt...
|
||||
* size_t ndata = XXX;
|
||||
* uint8_t *key = ....some encryption key...
|
||||
* size_t nkey = XXX;
|
||||
* uint8_t *iv;
|
||||
* size_t niv;
|
||||
* size_t sector = 0;
|
||||
*
|
||||
* g_assert((ndata % 512) == 0);
|
||||
*
|
||||
* QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV,
|
||||
* QCRYPTO_CIPHER_ALG_AES_128,
|
||||
* QCRYPTO_HASH_ALG_SHA256,
|
||||
* key, nkey, errp);
|
||||
* if (!ivgen) {
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
* QCRYPTO_CIPHER_MODE_CBC,
|
||||
* key, nkey, errp);
|
||||
* if (!cipher) {
|
||||
* goto error;
|
||||
* }
|
||||
*
|
||||
* niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
* QCRYPTO_CIPHER_MODE_CBC);
|
||||
* iv = g_new0(uint8_t, niv);
|
||||
*
|
||||
*
|
||||
* while (ndata) {
|
||||
* if (qcrypto_ivgen_calculate(ivgen, sector, iv, niv, errp) < 0) {
|
||||
* goto error;
|
||||
* }
|
||||
* if (qcrypto_cipher_setiv(cipher, iv, niv, errp) < 0) {
|
||||
* goto error;
|
||||
* }
|
||||
* if (qcrypto_cipher_encrypt(cipher,
|
||||
* data + (sector * 512),
|
||||
* data + (sector * 512),
|
||||
* 512, errp) < 0) {
|
||||
* goto error;
|
||||
* }
|
||||
* sector++;
|
||||
* ndata -= 512;
|
||||
* }
|
||||
*
|
||||
* g_free(iv);
|
||||
* qcrypto_ivgen_free(ivgen);
|
||||
* qcrypto_cipher_free(cipher);
|
||||
* return 0;
|
||||
*
|
||||
*error:
|
||||
* g_free(iv);
|
||||
* qcrypto_ivgen_free(ivgen);
|
||||
* qcrypto_cipher_free(cipher);
|
||||
* return -1;
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
typedef struct QCryptoIVGen QCryptoIVGen;
|
||||
|
||||
/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_new:
|
||||
* @alg: the initialization vector generation algorithm
|
||||
* @cipheralg: the cipher algorithm or 0
|
||||
* @hash: the hash algorithm or 0
|
||||
* @key: the encryption key or NULL
|
||||
* @nkey: the size of @key in bytes
|
||||
*
|
||||
* Create a new initialization vector generator that uses
|
||||
* the algorithm @alg. Whether the remaining parameters
|
||||
* are required or not depends on the choice of @alg
|
||||
* requested.
|
||||
*
|
||||
* - QCRYPTO_IVGEN_ALG_PLAIN
|
||||
*
|
||||
* The IVs are generated by the 32-bit truncated sector
|
||||
* number. This should never be used for block devices
|
||||
* that are larger than 2^32 sectors in size.
|
||||
* All the other parameters are unused.
|
||||
*
|
||||
* - QCRYPTO_IVGEN_ALG_PLAIN64
|
||||
*
|
||||
* The IVs are generated by the 64-bit sector number.
|
||||
* All the other parameters are unused.
|
||||
*
|
||||
* - QCRYPTO_IVGEN_ALG_ESSIV:
|
||||
*
|
||||
* The IVs are generated by encrypting the 64-bit sector
|
||||
* number with a hash of an encryption key. The @cipheralg,
|
||||
* @hash, @key and @nkey parameters are all required.
|
||||
*
|
||||
* Returns: a new IV generator, or NULL on error
|
||||
*/
|
||||
QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
|
||||
QCryptoCipherAlgorithm cipheralg,
|
||||
QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_calculate:
|
||||
* @ivgen: the IV generator object
|
||||
* @sector: the 64-bit sector number
|
||||
* @iv: a pre-allocated buffer to hold the generated IV
|
||||
* @niv: the number of bytes in @iv
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Calculate a new initialiation vector for the data
|
||||
* to be stored in sector @sector. The IV will be
|
||||
* written into the buffer @iv of size @niv.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
|
||||
uint64_t sector,
|
||||
uint8_t *iv, size_t niv,
|
||||
Error **errp);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_get_algorithm:
|
||||
* @ivgen: the IV generator object
|
||||
*
|
||||
* Get the algorithm used by this IV generator
|
||||
*
|
||||
* Returns: the IV generator algorithm
|
||||
*/
|
||||
QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_get_cipher:
|
||||
* @ivgen: the IV generator object
|
||||
*
|
||||
* Get the cipher algorithm used by this IV generator (if
|
||||
* applicable)
|
||||
*
|
||||
* Returns: the cipher algorithm
|
||||
*/
|
||||
QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_get_hash:
|
||||
* @ivgen: the IV generator object
|
||||
*
|
||||
* Get the hash algorithm used by this IV generator (if
|
||||
* applicable)
|
||||
*
|
||||
* Returns: the hash algorithm
|
||||
*/
|
||||
QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_ivgen_free:
|
||||
* @ivgen: the IV generator object
|
||||
*
|
||||
* Release all resources associated with @ivgen, or a no-op
|
||||
* if @ivgen is NULL
|
||||
*/
|
||||
void qcrypto_ivgen_free(QCryptoIVGen *ivgen);
|
||||
|
||||
#endif /* QCRYPTO_IVGEN_H__ */
|
||||
152
include/crypto/pbkdf.h
Normal file
152
include/crypto/pbkdf.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_PBKDF_H__
|
||||
#define QCRYPTO_PBKDF_H__
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
/**
|
||||
* This module provides an interface to the PBKDF2 algorithm
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/PBKDF2
|
||||
*
|
||||
* <example>
|
||||
* <title>Generating an AES encryption key from a user password</title>
|
||||
* <programlisting>
|
||||
* #include "crypto/cipher.h"
|
||||
* #include "crypto/random.h"
|
||||
* #include "crypto/pbkdf.h"
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* char *password = "a-typical-awful-user-password";
|
||||
* size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALG_AES_128);
|
||||
* uint8_t *salt = g_new0(uint8_t, nkey);
|
||||
* uint8_t *key = g_new0(uint8_t, nkey);
|
||||
* int iterations;
|
||||
* QCryptoCipher *cipher;
|
||||
*
|
||||
* if (qcrypto_random_bytes(salt, nkey, errp) < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
|
||||
* (const uint8_t *)password,
|
||||
* strlen(password),
|
||||
* salt, nkey, errp);
|
||||
* if (iterations < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* if (qcrypto_pbkdf2(QCRYPTO_HASH_ALG_SHA256,
|
||||
* (const uint8_t *)password, strlen(password),
|
||||
* salt, nkey, iterations, key, nkey, errp) < 0) {
|
||||
* g_free(key);
|
||||
* g_free(salt);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* g_free(salt);
|
||||
*
|
||||
* cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
|
||||
* QCRYPTO_CIPHER_MODE_ECB,
|
||||
* key, nkey, errp);
|
||||
* g_free(key);
|
||||
*
|
||||
* ....encrypt some data...
|
||||
*
|
||||
* qcrypto_cipher_free(cipher);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2_supports:
|
||||
* @hash: the hash algorithm
|
||||
*
|
||||
* Determine if the current build supports the PBKDF2 algorithm
|
||||
* in combination with the hash @hash.
|
||||
*
|
||||
* Returns true if supported, false otherwise
|
||||
*/
|
||||
bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2:
|
||||
* @hash: the hash algorithm to use
|
||||
* @key: the user password / key
|
||||
* @nkey: the length of @key in bytes
|
||||
* @salt: a random salt
|
||||
* @nsalt: length of @salt in bytes
|
||||
* @iterations: the number of iterations to compute
|
||||
* @out: pointer to pre-allocated buffer to hold output
|
||||
* @nout: length of @out in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Apply the PBKDF2 algorithm to derive an encryption
|
||||
* key from a user password provided in @key. The
|
||||
* @salt parameter is used to perturb the algorithm.
|
||||
* The @iterations count determines how many times
|
||||
* the hashing process is run, which influences how
|
||||
* hard it is to crack the key. The number of @iterations
|
||||
* should be large enough such that the algorithm takes
|
||||
* 1 second or longer to derive a key. The derived key
|
||||
* will be stored in the preallocated buffer @out.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
unsigned int iterations,
|
||||
uint8_t *out, size_t nout,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_pbkdf2_count_iters:
|
||||
* @hash: the hash algorithm to use
|
||||
* @key: the user password / key
|
||||
* @nkey: the length of @key in bytes
|
||||
* @salt: a random salt
|
||||
* @nsalt: length of @salt in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Time the PBKDF2 algorithm to determine how many
|
||||
* iterations are required to derive an encryption
|
||||
* key from a user password provided in @key in 1
|
||||
* second of compute time. The result of this can
|
||||
* be used as a the @iterations parameter of a later
|
||||
* call to qcrypto_pbkdf2().
|
||||
*
|
||||
* Returns: number of iterations in 1 second, -1 on error
|
||||
*/
|
||||
int qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
|
||||
const uint8_t *key, size_t nkey,
|
||||
const uint8_t *salt, size_t nsalt,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_PBKDF_H__ */
|
||||
44
include/crypto/random.h
Normal file
44
include/crypto/random.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* QEMU Crypto random number provider
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_RANDOM_H__
|
||||
#define QCRYPTO_RANDOM_H__
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_random_bytes:
|
||||
* @buf: the buffer to fill
|
||||
* @buflen: length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Fill @buf with @buflen bytes of cryptographically strong
|
||||
* random data
|
||||
*
|
||||
* Returns 0 on sucess, -1 on error
|
||||
*/
|
||||
int qcrypto_random_bytes(uint8_t *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
||||
#endif /* QCRYPTO_RANDOM_H__ */
|
||||
86
include/crypto/xts.h
Normal file
86
include/crypto/xts.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QCRYPTO_XTS_H_
|
||||
#define QCRYPTO_XTS_H_
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
||||
#define XTS_BLOCK_SIZE 16
|
||||
|
||||
typedef void xts_cipher_func(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data decryption
|
||||
* @tweakctx: the cipher context for tweak decryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the decrypted plaintext
|
||||
* @src: buffer providing the ciphertext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data encryption
|
||||
* @tweakctx: the cipher context for tweak encryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the encrypted ciphertext
|
||||
* @src: buffer providing the plaintext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
|
||||
#endif /* QCRYPTO_XTS_H_ */
|
||||
@@ -18,6 +18,7 @@ extern PropertyInfo qdev_prop_string;
|
||||
extern PropertyInfo qdev_prop_chr;
|
||||
extern PropertyInfo qdev_prop_ptr;
|
||||
extern PropertyInfo qdev_prop_macaddr;
|
||||
extern PropertyInfo qdev_prop_on_off_auto;
|
||||
extern PropertyInfo qdev_prop_losttickpolicy;
|
||||
extern PropertyInfo qdev_prop_bios_chs_trans;
|
||||
extern PropertyInfo qdev_prop_fdc_drive_type;
|
||||
@@ -155,6 +156,8 @@ extern PropertyInfo qdev_prop_arraylen;
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockBackend *)
|
||||
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
|
||||
#define DEFINE_PROP_ON_OFF_AUTO(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_on_off_auto, OnOffAuto)
|
||||
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
|
||||
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
|
||||
LostTickPolicy)
|
||||
|
||||
@@ -100,9 +100,6 @@
|
||||
#define QERR_UNDEFINED_ERROR \
|
||||
"An undefined error has occurred"
|
||||
|
||||
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
|
||||
"'%s' uses a %s feature which is not supported by this qemu version: %s"
|
||||
|
||||
#define QERR_UNSUPPORTED \
|
||||
"this feature or command is not currently supported"
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ extern int daemon(int, int);
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
/* setjmp must be declared before sysemu/os-win32.h
|
||||
* because it is redefined there. */
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef QEMU_CPU_H
|
||||
#define QEMU_CPU_H
|
||||
|
||||
#include <setjmp.h>
|
||||
#include "hw/qdev-core.h"
|
||||
#include "disas/bfd.h"
|
||||
#include "exec/hwaddr.h"
|
||||
|
||||
@@ -59,11 +59,10 @@ typedef struct BlockDevOps {
|
||||
void (*resize_cb)(void *opaque);
|
||||
} BlockDevOps;
|
||||
|
||||
BlockBackend *blk_new(const char *name, Error **errp);
|
||||
BlockBackend *blk_new_with_bs(const char *name, Error **errp);
|
||||
BlockBackend *blk_new_open(const char *name, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
Error **errp);
|
||||
BlockBackend *blk_new(Error **errp);
|
||||
BlockBackend *blk_new_with_bs(Error **errp);
|
||||
BlockBackend *blk_new_open(const char *filename, const char *reference,
|
||||
QDict *options, int flags, Error **errp);
|
||||
int blk_get_refcnt(BlockBackend *blk);
|
||||
void blk_ref(BlockBackend *blk);
|
||||
void blk_unref(BlockBackend *blk);
|
||||
@@ -71,13 +70,14 @@ void blk_remove_all_bs(void);
|
||||
const char *blk_name(BlockBackend *blk);
|
||||
BlockBackend *blk_by_name(const char *name);
|
||||
BlockBackend *blk_next(BlockBackend *blk);
|
||||
BlockDriverState *blk_next_root_bs(BlockDriverState *bs);
|
||||
bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp);
|
||||
void monitor_remove_blk(BlockBackend *blk);
|
||||
|
||||
BlockDriverState *blk_bs(BlockBackend *blk);
|
||||
void blk_remove_bs(BlockBackend *blk);
|
||||
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
|
||||
|
||||
void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk);
|
||||
|
||||
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
|
||||
void blk_iostatus_enable(BlockBackend *blk);
|
||||
bool blk_iostatus_is_enabled(const BlockBackend *blk);
|
||||
@@ -127,6 +127,7 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors);
|
||||
int blk_co_flush(BlockBackend *blk);
|
||||
int blk_flush(BlockBackend *blk);
|
||||
int blk_flush_all(void);
|
||||
int blk_commit_all(void);
|
||||
void blk_drain(BlockBackend *blk);
|
||||
void blk_drain_all(void);
|
||||
void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "audio/audio.h"
|
||||
#include "disas/disas.h"
|
||||
#include "sysemu/balloon.h"
|
||||
@@ -3483,7 +3484,7 @@ static void monitor_find_completion_by_table(Monitor *mon,
|
||||
int i;
|
||||
const char *ptype, *str, *name;
|
||||
const mon_cmd_t *cmd;
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk = NULL;
|
||||
|
||||
if (nb_args <= 1) {
|
||||
/* command completion */
|
||||
@@ -3538,8 +3539,8 @@ static void monitor_find_completion_by_table(Monitor *mon,
|
||||
case 'B':
|
||||
/* block device name completion */
|
||||
readline_set_completion_index(mon->rs, strlen(str));
|
||||
for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
|
||||
name = bdrv_get_device_name(bs);
|
||||
while ((blk = blk_next(blk)) != NULL) {
|
||||
name = blk_name(blk);
|
||||
if (str[0] == '\0' ||
|
||||
!strncmp(name, str, strlen(str))) {
|
||||
readline_add_completion(mon->rs, name);
|
||||
|
||||
@@ -189,7 +189,7 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
|
||||
DumpNetClient *dnc;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
|
||||
dump = opts->u.dump;
|
||||
dump = opts->u.dump.data;
|
||||
|
||||
assert(peer);
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ int net_init_hubport(const NetClientOptions *opts, const char *name,
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
|
||||
assert(!peer);
|
||||
hubport = opts->u.hubport;
|
||||
hubport = opts->u.hubport.data;
|
||||
|
||||
net_hub_add_port(hubport->hubid, name);
|
||||
return 0;
|
||||
|
||||
@@ -546,7 +546,7 @@ int net_init_l2tpv3(const NetClientOptions *opts,
|
||||
s->header_mismatch = false;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
|
||||
l2tpv3 = opts->u.l2tpv3;
|
||||
l2tpv3 = opts->u.l2tpv3.data;
|
||||
|
||||
if (l2tpv3->has_ipv6 && l2tpv3->ipv6) {
|
||||
s->ipv6 = l2tpv3->ipv6;
|
||||
|
||||
@@ -893,7 +893,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,
|
||||
const NetLegacyNicOptions *nic;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
|
||||
nic = opts->u.nic;
|
||||
nic = opts->u.nic.data;
|
||||
|
||||
idx = nic_get_free_idx();
|
||||
if (idx == -1 || nb_nics >= MAX_NICS) {
|
||||
@@ -1025,7 +1025,7 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
|
||||
|
||||
/* Do not add to a vlan if it's a nic with a netdev= parameter. */
|
||||
if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC ||
|
||||
!opts->u.nic->has_netdev) {
|
||||
!opts->u.nic.data->has_netdev) {
|
||||
peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ static NetClientInfo net_netmap_info = {
|
||||
int net_init_netmap(const NetClientOptions *opts,
|
||||
const char *name, NetClientState *peer, Error **errp)
|
||||
{
|
||||
const NetdevNetmapOptions *netmap_opts = opts->u.netmap;
|
||||
const NetdevNetmapOptions *netmap_opts = opts->u.netmap.data;
|
||||
struct nm_desc *nmd;
|
||||
NetClientState *nc;
|
||||
Error *err = NULL;
|
||||
|
||||
@@ -814,7 +814,7 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
|
||||
const char **dnssearch;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
|
||||
user = opts->u.user;
|
||||
user = opts->u.user.data;
|
||||
|
||||
vnet = user->has_net ? g_strdup(user->net) :
|
||||
user->has_ip ? g_strdup_printf("%s/24", user->ip) :
|
||||
|
||||
@@ -704,7 +704,7 @@ int net_init_socket(const NetClientOptions *opts, const char *name,
|
||||
const NetdevSocketOptions *sock;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
|
||||
sock = opts->u.socket;
|
||||
sock = opts->u.socket.data;
|
||||
|
||||
if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
|
||||
sock->has_udp != 1) {
|
||||
|
||||
@@ -795,7 +795,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
|
||||
const NetdevTapOptions *tap;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
|
||||
tap = opts->u.tap;
|
||||
tap = opts->u.tap.data;
|
||||
|
||||
if (!tap->has_ifname) {
|
||||
error_report("tap: no interface name");
|
||||
|
||||
@@ -565,7 +565,7 @@ int net_init_bridge(const NetClientOptions *opts, const char *name,
|
||||
int fd, vnet_hdr;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
|
||||
bridge = opts->u.bridge;
|
||||
bridge = opts->u.bridge.data;
|
||||
|
||||
helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
|
||||
br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE;
|
||||
@@ -728,7 +728,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
|
||||
char ifname[128];
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
|
||||
tap = opts->u.tap;
|
||||
tap = opts->u.tap.data;
|
||||
queues = tap->has_queues ? tap->queues : 1;
|
||||
vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ int net_init_vde(const NetClientOptions *opts, const char *name,
|
||||
const NetdevVdeOptions *vde;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
|
||||
vde = opts->u.vde;
|
||||
vde = opts->u.vde.data;
|
||||
|
||||
/* missing optional values have been initialized to "all bits zero" */
|
||||
if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group,
|
||||
|
||||
@@ -306,7 +306,7 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
|
||||
CharDriverState *chr;
|
||||
|
||||
assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
|
||||
vhost_user_opts = opts->u.vhost_user;
|
||||
vhost_user_opts = opts->u.vhost_user.data;
|
||||
|
||||
chr = net_vhost_parse_chardev(vhost_user_opts, errp);
|
||||
if (!chr) {
|
||||
|
||||
4
numa.c
4
numa.c
@@ -228,7 +228,7 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
|
||||
|
||||
switch (object->type) {
|
||||
case NUMA_OPTIONS_KIND_NODE:
|
||||
numa_node_parse(object->u.node, opts, &err);
|
||||
numa_node_parse(object->u.node.data, opts, &err);
|
||||
if (err) {
|
||||
goto error;
|
||||
}
|
||||
@@ -482,7 +482,7 @@ static void numa_stat_memory_devices(uint64_t node_mem[])
|
||||
if (value) {
|
||||
switch (value->type) {
|
||||
case MEMORY_DEVICE_INFO_KIND_DIMM:
|
||||
node_mem[value->u.dimm->node] += value->u.dimm->size;
|
||||
node_mem[value->u.dimm.data->node] += value->u.dimm.data->size;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -753,9 +753,9 @@
|
||||
'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }
|
||||
|
||||
##
|
||||
# @CpuInfoBase:
|
||||
# @CpuInfo:
|
||||
#
|
||||
# Common information about a virtual CPU
|
||||
# Information about a virtual CPU
|
||||
#
|
||||
# @CPU: the index of the virtual CPU
|
||||
#
|
||||
@@ -776,18 +776,10 @@
|
||||
# Notes: @halted is a transient state that changes frequently. By the time the
|
||||
# data is sent to the client, the guest may no longer be halted.
|
||||
##
|
||||
{ 'struct': 'CpuInfoBase',
|
||||
'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
|
||||
'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' } }
|
||||
|
||||
##
|
||||
# @CpuInfo:
|
||||
#
|
||||
# Information about a virtual CPU
|
||||
#
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'union': 'CpuInfo', 'base': 'CpuInfoBase', 'discriminator': 'arch',
|
||||
{ 'union': 'CpuInfo',
|
||||
'base': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
|
||||
'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' },
|
||||
'discriminator': 'arch',
|
||||
'data': { 'x86': 'CpuInfoX86',
|
||||
'sparc': 'CpuInfoSPARC',
|
||||
'ppc': 'CpuInfoPPC',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user