git: fe019d5e443b - stable/14 - bhyve: TPM 2.0 emulation with swtpm
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 12 Nov 2024 07:55:46 UTC
The branch stable/14 has been updated by corvink: URL: https://cgit.FreeBSD.org/src/commit/?id=fe019d5e443bdf3b40eec06078d2c596e84f8c56 commit fe019d5e443bdf3b40eec06078d2c596e84f8c56 Author: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> AuthorDate: 2024-09-09 08:45:40 +0000 Commit: Corvin Köhne <corvink@FreeBSD.org> CommitDate: 2024-11-12 07:54:22 +0000 bhyve: TPM 2.0 emulation with swtpm Implement a TPM 2.0 emulation backend to connect to a running swtpm instance using a UNIX domain socket. Reviewed by: corvink MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D46373 (cherry picked from commit d93fbcf0222b05fcd7704b35bc94e5513c2682e2) --- usr.sbin/bhyve/Makefile | 1 + usr.sbin/bhyve/bhyve.8 | 26 ++++++-- usr.sbin/bhyve/bhyve_config.5 | 45 ++++++++++---- usr.sbin/bhyve/tpm_emul_swtpm.c | 132 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+), 17 deletions(-) diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index 03ea77769754..f4dae2f09904 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -54,6 +54,7 @@ SRCS= \ sockstream.c \ tpm_device.c \ tpm_emul_passthru.c \ + tpm_emul_swtpm.c \ tpm_intf_crb.c \ tpm_ppi_qemu.c \ uart_backend.c \ diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index ffdaf71d1d8a..90f34b3314f8 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -374,7 +374,7 @@ PCI 16550 serial device. .It Cm lpc LPC PCI-ISA bridge with COM1, COM2, COM3, and COM4 16550 serial ports, a boot ROM, and, -optionally, a fwcfg type and the debug/test device. +optionally, a TPM module, a fwcfg type, and the debug/test device. The LPC bridge emulation can only be configured on bus 0. .It Cm fbuf Raw framebuffer device attached to VNC server. @@ -566,10 +566,25 @@ process. Use the host TTY device for serial port I/O. .El .Pp -TPM device backends: -.Bl -tag -width 10n -.It Ar type Ns \&, Ns Ar path Ns Op Cm \&, Ns Ar tpm-device-options Emulate a TPM device. +Supported options for +.Ar type : +.Bl -tag -width 10n +.It Cm passthru +Use a physical TPM device. +The argument +.Ar path +needs to point to a valid TPM device path, i.e. +.Pa /dev/tpm0 . +.It Cm swtpm +Connect to a running +.Cm swtpm +instance. +The argument +.Ar path +needs to point to a UNIX domain socket that a +.Cm swtpm +process is listening on. .El .Pp The @@ -579,7 +594,8 @@ are: .It Cm version= Ns Ar version Version of the TPM device according to the TCG specification. Defaults to -.Cm 2.0 +.Cm 2.0 , +which is the only version currently supported. .El .Pp Boot ROM device backends: diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5 index cb2de997e63e..38a52b635ec8 100644 --- a/usr.sbin/bhyve/bhyve_config.5 +++ b/usr.sbin/bhyve/bhyve_config.5 @@ -146,15 +146,6 @@ Specify the keyboard layout name with the file name in This value only works when loaded with UEFI mode for VNC, and used a VNC client that don't support QEMU Extended Key Event Message (e.g. TightVNC). -.It Va tpm.path Ta string Ta Ta -Path to the host TPM device. -This is typically /dev/tpm0. -.It Va tpm.type Ta string Ta Ta -Type of the TPM device passed to the guest. -Currently, only "passthru" is supported. -.It Va tpm.version Ta string Ta 2.0 Ta -Version of the TPM device according to the TCG specification. -Currently, only version 2.0 is supported. .It Va rtc.use_localtime Ta bool Ta true Ta The real time clock uses the local time of the host. If this is set to false, the real time clock uses UTC. @@ -274,9 +265,8 @@ Intel e82545 network interface. VGA framebuffer device attached to VNC server. .It Li lpc LPC PCI-ISA bridge with COM1-COM4 16550 serial ports, -a boot ROM, -an optional fwcfg type, -and an optional debug/test device. +a boot ROM, and, optionally, a TPM module, a fwcfg type, +and a debug/test device. This device must be configured on bus 0. .It Li hda High Definition audio controller. @@ -593,6 +583,37 @@ This value is required for the Intel GOP driver to work properly. .It Va subdevice Ta 0 .El .El +.Ss TPM Device Settings +The TPM device stores its configuration under a top-level +.Va tpm +node rather than under the LPC TPM device's node. +Only one TPM device is supported. +The following nodes are available under +.Va tpm : +.Bl -column "tpm.version" "Format" "Default" +.It Sy Name Ta Sy Format Ta Sy Default Ta Sy Description +.It Va tpm.path Ta string Ta Ta +Path to the TPM backend. +Depending on the +.Va tpm.type , +this is either the host TPM device, typically +.Pa /dev/tpm0 , +or any UNIX domain socket on which a +.Cm swtpm +process is listening. +.It Va tpm.type Ta string Ta Ta +Type of the TPM device passed to the guest. +This can be either +.Dq passthru +to use the host TPM devices, or +.Dq swtpm +to connect to a running +.Cm swtpm +process. +.It Va tpm.version Ta string Ta 2.0 Ta +Version of the TPM device according to the TCG specification. +Currently, only version 2.0 is supported. +.El .Ss NVMe Controller Settings Each NVMe controller supports a single storage device. The device can be backed either by a memory disk described by the diff --git a/usr.sbin/bhyve/tpm_emul_swtpm.c b/usr.sbin/bhyve/tpm_emul_swtpm.c new file mode 100644 index 000000000000..aaa0c9c358cd --- /dev/null +++ b/usr.sbin/bhyve/tpm_emul_swtpm.c @@ -0,0 +1,132 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Hans Rosenfeld + * Author: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <malloc_np.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include "config.h" +#include "tpm_device.h" +#include "tpm_emul.h" + +struct tpm_swtpm { + int fd; +}; + +struct tpm_resp_hdr { + uint16_t tag; + uint32_t len; + uint32_t errcode; +} __packed; + +static int +tpm_swtpm_init(void **sc, nvlist_t *nvl) +{ + struct tpm_swtpm *tpm; + const char *path; + struct sockaddr_un tpm_addr; + + tpm = calloc(1, sizeof (struct tpm_swtpm)); + if (tpm == NULL) { + warnx("%s: failed to allocate tpm_swtpm", __func__); + return (ENOMEM); + } + + path = get_config_value_node(nvl, "path"); + if (path == NULL) { + warnx("%s: no socket path specified", __func__); + return (ENOENT); + } + + tpm->fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (tpm->fd < 0) { + warnx("%s: unable to open tpm socket", __func__); + return (ENOENT); + } + + bzero(&tpm_addr, sizeof (tpm_addr)); + tpm_addr.sun_family = AF_UNIX; + strlcpy(tpm_addr.sun_path, path, sizeof (tpm_addr.sun_path) - 1); + + if (connect(tpm->fd, (struct sockaddr *)&tpm_addr, sizeof (tpm_addr)) == + -1) { + warnx("%s: unable to connect to tpm socket \"%s\"", __func__, + path); + return (ENOENT); + } + + *sc = tpm; + + return (0); +} + +static int +tpm_swtpm_execute_cmd(void *sc, void *cmd, uint32_t cmd_size, void *rsp, + uint32_t rsp_size) +{ + struct tpm_swtpm *tpm; + ssize_t len; + + if (rsp_size < (ssize_t)sizeof(struct tpm_resp_hdr)) { + warn("%s: rsp_size of %u is too small", __func__, rsp_size); + return (EINVAL); + } + + tpm = sc; + + len = send(tpm->fd, cmd, cmd_size, MSG_NOSIGNAL|MSG_DONTWAIT); + if (len == -1) + err(1, "%s: cmd send failed, is swtpm running?", __func__); + if (len != cmd_size) { + warn("%s: cmd write failed (bytes written: %zd / %d)", __func__, + len, cmd_size); + return (EFAULT); + } + + len = recv(tpm->fd, rsp, rsp_size, 0); + if (len == -1) + err(1, "%s: rsp recv failed, is swtpm running?", __func__); + if (len < (ssize_t)sizeof(struct tpm_resp_hdr)) { + warn("%s: rsp read failed (bytes read: %zd / %d)", __func__, + len, rsp_size); + return (EFAULT); + } + + return (0); +} + +static void +tpm_swtpm_deinit(void *sc) +{ + struct tpm_swtpm *tpm; + + tpm = sc; + if (tpm == NULL) + return; + + if (tpm->fd >= 0) + close(tpm->fd); + + free(tpm); +} + +static const struct tpm_emul tpm_emul_swtpm = { + .name = "swtpm", + .init = tpm_swtpm_init, + .deinit = tpm_swtpm_deinit, + .execute_cmd = tpm_swtpm_execute_cmd, +}; +TPM_EMUL_SET(tpm_emul_swtpm);