QEMU provides 'mktme-guest' object which is used to launch encrypted
VMs on Intel platform using MKTME feature. The various inputs required to
launch MKTME guest is provided through the <launchSecurity> tag.
MKTME guest launch command:
# Qemu ...\
-machine pc,memory-encryption=m0 -object mktme-guest,id=m0,handle=${serial}
Using system call to generate mktme handle.
Required input to generate MKTME key which returns key handle:
CPU Mode: type=cpu algorithm=ats-xts-128
User Mode: type=user algorithm=ats-xts-128 key=1234567887654321 tweak=1234567887654321
---
src/libvirt_private.syms | 3 +
src/qemu/qemu_command.c | 40 ++++++++++++
src/util/Makefile.inc.am | 2 +
src/util/virmktme.c | 127 +++++++++++++++++++++++++++++++++++++++
src/util/virmktme.h | 34 +++++++++++
5 files changed, 206 insertions(+)
create mode 100644 src/util/virmktme.c
create mode 100644 src/util/virmktme.h
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1b83e44b15..90f98097ef 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2353,6 +2353,9 @@ virMediatedDeviceSetUsedBy;
virMediatedDeviceTypeFree;
virMediatedDeviceTypeReadAttrs;
+# util/virmktme.h
+virGetMktmeKeyHandle;
+virIsMktmeEnabled;
# util/virmodule.h
virModuleLoad;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index aae2f43044..2b35a1116e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -59,6 +59,7 @@
#include "virgic.h"
#include "virmdev.h"
#include "virdomainsnapshotobjlist.h"
+#include "virmktme.h"
#if defined(__linux__)
# include <linux/capability.h>
#endif
@@ -7788,6 +7789,9 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
if (def->sev)
virBufferAddLit(&buf, ",memory-encryption=sev0");
+ if (def->mktme)
+ virBufferAddLit(&buf, ",memory-encryption=m0");
+
virCommandAddArgBuffer(cmd, &buf);
ret = 0;
@@ -10291,6 +10295,39 @@ qemuBuildSEVCommandLine(virDomainObjPtr vm, virCommandPtr cmd,
return ret;
}
+
+static int
+qemuBuildMKTMECommandLine(virCommandPtr cmd,
+ virDomainMKTMEDefPtr mktme)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int ret = -1;
+
+ if (!mktme)
+ return 0;
+
+ if ((mktme->key_handle = virGetMktmeKeyHandle(mktme->id, mktme->key_type,
+ mktme->key, mktme->encryption_algorithm)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get MKTME key handle id %s"), mktme->id);
+ return -1;
+
+ }
+
+ VIR_DEBUG("id=%s key_type=%s key_handle=0x%x",
+ mktme->id, mktme->key_type, mktme->key_handle);
+
+ virBufferAsprintf(&buf, "mktme-guest,id=m0,handle=%d",
mktme->key_handle);
+
+ virCommandAddArg(cmd, "-object");
+ virCommandAddArgBuffer(cmd, &buf);
+ ret = 0;
+
+ virBufferFreeAndReset(&buf);
+ return ret;
+}
+
+
static int
qemuBuildVMCoreInfoCommandLine(virCommandPtr cmd,
const virDomainDef *def,
@@ -10911,6 +10948,9 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
if (qemuBuildSEVCommandLine(vm, cmd, def->sev) < 0)
goto error;
+ if (qemuBuildMKTMECommandLine(cmd, def->mktme) < 0)
+ goto error;
+
if (snapshot)
virCommandAddArgList(cmd, "-loadvm", snapshot->def->name, NULL);
diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am
index c757f5a6ae..2dc920f47c 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -228,6 +228,8 @@ UTIL_SOURCES = \
util/virmdev.h \
util/virfilecache.c \
util/virfilecache.h \
+ util/virmktme.c \
+ util/virmktme.h \
$(NULL)
diff --git a/src/util/virmktme.c b/src/util/virmktme.c
new file mode 100644
index 0000000000..f78d5de8d6
--- /dev/null
+++ b/src/util/virmktme.c
@@ -0,0 +1,127 @@
+/*
+ * virmktme.c: interaction with mktme key ring services
+ *
+ * Copyright (C) 2010-2015 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.1 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/>.
+ *
+ */
+
+#ifdef __linux__
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include <linux/keyctl.h>
+#endif
+#include "virerror.h"
+#include "virlog.h"
+#include "viraudit.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virutil.h"
+#include "virstring.h"
+#include "virrandom.h"
+#include "virmktme.h"
+
+VIR_LOG_INIT("util.mktme");
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define MKTME_AES_XTS_SIZE 16
+
+#ifdef __linux__
+#define GET_MKTME_DEST_RING() \
+ { \
+ destringid = syscall(__NR_request_key, \
+ "keyring", \
+ LIBVIRT_MKTME_KEY_RING_NAME, \
+ KEY_SPEC_PROCESS_KEYRING); \
+ }
+#else
+#define GET_MKTME_DEST_RING()
+#endif
+
+/**
+ * virGetMktmeKey:
+ * @id: mktme id-string
+ * @type: mktme key type
+ * @key: user key value
+ * @encyption_algorithm: encryption algorithm
+ *
+ * Request's a key handle, which is required to launch a encrypted guest
+ *
+ * Returns mktme key handle in case of success, and -1 in case of failure
+ */
+int
+virGetMktmeKeyHandle(const char *id,
+ const char *type,
+ const char *key,
+ const char *algorithm)
+{
+ char *callout = NULL;
+ int destringid = -1;
+ unsigned char kern_entropy[MKTME_AES_XTS_SIZE];
+
+ int ret = -1;
+
+ if (!id || !type || !algorithm)
+ return -1;
+
+ GET_MKTME_DEST_RING();
+ if (destringid < 0)
+ return -1;
+
+ if (key) {
+ if (sizeof(key) != MKTME_AES_XTS_SIZE) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Invalid MKTME key length"));
+ return -1;
+ }
+ if (virRandomBytes(kern_entropy, MKTME_AES_XTS_SIZE) < 0)
+ return -1;
+ if (virAsprintf(&callout, "type=%s algorithm=%s key=%s tweak=%s",
+ type, algorithm, key, kern_entropy) < 0)
+ return -1;
+ } else {
+ if (virAsprintf(&callout, "type=%s algorithm=%s", type, algorithm)
< 0)
+ return -1;
+ }
+
+#ifdef __linux__
+ ret = syscall(__NR_request_key, "mktme", id, callout, destringid);
+ VIR_FREE(callout);
+#endif
+ return ret;
+}
+
+/**
+ * virIsMktmeEnabled:
+ *
+ * Check if mktme key ring exists.
+ *
+ * Returns 0 in case mktme key ring exists, and -1 in case not present
+ */
+int
+virIsMktmeEnabled(void)
+{
+ int destringid = -1;
+ GET_MKTME_DEST_RING();
+ if (destringid < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/src/util/virmktme.h b/src/util/virmktme.h
new file mode 100644
index 0000000000..e417e6eb67
--- /dev/null
+++ b/src/util/virmktme.h
@@ -0,0 +1,34 @@
+/*
+ * virmktme.h: MKTME kernel calls
+ *
+ * Copyright (C) 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.1 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 LIBVIRT_VIRMKTME_H
+# define LIBVIRT_VIRMKTME_H
+
+int
+virGetMktmeKeyHandle(const char *id,
+ const char *type,
+ const char *key,
+ const char *algorithm);
+
+int
+virIsMktmeEnabled(void);
+
+# define LIBVIRT_MKTME_KEY_RING_NAME "mktme_key_ring_service"
+#endif /* LIBVIRT_VIRMKTME_H */
--
2.21.0.windows.1