[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v1 12/26] kvm: vmi: add 'key' property
From: |
Adalbert Lazăr |
Subject: |
[RFC PATCH v1 12/26] kvm: vmi: add 'key' property |
Date: |
Wed, 15 Apr 2020 03:59:24 +0300 |
The introspection tool can be authenticated if the 'key' parameter is
set with the ID of a secret object holding a shared secret between the
introspection tool and QEMU of the introspected VM.
Signed-off-by: Adalbert Lazăr <address@hidden>
---
accel/kvm/vmi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c
index 5659663caa..f456ca56ef 100644
--- a/accel/kvm/vmi.c
+++ b/accel/kvm/vmi.c
@@ -14,6 +14,8 @@
#include "qom/object_interfaces.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
+#include "crypto/secret.h"
+#include "crypto/hash.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
@@ -31,6 +33,11 @@ typedef struct VMIntrospection {
CharBackend sock;
int sock_fd;
+ char *keyid;
+ Object *key;
+ uint8_t cookie_hash[QEMU_VMI_COOKIE_HASH_SIZE];
+ bool key_with_cookie;
+
qemu_vmi_from_introspector hsk_in;
uint64_t hsk_in_read_pos;
uint64_t hsk_in_read_size;
@@ -109,6 +116,14 @@ static void prop_set_chardev(Object *obj, const char
*value, Error **errp)
i->chardevid = g_strdup(value);
}
+static void prop_set_key(Object *obj, const char *value, Error **errp)
+{
+ VMIntrospection *i = VM_INTROSPECTION(obj);
+
+ g_free(i->keyid);
+ i->keyid = g_strdup(value);
+}
+
static void prop_get_uint32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -153,6 +168,7 @@ static void instance_init(Object *obj)
update_vm_start_time(i);
object_property_add_str(obj, "chardev", NULL, prop_set_chardev, NULL);
+ object_property_add_str(obj, "key", NULL, prop_set_key, NULL);
i->handshake_timeout = HANDSHAKE_TIMEOUT_SEC;
object_property_add(obj, "handshake_timeout", "uint32",
@@ -213,6 +229,7 @@ static void instance_finalize(Object *obj)
VMIntrospection *i = VM_INTROSPECTION(obj);
g_free(i->chardevid);
+ g_free(i->keyid);
cancel_handshake_timer(i);
@@ -276,6 +293,16 @@ static bool send_handshake_info(VMIntrospection *i, Error
**errp)
return true;
}
+static bool validate_handshake_cookie(VMIntrospection *i)
+{
+ if (!i->key_with_cookie) {
+ return true;
+ }
+
+ return 0 == memcmp(&i->cookie_hash, &i->hsk_in.cookie_hash,
+ sizeof(i->cookie_hash));
+}
+
static bool validate_handshake(VMIntrospection *i, Error **errp)
{
uint32_t min_accepted_size;
@@ -288,6 +315,11 @@ static bool validate_handshake(VMIntrospection *i, Error
**errp)
return false;
}
+ if (!validate_handshake_cookie(i)) {
+ error_setg(errp, "VMI: received cookie doesn't match");
+ return false;
+ }
+
/*
* Check hsk_in.struct_size and sizeof(hsk_in) before accessing any
* other fields. We might get fewer bytes from applications using
@@ -468,6 +500,31 @@ static void chr_event(void *opaque, QEMUChrEvent event)
}
}
+static bool make_cookie_hash(const char *key_id, uint8_t *cookie_hash,
+ Error **errp)
+{
+ uint8_t *cookie = NULL, *hash = NULL;
+ size_t cookie_size, hash_size = 0;
+ bool done = false;
+
+ if (qcrypto_secret_lookup(key_id, &cookie, &cookie_size, errp) == 0
+ && qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA1,
+ (const char *)cookie, cookie_size,
+ &hash, &hash_size, errp) == 0) {
+ if (hash_size == QEMU_VMI_COOKIE_HASH_SIZE) {
+ memcpy(cookie_hash, hash, QEMU_VMI_COOKIE_HASH_SIZE);
+ done = true;
+ } else {
+ error_setg(errp, "VMI: hash algorithm size mismatch");
+ }
+ }
+
+ g_free(cookie);
+ g_free(hash);
+
+ return done;
+}
+
static Error *vm_introspection_init(VMIntrospection *i)
{
Error *err = NULL;
@@ -486,6 +543,15 @@ static Error *vm_introspection_init(VMIntrospection *i)
return err;
}
+ if (i->keyid) {
+ if (!make_cookie_hash(i->keyid, i->cookie_hash, &err)) {
+ return err;
+ }
+ i->key_with_cookie = true;
+ } else {
+ warn_report("VMI: the introspection tool won't be 'authenticated'");
+ }
+
chr = qemu_chr_find(i->chardevid);
if (!chr) {
error_setg(&err, "VMI: device '%s' not found", i->chardevid);
- Re: [RFC PATCH v1 02/26] char-socket: allow vsock parameters (cid, port), (continued)
- [RFC PATCH v1 01/26] chardev: tcp: allow to change the reconnect timer, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 14/26] kvm: vmi: allow only one instance of the introspection object, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 11/26] kvm: vmi: add 'handshake_timeout' property, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 15/26] kvm: vmi: reconnect the socket on reset, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 19/26] kvm: vmi: intercept force-reset, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 22/26] kvm: vmi: add 'async_unhook' property, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 17/26] kvm: vmi: add 'unhook_timeout' property, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 24/26] kvm: vmi: add 'unhook_on_shutdown' property, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 12/26] kvm: vmi: add 'key' property,
Adalbert Lazăr <=
- [RFC PATCH v1 21/26] kvm: vmi: postpone the OK response from qmp_stop(), Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 18/26] kvm: vmi: store/restore 'vm_start_time' on migrate/snapshot, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 23/26] kvm: vmi: intercept shutdown, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 16/26] kvm: vmi: intercept pause/resume, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 25/26] kvm: vmi: extend handshake to include the e820 table, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 26/26] kvm: vmi: add 'command' and 'event' properties, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 10/26] kvm: vmi: add the handshake with the introspection tool, Adalbert Lazăr, 2020/04/14
- [RFC PATCH v1 20/26] kvm: vmi: intercept live migration, Adalbert Lazăr, 2020/04/14