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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list