mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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
This commit is contained in:
1 parent
bc3d09e90b
commit
d93fbcf022
4 files changed
+184
-20
No files matched your search
@@ -60,6 +60,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 \
|
||||
|
||||
+18
-8
@@ -435,7 +435,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.
|
||||
@@ -636,16 +636,25 @@ access is appropriately restricted.
|
||||
.Sm on
|
||||
.El
|
||||
.Pp
|
||||
Emulate a TPM device. The argument
|
||||
.Ar path
|
||||
needs to point to a valid TPM device path, i.e.
|
||||
.Pa /dev/tpm0 .
|
||||
.Pp
|
||||
Emulate a TPM device.
|
||||
Supported options for
|
||||
.Ar type :
|
||||
.Bl -tag -width 10n
|
||||
.It Cm passthru
|
||||
pass a physical TPM device through to the guest
|
||||
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
|
||||
@@ -655,7 +664,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
|
||||
.Ss Boot ROM device backends
|
||||
.Sm off
|
||||
|
||||
@@ -160,15 +160,6 @@ Message (e.g. TightVNC).
|
||||
.It Va pci.enable_bars Ta bool Ta Ta
|
||||
Enable and map PCI BARs before executing any guest code.
|
||||
This setting is false by default when using a boot ROM and true otherwise.
|
||||
.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.
|
||||
@@ -288,9 +279,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.
|
||||
@@ -602,6 +592,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
|
||||
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user