[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v11 2/2] tpm: add backend for mssim
From: |
Philippe Mathieu-Daudé |
Subject: |
Re: [PATCH v11 2/2] tpm: add backend for mssim |
Date: |
Tue, 7 Jan 2025 08:40:52 +0100 |
User-agent: |
Mozilla Thunderbird |
Hi James,
On 12/12/24 18:05, James Bottomley wrote:
The Microsoft Simulator (mssim) is the reference emulation platform
for the TCG TPM 2.0 specification.
https://github.com/Microsoft/ms-tpm-20-ref.git
It exports a fairly simple network socket based protocol on two
sockets, one for command (default 2321) and one for control (default
2322). This patch adds a simple backend that can speak the mssim
protocol over the network. It also allows the two sockets to be
specified on the command line. The benefits are twofold: firstly it
gives us a backend that actually speaks a standard TPM emulation
protocol instead of the linux specific TPM driver format of the
current emulated TPM backend and secondly, using the microsoft
protocol, the end point of the emulator can be anywhere on the
network, facilitating the cloud use case where a central TPM service
can be used over a control network.
The implementation does basic control commands like power off/on, but
doesn't implement cancellation or startup. The former because
cancellation is pretty much useless on a fast operating TPM emulator
and the latter because this emulator is designed to be used with OVMF
which itself does TPM startup and I wanted to validate that.
To run this, simply download an emulator based on the MS specification
(package ibmswtpm2 on openSUSE) and run it, then add these two lines
to the qemu command and it will use the emulator.
-tpmdev mssim,id=tpm0 \
-device tpm-crb,tpmdev=tpm0 \
to use a remote emulator replace the first line with
-tpmdev
"{'type':'mssim','id':'tpm0','command':{'type':inet,'host':'remote','port':'2321'}}"
tpm-tis also works as the backend.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
---
v2: convert to SocketAddr json and use qio_channel_socket_connect_sync()
v3: gate control power off by migration state keep control socket disconnected
to test outside influence and add docs.
v7: TPMmssim -> TPMMssim; doc and json fixes
Make command socket open each time (makes OS debugging easier)
v11: add startup method to make sure TPM is reset on reboot
---
MAINTAINERS | 6 +
backends/tpm/Kconfig | 5 +
backends/tpm/meson.build | 1 +
backends/tpm/tpm_mssim.c | 335 +++++++++++++++++++++++++++++++++++++++
backends/tpm/tpm_mssim.h | 44 +++++
docs/specs/tpm.rst | 39 +++++
qapi/tpm.json | 31 +++-
system/tpm-hmp-cmds.c | 9 ++
8 files changed, 466 insertions(+), 4 deletions(-)
create mode 100644 backends/tpm/tpm_mssim.c
create mode 100644 backends/tpm/tpm_mssim.h
+static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error **errp)
+{
+ int ret, retc;
+ Error *local_err = NULL;
+
+ ret = qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp);
+ if (ret != 0) {
+ return ret;
+ }
+ cmd = htonl(cmd);
I'd rather not use <arpa/inet.h> here, but:
cpu_to_be32s(&cmd);
+ ret = qio_channel_write_all(QIO_CHANNEL(t->ctrl_qc),
+ (char *)&cmd, sizeof(cmd), errp);
+ if (ret != 0) {
+ goto out;
+ }
+
+ ret = qio_channel_read_all(QIO_CHANNEL(t->ctrl_qc),
+ (char *)&cmd, sizeof(cmd), errp);
+ if (ret != 0) {
+ goto out;
+ }
+ if (cmd != 0) {
+ error_setg(errp, ERROR_PREFIX
+ "Incorrect ACK recieved on control channel 0x%x", cmd);
+ ret = -1;
+ }
+ out:
+ /*
+ * need to close the channel here, but if that fails report it
+ * while not letting a prior failure get overwritten
+ */
+ retc = qio_channel_close(QIO_CHANNEL(t->ctrl_qc), &local_err);
+ error_propagate(errp, local_err);
+ return retc ? retc : ret;
+}
+static void tpm_mssim_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
+ Error **errp)
+{
+ TPMMssim *t = TPM_MSSIM(tb);
+ uint32_t header, len;
+ uint8_t locality = cmd->locty;
+ struct iovec iov[4];
+ int ret;
+
+ ret = qio_channel_socket_connect_sync(t->cmd_qc, t->opts.command, errp);
+ if (ret != 0) {
+ goto fail_msg;
+ }
+
+ header = htonl(TPM_SEND_COMMAND);
+ len = htonl(cmd->in_len);
cpu_to_be32()
+ iov[0].iov_base = &header;
+ iov[0].iov_len = sizeof(header);
+ iov[1].iov_base = &locality;
+ iov[1].iov_len = sizeof(locality);
+ iov[2].iov_base = &len;
+ iov[2].iov_len = sizeof(len);
+ iov[3].iov_base = (void *)cmd->in;
+ iov[3].iov_len = cmd->in_len;
+
+ ret = qio_channel_writev_all(QIO_CHANNEL(t->cmd_qc), iov, 4, errp);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc),
+ (char *)&len, sizeof(len), errp);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ len = ntohl(len);
be32_to_cpu()
+ if (len > cmd->out_len) {
+ error_setg(errp, "receive size is too large");
+ goto fail;
+ }
+ ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc),
+ (char *)cmd->out, len, errp);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ /* ACK packet */
+ ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc),
+ (char *)&header, sizeof(header), errp);
+ if (ret != 0) {
+ goto fail;
+ }
+ if (header != 0) {
+ error_setg(errp, "incorrect ACK received on command channel 0x%x",
len);
+ goto fail;
+ }
+
+ ret = qio_channel_close(QIO_CHANNEL(t->cmd_qc), errp);
+ if (ret != 0) {
+ goto fail_msg;
+ }
+
+ return;
+
+ fail:
+ /* we're already failing, so don't worry if this fails too */
+ qio_channel_close(QIO_CHANNEL(t->cmd_qc), NULL);
+ fail_msg:
+ error_prepend(errp, ERROR_PREFIX);
+ tpm_util_write_fatal_error_response(cmd->out, cmd->out_len);
+}
+static const TypeInfo tpm_mssim_info = {
+ .name = TYPE_TPM_MSSIM,
+ .parent = TYPE_TPM_BACKEND,
+ .instance_size = sizeof(TPMMssim),
+ .class_init = tpm_mssim_class_init,
+ .instance_init = tpm_mssim_instance_init,
+ .instance_finalize = tpm_mssim_instance_finalize,
+};
+
+static void tpm_mssim_register(void)
+{
+ type_register_static(&tpm_mssim_info);
+}
+
+type_init(tpm_mssim_register)
Preferably DEFINE_TYPES().
Otherwise (modulo Daniel comments), LGTM!
Regards,
Phil.