Re: [PATCH v10 2/2] tpm: add backend for mssim

2024-05-01 Thread James Bottomley
On Wed, 2024-05-01 at 13:20 -0400, Stefan Berger wrote:
> 
> 
> On 5/1/24 12:52, James Bottomley wrote:
> > On Wed, 2024-05-01 at 12:31 -0400, Stefan Berger wrote:
> > > 
> > > 
> > > On 5/1/24 12:21, James Bottomley wrote:
> > > > On Tue, 2024-04-30 at 17:12 -0400, Stefan Berger wrote:
> > > > > On 4/30/24 15:08, James Bottomley wrote:
> > > > [...]
> > > > > > +The mssim backend supports snapshotting and migration by
> > > > > > not resetting
> > > > > 
> > > > > I don't thing snapshotting is supported because snapshooting
> > > > > would require you to be able to set the state of the vTPM
> > > > > from the snapshot you started. I would remove the claim.
> > > > 
> > > > I thought we established last time that it can definitely do
> > > > both (and I've tested it because you asked me to). 
> > > > Snapshotting and migration are essentially the same thing, with
> > > > snapshotting being easier because it can be done on the same
> > > > host meaning the same command line parameters.  If you migrate
> > > > to a different host you need the socket to point back to the
> > > > host serving the vTPM.
> > > > 
> > > > To do this easily you simply keep the vTPM running while the VM
> > > > is undergoing snapshot and migration.  If you're thinking of
> > > > and extended down time for the snapshot, then it's up to the
> > > > vTPM implementation to store the state (or simply keep it
> > > > running for an extended time doing nothing).
> > > 
> > > Which part of the code injects the state into the vTPM so that it
> > > resumes with the state of the TPM (PCRs, NVRAM indices, keys,
> > > sessions etc.) from when the snapshot was taken?
> > 
> > We've had this conversation before too:
> > 
> > https://lore.kernel.org/qemu-devel/f928986fd4095b1f27c83ede96f3b0dd65ad965e.ca...@linux.ibm.com/T/#u
> > 
> > But the synopsis is nothing does.  The design is to be entirely
> > independent of vTPM implementation: it will actually work with any
> > TPM obeying the simulator IP protocol (MS reference, ibmswtpm2 or
> > even your swtpm) but the price of this is that the user has to
> > preserve the vTPM state, by whatever means they deem appropriate,
> > independently of the VM snapshot image.
> 
> Unless your backend can retrieve the state upon snapshot save and
> inject state into the vTPM upon snapshot resume, 'snapshotting' is
> not working  (correctly).

That's too narrow a definition.  Snapshot is working if you can capture
and restore the machine state.  A qemu snapshot can helpfully capture
some device states, but not all of it (Devices that are passed through,
like accelerators and AI units, are particularly problematic).  How you
get the external device state (IBM cloud has an elaborate scripted
state capture for GPUs, for instance) is up to the person implementing
the snapshot.  For this case, the added doc specifically warns "... the
state of the Microsoft Simulator server must be preserved (or the
server kept running) outside of QEMU for restore to be successful", so
I don't think there's going to be an expectation mismatch.

James





Re: [PATCH v10 2/2] tpm: add backend for mssim

2024-05-01 Thread James Bottomley
On Wed, 2024-05-01 at 12:31 -0400, Stefan Berger wrote:
> 
> 
> On 5/1/24 12:21, James Bottomley wrote:
> > On Tue, 2024-04-30 at 17:12 -0400, Stefan Berger wrote:
> > > On 4/30/24 15:08, James Bottomley wrote:
> > [...]
> > > > +The mssim backend supports snapshotting and migration by not
> > > > resetting
> > > 
> > > I don't thing snapshotting is supported because snapshooting
> > > would require you to be able to set the state of the vTPM from
> > > the snapshot you started. I would remove the claim.
> > 
> > I thought we established last time that it can definitely do both
> > (and I've tested it because you asked me to).  Snapshotting and
> > migration are essentially the same thing, with snapshotting being
> > easier because it can be done on the same host meaning the same
> > command line parameters.  If you migrate to a different host you
> > need the socket to point back to the host serving the vTPM.
> > 
> > To do this easily you simply keep the vTPM running while the VM is
> > undergoing snapshot and migration.  If you're thinking of and
> > extended down time for the snapshot, then it's up to the vTPM
> > implementation to store the state (or simply keep it running for an
> > extended time doing nothing).
> 
> Which part of the code injects the state into the vTPM so that it 
> resumes with the state of the TPM (PCRs, NVRAM indices, keys,
> sessions etc.) from when the snapshot was taken?

We've had this conversation before too:

https://lore.kernel.org/qemu-devel/f928986fd4095b1f27c83ede96f3b0dd65ad965e.ca...@linux.ibm.com/T/#u

But the synopsis is nothing does.  The design is to be entirely
independent of vTPM implementation: it will actually work with any TPM
obeying the simulator IP protocol (MS reference, ibmswtpm2 or even your
swtpm) but the price of this is that the user has to preserve the vTPM
state, by whatever means they deem appropriate, independently of the VM
snapshot image.

James




Re: [PATCH v10 2/2] tpm: add backend for mssim

2024-05-01 Thread James Bottomley
On Tue, 2024-04-30 at 17:12 -0400, Stefan Berger wrote:
> On 4/30/24 15:08, James Bottomley wrote:
[...]
> > +The mssim backend supports snapshotting and migration by not
> > resetting
> 
> I don't thing snapshotting is supported because snapshooting would 
> require you to be able to set the state of the vTPM from the snapshot
> you started. I would remove the claim.

I thought we established last time that it can definitely do both (and
I've tested it because you asked me to).  Snapshotting and migration
are essentially the same thing, with snapshotting being easier because
it can be done on the same host meaning the same command line
parameters.  If you migrate to a different host you need the socket to
point back to the host serving the vTPM.

To do this easily you simply keep the vTPM running while the VM is
undergoing snapshot and migration.  If you're thinking of and extended
down time for the snapshot, then it's up to the vTPM implementation to
store the state (or simply keep it running for an extended time doing
nothing).


> Rest LGTM.

Thanks!

Regards,

James




[PATCH v10 2/2] tpm: add backend for mssim

2024-04-30 Thread James Bottomley
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 
Acked-by: Markus Armbruster 

---

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)
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 319 +++
 backends/tpm/tpm_mssim.h |  44 ++
 docs/specs/tpm.rst   |  39 +
 qapi/tpm.json|  31 +++-
 system/tpm-hmp-cmds.c|   9 ++
 8 files changed, 450 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 302b6fd00c..6bd7e82d1b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3386,10 +3386,16 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 F: docs/specs/tpm.rst
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 0bfa6c422b..c6f7c24cb1 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   system_ss.add(files('tpm_util.c'))
   system_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   system_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  system_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..962ad340c3
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,319 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMMssim, TPM_MSSIM)
+
+struct TPMMssim {
+TPMBackend parent;
+
+TPMMssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error **errp)
+{
+int ret, retc;
+Error *local_err = NUL

[PATCH v10 1/2] tpm: convert tpmdev options processing to new visitor format

2024-04-30 Thread James Bottomley
Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 
Tested-by: Stefan Berger 
Reviewed-by: Stefan Berger 

---
v4: add TpmConfiOptions
v5: exit(0) for help
v7: adjust line lengths, free options
v8: minor updates; add tested/reviewed-by
v9: optarg->optstr
---
 backends/tpm/tpm_emulator.c| 25 --
 backends/tpm/tpm_passthrough.c | 23 +++--
 include/sysemu/tpm.h   |  5 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 21 
 system/tpm.c   | 91 ++
 system/vl.c| 19 +--
 7 files changed, 81 insertions(+), 105 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 5a8fba9bde..99ab0019cc 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -580,33 +580,29 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu,
+   TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+ opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -645,7 +641,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -968,7 +964,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -985,7 +980,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 179697a3a9..54183b89a4 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,21 +252,13 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt,
+   TpmCreateOptions *opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path :
+TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -288,11 +280,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -344,7 +336,6 @@ static void tpm_passthrough_inst_init(Object *obj)
 {
 

[PATCH v10 0/2] tpm: add mssim backend

2024-04-30 Thread James Bottomley
The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs

v5 updates help to exit zero; does some checkpatch tidying

v7 merge review feedback and add acks.

v8 adds better error handling, more code tidies and adds command
   socket disconnection/reconnection (instead of trying to keep the
   socket open the whole time).  This adds overhead, but makes
   debugging guest kernel TPM issues much easier.

v9 Fix merge conflict with optarg->optstr conversion

v10 Fix more merge conflicts and update API versions

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  25 ++-
 backends/tpm/tpm_mssim.c   | 319 +
 backends/tpm/tpm_mssim.h   |  44 +
 backends/tpm/tpm_passthrough.c |  23 +--
 docs/specs/tpm.rst |  39 
 include/sysemu/tpm.h   |   5 +-
 include/sysemu/tpm_backend.h   |   2 +-
 qapi/tpm.json  |  50 +-
 system/tpm-hmp-cmds.c  |   9 +
 system/tpm.c   |  91 --
 system/vl.c|  19 +-
 14 files changed, 530 insertions(+), 108 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: RFC i386/sev: kernel-hashes, reference measurements and event logs

2024-02-12 Thread James Bottomley
On Mon, 2024-02-12 at 12:16 -0800, Dionna Amalie Glaze wrote:
> This is not a patch but it felt inappropriate to derail a recent
> patch that's just refactoring the kernel-hashes object_class_property
> definition. Apologies if this has been discussed before, as I'm not
> particularly active here.

I haven't seen that patch, but I presume it's not relevant?

> Regarding kernel-hashes, how is that load-time information passed
> along to the guest beyond, say, OVMF? Can we require that these
> hashes
> are also present in fw_cfg so they can be read from the kernel? In
> Linux it'd be nice to have /sys/firmware/qemu_fw_cfg/sev_kernel_hash,
> /sys/firmware/qemu_fw_cfg/sev_cmdline_hash,
> /sys/firmware/qemu_fw_cfg/sev_initrd_hash

Are you referring to measured direct boot?  In that case, there's no
point having hashes in the fw_cfg, because OVMF in the guest needs to
hash the kernel itself and then compare to a trusted source (which the
fw_cfg file wouldn't be because it's under the control of the
hypervisor).  For SEV, the trusted source is a table in the launch
measured ROM, but I'm sure TDX does something similar.

> I'm working on how to use standard document formats for providing
> reference measurements of the Google Compute Engine virtual firmware
> for remote attestation, and these hashes have an impact not just on
> the measurement but on the entire model that the IETF RATS working
> group is considering for authorizing attestation measurements.
> 
> If you're assembling a VM launch configuration with firmware provided
> by a trusted vendor (say Google), and your hashes are passed in from
> an API, there's no easy rendezvous to state that the combination
> produces the expected hardware measurement. This makes adding
> kernel-hashes support unappetizing, since it makes the hardware
> attestation report's measurement have no meaning, or at least, it
> makes life difficult for people trying to assign it meaning.

Well, no, since firmware tends to update on a longer timeframe than the
kernel and the cmdline and initrd tend to have quicker update cycles
than the kernel.  Thus there's no one golden reference.  Instead you
give a tool (say the virtee sev_snp_measure tool

https://github.com/virtee/sev-snp-measure

) the hashes of the firmware, kernel, command line and initrd and it
caclulates the expected launch measure

> The measurement is the product of two different entities as assembled
> by the VMM given a trusted firmware and the kernel hashes. It's a bit
> of a sandwich of (GCE) core firmware, (User) SEV hashes, (GCE) BSP
> VMSA, AP VMSA*.
> 
> When you collect "evidence" to verify locally or pass along to a
> verification service, you need more than just the hardware
> attestation report to make sense of the combined bits. You have a PCR
> situation like with TPM, so you need an event log for these different
> aspects of the ultimate measurement. There is no event log for this
> -kernel-hashes construction.

That's because it's a pre-launch measure.  The TCG log is only for post
launch.  The idea being those values are needed for you to approve
something in pre-launch, like key release, before the TPM starts
running.

That's not to say we shouldn't have log entries for pre-launch, but
that's a generic problem and not specific to measured direct boot.

> We can use the TCG TPM event log to post EV_NO_ACTION events about
> the PlatformRIM, specifically, to point at a UEFI variable that we
> populate to store our signed document about the expected measurements
> with the Qemu-SEV-SNP-boot-protocol, but I don't see how we might
> collect the kernel-hashes values as extra evidence to combine and
> derive the attestation report's MEASUREMENT field to accept
> "evidence" objects for the core firmware component and the kernel
> hashes component.

This sounds like a first measurement thing.  In many ways, the pre-
launch measurement is equivalent to the SRTM of a physical system which
is collected in the EV_S_CRTM_* events.  But for that to happen, I
think the TCG would have to bless it in some form.

James

> So my question is if this feature is to be a long term feature, how
> do you expect to collect the SEV hashes as a separate evidence object
> to play nicely with IETF RATS?
> 
> Is this a long term feature, or are we expecting it to be deprecated
> by SVSM?
> 
> I've tagged in people in CC that I could imagine would have something
> to say about this.
> 
> Thanks y'all
> 
> --
> -Dionna Glaze, PhD (she/her)




Re: [PATCH v8 2/2] tpm: add backend for mssim

2023-10-05 Thread James Bottomley
On Thu, 2023-10-05 at 18:11 +0200, Philippe Mathieu-Daudé wrote:
> On 5/10/23 15:57, James Bottomley wrote:
> > On Thu, 2023-10-05 at 08:49 +0200, Philippe Mathieu-Daudé wrote:
> > > On 4/10/23 20:42, James Bottomley wrote:
> > > > From: James Bottomley 
[...]
> > > > +.. code-block:: console
> > > > +
> > > > +  qemu-system-x86_64  \
> > > > +    -tpmdev
> > > > "{'type':'mssim','id':'tpm0','command':{'type':'inet','host':'r
> > > > emot
> > > > e','port':'2321'},'control':{'type':'inet','host':'remote','por
> > > > t':'
> > > > 2322'}}" \
> > > > +    -device tpm-crb,tpmdev=tpm0
> > > 
> > > Did you test running this command line on a big-endian host?
> > 
> > Well no, big endian machines are rather rare nowadays.  However,
> > since the QIOChannelSocket abstraction is based on SocketAddress,
> > which is a qapi wrapper around strings, what makes you think the
> > endianness would matter?
> 
> You use ntoh/hton in tpm_mssim_handle_request(), so I wonder about
> the 'uint32_t cmd' in tpm_send_ctrl().

tpm_send_ctrl has a htonl for the send control command as well (The TPM
server is always network ordered, i.e. big endian).  The reason it
doesn't have one for the receive is that it only checks against zero
which is endian invariant, if that's what you're asking?

James




Re: [PATCH v8 2/2] tpm: add backend for mssim

2023-10-05 Thread James Bottomley
On Thu, 2023-10-05 at 08:49 +0200, Philippe Mathieu-Daudé wrote:
> Hi James,
> 
> On 4/10/23 20:42, James Bottomley wrote:
> > From: James Bottomley 
> > 
> > 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 
> > Acked-by: Markus Armbruster 
> > 
> > ---
> > 
> > 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)
> > ---
> >   MAINTAINERS  |   6 +
> >   backends/tpm/Kconfig |   5 +
> >   backends/tpm/meson.build |   1 +
> >   backends/tpm/tpm_mssim.c | 319
> > +++
> >   backends/tpm/tpm_mssim.h |  44 ++
> >   docs/specs/tpm.rst   |  39 +
> >   qapi/tpm.json    |  32 +++-
> >   softmmu/tpm-hmp-cmds.c   |   9 ++
> >   8 files changed, 451 insertions(+), 4 deletions(-)
> >   create mode 100644 backends/tpm/tpm_mssim.c
> >   create mode 100644 backends/tpm/tpm_mssim.h
> 
> 
> > diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst
> > index efe124a148..4fe6c5f051 100644
> > --- a/docs/specs/tpm.rst
> > +++ b/docs/specs/tpm.rst
> > @@ -274,6 +274,42 @@ available as a module (assuming a TPM 2 is
> > passed through):
> >     /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-
> > sha256/9
> >     ...
> >   
> > +The QEMU TPM Microsoft Simulator Device
> > +---
> > +
> > +The Microsoft Simulator (mssim) is the reference emulation
> > platform
> > +for the TCG TPM 2.0 specification.  It provides a reference
> > +implementation for the TPM 2.0 written by Microsoft (See
> > +`ms-tpm-20-ref`_ on github).  The reference implementation starts
> > a
> > +network server and listens for TPM commands on port 2321 and TPM
> > +Platform control commands on port 2322, although these can be
> > altered.
> > +The QEMU mssim TPM backend talks to this implementation.  By
> > default
> > +it connects to the default ports on localhost:
> > +
> > +.. code-block:: console
> > +
> > +  qemu-system-x86_64  \
> > +    -tpmdev mssim,id=tpm0 \
> > +    -device tpm-crb,tpmdev=tpm0
> > +
> > +
> > +Although it can also communicate with a remote host, which must be
> > +specified as a SocketAddress via json or dotted keys on the
> > command
> > +line for each of the command and control ports:
> > +
> > +.. code-block:: console
> > +
> > +  qemu-system-x86_64  \
> > +    -tpmdev
> > "{'type':'mssim','id':'tpm0','command':{'type':'inet','host':'remot
> > e','port':'2321'},'control':{'type':'inet','host':'remote','port':'
> > 2322'}}" \
> > +    -device tpm-crb,tpmdev=tpm0
> 
> Did you test running this command line on a big-endian host?

Well no, big endian machines are rather rare nowadays.  However, since
the QIOChannelSocket abstraction is based on SocketAddress, which is a
qapi wrapper around strings, what makes you think the endianness would
matter?

James




[PATCH v8 2/2] tpm: add backend for mssim

2023-10-04 Thread James Bottomley
From: James Bottomley 

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 
Acked-by: Markus Armbruster 

---

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)
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 319 +++
 backends/tpm/tpm_mssim.h |  44 ++
 docs/specs/tpm.rst   |  39 +
 qapi/tpm.json|  32 +++-
 softmmu/tpm-hmp-cmds.c   |   9 ++
 8 files changed, 451 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 81625f036b..c7204ca184 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3197,10 +3197,16 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 F: docs/specs/tpm.rst
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 0bfa6c422b..c6f7c24cb1 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   system_ss.add(files('tpm_util.c'))
   system_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   system_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  system_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..962ad340c3
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,319 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMMssim, TPM_MSSIM)
+
+struct TPMMssim {
+TPMBackend parent;
+
+TPMMssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error **errp)
+{
+int ret, retc

[PATCH v8 1/2] tpm: convert tpmdev options processing to new visitor format

2023-10-04 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 
Tested-by: Stefan Berger 
Reviewed-by: Stefan Berger 

---
v4: add TpmConfiOptions
v5: exit(0) for help
v7: adjust line lengths, free options
v8: minor updates; add tested/reviewed-by
---
 backends/tpm/tpm_emulator.c| 25 --
 backends/tpm/tpm_passthrough.c | 23 +++--
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 91 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 78 insertions(+), 105 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 402a2d6312..e66a54d646 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -583,33 +583,29 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu,
+   TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+ opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -648,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -971,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -989,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 179697a3a9..54183b89a4 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,21 +252,13 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt,
+   TpmCreateOptions *opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path :
+TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -288,11 +280,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -344,7 +336,6 @@ static void tpm_passthrough_inst_init(Object *obj)
 {
 TPM

[PATCH v8 0/2] tpm: add mssim backend

2023-10-04 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs

v5 updates help to exit zero; does some checkpatch tidying

v7 merge review feedback and add acks.

v8 adds better error handling, more code tidies and adds command
   socket disconnection/reconnection (instead of trying to keep the
   socket open the whole time).  This adds overhead, but makes
   debugging guest kernel TPM issues much easier.

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  25 ++-
 backends/tpm/tpm_mssim.c   | 319 +
 backends/tpm/tpm_mssim.h   |  44 +
 backends/tpm/tpm_passthrough.c |  23 +--
 docs/specs/tpm.rst |  39 
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 qapi/tpm.json  |  49 -
 softmmu/tpm-hmp-cmds.c |   9 +
 softmmu/tpm.c  |  91 --
 softmmu/vl.c   |  19 +-
 14 files changed, 528 insertions(+), 108 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH v7 2/2] tpm: add backend for mssim

2023-09-28 Thread James Bottomley
On Thu, 2023-09-28 at 07:29 +0200, Markus Armbruster wrote:
> Daniel P. Berrangé  writes:
> 
> > On Wed, Sep 27, 2023 at 12:49:08PM -0400, James Bottomley wrote:
> > > From: James Bottomley 
> > > 
> > > 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':'remot
> > > e','port':'2321'}}"
> > > 
> > > tpm-tis also works as the backend.
> > > 
> > > Signed-off-by: James Bottomley 
> > > Acked-by: Markus Armbruster 
> 
> [...]
> 
> > > diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
> > > new file mode 100644
> > > index 00..b8a12dce04
> > > --- /dev/null
> > > +++ b/backends/tpm/tpm_mssim.c
> > > @@ -0,0 +1,290 @@
> > > +/*
> > > + * Emulator TPM driver which connects over the mssim protocol
> > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > + *
> > > + * Copyright (c) 2022
> > > + * Author: James Bottomley 
> > > + */
> > > +
> > > +#include "qemu/osdep.h"
> > > +#include "qemu/error-report.h"
> > > +#include "qemu/sockets.h"
> > > +
> > > +#include "qapi/clone-visitor.h"
> > > +#include "qapi/qapi-visit-tpm.h"
> > > +
> > > +#include "io/channel-socket.h"
> > > +
> > > +#include "sysemu/runstate.h"
> > > +#include "sysemu/tpm_backend.h"
> > > +#include "sysemu/tpm_util.h"
> > > +
> > > +#include "qom/object.h"
> > > +
> > > +#include "tpm_int.h"
> > > +#include "tpm_mssim.h"
> > > +
> > > +#define ERROR_PREFIX "TPM mssim Emulator: "
> > > +
> > > +#define TYPE_TPM_MSSIM "tpm-mssim"
> > > +OBJECT_DECLARE_SIMPLE_TYPE(TPMMssim, TPM_MSSIM)
> > > +
> > > +struct TPMMssim {
> > > +    TPMBackend parent;
> > > +
> > > +    TPMMssimOptions opts;
> > > +
> > > +    QIOChannelSocket *cmd_qc, *ctrl_qc;
> > > +};
> > > +
> > > +static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error
> > > **errp)
> > > +{
> > > +    int ret;
> > > +
> > > +    qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control,
> > > errp);
> > 
> > Need to assign to 'ret' and check for failure here, otherwise the
> > next call to write_all will overwrite the useful message in 'errp'
> > with a less helpful one.
> 
> No, it'll crash :)
> 
> An @errp argument m

[PATCH v7 1/2] tpm: convert tpmdev options processing to new visitor format

2023-09-27 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 

---
v4: add TpmConfiOptions
v5: exit(0) for help
v7: adjust line lengths, free options
---
 backends/tpm/tpm_emulator.c| 25 --
 backends/tpm/tpm_passthrough.c | 23 +++--
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 91 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 78 insertions(+), 105 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 402a2d6312..833520e49a 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -583,33 +583,29 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu,
+   TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -648,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -971,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -989,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 179697a3a9..54183b89a4 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,21 +252,13 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt,
+   TpmCreateOptions *opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path :
+TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -288,11 +280,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -344,7 +336,6 @@ static void tpm_passthrough_inst_init(Object *obj)
 {
 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
 
-tpm_pt->options = g_new0(TPMPassthroughO

[PATCH v7 2/2] tpm: add backend for mssim

2023-09-27 Thread James Bottomley
From: James Bottomley 

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 
Acked-by: Markus Armbruster 

---

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
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 290 +++
 backends/tpm/tpm_mssim.h |  44 ++
 docs/specs/tpm.rst   |  39 ++
 qapi/tpm.json|  32 -
 softmmu/tpm-hmp-cmds.c   |   9 ++
 8 files changed, 422 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index bf2366815b..939e0e65c3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3182,10 +3182,16 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 F: docs/specs/tpm.rst
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 0bfa6c422b..c6f7c24cb1 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   system_ss.add(files('tpm_util.c'))
   system_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   system_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  system_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..b8a12dce04
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,290 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMMssim, TPM_MSSIM)
+
+struct TPMMssim {
+TPMBackend parent;
+
+TPMMssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp

[PATCH v7 0/2] tpm: add mssim backend

2023-09-27 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs

v5 updates help to exit zero; does some checkpatch tidying

v7 merge review feedback and add acks.

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  25 ++-
 backends/tpm/tpm_mssim.c   | 290 +
 backends/tpm/tpm_mssim.h   |  44 +
 backends/tpm/tpm_passthrough.c |  23 +--
 docs/specs/tpm.rst |  39 +
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 qapi/tpm.json  |  49 +-
 softmmu/tpm-hmp-cmds.c |   9 +
 softmmu/tpm.c  |  91 +--
 softmmu/vl.c   |  19 +--
 14 files changed, 499 insertions(+), 108 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH v6 2/2] tpm: add backend for mssim

2023-09-25 Thread James Bottomley
On Fri, 2023-09-22 at 08:00 +0200, Markus Armbruster wrote:
> Found this cleaning out old mail, sorry for missing it until now!
> 
> I think we owe James a quick decision wether we're willing to take
> the
> feature.  Stefan, thoughts?
> 
> James Bottomley  writes:
> 
> > From: James Bottomley 
> > 
> > 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 
> 
> [...]
> 
> > diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst
> > index 535912a92b..1398735956 100644
> > --- a/docs/specs/tpm.rst
> > +++ b/docs/specs/tpm.rst
> > @@ -270,6 +270,38 @@ available as a module (assuming a TPM 2 is
> > passed through):
> >    /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-
> > sha256/9
> >    ...
> >  
> > +The QEMU TPM Microsoft Simulator Device
> > +---
> > +
> > +The TCG provides a reference implementation for TPM 2.0 written by
> 
> 
> Suggest to copy the cover letter's nice introductory paragraph here:
> 
>   The Microsoft Simulator (mssim) is the reference emulation platform
>   for the TCG TPM 2.0 specification.
> 
>   It provides a reference implementation for TPM 2.0 written by

Sure, that's easy.

> > +Microsoft (See `ms-tpm-20-ref`_ on github).  The reference
> > implementation
> > +starts a network server and listens for TPM commands on port 2321
> > and
> > +TPM Platform control commands on port 2322, although these can be
> > +altered.  The QEMU mssim TPM backend talks to this
> > implementation.  By
> > +default it connects to the default ports on localhost:
> > +
> > +.. code-block:: console
> > +
> > +  qemu-system-x86_64  \
> > +    -tpmdev mssim,id=tpm0 \
> > +    -device tpm-crb,tpmdev=tpm0
> > +
> > +
> > +Although it can also communicate with a remote host, which must be
> > +specified as a SocketAddress via json on the command line for each
> > of
> 
> Is the "via JSON" part in "must be specified ... on the command line"
> correct?  I'd expect to be able to use dotted keys as well, like
> 
>     -tpmdev
> type=mssim,id=tpm0,command.type=inet,command.host=remote,command.port
> =2321',control.type=inet,control.host=remote,control.port=2322

Yes, I've verified that the dot notation works as well.  However, I
thought QEMU was calling all stuff like this JSON notation?  If not,
what do you usually call it? "json or dot notation"?

> 
> Aside: I do recommend management applications stick to JSON.
> 
> > +the command and control ports:
> > +
> > +.. code-block:: console
> > +
> > +  qemu-system-x86_64  \
> > +    -tpmdev
> > "{'type':'mssim','i

Re: [PATCH v6 2/2] tpm: add backend for mssim

2023-09-25 Thread James Bottomley
On Fri, 2023-09-22 at 09:27 -0400, Stefan Berger wrote:
> 
> On 9/22/23 09:02, Daniel P. Berrangé wrote:
> > On Fri, Sep 22, 2023 at 08:41:19AM -0400, Stefan Berger wrote:
> > > On 9/22/23 02:00, Markus Armbruster wrote:
> > > > Found this cleaning out old mail, sorry for missing it until
> > > > now!
> > > > 
> > > > I think we owe James a quick decision wether we're willing to
> > > > take the feature.  Stefan, thoughts?
> > > I thought we discusses it back then. Does it handle snapshotting
> > > and migration correctly?
> > To quote the patch itself:
> > 
> >    +The mssim backend supports snapshotting and migration, but the
> > state
> >    +of the Microsoft Simulator server must be preserved (or the
> > server
> >    +kept running) outside of QEMU for restore to be successful.
> 
> How does 'it' support snapshotting where the state of the TPM can be 
> completely different depending on the snapshot?

In the same way we support things like external disk devices across
snapshot and migration: it's up to the owner of the device to preserve
the state for the next resume. If you muck with the state (or connect
the wrong device) all bets are off.

>   I know what it took to support this feature with swtpm/libtpms but
> I don't see the equivalent here in this backend driver nor in the TCG
> reference code that the underlying TPM 2 simulator is based upon.
> 
> I do not want to stand in the way of it being merged but please 
> understand that I will also neither maintain nor fix bugs related to
> it nor its related underlying simulator -- with James being the
> maintainer of it, this should be clear. I have reason why I am saying
> this and they come from dealing with the upstream TPM 2 reference
> code.

I already said I'll support this, and added a Maintainers entry and a
specific exclusion from your TPM maintainer entry. I'm not sure what
additional assurances I can give?

James







Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-02 Thread James Bottomley
On Thu, 2023-02-02 at 07:03 -0800, H. Peter Anvin wrote:
[...]
> NAK. We need to fix the actual problem of the kernel stomping on
> memory it shouldn't, not paper around it.

This is a first boot situation, not kexec (I just updated kexec because
it should use any new mechanism we propose).  Unlike kexec, for first
boot we're very constrained by the amount of extra space QEMU has to do
this.  The boot_params are the first page of the kernel load, but the
kernel proper begins directly after it, so we can't expand it.  The two
schemes tried: loading after the kernel and loading after the command
line both tamper with integrity protected files, so we shouldn't use
this mechanism.  This is the essence of the problem: If we add this
area at boot, it has to go in an existing memory location; we can't
steal random guest areas.  All current config parameters are passed
through as fw_config files, so we can only use that mechanism *if* we
know where the area ends up in the loaded kernel *and* the file isn't
integrity protected (this latter is expanding over time).

If we could wind back time, I'd have added the 32 byte random seed to
boot_params properly not coded it as a setup_data addition, but now
we're stuck with coping with existing behaviour, which is why I thought
the retro fit to boot_params would be the better path forward, but if
you have any alternatives, I'm sure we could look at them.

James




Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-02 Thread James Bottomley
On Wed, 2023-02-01 at 15:48 -0500, Jason A. Donenfeld wrote:
[...]
> But it sounds like you might now have a concrete suggestion on
> something even better. I'm CCing hpa, as this is his wheelhouse, and
> maybe you two can divise the next step while I'm away. Maybe the pad9
> thing you mentioned is the super nice solution we've been searching
> for this whole time. When I'm home in 10 days and have internet
> again, I'll take a look at where thing's are out and try to figure
> out how I can be productive again with it.

OK, so just FYI HPA, this is the patch I'm thinking of sending to
linux-kernel to reserve space in struct boot_params for this.  If you
could take a look and advise on the location before I send the final
patch, I'd be grateful.  I took space in _pad9 because that's the
standard method (add on to end), but it does strike me we could also
use all of _pad8 for the (the addition is only 48 bytes) or even _pad3
+ hd0_info + hd1_info.

James

---

diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 9338c68e7413..0120ab77dac9 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -308,7 +308,7 @@ _start:
# Part 2 of the header, from the old setup.S
 
.ascii  "HdrS"  # header signature
-   .word   0x020f  # header version number (>= 0x0105)
+   .word   0x0210  # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
 realmode_swtch:.word   0, 0# default_switch, SETUPSEG
diff --git a/arch/x86/include/uapi/asm/bootparam.h 
b/arch/x86/include/uapi/asm/bootparam.h
index 01d19fc22346..c614ff0755f2 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -181,6 +181,19 @@ struct ima_setup_data {
__u64 size;
 } __attribute__((packed));
 
+/*
+ * Define a boot_param area for the RNG seed which can be used via the
+ * setup_data mechanism (so must have a setup_data header) but which
+ * is embedded in boot_params because qemu has been unable to find
+ * a safe data space for it.  The value RNG_SEED_LENGTH must not
+ * change (pad length dependent on it) and must match the value in QEMU
+ */
+#define RNG_SEED_LENGTH32
+struct random_seed_data {
+   struct  setup_data s;
+   __u8data[RNG_SEED_LENGTH];
+} __attribute__((packed));
+
 /* The so-called "zeropage" */
 struct boot_params {
struct screen_info screen_info; /* 0x000 */
@@ -228,7 +241,8 @@ struct boot_params {
struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]; /* 0x2d0 
*/
__u8  _pad8[48];/* 0xcd0 */
struct edd_info eddbuf[EDDMAXNR];   /* 0xd00 */
-   __u8  _pad9[276];   /* 0xeec */
+   struct random_seed_data random_seed;/* 0xeec */
+   __u8  _pad9[228];   /* 0xf1c */
 } __attribute__((packed));
 
 /**
diff --git a/arch/x86/kernel/kexec-bzimage64.c 
b/arch/x86/kernel/kexec-bzimage64.c
index 6b58610a1552..fb719682579d 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -110,13 +110,10 @@ static int setup_e820_entries(struct boot_params *params)
return 0;
 }
 
-enum { RNG_SEED_LENGTH = 32 };
-
 static void
-setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
-  unsigned int rng_seed_setup_data_offset)
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr)
 {
-   struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+   struct setup_data *sd = >random_seed.s;
unsigned long setup_data_phys;
 
if (!rng_is_initialized())
@@ -125,7 +122,8 @@ setup_rng_seed(struct boot_params *params, unsigned long 
params_load_addr,
sd->type = SETUP_RNG_SEED;
sd->len = RNG_SEED_LENGTH;
get_random_bytes(sd->data, RNG_SEED_LENGTH);
-   setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+   setup_data_phys = params_load_addr + offsetof(struct boot_params,
+ random_seed);
sd->next = params->hdr.setup_data;
params->hdr.setup_data = setup_data_phys;
 }
@@ -306,7 +304,7 @@ setup_boot_parameters(struct kimage *image, struct 
boot_params *params,
}
 
/* Setup RNG seed */
-   setup_rng_seed(params, params_load_addr, setup_data_offset);
+   setup_rng_seed(params, params_load_addr);
 
/* Setup EDD info */
memcpy(params->eddbuf, boot_params.eddbuf,




Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
On Wed, 2023-02-01 at 12:51 -0500, Jason A. Donenfeld wrote:
> It's not a secret, but I have so little internet right now that I
> can't even load a webpage, and I'm on my phone, hence the short
> HTMLified emails.
> 
> In brief, though, it gets rid of all modifications to the kernel
> image all together, so it should fix your issue.

We've already tested it and established it doesn't because you simply
added your rng data to the end of a different integrity protected file
which now fails the integrity check instead of the kernel.

I checked the kernel source as well; I thought you'd have done the
usual thing and bumped the boot protocol version to steal space in
__pad9, but you didn't apparently.  To fix this up after the fact, I
recommend that we still steal space in _pad9[] but we make it have
enough space for a setup_data header as well as the 32 random bytes, so
we've officially reserved the space, but in earlier kernels than this
change gets to you can still use the setup_data_offset method, except
that it now uses the empty space in _pad9 via the setup_data mechanism.
That should find you space and get you out of having to expand any
integrity protected files.  The SEV direct boot will still work because
there's a check further down that doesn't copy the modified header back
over the kernel because it is ignored on efi stub boot anyway.

James




Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
On Wed, 2023-02-01 at 16:50 +, Peter Maydell wrote:
> On Wed, 1 Feb 2023 at 15:25, James Bottomley 
> wrote:
> > 
> > On Wed, 2023-02-01 at 10:10 -0500, Jason A. Donenfeld wrote:
> > > This is already fixed via the patch that MST just sent in his
> > > pull.
> > > So wait a few days for that to be merged and it'll be all set.
> > > 
> > > No need for this patch here. Do not merge.
> > 
> > If it's not a secret, would it be too much trouble to point to the
> > branch so we can actually test it?  It does seem that the biggest
> > problem this issue shows is that there wasn't wide enough
> > configuration
> > testing done on the prior commits before they were merged.
> 
> In general you shouldn't expect commits to be visible in
> a git branch before they get merged -- the QEMU process
> is not exactly identical to the kernel one.
> 
> For a particular patch on the mailing list, you can get a git branch
> with it applied by looking for the patch in https://patchew.org/QEMU/
> if that's more convenient than just applying it by hand.

The real issue is there have been so many patches flying around for
this, it's not clear exactly what combination needed to be tested.  Dov
found the branch in tags/for_upstream but it's still failing measured 
direct boot, although the failure has shifted from the hash check of
the kernel to the hash check of the command line.

All I really wanted was a link to the patch ... I don't need the tree
because inspection will tell me that it adds unexpected data at the end
of an integrity checked file.

> We also don't tend to want patches hanging around for testing
> before they get merged[*] -- we figure that "in upstream git"
> is the place that actually gets tested in practice; almost
> nobody will be working with or testing anything else.
> 
> [*] The fix Jason refers to here that's in MST's pullreq
> unfortunately hasn't made it upstream as quickly as I
> would like, due to a combination of things including us
> having to pause CI for a week when we ran out of minutes.

OK, so the problem is still the same as it was before: adding
unexpected data to an integrity checked file.

I don't get why there's all this dancing around trying to find space. 
Surely when the parameter was added, since it was a fixed size, the
kernel header was expanded and the boot protocol version bumped?  So we
can use that to identify kernels which can use this property and have
the space to insert it directly.

James




Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
On Wed, 2023-02-01 at 10:10 -0500, Jason A. Donenfeld wrote:
> This is already fixed via the patch that MST just sent in his pull.
> So wait a few days for that to be merged and it'll be all set.
> 
> No need for this patch here. Do not merge.

If it's not a secret, would it be too much trouble to point to the
branch so we can actually test it?  It does seem that the biggest
problem this issue shows is that there wasn't wide enough configuration
testing done on the prior commits before they were merged.

James




Re: [PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
On Wed, 2023-02-01 at 14:35 +, Daniel P. Berrangé wrote:
> On Wed, Feb 01, 2023 at 08:57:10AM -0500, James Bottomley wrote:
> > The origin commit for rng seeding 67f7e426e5 ("hw/i386: pass RNG
> > seed
> > via setup_data entry") modifies the kernel image file to append a
> > random seed.  Obviously this makes the hash of the kernel file
> > non-deterministic and so breaks both measured and some signed
> > boots.
> 
> I recall raising that at the time
> 
>   https://lists.gnu.org/archive/html/qemu-devel/2022-08/msg00710.html
> 
> and Jason pointed me to a followup which I tested and believe
> fixed it for SEV:
> 
>   https://lists.gnu.org/archive/html/qemu-devel/2022-08/msg00601.html
> 
> but it doesn't look like that second patch ever merged. We went
> through so many patches I think it probably got obsoleted by
> something else, and no one rechecked SEV again.

The kernel file problem is a pretty huge one.  OVMF lays it down on an
internal file system and without the second patch, it now contains
random junk at the end.  Anything that hashes the whole file (which
includes not only the measured direct boot but also grub signatures and
probably other bootloader signing mechanisms) will have an issue.

> > The commit notes it's only for non-EFI (because EFI has a different
> > RNG seeding mechanism) so, since there are no non-EFI q35 systems,
> > this should be disabled for the whole of the q35 machine type to
> > bring back deterministic kernel file hashes.
> 
> SeaBIOS is the default firmware for both q35 and i440fx. The
> majority of systems using q35 will be non-EFI today, and that
> is what the random seed was intended to address. I don't think
> we can just disable this for the whole of q35.
> 
> When you say it breaks measured / signed boots, I presume you
> are specifically referring to SEV kernel hashes measurements ?
> Or is there a more general problem to solve ?

No it generally breaks measured/signed boots because it adds random
junk to the kernel file.  The second patch will fix this if you apply
it because setup data isn't measured or signed (yet ... however see the
linux-coco debate about how it should be).

I also note there was a v3 of the patch and considerable discussion
saying it couldn't work:

https://lore.kernel.org/qemu-devel/20220804230411.17720-1-ja...@zx2c4.com/

Which is likely why it never went in ... although the discussion does
seem to resolve towards the end.

James




[PATCH v2] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
The origin commit for rng seeding 67f7e426e5 ("hw/i386: pass RNG seed
via setup_data entry") modifies the kernel image file to append a
random seed.  Obviously this makes the hash of the kernel file
non-deterministic and so breaks both measured and some signed boots.
The commit notes it's only for non-EFI (because EFI has a different
RNG seeding mechanism) so, since there are no non-EFI q35 systems, this
should be disabled for the whole of the q35 machine type to bring back
deterministic kernel file hashes.

Obviously this still leaves the legacy bios case broken for at least
measured boot, but I don't think anyone cares about that now.

Signed-off-by: James Bottomley 
---
v2: with non wrapped lines this time

 hw/i386/pc_q35.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 83c57c6eb1..11e8dd7ca7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -357,6 +357,7 @@ static void pc_q35_machine_options(MachineClass *m)
 pcmc->default_nic_model = "e1000e";
 pcmc->pci_root_uid = 0;
 pcmc->default_cpu_version = 1;
+pcmc->legacy_no_rng_seed = true;
 
 m->family = "pc_q35";
 m->desc = "Standard PC (Q35 + ICH9, 2009)";
@@ -394,9 +395,7 @@ DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL,
 
 static void pc_q35_7_1_machine_options(MachineClass *m)
 {
-PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 pc_q35_7_2_machine_options(m);
-pcmc->legacy_no_rng_seed = true;
 compat_props_add(m->compat_props, hw_compat_7_1, hw_compat_7_1_len);
 compat_props_add(m->compat_props, pc_compat_7_1, pc_compat_7_1_len);
 }
-- 
2.35.3





[PATCH] x86: fix q35 kernel measurements broken due to rng seeding

2023-02-01 Thread James Bottomley
The origin commit for rng seeding 67f7e426e5 ("hw/i386: pass RNG seed
via setup_data entry") modifies the kernel image file to append a
random seed.  Obviously this makes the hash of the kernel file
non-deterministic and so breaks both measured and some signed boots.
The commit notes it's only for non-EFI (because EFI has a different
RNG seeding mechanism) so, since there are no non-EFI q35 systems, this
should be disabled for the whole of the q35 machine type to bring back
deterministic kernel file hashes.

Obviously this still leaves the legacy bios case broken for at least
measured boot, but I don't think anyone cares about that now.

Signed-off-by: James Bottomley 
---
 hw/i386/pc_q35.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 83c57c6eb1..11e8dd7ca7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -357,6 +357,7 @@ static void pc_q35_machine_options(MachineClass *m)
 pcmc->default_nic_model = "e1000e";
 pcmc->pci_root_uid = 0;
 pcmc->default_cpu_version = 1;
+pcmc->legacy_no_rng_seed = true;
 
 m->family = "pc_q35";
 m->desc = "Standard PC (Q35 + ICH9, 2009)";
@@ -394,9 +395,7 @@ DEFINE_Q35_MACHINE(v7_2, "pc-q35-7.2", NULL,
 
 static void pc_q35_7_1_machine_options(MachineClass *m)
 {
-PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
 pc_q35_7_2_machine_options(m);
-pcmc->legacy_no_rng_seed = true;
 compat_props_add(m->compat_props, hw_compat_7_1,
hw_compat_7_1_len);
 compat_props_add(m->compat_props, pc_compat_7_1,
pc_compat_7_1_len);
 }
-- 
2.35.3





Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-10 Thread James Bottomley
On Tue, 2023-01-10 at 09:47 -0500, Stefan Berger wrote:
> On 1/10/23 09:14, James Bottomley wrote:
> > On Mon, 2023-01-09 at 16:06 -0500, Stefan Berger wrote:
> > > On 1/9/23 14:01, Stefan Berger wrote:
> > [...]
> > > If you use TPM 2 for attestation then certain TPM 2 state
> > > migration scenarios may become problematic. One could construct a
> > > scenario where attestation preceeds some action that requires
> > > trust to have been established in the system in the preceeding
> > > attestation step and support for snapshotting the state of the
> > > TPM 2 could become an issue if I was to wait for the attestation
> > > to have been concluded and then I quickly restart a different
> > > snapshot that is not trustworthy and the client proceeds thinking
> > > that the system is trustworthy (maybe a few SYNs from the client
> > > went into the void)
> > 
> > You're over thinking this.  For a non-confidential VM, Migration
> > gives you a saved image you can always replay from (this is seen as
> > a feature for fast starts) and if you use the tpm_simulator the TPM
> > state is stored in the migration image, so you can always roll it
> > back if you
> 
> 'How' is it stored in the migration image? Does tpm_simulator marshal
> and unmarshal the state so that it is carried inside the save image?
> For the tpm_emulator backend this particular code is here:
> -
> https://github.com/qemu/qemu/blob/master/backends/tpm/tpm_emulator.c#L758
> -
> https://github.com/qemu/qemu/blob/master/backends/tpm/tpm_emulator.c#L792

We seem to be going around in circles: your TPM simulator stores the
TPM state in the migration image, mine keeps it in the external TPM. 
The above paragraph is referring to your simulator.

> > have access to the migration file.  Saving the image state is also
> > a huge problem because the TPM seeds are in the clear if the
> > migration image isn't encrypted.  The other big problem is that an
> > external
> 
> True. DAC protection of the file versus protection via encryption.
> Neither really helps against malicious root.
> 
> > software TPM is always going to give up its state to the service
> > provider, regardless of migration, so you have to have some trust
> > in the provider and thus you'd also have to trust them with the
> > migration replay policy.  For Confidential VMs, this is a bit
> > different because the vTPM runs in a secure ring inside the
> > confidential enclave and the secure migration agent ensures that
> > either migration and startup happen or migration doesn't happen at
> > all, so for them you don't have to worry about rollback.
> 
> what is the enclave here? Is it an SGX enclave or is it running
> somewhere inside the address space of the VM?

The only current one we're playing with is the SEV-SNP SVSM vTPM which
runs the TPM in VMPL0.

> > 
> > Provided you can trust the vTPM provider, having external state not
> > stored in the migration image has the potential actually to solve
> > the rollback problem because you could keep the TPM clock running
> > and potentially increase the reset count, so migrations would show
> > up in TPM quotes and you don't have control of the state of the
> > vTPM to replay it.
> 
> I just don't see how you do that and prevent scenarios where VM A is
> suspended and then the tpm_simulator just sits there with
> the state and one resumes VM B with the state.

You can't with your TPM simulator because it stores state in the image.
If the state is external (not stored in the image) then rolling back
the image doesn't roll back the TPM state.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-10 Thread James Bottomley
On Mon, 2023-01-09 at 16:06 -0500, Stefan Berger wrote:
> On 1/9/23 14:01, Stefan Berger wrote:
[...]
> If you use TPM 2 for attestation then certain TPM 2 state migration
> scenarios may become problematic. One could construct a scenario
> where attestation preceeds some action that requires trust to have
> been established in the system in the preceeding attestation step and
> support for snapshotting the state of the TPM 2 could become an issue
> if I was to wait for the attestation to have been concluded and then
> I quickly restart a different snapshot that is not trustworthy and
> the client proceeds thinking that the system is trustworthy (maybe a
> few SYNs from the client went into the void)

You're over thinking this.  For a non-confidential VM, Migration gives
you a saved image you can always replay from (this is seen as a feature
for fast starts) and if you use the tpm_simulator the TPM state is
stored in the migration image, so you can always roll it back if you
have access to the migration file.  Saving the image state is also a
huge problem because the TPM seeds are in the clear if the migration
image isn't encrypted.  The other big problem is that an external
software TPM is always going to give up its state to the service
provider, regardless of migration, so you have to have some trust in
the provider and thus you'd also have to trust them with the migration
replay policy.  For Confidential VMs, this is a bit different because
the vTPM runs in a secure ring inside the confidential enclave and the
secure migration agent ensures that either migration and startup happen
or migration doesn't happen at all, so for them you don't have to worry
about rollback.

Provided you can trust the vTPM provider, having external state not
stored in the migration image has the potential actually to solve the
rollback problem because you could keep the TPM clock running and
potentially increase the reset count, so migrations would show up in
TPM quotes and you don't have control of the state of the vTPM to
replay it.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-09 Thread James Bottomley
On Mon, 2023-01-09 at 18:54 +, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > On Mon, 2023-01-09 at 13:34 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 1/9/23 12:55, James Bottomley wrote:
> > > > On Mon, 2023-01-09 at 17:52 +, Dr. David Alan Gilbert
> > > > wrote:
> > > > > * James Bottomley (j...@linux.ibm.com) wrote:
> > > > [...]
> > > > > > external MSSIM TPM emulator has to be kept running to
> > > > > > preserve
> > > > > > the state.  If you restart it, the migration will fail.
> > > > > 
> > > > > Document that and we're getting there.
> > > > 
> > > > 
> > > > The documentation in the current patch series says
> > > > 
> > > > 
> > > > The mssim backend supports snapshotting and migration, but the
> > > > state of the Microsoft Simulator server must be preserved (or
> > > > the
> > > > server kept running) outside of QEMU for restore to be
> > > > successful.
> > > > 
> > > > 
> > > > What, beyond this would you want to see?
> > > 
> > > mssim today lacks the functionality of marshalling and
> > > unmarshalling
> > > the permanent and volatile state of the TPM 2, which are both
> > > needed
> > > for snapshot support. How does this work with mssim?
> > 
> > You preserve the state by keeping the simulator running as the
> > above
> > says.  As long as you can preserve the state, there's no maximum
> > time
> > between snapshots.  There's no need of marshal/unmarshal if you do
> > this.
> 
> So I think I can understand how that works with a suspend/resume; I'm
> less sure about a live migration.
> 
> In a live migration, you normally start up the destination VM
> qemu process and other processes attached to it, prior to the inwards
> live migration of state.  Then you live migrate the state, then kill
> the source.
> 
> With this mssim setup, will the start up of the destination attempt
> to change the vtpm state during the initialisation?

The backend driver contains state checks to prevent this, so if you
follow the standard migration in

https://www.qemu.org/docs/master/devel/migration.html

it detects that you have done a migration on shutdown and simply closes
the TPM socket.  On start up it sees you're in migrate and doesn't do
the power on reset of the TPM.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-09 Thread James Bottomley
On Mon, 2023-01-09 at 13:34 -0500, Stefan Berger wrote:
> 
> 
> On 1/9/23 12:55, James Bottomley wrote:
> > On Mon, 2023-01-09 at 17:52 +, Dr. David Alan Gilbert wrote:
> > > * James Bottomley (j...@linux.ibm.com) wrote:
> > [...]
> > > > external MSSIM TPM emulator has to be kept running to preserve
> > > > the state.  If you restart it, the migration will fail.
> > > 
> > > Document that and we're getting there.
> > 
> > 
> > The documentation in the current patch series says
> > 
> > 
> > The mssim backend supports snapshotting and migration, but the
> > state of the Microsoft Simulator server must be preserved (or the
> > server kept running) outside of QEMU for restore to be successful.
> > 
> > 
> > What, beyond this would you want to see?
> 
> mssim today lacks the functionality of marshalling and unmarshalling
> the permanent and volatile state of the TPM 2, which are both needed
> for snapshot support. How does this work with mssim?

You preserve the state by keeping the simulator running as the above
says.  As long as you can preserve the state, there's no maximum time
between snapshots.  There's no need of marshal/unmarshal if you do
this.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-09 Thread James Bottomley
On Mon, 2023-01-09 at 17:52 +, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
[...]
> > external MSSIM TPM emulator has to be kept running to preserve the
> > state.  If you restart it, the migration will fail.
> 
> Document that and we're getting there.


The documentation in the current patch series says


The mssim backend supports snapshotting and migration, but the state
of the Microsoft Simulator server must be preserved (or the server
kept running) outside of QEMU for restore to be successful.


What, beyond this would you want to see?

James




Re: [PATCH 2/2] tpm: add backend for mssim

2023-01-09 Thread James Bottomley
On Mon, 2023-01-09 at 16:59 +, Dr. David Alan Gilbert wrote:
> * Daniel P. Berrangé (berra...@redhat.com) wrote:
> > On Fri, Dec 16, 2022 at 08:32:44AM -0500, Stefan Berger wrote:
[...]
> > > I do see it because the *volatile state* cannot be extracted from
> > > this device. The state of the PCRs is going to be lost.
> > 
> > All the objections you're raising are related to the current
> > specifics of the implementation of the mssim remote server.
> > While valid, this is of no concern to QEMU when deciding whether
> > to require a migration blocker on the client side. This is 3rd
> > party remote service that should be considered a black box from
> > QEMU's POV. It is possible to write a remote server that supports
> > the mssim network protocol, and has the ability to serialize
> > its state. Whether such an impl exists today or not is separate.
> 
> We would normally want an example of a working implementation though
> wouldn't we?
> 
> So I think it's fair to at least want some documentation; if it can
> be documented and works, fine; if it doesn't work, then it needs a
> blocker.

It works under limited circumstances ... in fact similar circumstances
passthrough migration works under, which is also not documented.  The
external MSSIM TPM emulator has to be kept running to preserve the
state.  If you restart it, the migration will fail.

James




[PATCH v6 2/2] tpm: add backend for mssim

2023-01-09 Thread James Bottomley
From: James Bottomley 

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 

---

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.
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 290 +++
 backends/tpm/tpm_mssim.h |  44 ++
 docs/specs/tpm.rst   |  35 +
 monitor/hmp-cmds.c   |   9 ++
 qapi/tpm.json|  28 +++-
 8 files changed, 414 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7a40d4d865..666ca1eb1c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3063,10 +3063,16 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 F: docs/specs/tpm.rst
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..ed1c4cfd35
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,290 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TPMmssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp);
+cmd = htonl(cmd);
+ret = qio_channel_write_all(QIO_CHANNEL(

[PATCH v6 1/2] tpm: convert tpmdev options processing to new visitor format

2023-01-09 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 

---
v4: add TpmConfiOptions
v5: exit(0) for help
---
 backends/tpm/tpm_emulator.c| 24 -
 backends/tpm/tpm_passthrough.c | 22 +++--
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 90 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 75 insertions(+), 105 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..cb6bf9d7c2 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -972,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 179697a3a9..3da467ef01 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,21 +252,12 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, TpmCreateOptions 
*opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path :
+TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -288,11 +279,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -344,7 +335,6 @@ static void tpm_passthrough_inst_init(Object *obj)
 {
 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj);
 
-tpm_pt->options = g_new0(TPMPassthroughOptions, 1);
 tpm_pt->tpm_fd = -1;
 tpm_pt->cancel_fd = -1;
 }
diff --git a/include/sysemu/tpm.h b/incl

[PATCH v6 0/2] tpm: add mssim backend

2023-01-09 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs

v5 updates help to exit zero; does some checkpatch tidying

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  24 +--
 backends/tpm/tpm_mssim.c   | 290 +
 backends/tpm/tpm_mssim.h   |  44 +
 backends/tpm/tpm_passthrough.c |  22 +--
 docs/specs/tpm.rst |  35 
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 monitor/hmp-cmds.c |   9 +
 qapi/tpm.json  |  45 -
 softmmu/tpm.c  |  90 --
 softmmu/vl.c   |  19 +--
 14 files changed, 488 insertions(+), 108 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH v5 2/2] tpm: add backend for mssim

2023-01-05 Thread James Bottomley
On Thu, 2023-01-05 at 11:20 -0500, Stefan Berger wrote:
> 
> 
> On 1/5/23 08:00, James Bottomley wrote:
[...]
> > +The mssim backend supports snapshotting and migration, but the
> > state
> > +of the Microsoft Simulator server must be preserved (or the server
> > +kept running) outside of QEMU for restore to be successful.
> 
> My comments to v3 still apply here.

You didn't make any v3 comments on migration.

> I also just tried migration and on the -incoming side it did not work
> anymore. Did you test this?

Well, yes, as I said.  However, I seem to have left one change in my
local tree which I forgot to sync to the patch:

diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
index 75dce165b8..125c8d0b15 100644
--- a/backends/tpm/tpm_mssim.c
+++ b/backends/tpm/tpm_mssim.c
@@ -66,7 +66,7 @@ static void tpm_mssim_instance_finalize(Object *obj)
 {
 TPMmssim *t = TPM_MSSIM(obj);
 
-if (t->ctrl_qc && !runstate_check(RUN_STATE_INMIGRATE))
+if (t->cmd_qc && !runstate_check(RUN_STATE_POSTMIGRATE))
 tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, NULL);
 
 object_unref(OBJECT(t->ctrl_qc));

James




Re: [PATCH v5 1/2] tpm: convert tpmdev options processing to new visitor format

2023-01-05 Thread James Bottomley
On Thu, 2023-01-05 at 09:59 -0500, Stefan Berger wrote:
[...]
> > @@ -2658,7 +2646,6 @@ void qemu_init(int argc, char **argv)
> >   qemu_add_opts(_boot_opts);
> >   qemu_add_opts(_add_fd_opts);
> >   qemu_add_opts(_object_opts);
> > -    qemu_add_opts(_tpmdev_opts);
> >   qemu_add_opts(_overcommit_opts);
> >   qemu_add_opts(_msg_opts);
> >   qemu_add_opts(_name_opts);
> > @@ -2906,9 +2893,7 @@ void qemu_init(int argc, char **argv)
> >   break;
> >   #ifdef CONFIG_TPM
> >   case QEMU_OPTION_tpmdev:
> > -    if (tpm_config_parse(qemu_find_opts("tpmdev"),
> > optarg) < 0) {
> > -    exit(1);
> > -    }
> > +    tpm_config_parse(optarg);
> 
> The comment to v4 still applies:
> 
> $ qemu-system-x86_64 --tpmdev help
> Supported TPM types (choose only one):
>   passthrough   Passthrough TPM backend driver
>  emulator   TPM emulator backend driver
>     mssim   TPM mssim emulator backend driver
> VNC server running on ::1:5900

So I think if I parse this correctly, your complaint is the help option
no longer exit(1)'s?  It shouldn't do that because it's not a failure,
but I can code it to exit(0).

James




[PATCH v5 1/2] tpm: convert tpmdev options processing to new visitor format

2023-01-05 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 

---
v4: add TpmConfiOptions
---
 backends/tpm/tpm_emulator.c| 24 -
 backends/tpm/tpm_passthrough.c | 25 +++---
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 90 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 76 insertions(+), 107 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..cb6bf9d7c2 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -972,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 179697a3a9..4a30143257 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,21 +252,11 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, TpmCreateOptions 
*opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path : 
TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -288,11 +278,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -319,8 +309,8 @@ static TpmTypeOptions 
*tpm_passthrough_get_tpm_options(TPMBackend *tb)
 TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
 
 options->type = TPM_TYPE_PASSTHROUGH;
-options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
- TPM_PASSTHRO

[PATCH v5 2/2] tpm: add backend for mssim

2023-01-05 Thread James Bottomley
From: James Bottomley 

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 

---

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.
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 263 +++
 backends/tpm/tpm_mssim.h |  43 +++
 docs/specs/tpm.rst   |  35 ++
 monitor/hmp-cmds.c   |   7 ++
 qapi/tpm.json|  28 -
 8 files changed, 384 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7a40d4d865..666ca1eb1c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3063,10 +3063,16 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 F: docs/specs/tpm.rst
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..75dce165b8
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,263 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TPMmssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp);
+cmd = htonl(cmd);
+ret = qio_channel_write_all(QIO_CHANNEL(t-&g

[PATCH v5 0/2] tpm: add mssim backend

2023-01-05 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  24 ++-
 backends/tpm/tpm_mssim.c   | 263 +
 backends/tpm/tpm_mssim.h   |  43 ++
 backends/tpm/tpm_passthrough.c |  25 +---
 docs/specs/tpm.rst |  35 +
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 monitor/hmp-cmds.c |   7 +
 qapi/tpm.json  |  45 +-
 softmmu/tpm.c  |  90 +--
 softmmu/vl.c   |  19 +--
 14 files changed, 459 insertions(+), 110 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH v4 1/2] tpm: convert tpmdev options processing to new visitor format

2022-12-30 Thread James Bottomley
On Fri, 2022-12-30 at 12:01 -0500, Stefan Berger wrote:
> On 12/30/22 10:24, James Bottomley wrote:
[...]
> > @@ -2906,9 +2893,7 @@ void qemu_init(int argc, char **argv)
> >   break;
> >   #ifdef CONFIG_TPM
> >   case QEMU_OPTION_tpmdev:
> > -    if (tpm_config_parse(qemu_find_opts("tpmdev"),
> > optarg) < 0) {
> > -    exit(1);
> > -    }
> > +    tpm_config_parse(optarg);
> 
> The patches don't apply to upstream's master.

I think it depends how you apply them.  If you use git, they do except
a minor merge conflict in tpm_passthrough.c

More seriously there's now a compile failure in tpm_mssim.c because of
the lost has_X for X pointer options, but it's also easily fixable.

> This used to exit() on failure but doesn't do this anymore, though it
> probably should.

Actually it still does.  I converted it to the standard _fatal
way of doing this, which will cause an exit(1) if we get an error.  The
error_fatal construct seems to have been done precisely to cure this
type of return value threading.

James




[PATCH v4 2/2] tpm: add backend for mssim

2022-12-30 Thread James Bottomley
From: James Bottomley 

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 

---

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.
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 265 +++
 backends/tpm/tpm_mssim.h |  43 +++
 docs/specs/tpm.rst   |  35 ++
 monitor/hmp-cmds.c   |   7 ++
 qapi/tpm.json|  28 -
 8 files changed, 386 insertions(+), 4 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6966490c94..b0f5cceda1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3043,9 +3043,15 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..e83cef
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,265 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TPMmssimOptions opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp);
+cmd = htonl(cmd);
+ret = qio_channel_write_all(QIO_CHANNEL(t->ctrl_qc), (char *), 

[PATCH v4 1/2] tpm: convert tpmdev options processing to new visitor format

2022-12-30 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 

---
v4: add TpmConfiOptions
---
 backends/tpm/tpm_emulator.c| 24 -
 backends/tpm/tpm_passthrough.c | 27 +++---
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 90 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 76 insertions(+), 109 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..cb6bf9d7c2 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -972,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 5a2f74db1b..f9771eaf1f 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,23 +252,11 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, TpmCreateOptions 
*opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-tpm_pt->options->has_cancel_path = true;
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->has_path = true;
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.has_path ? opts->u.passthrough.path 
: TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -290,11 +278,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 object_unref(obj);
 return NULL;
 }
@@ -321,8 +309,8 @@ static TpmTypeOptions 
*tpm_passthrough_get_tpm_options(TPMBackend *tb)
 TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
 
 options->type = TPM_TYPE_PASSTHROUGH;
-

[PATCH v4 0/2] tpm: add mssim backend

2022-12-30 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

v4 puts back the wrapper options (but doesn't add any for mssim since
it post dates the necessity)

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  24 ++-
 backends/tpm/tpm_mssim.c   | 265 +
 backends/tpm/tpm_mssim.h   |  43 ++
 backends/tpm/tpm_passthrough.c |  27 +---
 docs/specs/tpm.rst |  35 +
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 monitor/hmp-cmds.c |   7 +
 qapi/tpm.json  |  45 +-
 softmmu/tpm.c  |  90 +--
 softmmu/vl.c   |  19 +--
 14 files changed, 461 insertions(+), 112 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH v3 1/2] tpm: convert tpmdev options processing to new visitor format

2022-12-21 Thread James Bottomley
On Wed, 2022-12-21 at 16:32 +, Daniel P. Berrangé wrote:
> This isn't a valid change todo, as it affects the public facing
> data structure for the  query-tpm command.
> 
> I understand why you're doing it though, to get rid fo the
> extra nesting, which is a hangover from earlier QAPI days
> where we couldn't cope with flat unions.
> 
> Instead of changing TpmTypeOptions, you'll need to introduce
> a new TpmTypeCreateOptions that eliminates the wrapping, and
> use that in the CLI creation path, leaving the query-tpm
> command unchanged.


Well, it makes the diffstat less favourable, but how about this (I'm
also assuming I don't need to wrapper the new mssim options)?

James

---

 backends/tpm/tpm_emulator.c| 24 -
 backends/tpm/tpm_passthrough.c | 27 +++---
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 qapi/tpm.json  | 19 +++
 softmmu/tpm.c  | 90 ++
 softmmu/vl.c   | 19 +--
 7 files changed, 76 insertions(+), 109 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..cb6bf9d7c2 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmCreateOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, >u.emulator);
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -972,7 +967,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +984,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 5a2f74db1b..f9771eaf1f 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -252,23 +252,11 @@ static int 
tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
 }
 
 static int
-tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts)
+tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, TpmCreateOptions 
*opts)
 {
-const char *value;
+tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, >u.passthrough);
 
-value = qemu_opt_get(opts, "cancel-path");
-if (value) {
-tpm_pt->options->cancel_path = g_strdup(value);
-tpm_pt->options->has_cancel_path = true;
-}
-
-value = qemu_opt_get(opts, "path");
-if (value) {
-tpm_pt->options->has_path = true;
-tpm_pt->options->path = g_strdup(value);
-}
-
-tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE;
+tpm_pt->tpm_dev = opts->u.passthrough.has_path ? opts->u.passthrough.path 
: TPM_PASSTHROUGH_DEFAULT_DEVICE;
 tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR);
 if (tpm_pt->tpm_fd < 0) {
 error_report("Cannot access TPM device using '%s': %s",
@@ -290,11 +278,11 @@ tpm_passthrough_handle_device_opts(TPMPassthruState 
*tpm_pt, QemuOpts *opts)
 return 0;
 }
 
-static TPMBackend *tpm_passthrough_create(QemuOpts *opts)
+static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco)
 {
 Object *obj = object_new(TYPE_TPM_PASSTHROUGH);
 
-if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) {
+if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) {
 

Re: [PATCH v3 0/2] tpm: add mssim backend

2022-12-19 Thread James Bottomley
On Mon, 2022-12-19 at 10:16 -0500, Stefan Berger wrote:
> 
> 
> On 12/19/22 08:13, James Bottomley wrote:
> > From: James Bottomley 
> > 
> > The requested feedback was to convert the tpmdev handler to being
> > json
> > based, which requires rethreading all the backends.  The good news
> > is
> > this reduced quite a bit of code (especially as I converted it to
> > error_fatal handling as well, which removes the return status
> > threading).  The bad news is I can't test any of the conversions.
> > swtpm still isn't building on opensuse and, apparently, passthrough
> > doesn't like my native TPM because it doesn't allow cancellation.
> 
> For passthrough you can use /dev/null in place of the cancel file.
> Libvirt does that also:
> 
> https://github.com/stefanberger/libvirt-tpm/blob/master/src/util/virtpm.c#L88

OK, so passthrough works with the visitor conversion.  If /dev/null is
the default for no cancel path, the backend shouldn't really beat the
end user up about not specifying it if it can't find the cancel path
for the chosen host TPM.

James




Re: [PATCH v3 0/2] tpm: add mssim backend

2022-12-19 Thread James Bottomley
On Mon, 2022-12-19 at 09:15 -0500, Stefan Berger wrote:
> 
> 
> On 12/19/22 08:55, James Bottomley wrote:
> > On Mon, 2022-12-19 at 08:51 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/19/22 08:13, James Bottomley wrote:
> > > > From: James Bottomley 
> > > > 
> > > > The requested feedback was to convert the tpmdev handler to
> > > > being json based, which requires rethreading all the backends. 
> > > > The good news is this reduced quite a bit of code (especially
> > > > as I converted it to error_fatal handling as well, which
> > > > removes the return status threading).  The bad news is I can't
> > > > test any of the conversions. swtpm still isn't building on
> > > > opensuse and, apparently, passthrough
> > > 
> > > The package seems to be available:
> > > https://software.opensuse.org/package/swtpm
> > 
> > It's not building for any of the platforms I currently have.
> 
> You would have to tell me what is failing. I have been building it
> for several platforms for a while and the build works, including
> OpenSuSE Tumbleweed:
> 
> 
> https://app.travis-ci.com/github/stefanberger/swtpm-distro-compile/builds/258769183
> 
> There have been issues with what seems to be seccomp policy on 2 of
> these platforms for a while but this is unrelated to SuSE and build
> issues -- obviously.

All I know is what the build service says, which is the URL I first
pointed you to:

https://build.opensuse.org/package/show/security/swtpm

I haven't dug into the problem.

James




Re: [PATCH v3 0/2] tpm: add mssim backend

2022-12-19 Thread James Bottomley
On Mon, 2022-12-19 at 08:51 -0500, Stefan Berger wrote:
> 
> 
> On 12/19/22 08:13, James Bottomley wrote:
> > From: James Bottomley 
> > 
> > The requested feedback was to convert the tpmdev handler to being
> > json based, which requires rethreading all the backends.  The good
> > news is this reduced quite a bit of code (especially as I converted
> > it to error_fatal handling as well, which removes the return status
> > threading).  The bad news is I can't test any of the conversions.
> > swtpm still isn't building on opensuse and, apparently, passthrough
> 
> The package seems to be available:
> https://software.opensuse.org/package/swtpm

It's not building for any of the platforms I currently have.

I think I've tested most of the option processing, though, before it
tells me it can't connect.

> I'll get to looking at this in more depth once I am back in office.

That's great, thanks ... it would certainly be better to test option
processing on a working platform.

James




[PATCH v3 2/2] tpm: add backend for mssim

2022-12-19 Thread James Bottomley
From: James Bottomley 

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 

---

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.
---
 MAINTAINERS  |   6 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 264 +++
 backends/tpm/tpm_mssim.h |  43 +++
 docs/specs/tpm.rst   |  35 ++
 monitor/hmp-cmds.c   |   7 ++
 qapi/tpm.json|  25 +++-
 8 files changed, 383 insertions(+), 3 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6966490c94..b0f5cceda1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3043,9 +3043,15 @@ F: include/hw/acpi/tpm.h
 F: include/sysemu/tpm*
 F: qapi/tpm.json
 F: backends/tpm/
+X: backends/tpm/tpm_mssim.*
 F: tests/qtest/*tpm*
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..1b990bfa30
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,264 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/runstate.h"
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TpmTypeOptions *opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+qio_channel_socket_connect_sync(t->ctrl_qc, t->opts->u.mssim.control, 
errp);
+cmd = htonl(cmd);
+ret = qio_channel_write_all(QIO_CHANNEL(t->ct

[PATCH v3 0/2] tpm: add mssim backend

2022-12-19 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

v3 pulls out more unneeded code in the visitor conversion, makes
migration work on external state preservation of the simulator and
adds documentation

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   6 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  35 ++---
 backends/tpm/tpm_mssim.c   | 264 +
 backends/tpm/tpm_mssim.h   |  43 ++
 backends/tpm/tpm_passthrough.c |  37 ++---
 docs/specs/tpm.rst |  35 +
 include/sysemu/tpm.h   |   4 +-
 include/sysemu/tpm_backend.h   |   2 +-
 monitor/hmp-cmds.c |  11 +-
 qapi/tpm.json  |  37 ++---
 softmmu/tpm.c  |  90 +--
 softmmu/vl.c   |  19 +--
 14 files changed, 449 insertions(+), 140 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




[PATCH v3 1/2] tpm: convert tpmdev options processing to new visitor format

2022-12-19 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 
---
 backends/tpm/tpm_emulator.c| 35 ++---
 backends/tpm/tpm_passthrough.c | 37 +-
 include/sysemu/tpm.h   |  4 +-
 include/sysemu/tpm_backend.h   |  2 +-
 monitor/hmp-cmds.c |  4 +-
 qapi/tpm.json  | 26 ++
 softmmu/tpm.c  | 90 ++
 softmmu/vl.c   | 19 +--
 8 files changed, 73 insertions(+), 144 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..82988a2986 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -69,7 +69,7 @@ typedef struct TPMBlobBuffers {
 struct TPMEmulator {
 TPMBackend parent;
 
-TPMEmulatorOptions *options;
+TpmTypeOptions *options;
 CharBackend ctrl_chr;
 QIOChannel *data_ioc;
 TPMVersion tpm_version;
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmTypeOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = opts;
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -621,7 +616,7 @@ static int tpm_emulator_handle_device_opts(TPMEmulator 
*tpm_emu, QemuOpts *opts)
 if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
  _emu->tpm_version)) {
 error_report("'%s' is not emulating TPM device. Error: %s",
-  tpm_emu->options->chardev, strerror(errno));
+  tpm_emu->options->u.emulator.chardev, strerror(errno));
 goto err;
 }
 
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmTypeOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -664,10 +659,9 @@ static TPMBackend *tpm_emulator_create(QemuOpts *opts)
 static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
 {
 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+TpmTypeOptions *options;
 
-options->type = TPM_TYPE_EMULATOR;
-options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, 
tpm_emu->options);
+options = QAPI_CLONE(TpmTypeOptions, tpm_emu->options);
 
 return options;
 }
@@ -972,7 +966,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +983,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
@@ -1015,7 +1008,7 @@ static void tpm_emulator_inst_finalize(Object *obj)
 
 qemu_chr_fe_deinit(_emu->ctrl_chr, false);
 
-qapi_free_TPMEmulatorOptions(tpm_emu->options);
+qapi_free_TpmTypeOptions(tpm_emu->options);
 
 if (tpm_emu->migration_blocker) {
 migrate_del_blocker(tpm_emu->migration_blocker);
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 5a2f74db1b..2ce39b2167 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -41,7 +41,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TPMPassthruState, TPM_PASSTHROUGH)
 struct TPMPassthruState {
 TPMBackend parent;
 
-TPMPassthroughOptions *options;
+TpmTypeOptions *options;
 const char *tpm_dev;
 int tpm_fd;
 bool tpm_executing;
@@ -214,8 +214,8 @@ static int 

Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-19 Thread James Bottomley
On Mon, 2022-12-19 at 06:49 -0500, Stefan Berger wrote:
> 
> 
> On 12/16/22 08:53, James Bottomley wrote:
> 
> > 
> > I could do a blog post, but I really don't think you want this in
> > official documentation because that creates support expectations.
> 
> We get support expectations if we don't mention it as not being
> supported. So, since this driver is not supported the documentation
> for QEMU should state something along the lines of 'this driver is
> for experimental or testing purposes and is otherwise unsupported.'
> That's fair to the user and maintainer.

Open source project don't provide support.  I already added a
Maintainer entry for it, so I'll maintain it.

>  Nevertheless, if the documentation (or as a matter of fact the code)
> was to claim that VM / TPM state migration scenarios, such as VM
> snapshotting, are working then users should be able to ask someone
> 'how' this can be done with the mssim protocol **today**. Since I
> cannot answer that question you may need to find a way for how to
> address this concern.

I already proposed all of this ... you were the one wanting to document
migration.  The current wording is:

   The mssim backend supports snapshotting and migration, but the state
   of the Microsoft Simulator server must be preserved (or the server
   kept running) outside of QEMU for restore to be successful.

James





Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-16 Thread James Bottomley
On Fri, 2022-12-16 at 11:08 -0500, Stefan Berger wrote:
> On 12/16/22 10:48, James Bottomley wrote:
[...]
> > +The mssim backend supports snapshotting and migration, but the
> > state
> > +of the Microsoft Simulator server must be preserved (or the server
> > +kept running) outside of QEMU for restore to be successful.
> 
> You said you tested it. Can you show how to set it up with command
> lines? I want to try out at least suspend and resume .

I already did here:

https://lore.kernel.org/qemu-devel/77bc5a11fcb7b06deba1c54b1ef2de28e0c53fb1.ca...@linux.ibm.com/

But to recap, it's

stop   
migrate "exec:gzip -c > STATEFILE.gz"  
quit

Followed by a restart with

 -incoming "exec: gzip -c -d STATEFILE.gz"

James




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-16 Thread James Bottomley
On Fri, 2022-12-16 at 09:55 -0500, Stefan Berger wrote:
> 
> 
> On 12/16/22 09:29, Daniel P. Berrangé wrote:
> 
> > 
> > All the objections you're raising are related to the current
> > specifics of the implementation of the mssim remote server.
> > While valid, this is of no concern to QEMU when deciding whether
> > to require a migration blocker on the client side. This is 3rd
> > party remote service that should be considered a black box from
> > QEMU's POV. It is possible to write a remote server that supports
> > the mssim network protocol, and has the ability to serialize
> > its state. Whether such an impl exists today or not is separate.
> 
> Then let's document the scenarios so someone can repeat them, I think
> this is just fair. James said he tested state migration scenarios and
> it works, so let's enable others to do it as well. I am open to
> someone maintaining just this driver and the dynamics that may
> develop around it.

Well, OK, this is what I think would be appropriate ... I'll fold it in
to the second patch.

James

---

diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst
index 535912a92b..985d0775a0 100644
--- a/docs/specs/tpm.rst
+++ b/docs/specs/tpm.rst
@@ -270,6 +270,38 @@ available as a module (assuming a TPM 2 is passed through):
   /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/9
   ...
 
+The QEMU TPM Microsoft Simulator Device
+---
+
+The TCG provides a reference implementation for TPM 2.0 written by
+Microsoft (See `ms-tpm-20-ref`_ on github).  The reference implementation
+starts a network server and listens for TPM commands on port 2321 and
+TPM Platform control commands on port 2322, although these can be
+altered.  The QEMU mssim TPM backend talks to this implementation.  By
+default it connects to the default ports on localhost:
+
+.. code-block:: console
+
+  qemu-system-x86_64  \
+-tpmdev mssim,id=tpm0 \
+-device tpm-crb,tpmdev=tpm0
+
+
+Although it can also communicate with a remote host, which must be
+specified as a SocketAddress via json on the command line for each of
+the command and control ports:
+
+.. code-block:: console
+
+  qemu-system-x86_64  \
+-tpmdev 
"{'type':'mssim','id':'tpm0','command':{'type':inet,'host':'remote','port':'2321'},'control':{'type':'inet','host':'remote','port':'2322'}}"
 \
+-device tpm-crb,tpmdev=tpm0
+
+
+The mssim backend supports snapshotting and migration, but the state
+of the Microsoft Simulator server must be preserved (or the server
+kept running) outside of QEMU for restore to be successful.
+
 The QEMU TPM emulator device
 
 
@@ -526,3 +558,6 @@ the following:
 
 .. _SWTPM protocol:
https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod
+
+.. _ms-tpm-20-ref:
+   https://github.com/microsoft/ms-tpm-20-ref




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-16 Thread James Bottomley
On Fri, 2022-12-16 at 08:32 -0500, Stefan Berger wrote:
> On 12/16/22 07:54, Daniel P. Berrangé wrote:
> > On Fri, Dec 16, 2022 at 07:28:59AM -0500, Stefan Berger wrote:
[...]
> > > Nevertheless it needs documentation and has to handle migration
> > > scenarios either via a blocker or it has to handle them all
> > > correctly. Since it's supposed to be a TPM running remote you
> > > had asked for TLS support iirc.
> > 
> > If the mssim implmentation doesn't provide TLS itself, then I don't
> > consider that a blocker on the QEMU side, merely a nice-to-have.
> > 
> > With swtpm the control channel is being used to load and store
> > state during the migration dance. This makes the use of an external
> > process largely transparent to the user, since QEMU handles all the
> > state save/load as part of its migration data stream.
> > 
> > With mssim there is state save/load co-ordination with QEMU.
> > Instead whomever/whatever is managing the mssim instance, is
> > responsible for ensuring it is running with the correct state at
> > the time QEMU does a vmstate load. If doing a live migration this
> > co-ordination is trivial if you just use the same mssim instance
> > for both src/dst to connect to.
> > 
> > If doing save/store to disk, the user needs to be able to save the
> > mssim state and load it again later. If doing snapshots and
> > reverting to old
> 
> There is no way for storing and loading the *volatile state* of the
> mssim device.

Well, yes there is, it saves internal TPM state to an NVChip file:

https://github.com/microsoft/ms-tpm-20-ref/blob/main/TPMCmd/Platform/src/NVMem.c

However, if I were running this as a service, I'd condition saving and
restoring state on a connection protocol, which would mean QEMU
wouldn't have to worry about it.  The simplest approach, of course, is
just to keep the service running even when the VM is suspended so the
state is kept internally.

> > snapshots, then again whomever manages mssim needs to be keeping
> > saved TPM state corresponding to each QEMU snapshot saved, and
> > picking the right one when restoring to old snapshots.
> 
> This doesn't work.

I already told you I tested this and it does work.  I'll actually add
the migration state check to the power on/off path because I need that
for testing S3 anyway.

> Either way, if it's possible it can be documented and shown how this
> works.

I could do a blog post, but I really don't think you want this in
official documentation because that creates support expectations.
> 
> > QEMU exposes enough functionality to enable a mgmt app / admin us>
> > achieve all of this.
> 
> How do you store the volatile state of this device, like the current
> state of the PCRs, loaded sessions etc? It doesn't support this.

That's not the only way of doing migration.  This precise problem
exists for VFIO and PCI pass through devices as well: external state is
stored in the card and that state must be matched in some way for the
card to work on resume.  Pretty much any external device coupled to the
VM has this problem.  As I keep saying you're thinking about this in
the wrong way: it's not a system directly slaved to QEMU it's an
independent daemon which must be managed separately.  The design is for
it to function like a passthrough.

> > This is not as seemlessly integrated with swtpm is, but it is still
> > technically posssible todo the right thing with migration from
> > QEMU's POV. Whether or not the app/person managing mssim instance
> > actually does the right thing in practice is not a concern of QEMU.
> > I don't see a need for a migration blocker here.
> 
> I do see it because the *volatile state* cannot be extracted from
> this device. The state of the PCRs is going to be lost.

Installing a migration blocker would prevent me from exercising the S3
paths, which I want to test.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-15 Thread James Bottomley
On Thu, 2022-12-15 at 15:22 -0500, Stefan Berger wrote:
> On 12/15/22 15:07, James Bottomley wrote:
[...]
> > don't really have much interest in the migration use case, but I
> > knew it should work like the passthrough case, so that's what I
> > tested.
> 
> I think your device needs to block migrations since it doesn't handle
> all migration scenarios correctly.

Passthrough doesn't block migrations either, presumably because it can
also be made to work if you know what you're doing.  I might not be
particularly interested in migrations, but that's not really a good
reason to prevent anyone from ever using them, particularly when the
experiment says they do work.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-15 Thread James Bottomley
On Thu, 2022-12-15 at 14:57 -0500, Stefan Berger wrote:
> On 12/15/22 14:40, James Bottomley wrote:
> > On Thu, 2022-12-15 at 14:35 -0500, Stefan Berger wrote:
[...]
> > > You should also add a description to docs/specs/tpm.rst.
> > 
> > Description of what?  It functions exactly like passthrough on
> 
> Please describe all the scenarios so that someone else can repeat
> them when trying out **your** device.
> 
> There are sections describing how things for swtpm and you should add
> how things work for the mssim TPM.
> 
> https://github.com/qemu/qemu/blob/master/docs/specs/tpm.rst#the-qemu-tpm-emulator-device
> https://github.com/qemu/qemu/blob/master/docs/specs/tpm.rst#migration-with-the-tpm-emulator

The passthrough snapshot/restore isn't described there either.  This
behaves exactly the same in that it's caveat emptor.  If something
happens in the interim to upset the TPM state then the restore will
have unexpected effects due to the externally changed TPM state.  This
is actually a feature: I'm checking our interposer defences by doing
external state manipulation.

> > migration.  Since the TPM state is retained in the server a
> > reconnection just brings everything back to where it was.
> 
> So it's remote. And the ports are always open and someone can just
> connect to the open ports and power cycle the device?

in the same way as you can power off the hardware and have issues with
a passthrough TPM on vm restore, yes.

> This may not be the most important scenario but nevertheless I
> wouldn't want to deal with bug reports if someone does 'VM
> snapshotting' -- how this is correctly handled would be of interest.

I'd rather say nothing, like passthrough, then there are no
expectations beyond it might work if you know what you're doing.  I
don't really have much interest in the migration use case, but I knew
it should work like the passthrough case, so that's what I tested.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-15 Thread James Bottomley
On Thu, 2022-12-15 at 14:35 -0500, Stefan Berger wrote:
> 
> 
> On 12/15/22 14:22, James Bottomley wrote:
> > On Thu, 2022-12-15 at 13:46 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/15/22 13:01, James Bottomley wrote:
> > > > From: James Bottomley 
> > > > 
> > > > 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 baset 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 host, and two
> > > > ports
> > > > to
> > > > be specified on the qemu 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':'rem
> > > > ote'
> > > > ,'port':'2321'}}"
> > > > 
> > > > tpm-tis also works as the backend.
> > > 
> > > Since this device does not properly support migration you have to
> > > register a migration blocker.
> > 
> > Actually it seems to support migration just fine.  Currently the
> > PCR's
> > get zero'd which is my fault for doing a TPM power off/on, but
> > switching that based on state should be an easy fix.
> 
> How do you handle virsh save  -> host reboot -> virsh restore?

I didn't.  I just pulled out the TPM power state changes and followed
the guide here using the migrate "exec:gzip -c > STATEFILE.gz" recipe:

https://www.linux-kvm.org/page/Migration

and verified the TPM pcrs and the null name were unchanged.

> You should also add a description to docs/specs/tpm.rst.

Description of what?  It functions exactly like passthrough on
migration.  Since the TPM state is retained in the server a
reconnection just brings everything back to where it was.

James




Re: [PATCH 2/2] tpm: add backend for mssim

2022-12-15 Thread James Bottomley
On Thu, 2022-12-15 at 13:46 -0500, Stefan Berger wrote:
> 
> 
> On 12/15/22 13:01, James Bottomley wrote:
> > From: James Bottomley 
> > 
> > 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 baset 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 host, and two ports
> > to
> > be specified on the qemu 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.
> 
> Since this device does not properly support migration you have to
> register a migration blocker.

Actually it seems to support migration just fine.  Currently the PCR's
get zero'd which is my fault for doing a TPM power off/on, but
switching that based on state should be an easy fix.

James




[PATCH 2/2] tpm: add backend for mssim

2022-12-15 Thread James Bottomley
From: James Bottomley 

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 baset 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 host, and two ports to
be specified on the qemu 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 

---

v2: convert to SocketAddr json and use qio_channel_socket_connect_sync()
---
 MAINTAINERS  |   5 +
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 251 +++
 backends/tpm/tpm_mssim.h |  43 +++
 monitor/hmp-cmds.c   |   7 ++
 qapi/tpm.json|  25 +++-
 7 files changed, 334 insertions(+), 3 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6966490c94..a4a3bf9ab4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3046,6 +3046,11 @@ F: backends/tpm/
 F: tests/qtest/*tpm*
 T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
 
+MSSIM TPM Backend
+M: James Bottomley 
+S: Maintained
+F: backends/tpm/tpm_mssim.*
+
 Checkpatch
 S: Odd Fixes
 F: scripts/checkpatch.pl
diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..7c10ce2944
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,251 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TpmTypeOptions *opts;
+
+QIOChannelSocket *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+cmd = htonl(cmd);
+ret = qio_channel_write_all(QIO_CHANNEL(t->ctrl_qc), (char *), 
sizeof(cmd), errp);
+if (ret != 0)
+return ret;
+ret = qio_channel_read_all(QIO_CHANNEL(t->ctrl_qc), (char *), 
sizeof(cmd), errp);
+if (ret != 0)
+return ret;
+if (cmd != 0) {
+error_setg(errp, ERROR_PREFIX "Incorrect ACK recieved on control 
channel 0x%x\n", cmd);
+return -1;
+}
+return

[PATCH 1/2] tpm: convert tpmdev options processing to new visitor format

2022-12-15 Thread James Bottomley
From: James Bottomley 

Instead of processing the tpmdev options using the old qemu options,
convert to the new visitor format which also allows the passing of
json on the command line.

Signed-off-by: James Bottomley 
---
 backends/tpm/tpm_emulator.c| 35 ++
 backends/tpm/tpm_passthrough.c | 37 +--
 include/sysemu/tpm.h   |  2 +-
 include/sysemu/tpm_backend.h   |  2 +-
 monitor/hmp-cmds.c |  4 +-
 qapi/tpm.json  | 26 ++-
 softmmu/tpm.c  | 84 +++---
 softmmu/vl.c   |  4 +-
 8 files changed, 71 insertions(+), 123 deletions(-)

diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 49cc3d749d..82988a2986 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -69,7 +69,7 @@ typedef struct TPMBlobBuffers {
 struct TPMEmulator {
 TPMBackend parent;
 
-TPMEmulatorOptions *options;
+TpmTypeOptions *options;
 CharBackend ctrl_chr;
 QIOChannel *data_ioc;
 TPMVersion tpm_version;
@@ -584,33 +584,28 @@ err_exit:
 return -1;
 }
 
-static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts 
*opts)
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, 
TpmTypeOptions *opts)
 {
-const char *value;
 Error *err = NULL;
 Chardev *dev;
 
-value = qemu_opt_get(opts, "chardev");
-if (!value) {
-error_report("tpm-emulator: parameter 'chardev' is missing");
-goto err;
-}
+tpm_emu->options = opts;
+tpm_emu->data_ioc = NULL;
 
-dev = qemu_chr_find(value);
+dev = qemu_chr_find(opts->u.emulator.chardev);
 if (!dev) {
-error_report("tpm-emulator: tpm chardev '%s' not found", value);
+error_report("tpm-emulator: tpm chardev '%s' not found",
+opts->u.emulator.chardev);
 goto err;
 }
 
 if (!qemu_chr_fe_init(_emu->ctrl_chr, dev, )) {
 error_prepend(, "tpm-emulator: No valid chardev found at '%s':",
-  value);
+  opts->u.emulator.chardev);
 error_report_err(err);
 goto err;
 }
 
-tpm_emu->options->chardev = g_strdup(value);
-
 if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) {
 goto err;
 }
@@ -621,7 +616,7 @@ static int tpm_emulator_handle_device_opts(TPMEmulator 
*tpm_emu, QemuOpts *opts)
 if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd,
  _emu->tpm_version)) {
 error_report("'%s' is not emulating TPM device. Error: %s",
-  tpm_emu->options->chardev, strerror(errno));
+  tpm_emu->options->u.emulator.chardev, strerror(errno));
 goto err;
 }
 
@@ -649,7 +644,7 @@ err:
 return -1;
 }
 
-static TPMBackend *tpm_emulator_create(QemuOpts *opts)
+static TPMBackend *tpm_emulator_create(TpmTypeOptions *opts)
 {
 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
 
@@ -664,10 +659,9 @@ static TPMBackend *tpm_emulator_create(QemuOpts *opts)
 static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
 {
 TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
-TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
+TpmTypeOptions *options;
 
-options->type = TPM_TYPE_EMULATOR;
-options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, 
tpm_emu->options);
+options = QAPI_CLONE(TpmTypeOptions, tpm_emu->options);
 
 return options;
 }
@@ -972,7 +966,6 @@ static void tpm_emulator_inst_init(Object *obj)
 
 trace_tpm_emulator_inst_init();
 
-tpm_emu->options = g_new0(TPMEmulatorOptions, 1);
 tpm_emu->cur_locty_number = ~0;
 qemu_mutex_init(_emu->mutex);
 tpm_emu->vmstate =
@@ -990,7 +983,7 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
 {
 ptm_res res;
 
-if (!tpm_emu->options->chardev) {
+if (!tpm_emu->data_ioc) {
 /* was never properly initialized */
 return;
 }
@@ -1015,7 +1008,7 @@ static void tpm_emulator_inst_finalize(Object *obj)
 
 qemu_chr_fe_deinit(_emu->ctrl_chr, false);
 
-qapi_free_TPMEmulatorOptions(tpm_emu->options);
+qapi_free_TpmTypeOptions(tpm_emu->options);
 
 if (tpm_emu->migration_blocker) {
 migrate_del_blocker(tpm_emu->migration_blocker);
diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c
index 5a2f74db1b..2ce39b2167 100644
--- a/backends/tpm/tpm_passthrough.c
+++ b/backends/tpm/tpm_passthrough.c
@@ -41,7 +41,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TPMPassthruState, TPM_PASSTHROUGH)
 struct TPMPassthruState {
 TPMBackend parent;
 
-TPMPassthroughOptions *options;
+TpmTypeOptions *options;
 const char *tpm_dev;
 int tpm_fd;
 bool tpm_executing;
@@ -214,8 +214,8 @@ static int 

[PATCH 0/2] tpm: add mssim backend

2022-12-15 Thread James Bottomley
From: James Bottomley 

The requested feedback was to convert the tpmdev handler to being json
based, which requires rethreading all the backends.  The good news is
this reduced quite a bit of code (especially as I converted it to
error_fatal handling as well, which removes the return status
threading).  The bad news is I can't test any of the conversions.
swtpm still isn't building on opensuse and, apparently, passthrough
doesn't like my native TPM because it doesn't allow cancellation.

James

---

James Bottomley (2):
  tpm: convert tpmdev options processing to new visitor format
  tpm: add backend for mssim

 MAINTAINERS|   5 +
 backends/tpm/Kconfig   |   5 +
 backends/tpm/meson.build   |   1 +
 backends/tpm/tpm_emulator.c|  35 ++---
 backends/tpm/tpm_mssim.c   | 251 +
 backends/tpm/tpm_mssim.h   |  43 ++
 backends/tpm/tpm_passthrough.c |  37 ++---
 include/sysemu/tpm.h   |   2 +-
 include/sysemu/tpm_backend.h   |   2 +-
 monitor/hmp-cmds.c |  11 +-
 qapi/tpm.json  |  37 ++---
 softmmu/tpm.c  |  84 +--
 softmmu/vl.c   |   4 +-
 13 files changed, 398 insertions(+), 119 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

-- 
2.35.3




Re: [PATCH] tpm: add backend for mssim

2022-12-14 Thread James Bottomley
On Wed, 2022-12-14 at 11:31 +, Daniel P. Berrangé wrote:
> On Mon, Dec 12, 2022 at 05:06:05PM -0500, James Bottomley wrote:
> > On Mon, 2022-12-12 at 15:47 +, Daniel P. Berrangé wrote:
> > > Copy'ing Markus for QAPI design feedback.
> > > 
> > > On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
> > [...]
> > > > +##
> > > > +# @TPMmssimOptions:
> > > > +#
> > > > +# Information for the mssim emulator connection
> > > > +#
> > > > +# @host: host name or IP address to connect to
> > > > +# @port: port for the standard TPM commands
> > > > +# @ctrl: control port for TPM state changes
> > > > +#
> > > > +# Since: 7.2.0
> > > > +##
> > > > +{ 'struct': 'TPMmssimOptions',
> > > > +  'data': {
> > > > +  'host': 'str',
> > > > +  'port': 'str',
> > > > +  'ctrl': 'str' },
> > > > +  'if': 'CONFIG_TPM' }
> > > 
> > > We don't want to be adding new code using plain host/port combos,
> > > as that misses extra functionality for controlling IPv4 vs IPv6
> > > usage.
> > > 
> > > The existing 'emulator' backend references a chardev, but I'm
> > > not especially in favour of using the chardev indirection either,
> > > when all we should really need is a SocketAddress
> > > 
> > > IOW, from a QAPI design POV, IMHO the best practice would be
> > > 
> > >  { 'struct': 'TPMmssimOptions',
> > >    'data': {
> > >    'command': 'SocketAddress',
> > >    'control': 'SocketAddress' },
> > >    'if': 'CONFIG_TPM' }
> > > 
> > > 
> > > The main wrinkle with this is that exprssing nested struct fields
> > > with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> > > JSON syntax.
> > > 
> > > IMHO we should just fix the latter problem, as I don't think it
> > > ought to be too hard. Probably a cut+paste / search/replace job
> > > on the chanmge we did for -device in:
> > > 
> > >   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
> > >   Author: Kevin Wolf 
> > >   Date:   Fri Oct 8 15:34:42 2021 +0200
> > > 
> > >     vl: Enable JSON syntax for -device
> > > 
> > > This would mean we could use plain -tpmdev for a local instance
> > > 
> > >    -tpmdev mssim,id=tpm0 \
> > >     -device tpm-crb,tpmdev=tpm0 \
> > > 
> > > but to use a remote emulator we would use
> > > 
> > >     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
> > >   'command': {
> > >  'type': 'inet',
> > >  'host': 'remote',
> > >  'port': '4455'
> > >    },
> > >   'control': {
> > >  'type': 'inet',
> > >  'host': 'remote',
> > >  'port': '4456'
> > >    }}"
> > > 
> > > (without the whitepace/newlines, which i just used for sake of
> > > clarity)
> > 
> > Just on this, might it not be easier for the commandline to do what
> > gluster does?  just use the '.' as a separator and subqdict
> > extraction, so you'd specify
> > 
> > -tpmdev
> > mssim,id=tpm0,command.type=inet,command.host=remote,command.port=44
> > 55,control.type=inet,control.host=remote,control.port=4456
> > 
> > With the added bonus that X.type could be defaulted to inet and
> > control.host could follow command.host and so on?
> 
> These days, we have a policy of not tyring to map nested data onto
> the flat QemuOpts. This has been done in several areas and we've
> ended up with a mess of ever so slightly different impls each with
> their own flaws. This is why our preferred approach these days is to
> add support for JSON syntax to enable non-flat config.

Well, OK, but I've got to say on behalf of shell script writers
everywhere that using json for command line arguments is a textbook
definition of cruel and unusual punishment.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-14 Thread James Bottomley
On Wed, 2022-12-14 at 11:52 +, Daniel P. Berrangé wrote:
> It is a shame there isn't a standardized protocol for software TPM
> communication, as that'd avoid the need for multiple backends.

Technically the mssim protocol is the standard, being part of the
reference implementation, but practically it's terrible:  Using two
ports per vTPM is hardly scalable in a cloud situation and, as you say,
it has no security.  Ideally someone with TCG connections would try to
standardize a more scalable network server protocol, something nicely
rest based that identified the vTPM by say its EK name.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 17:02 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 16:36, James Bottomley wrote:
> > On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
[...]
> > >   Either way, what is the latency that this introduces because I
> > > would expect that this slows down IMA since the PCR extensions &
> > > TPM 2 response now go back and forth across the network?
> > 
> > Most data centre protocols are now encrypted and networked (NVMeoF
> > would probably be the poster child) with no real ill effects.  In
> > terms of a TPM, the competition is an underpowered discrete chip
> > over a slow serial bus, so I think we'll actually improve the
> > latency not diminish it.
> 
> Compared to QEMU and swtpm talking over a local socket you probably
> have a decent amount of slow-down if this is over the network.

I can only repeat that doesn't happen with other much more volume and
latency bound networked protocols.

> I still fail to see the advantage over what we have at the moment.
> Also I don't see what advantage the mssim protocol brings over what
> swtpm provides.

I think I've said a couple of times now: The primary advantage is that
it talks to the reference implementation over its native protocol.

>  If you are willing to do a 'dnf -y install swtpm_setup' and start
> the VM via libvirt it really doesn't matter what protocol the TPM is
> running underneath since it's all transparent.

Swtpm currently isn't building for Leap:

https://build.opensuse.org/package/show/security/swtpm

And, as I said, this is primarily for testing, so I need the reference
implementation ... swtpm has started deviating from it.

James






Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 15:47 +, Daniel P. Berrangé wrote:
> Copy'ing Markus for QAPI design feedback.
> 
> On Sat, Dec 10, 2022 at 12:10:18PM -0500, James Bottomley wrote:
[...]
> > +##
> > +# @TPMmssimOptions:
> > +#
> > +# Information for the mssim emulator connection
> > +#
> > +# @host: host name or IP address to connect to
> > +# @port: port for the standard TPM commands
> > +# @ctrl: control port for TPM state changes
> > +#
> > +# Since: 7.2.0
> > +##
> > +{ 'struct': 'TPMmssimOptions',
> > +  'data': {
> > +  'host': 'str',
> > +  'port': 'str',
> > +  'ctrl': 'str' },
> > +  'if': 'CONFIG_TPM' }
> 
> We don't want to be adding new code using plain host/port combos,
> as that misses extra functionality for controlling IPv4 vs IPv6
> usage.
> 
> The existing 'emulator' backend references a chardev, but I'm
> not especially in favour of using the chardev indirection either,
> when all we should really need is a SocketAddress
> 
> IOW, from a QAPI design POV, IMHO the best practice would be
> 
>  { 'struct': 'TPMmssimOptions',
>    'data': {
>    'command': 'SocketAddress',
>    'control': 'SocketAddress' },
>    'if': 'CONFIG_TPM' }
> 
> 
> The main wrinkle with this is that exprssing nested struct fields
> with QemuOpts is a disaster zone, and -tpmdev doesn't yet support
> JSON syntax.
> 
> IMHO we should just fix the latter problem, as I don't think it
> ought to be too hard. Probably a cut+paste / search/replace job
> on the chanmge we did for -device in:
> 
>   commit 5dacda5167560b3af8eadbce5814f60ba44b467e
>   Author: Kevin Wolf 
>   Date:   Fri Oct 8 15:34:42 2021 +0200
> 
>     vl: Enable JSON syntax for -device
> 
> This would mean we could use plain -tpmdev for a local instance
> 
>    -tpmdev mssim,id=tpm0 \
>     -device tpm-crb,tpmdev=tpm0 \
> 
> but to use a remote emulator we would use
> 
>     -tpmdev "{'backend': 'mssim', 'id': 'tpm0',
>   'command': {
>  'type': 'inet',
>  'host': 'remote',
>  'port': '4455'
>    },
>   'control': {
>  'type': 'inet',
>  'host': 'remote',
>  'port': '4456'
>    }}"
> 
> (without the whitepace/newlines, which i just used for sake of
> clarity)

Just on this, might it not be easier for the commandline to do what
gluster does?  just use the '.' as a separator and subqdict extraction,
so you'd specify

-tpmdev 
mssim,id=tpm0,command.type=inet,command.host=remote,command.port=4455,control.type=inet,control.host=remote,control.port=4456

With the added bonus that X.type could be defaulted to inet and
control.host could follow command.host and so on?

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 14:32 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 14:12, James Bottomley wrote:
> > On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
> > > On 12/12/22 13:48, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > > > On 12/12/22 11:38, James Bottomley wrote:
> > [...]
> > > > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > > > standard mssim server is too simplistic to do transport
> > > > > > layer
> > > > > > security, but like everything that does this (or rather
> > > > > > doesn't
> > > > > > do this), you can front it with stunnel4.
> > > > > 
> > > > > And who or what is going to set this up?
> > > > 
> > > > I'm not sure I understand the question.  Stunnel4 is mostly
> > > > used to
> > > > convert unencrypted proxies like imap on 143 or smtp on 25 to
> > > > the
> > > > secure version.  Most people who run servers are fairly
> > > > familiar
> > > > with using it.  It's what IBM used for encrypted migration
> > > > initially.  You can run stunnel on both ends, or the qemu side
> > > > could be built in using the qemu tls-creds way of doing things
> > > > but
> > > > anything running the standard MS server would have to front it
> > > > with
> > > > stunnel still.
> > > 
> > > So it's up to libvirt to setup stunnel to support a completely
> > > different setup than what it has for swtpm already?
> > 
> > I don't think so, no.  Libvirt doesn't usually help with server
> > setup (witness the complexity of setting up a server side vtpm
> > proxy) so in the case tls-creds were built in, it would just work
> > if the object is
> 
> I see, so you are extending the TPM emulator with TLS on the client
> side so you don't need another tool to setup a TLS connection from
> the QEMU/client side.

I didn't say I would do this, just that it's an easy possibility with
the current qemu framework.  I actually need to fiddle with the TPM
externally to do some of my testing (like platform reset injection) so
I won't use TLS anyway.

> Is the server side across the network or on the same host?

It can be either.

>  Either way, what is the latency that this introduces because I would
> expect that this slows down IMA since the PCR extensions & TPM 2
> response now go back and forth across the network?

Most data centre protocols are now encrypted and networked (NVMeoF
would probably be the poster child) with no real ill effects.  In terms
of a TPM, the competition is an underpowered discrete chip over a slow
serial bus, so I think we'll actually improve the latency not diminish
it.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 13:58 -0500, Stefan Berger wrote:
> On 12/12/22 13:48, James Bottomley wrote:
> > On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> > > On 12/12/22 11:38, James Bottomley wrote:
[...]
> > > > the kernel use of the TPM, but I'm trying to fix that.  The
> > > > standard mssim server is too simplistic to do transport layer
> > > > security, but like everything that does this (or rather doesn't
> > > > do this), you can front it with stunnel4.
> > > 
> > > And who or what is going to set this up?
> > 
> > I'm not sure I understand the question.  Stunnel4 is mostly used to
> > convert unencrypted proxies like imap on 143 or smtp on 25 to the
> > secure version.  Most people who run servers are fairly familiar
> > with using it.  It's what IBM used for encrypted migration
> > initially.  You can run stunnel on both ends, or the qemu side
> > could be built in using the qemu tls-creds way of doing things but
> > anything running the standard MS server would have to front it with
> > stunnel still.
> 
> So it's up to libvirt to setup stunnel to support a completely
> different setup than what it has for swtpm already?

I don't think so, no.  Libvirt doesn't usually help with server setup
(witness the complexity of setting up a server side vtpm proxy) so in
the case tls-creds were built in, it would just work if the object is
specified.  The complexity is all on the server side to front it with
stunnel.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 11:59 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 11:38, James Bottomley wrote:
> > On Mon, 2022-12-12 at 15:47 +, Daniel P. Berrangé wrote:
> > > Copy'ing Markus for QAPI design feedback.
> > > 
> > > On Sat, Dec 10, 2022 at 12:10:18PM -0500, 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 baset 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
> > > > host, and two ports to be specified on the qemu 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.
> > > 
> > > What's the story with security for this ?  The patch isn't using
> > > TLS, so talking to any emulator over anything other than
> > > localhost looks insecure, unless I'm missing something.
> > 
> > Pretty much every TPM application fears interposers and should thus
> > be using the TPM transport security anyway. *If* this is the case,
> > then the transport is secure.  Note that this currently isn't the
> > case for
> 
> What about all the older kernels that are out there?

No current kernel uses transport security.  In the event the patch
eventually gets upstream, the kernel be secure against interposer
attacks going forwards.  I would imagine there might be pressure to
backport the patch given the current level of worry about interposers.

> > the kernel use of the TPM, but I'm trying to fix that.  The
> > standard mssim server is too simplistic to do transport layer
> > security, but like everything that does this (or rather doesn't do
> > this), you can front it with stunnel4.
> 
> And who or what is going to set this up?

I'm not sure I understand the question.  Stunnel4 is mostly used to
convert unencrypted proxies like imap on 143 or smtp on 25 to the
secure version.  Most people who run servers are fairly familiar with
using it.  It's what IBM used for encrypted migration initially.  You
can run stunnel on both ends, or the qemu side could be built in using
the qemu tls-creds way of doing things but anything running the
standard MS server would have to front it with stunnel still.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 15:47 +, Daniel P. Berrangé wrote:
> Copy'ing Markus for QAPI design feedback.
> 
> On Sat, Dec 10, 2022 at 12:10:18PM -0500, 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 baset 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 host, and
> > two ports to be specified on the qemu 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.
> 
> What's the story with security for this ?  The patch isn't using
> TLS, so talking to any emulator over anything other than localhost
> looks insecure, unless I'm missing something.

Pretty much every TPM application fears interposers and should thus be
using the TPM transport security anyway. *If* this is the case, then
the transport is secure.  Note that this currently isn't the case for
the kernel use of the TPM, but I'm trying to fix that.  The standard
mssim server is too simplistic to do transport layer security, but like
everything that does this (or rather doesn't do this), you can front it
with stunnel4.

> > diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
> > new file mode 100644
> > index 00..6864b1fbc0
> > --- /dev/null
> > +++ b/backends/tpm/tpm_mssim.c
> > @@ -0,0 +1,266 @@
> > +/*
> > + * Emulator TPM driver which connects over the mssim protocol
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Copyright (c) 2022
> 
> Copyright by whom ?  Presumably this line should have "IBM" present
> if we're going to have it at all.

It can either be me or IBM, we're joint owners, that's why I thought
just author.

> > + * Author: James Bottomley 
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/sockets.h"
> > +
> > +#include "qapi/clone-visitor.h"
> > +#include "qapi/qapi-visit-tpm.h"
> > +
> > +#include "io/channel-socket.h"
> > +
> > +#include "sysemu/tpm_backend.h"
> > +#include "sysemu/tpm_util.h"
> > +
> > +#include "qom/object.h"
> > +
> > +#include "tpm_int.h"
> > +#include "tpm_mssim.h"
> > +
> 
> > +static TPMBackend *tpm_mssim_create(QemuOpts *opts)
> > +{
> > +    TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM));
> > +    TPMmssim *t = TPM_MSSIM(be);
> > +    InetSocketAddress cmd_s, ctl_s;
> > +    int sock;
> > +    const char *host, *port, *ctrl;
> > +    Error *errp = NULL;
> > +
> > +    host = qemu_opt_get(opts, "host");
> > +    if (!host)
> > +    host = "localhost";
> > +    t->opts.host = g_strdup(host);
> > +
> > +    port = qemu_opt_get(opts, "port");
> > +    if (!port)
> > +    port = "2321";
> > +    t->opts.port = g_strdup(port);
> > +
> > +    ctrl = qemu_opt_get(opts, "ctrl");
> > +    if (!ctrl)
> > +    ctrl = "2322";
> > +    t->opts.ctrl = g_strdup(ctrl);
> > +
> > +    cmd_s.host = (char *)host;
> > +    cmd_s.port = (char *)port;
> > +
> > +    ctl_s.host = (char *)host;
> > +    ctl_s.port = (char *)ctrl;
> > +
> > +    sock = inet_connect_saddr(_s, );
> > +    if (sock < 0)
> > +    goto fail;
> > +    t->cmd_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock,
> > ));
> > +    if (errp)
> > +    goto fail;
> > +    sock = inet_connect_saddr(_s, );
> > +    if (sock < 0)
> > +    goto fail_unref_cmd;
> > +    t->ctrl_qc = QIO_CHANNEL(qio_channel_socket_new_fd(sock,
> > ));
> > +    if (errp)
> > +    goto fail_unref_cmd;
> 
> We don't want to be using inet_connect_saddr, that's a legacy
> API. All new code should be using the qio_channel_socket_connect*
> family of APIs. T

Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 10:20 -0500, Stefan Berger wrote:
> On 12/12/22 09:47, James Bottomley wrote:
[...]
> > I don't actually use virsh in my harness.  I'm mostly interested in
> > the running the kernel TPM selftests against the reference model. 
> > But I anticipate it wouldn't currently work because I don't believe
> > virsh triggers a S3 event which is why snapshot and migration
> > doesn't always work with PCI passthrough.
> 
> Then I think you should at least add a blocker to your model so that
> suspend/resume/snapshotting/migration are all disabled because the
> mssim reference implementation doesn't support permanent & volatile
> state suspend/resume (and upgrading!) without significant work on it
> as can be seen in libtpms.

Actually, I would think adding support, if that's what people wanted,
would be pretty simple.  Since the network end point is the identifier,
the protocol would be not to power down the TPM on suspend/resume and
simply to send TPM_STOP to close down the sockets gracefully.  Then the
next connection picks up the state where the previous one left off.

> Why would we support another model for the backend that provides no
> advantages over what is there right now?

The advantages were what was stated: ability to connect to the MS
reference model directly and no dependence on the Linux VTPM_PROXY
protocol.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 09:44 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 09:32, James Bottomley wrote:
> > On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/12/22 08:59, James Bottomley wrote:
> > > > On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> > > > > 
> > > > > 
> > > > > On 12/10/22 12:10, 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 baset protocol on
> > > > > > two
> > > > > 
> > > > > baset -> based.
> > > > > 
> > > > > > 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
> > > > > > host, and two ports to be specified on the qemu 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 ervice
> > > > > > 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.
> > > > > 
> > > > > How did you implement VM suspend/resume and snapshotting
> > > > > support?
> > > > 
> > > > TPM2 doesn't need to.  The mssim follows the reference model
> > > > which
> > > 
> > > 
> > > You mean TPM2 doesn't need to resume at the point where the VM
> > > resumes (I am not talking about ACPI resume but virsh
> > > save/restore)
> > > after for example a host reboot?
> > > What does this have to do with the mssim reference model and
> > > TPM2_Shutdown protocol?
> > 
> > Running S3 suspend/resume before doing VM save/restore could fix a
> > lot of issue with passthrough PCI and when QEMU gets around to
> > doing that a TPM following the standard model should just work. 
> > It's useful to have a driver supporting this work.
> Did you test it with virsh save / restore with the mssim TPM? Does it
> work? Does it work if you reboot the host in between?

I don't actually use virsh in my harness.  I'm mostly interested in the
running the kernel TPM selftests against the reference model.  But I
anticipate it wouldn't currently work because I don't believe virsh
triggers a S3 event which is why snapshot and migration doesn't always
work with PCI passthrough.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 09:27 -0500, Stefan Berger wrote:
> 
> 
> On 12/12/22 08:59, James Bottomley wrote:
> > On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> > > 
> > > 
> > > On 12/10/22 12:10, 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 baset protocol on two
> > > 
> > > baset -> based.
> > > 
> > > > 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
> > > > host, and two ports to be specified on the qemu 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 ervice 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.
> > > 
> > > How did you implement VM suspend/resume and snapshotting support?
> > 
> > TPM2 doesn't need to.  The mssim follows the reference model which
> 
> 
> You mean TPM2 doesn't need to resume at the point where the VM
> resumes (I am not talking about ACPI resume but virsh save/restore)
> after for example a host reboot?
> What does this have to do with the mssim reference model and
> TPM2_Shutdown protocol?

Running S3 suspend/resume before doing VM save/restore could fix a lot
of issue with passthrough PCI and when QEMU gets around to doing that a
TPM following the standard model should just work.  It's useful to have
a driver supporting this work.

James




Re: [PATCH] tpm: add backend for mssim

2022-12-12 Thread James Bottomley
On Mon, 2022-12-12 at 08:43 -0500, Stefan Berger wrote:
> 
> 
> On 12/10/22 12:10, 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 baset protocol on two
> 
> baset -> based.
> 
> > 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 host, and
> > two ports to be specified on the qemu 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 ervice 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.
> 
> How did you implement VM suspend/resume and snapshotting support?

TPM2 doesn't need to.  The mssim follows the reference model which
obeys the TPM2_Shutdown protocol, so the software does a power off with

TPM2_Shutdown(TPM_SU_STATE)

This allows poweroff to preserve the PCR state, provided the startup
does

TPM2_Startup(TPM_SU_STATE).

the edk2 SecurityPackage does this in OVMF on S3 Resume, so using this
backend allows us to check the OVMF startup for correctness.

Now getting QEMU to go through S3 suspend is another issue, but when it
does, the TPM should just work.

James




[PATCH] tpm: add backend for mssim

2022-12-10 Thread James Bottomley
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 baset 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 host, and two ports to
be specified on the qemu 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 mssim,it=tpm0,host=remote.host,port=4455,ctrl=4457 \

tpm-tis also works as the backend.

Signed-off-by: James Bottomley 
---
 backends/tpm/Kconfig |   5 +
 backends/tpm/meson.build |   1 +
 backends/tpm/tpm_mssim.c | 266 +++
 backends/tpm/tpm_mssim.h |  43 +++
 monitor/hmp-cmds.c   |   6 +
 qapi/tpm.json|  35 +-
 6 files changed, 353 insertions(+), 3 deletions(-)
 create mode 100644 backends/tpm/tpm_mssim.c
 create mode 100644 backends/tpm/tpm_mssim.h

diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig
index 5d91eb89c2..d6d6fa53e9 100644
--- a/backends/tpm/Kconfig
+++ b/backends/tpm/Kconfig
@@ -12,3 +12,8 @@ config TPM_EMULATOR
 bool
 default y
 depends on TPM_BACKEND
+
+config TPM_MSSIM
+bool
+default y
+depends on TPM_BACKEND
diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build
index 7f2503f84e..c7c3c79125 100644
--- a/backends/tpm/meson.build
+++ b/backends/tpm/meson.build
@@ -3,4 +3,5 @@ if have_tpm
   softmmu_ss.add(files('tpm_util.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: 
files('tpm_passthrough.c'))
   softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c'))
+  softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c'))
 endif
diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c
new file mode 100644
index 00..6864b1fbc0
--- /dev/null
+++ b/backends/tpm/tpm_mssim.c
@@ -0,0 +1,266 @@
+/*
+ * Emulator TPM driver which connects over the mssim protocol
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2022
+ * Author: James Bottomley 
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/sockets.h"
+
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
+
+#include "io/channel-socket.h"
+
+#include "sysemu/tpm_backend.h"
+#include "sysemu/tpm_util.h"
+
+#include "qom/object.h"
+
+#include "tpm_int.h"
+#include "tpm_mssim.h"
+
+#define ERROR_PREFIX "TPM mssim Emulator: "
+
+#define TYPE_TPM_MSSIM "tpm-mssim"
+OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM)
+
+struct TPMmssim {
+TPMBackend parent;
+
+TPMmssimOptions opts;
+
+QIOChannel *cmd_qc, *ctrl_qc;
+};
+
+static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp)
+{
+int ret;
+
+cmd = htonl(cmd);
+ret = qio_channel_write_all(t->ctrl_qc, (char *), sizeof(cmd), errp);
+if (ret != 0)
+return ret;
+ret = qio_channel_read_all(t->ctrl_qc, (char *), sizeof(cmd), errp);
+if (ret != 0)
+return ret;
+if (cmd != 0) {
+error_setg(errp, ERROR_PREFIX "Incorrect ACK recieved on control 
channel 0x%x\n", cmd);
+return -1;
+}
+return 0;
+}
+
+static void tpm_mssim_instance_init(Object *obj)
+{
+}
+
+static void tpm_mssim_instance_finalize(Object *obj)
+{
+TPMmssim *t = TPM_MSSIM(obj);
+
+tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, NULL);
+
+object_unref(OBJECT(t->ctrl_qc));
+object_unref(OBJECT(t->cmd_qc));
+}
+
+static void tpm_mssim_cancel_cmd(TPMBackend *tb)
+{
+return;
+}
+
+static TPMVersion tpm_mssim_get_version(TPMBackend *tb)
+{
+return TPM_VERSION_2_0;
+}
+
+static size_t tpm_mssim_get_buffer_size(TPMBackend *tb)
+{
+/* TCG standard profile max buffer size */
+return 4096;
+

Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-19 Thread James Bottomley
On Thu, 2021-08-19 at 15:28 +0100, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > On Thu, 2021-08-19 at 09:22 +0100, Dr. David Alan Gilbert wrote:
[...]
> > > I think it really does have to cope with migration to a new
> > > version of host.
> > 
> > Well, you're thinking of OVMF as belonging to the host because of
> > the way it is supplied, but think about the way it works in
> > practice now, forgetting about confidential computing: OVMF is RAM
> > resident in ordinary guests, so when you migrate them, the whole of
> > OVMF (or at least what's left at runtime) goes with the migration,
> > thus it's not possible to change the guest OVMF by migration.  The
> > above is really just an extension of that principle, the only
> > difference for confidential computing being you have to have an
> > image of the current OVMF ROM in the target to seed migration.
> > 
> > Technically, the problem is we can't overwrite running code and
> > once the guest is re-sited to the target, the OVMF there has to
> > match exactly what was on the source for the RT to still
> > function.   Once the migration has run, the OVMF on the target must
> > be identical to what was on the source (including internally
> > allocated OVMF memory), and if we can't copy the MH code, we have
> > to rely on the target image providing this identical code and we
> > copy the rest.
> 
> I'm OK with the OVMF now being part of the guest image, and having to
> exist on both; it's a bit delicate though unless we have a way to
> check it (is there an attest of the destination happening here?)

There will be in the final version.  The attestations of the source and
target, being the hash of the OVMF (with the registers in the -ES
case), should be the same (modulo any firmware updates to the PSP,
whose firmware version is also hashed) to guarantee the OVMF is the
same on both sides.  We'll definitely take an action to get QEMU to
verify this ... made a lot easier now we have signed attestations ...

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-19 Thread James Bottomley
On Thu, 2021-08-19 at 09:22 +0100, Dr. David Alan Gilbert wrote:
> * Tobin Feldman-Fitzthum (to...@linux.ibm.com) wrote:
> > On 8/18/21 3:04 PM, Dr. David Alan Gilbert wrote:
> > > * Tobin Feldman-Fitzthum (to...@linux.ibm.com) wrote:
> > > > On 8/17/21 6:04 PM, Steve Rutherford wrote:
> > > > > Ahh, It sounds like you are looking into sidestepping the
> > > > > existing AMD-SP flows for migration. I assume the idea is to
> > > > > spin up a VM on the target side, and have the two VMs attest
> > > > > to each other. How do the two sides know if the other is
> > > > > legitimate? I take it that the source is directing the LAUNCH
> > > > > flows?
> > > >  
> > > > Yeah we don't use PSP migration flows at all. We don't need to
> > > > send the MH code from the source to the target because the MH
> > > > lives in firmware, which is common between the two.
> > >  
> > > Are you relying on the target firmware to be *identical* or
> > > purely for it to be *compatible* ?  It's normal for a migration
> > > to be the result of wanting to do an upgrade; and that means the
> > > destination build of OVMF might be newer (or older, or ...).
> > > 
> > > Dave
> > 
> > This is a good point. The migration handler on the source and
> > target must have the same memory footprint or bad things will
> > happen. Using the same firmware on the source and target is an easy
> > way to guarantee this. Since the MH in OVMF is not a contiguous
> > region of memory, but a group of functions scattered around OVMF,
> > it is a bit difficult to guarantee that the memory footprint is the
> > same if the build is different.
> 
> Can you explain what the 'memory footprint' consists of? Can't it
> just be the whole of the OVMF rom space if you have no way of nudging
> the MH into it's own chunk?

It might be possible depending on how we link it. At the moment it's
using the core OVMF libraries, but it is possible to retool the OVMF
build to copy those libraries into the MH DXE.

> I think it really does have to cope with migration to a new version
> of host.

Well, you're thinking of OVMF as belonging to the host because of the
way it is supplied, but think about the way it works in practice now,
forgetting about confidential computing: OVMF is RAM resident in
ordinary guests, so when you migrate them, the whole of OVMF (or at
least what's left at runtime) goes with the migration, thus it's not
possible to change the guest OVMF by migration.  The above is really
just an extension of that principle, the only difference for
confidential computing being you have to have an image of the current
OVMF ROM in the target to seed migration.

Technically, the problem is we can't overwrite running code and once
the guest is re-sited to the target, the OVMF there has to match
exactly what was on the source for the RT to still function.   Once the
migration has run, the OVMF on the target must be identical to what was
on the source (including internally allocated OVMF memory), and if we
can't copy the MH code, we have to rely on the target image providing
this identical code and we copy the rest.

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-18 Thread James Bottomley
On Wed, 2021-08-18 at 18:30 +0100, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > On Wed, 2021-08-18 at 16:43 +0100, Dr. David Alan Gilbert wrote:
> > > * James Bottomley (j...@linux.ibm.com) wrote:
> > [...]
> > > > Given the lack of SMI, we can't guarantee that with plain SEV
> > > > and -ES. Once we move to -SNP, we can use VMPLs to achieve
> > > > this.
> > > 
> > > Doesn't the MH have access to different slots and running on
> > > separate vCPUs; so it's still got some separation?
> > 
> > Remember that the OVMF code is provided by the host, but its
> > attested to and run by the guest.  Once the guest takes control
> > (i.e. after OVMF boots the next thing), we can't guarantee that it
> > wont overwrite the MH code, so the host must treat the MH as
> > untrusted.
> 
> Yeh; if it's in a romimage I guess we could write protect it?
> (Not that I'd trust it still)

Yes, but unfortunately OVMF (and edk2 in general) has another pitfall
for you: the initial pflash may be a read only ROM image, but it
uncompresses itself to low RAM and executes itself out of there. 
Anything in either PEI or DXE (which is where the migration handler
lies) is RAM based after decompression.

> > > > But realistically, given the above API, even if the guest is
> > > > malicious, what can it do?  I think it's simply return bogus
> > > > pages that cause a crash on start after migration, which
> > > > doesn't look like a huge risk to the cloud to me (it's more a
> > > > self destructive act on behalf of the guest).
> > > 
> > > I'm a bit worried about the data structures that are shared
> > > between the migration code in qemu and the MH; the code in qemu
> > > is going to have to be paranoid about not trusting anything
> > > coming from the MH.
> > 
> > Given that we have to treat the host MH structure as untrusted,
> > this is definitely something we have to do.  Although the primary
> > API is simply "here's a buffer, please fill it", so there's not
> > much checking to do, we just have to be careful that we don't
> > expose any more of the buffer than the guest needs to write to ...
> > and, obviously, clean it before exposing it to the guest.
> 
> I was assuming life got a bit more complicated than that; and we had
> to have lists of pages we were requesting, and a list of pages that
> were cooked and the qemu thread and the helper thread all had to work
> in parallel.  So I'm guessing some list or bookkeeeping that we need
> to be very careful of.

I was more or less imagining a GPA address and length, so range based,
but it could be we need something more sophisticated ... Tobin will
look after that part.  However, either way, we just need to be careful.

Regards,

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-18 Thread James Bottomley
On Wed, 2021-08-18 at 16:43 +0100, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
[...]
> > Given the lack of SMI, we can't guarantee that with plain SEV and
> > -ES. Once we move to -SNP, we can use VMPLs to achieve this.
> 
> Doesn't the MH have access to different slots and running on separate
> vCPUs; so it's still got some separation?

Remember that the OVMF code is provided by the host, but its attested
to and run by the guest.  Once the guest takes control (i.e. after OVMF
boots the next thing), we can't guarantee that it wont overwrite the MH
code, so the host must treat the MH as untrusted.

> > But realistically, given the above API, even if the guest is
> > malicious, what can it do?  I think it's simply return bogus pages
> > that cause a crash on start after migration, which doesn't look
> > like a huge risk to the cloud to me (it's more a self destructive
> > act on behalf of the guest).
> 
> I'm a bit worried about the data structures that are shared between
> the migration code in qemu and the MH; the code in qemu is going to
> have to be paranoid about not trusting anything coming from the MH.

Given that we have to treat the host MH structure as untrusted, this is
definitely something we have to do.  Although the primary API is simply
"here's a buffer, please fill it", so there's not much checking to do,
we just have to be careful that we don't expose any more of the buffer
than the guest needs to write to ... and, obviously, clean it before
exposing it to the guest.

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-18 Thread James Bottomley
On Wed, 2021-08-18 at 16:31 +0100, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > On Wed, 2021-08-18 at 10:31 +, Ashish Kalra wrote:
> > > Hello Paolo,
> > > 
> > > On Mon, Aug 16, 2021 at 05:38:55PM +0200, Paolo Bonzini wrote:
> > > > On 16/08/21 17:13, Ashish Kalra wrote:
> > > > > > > I think that once the mirror VM starts booting and
> > > > > > > running the UEFI code, it might be only during the PEI or
> > > > > > > DXE phase where it will start actually running the MH
> > > > > > > code, so mirror VM probably still need to handles
> > > > > > > KVM_EXIT_IO when SEC phase does I/O, I can see PIC
> > > > > > > accesses and Debug Agent initialization stuff in SEC
> > > > > > > startup code.
> > > > > > That may be a design of the migration helper code that you
> > > > > > were working with, but it's not necessary.
> > > > > > 
> > > > > Actually my comments are about a more generic MH code.
> > > > 
> > > > I don't think that would be a good idea; designing QEMU's
> > > > migration helper interface to be as constrained as possible is
> > > > a good thing.  The migration helper is extremely security
> > > > sensitive code, so it should not expose itself to the attack
> > > > surface of the whole of QEMU.
> > 
> > The attack surface of the MH in the guest is simply the API.  The
> > API needs to do two things:
> > 
> >1. validate a correct endpoint and negotiate a wrapping key
> >2. When requested by QEMU, wrap a section of guest encrypted
> > memory
> >   with the wrapping key and return it.
> > 
> > The big security risk is in 1. if the MH can be tricked into
> > communicating with the wrong endpoint it will leak the entire
> > guest.  If we can lock that down, I don't see any particular
> > security problem with 2. So, provided we get the security
> > properties of the API correct, I think we won't have to worry over
> > much about exposure of the API.
> 
> Well, we'd have to make sure it only does stuff on behalf of qemu; if
> the guest can ever write to MH's memory it could do something that
> the guest shouldn't be able to.

Given the lack of SMI, we can't guarantee that with plain SEV and -ES. 
Once we move to -SNP, we can use VMPLs to achieve this.

But realistically, given the above API, even if the guest is malicious,
what can it do?  I think it's simply return bogus pages that cause a
crash on start after migration, which doesn't look like a huge risk to
the cloud to me (it's more a self destructive act on behalf of the
guest).

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-18 Thread James Bottomley
On Wed, 2021-08-18 at 10:31 +, Ashish Kalra wrote:
> Hello Paolo,
> 
> On Mon, Aug 16, 2021 at 05:38:55PM +0200, Paolo Bonzini wrote:
> > On 16/08/21 17:13, Ashish Kalra wrote:
> > > > > I think that once the mirror VM starts booting and running
> > > > > the UEFI code, it might be only during the PEI or DXE phase
> > > > > where it will start actually running the MH code, so mirror
> > > > > VM probably still need to handles KVM_EXIT_IO when SEC phase
> > > > > does I/O, I can see PIC accesses and Debug Agent
> > > > > initialization stuff in SEC startup code.
> > > > That may be a design of the migration helper code that you were
> > > > working with, but it's not necessary.
> > > > 
> > > Actually my comments are about a more generic MH code.
> > 
> > I don't think that would be a good idea; designing QEMU's migration
> > helper interface to be as constrained as possible is a good
> > thing.  The migration helper is extremely security sensitive code,
> > so it should not expose itself to the attack surface of the whole
> > of QEMU.

The attack surface of the MH in the guest is simply the API.  The API
needs to do two things:

   1. validate a correct endpoint and negotiate a wrapping key
   2. When requested by QEMU, wrap a section of guest encrypted memory
  with the wrapping key and return it.

The big security risk is in 1. if the MH can be tricked into
communicating with the wrong endpoint it will leak the entire guest. 
If we can lock that down, I don't see any particular security problem
with 2. So, provided we get the security properties of the API correct,
I think we won't have to worry over much about exposure of the API.

> > One question i have here, is that where exactly will the MH code
> exist in QEMU ?

I assume it will be only x86 platform specific code, we probably will
never support it on other platforms ?

So it will probably exist in hw/i386, something similar to "microvm"
support and using the same TYPE_X86_MACHINE ?

I don't think it should be x86 only.  The migration handler receiver
should be completely CPU agnostic.  It's possible other CPUs will grow
an encrypted memory confidential computing capability (Power already
has one and ARM is "thinking" about it, but even if it doesn't, there's
a similar problem if you want to use trustzone isolation in VMs).  I
would envisage migration working substantially similarly on all of them
(need to ask an agent in the guest to wrap an encrypted page for
transport) so I think we should add this capability to the generic QEMU
migration code and let other architectures take advantage of it as they
grow the facility.

> Also if we are not going to use the existing KVM support code and
> adding some duplicate KVM interface code, do we need to interface
> with this added KVM code via the QEMU accelerator framework, or
> simply invoke this KVM code statically ?

I think we need to design the interface as cleanly as possible, so it
just depends what's easiest.  We certainly need some KVM support for
the mirror CPUs, I think but it's not clear to me yet what the simplest
way to do the interface is.

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-17 Thread James Bottomley
On Tue, 2021-08-17 at 16:10 -0700, Steve Rutherford wrote:
> On Tue, Aug 17, 2021 at 3:57 PM James Bottomley 
> wrote:
> > Realistically, migration is becoming a royal pain, not just for
> > confidential computing, but for virtual functions in general.  I
> > really think we should look at S3 suspend, where we shut down the
> > drivers and then reattach on S3 resume as the potential pathway to
> > getting migration working both for virtual functions and this use
> > case.
> 
> This type of migration seems a little bit less "live", which makes me
> concerned about its performance characteristics.

Well, there are too many scenarios we just fail at migration today.  We
need help from the guest to quiesce or shut down the interior devices,
and S3 suspend seems to be the machine signal for that.  I think in
most clouds guests would accept some loss of "liveness" for a gain in
reliability as long as we keep them within the SLA ... which is 5
minutes a year for 5 nines.  Most failed migrations also instantly fail
SLAs because of the recovery times involved so I don't see what's to be
achieved by keeping the current "we can migrate sometimes" approach.

James





Re: [RFC PATCH 00/13] Add support for Mirror VM.

2021-08-17 Thread James Bottomley
On Wed, 2021-08-18 at 00:37 +0200, Paolo Bonzini wrote:
> On Tue, Aug 17, 2021 at 11:54 PM Steve Rutherford
>  wrote:
> > > 1) the easy one: the bottom 4G of guest memory are mapped in the
> > > mirror
> > > VM 1:1.  The ram_addr_t-based addresses are shifted by either 4G
> > > or a
> > > huge value such as 2^42 (MAXPHYADDR - physical address reduction
> > > - 1).
> > > This even lets the migration helper reuse the OVMF runtime
> > > services
> > > memory map (but be careful about thread safety...).
> > 
> > If I understand what you are proposing, this would only work for
> > SEV/SEV-ES, since the RMP prevents these remapping games. This
> > makes
> > me less enthusiastic about this (but I suspect that's why you call
> > this less future proof).
> 
> I called it less future proof because it allows the migration helper
> to rely more on OVMF details, but those may not apply in the future.
> 
> However you're right about SNP; the same page cannot be mapped twice
> at different GPAs by a single ASID (which includes the VM and the
> migration helper). :( That does throw a wrench in the idea of mapping
> pages by ram_addr_t(*), and this applies to both schemes.

Right, but in the current IBM approach, since we use the same mapping
for guest and mirror, we have the same GPA in both and it should work
with -SNP.

> Migrating RAM in PCI BARs is a mess anyway for SNP, because PCI BARs
> can be moved and every time they do the migration helper needs to
> wait for validation to happen. :(

Realistically, migration is becoming a royal pain, not just for
confidential computing, but for virtual functions in general.  I really
think we should look at S3 suspend, where we shut down the drivers and
then reattach on S3 resume as the potential pathway to getting
migration working both for virtual functions and this use case.

James





Re: [PULL 02/19] sev: update sev-inject-launch-secret to make gpa optional

2021-05-20 Thread James Bottomley
On Thu, 2021-05-20 at 23:36 +0200, Philippe Mathieu-Daudé wrote:
> On 2/15/21 2:16 PM, Paolo Bonzini wrote:
> > From: James Bottomley 
> > 
> > If the gpa isn't specified, it's value is extracted from the OVMF
> > properties table located below the reset vector (and if this
> > doesn't
> > exist, an error is returned).  OVMF has defined the GUID for the
> > SEV
> > secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format
> > of
> > the  is: | where both are uint32_t.  We extract
> >  and use it as the gpa for the injection.
> > 
> > Note: it is expected that the injected secret will also be GUID
> > described but since qemu can't interpret it, the format is left
> > undefined here.
> > 
> > Signed-off-by: James Bottomley 
> > 
> > Reviewed-by: Dr. David Alan Gilbert 
> > Message-Id: <20210204193939.16617-3-j...@linux.ibm.com>
> > Signed-off-by: Paolo Bonzini 
> > ---
> >  qapi/misc-target.json |  2 +-
> >  target/i386/monitor.c | 23 ++-
> >  2 files changed, 23 insertions(+), 2 deletions(-)
> > 
> > diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> > index 06ef8757f0..0c7491cd82 100644
> > --- a/qapi/misc-target.json
> > +++ b/qapi/misc-target.json
> > @@ -216,7 +216,7 @@
> >  #
> >  ##
> >  { 'command': 'sev-inject-launch-secret',
> > -  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa':
> > 'uint64' },
> > +  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa':
> > 'uint64' },
> >'if': 'defined(TARGET_I386)' }
> >  
> >  ##
> > diff --git a/target/i386/monitor.c b/target/i386/monitor.c
> > index 1bc91442b1..5994408bee 100644
> > --- a/target/i386/monitor.c
> > +++ b/target/i386/monitor.c
> > @@ -34,6 +34,7 @@
> >  #include "sev_i386.h"
> >  #include "qapi/qapi-commands-misc-target.h"
> >  #include "qapi/qapi-commands-misc.h"
> > +#include "hw/i386/pc.h"
> >  
> >  /* Perform linear address sign extension */
> >  static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
> > @@ -730,9 +731,29 @@ SevCapability
> > *qmp_query_sev_capabilities(Error **errp)
> >  return sev_get_capabilities(errp);
> >  }
> >  
> > +#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
> > +struct sev_secret_area {
> > +uint32_t base;
> > +uint32_t size;
> > +};
> > +
> >  void qmp_sev_inject_launch_secret(const char *packet_hdr,
> > -  const char *secret, uint64_t
> > gpa,
> > +  const char *secret,
> > +  bool has_gpa, uint64_t gpa,
> >Error **errp)
> >  {
> > +if (!has_gpa) {
> > +uint8_t *data;
> > +struct sev_secret_area *area;
> > +
> > +if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, ,
> > NULL)) {
> 
> FYI trying to build MicroVM standalone (--without-default-devices):
> 
> /usr/bin/ld: libqemu-i386-softmmu.fa.p/target_i386_monitor.c.o: in
> function `qmp_sev_inject_launch_secret':
> target/i386/monitor.c:749: undefined reference to
> `pc_system_ovmf_table_find'
> 
> I'm adding this to my TODO list.

I'm pretty clueless with the new meson build system but I think this is
something to do with CONFIG_PC not being defined ... can you verify? in
which case it could be fixed with a pc_sysfw-stub.c that builds it as a
function returning false.

James





Re: Interactive launch over QMP socket?

2021-02-10 Thread James Bottomley
On Wed, 2021-02-10 at 12:46 -0600, Connor Kuehl wrote:
> On 2/10/21 12:14 PM, James Bottomley wrote:
> > > I would like to add a message type to QMP which allows guest
> > > owners to supply this data over a socket and _not_ require these
> > > components a priori via command line arguments. In doing so, this
> > > would allow for a 100% remote attestation process over the
> > > socket. However, I'm not sure how to express this interactive
> > > "waiting" for this data to become available with internal APIs
> > > (assuming it's not supplied as a command  line argument).
> > 
> > Well, I never understood why qemu can't deduce the value of cbitpos
> > ... it even errors out if you get it wrong.  However, other things
> > like the policy and the session file have to be present at start of
> > day. They're not things that can be passed in after qemu starts
> > building the machine image because they need to be present to begin
> > building it.
> 
> Right, I didn't mean to include cbitpos in consideration for this.
> I'm only interested in supplying the session, policy, and certificate
> info over the socket.
> 
> Shouldn't the session, policy, and certificate information only be 
> required in time for the KVM_SEV_LAUNCH_START ioctl call? This is
> the place I'm interested in waiting for the relevant data.

Well, it could, but I see the session information as being the same as
the image file, which is also a command line argument, so if you can do
the image file on the command line, why not the session info as well?

The other problem is the session info is exchanged for a launch handle
in kvm_init, which is machine_init in qemu terms.  That's called
phenomenally early, so there's not much of kvm to pause before you do
that.  So either qemu has to be rewritten to pause before processing
command line arguments, and then any argument can be added over QMP, or
the handle exchange has to occur later.

James





Re: Interactive launch over QMP socket?

2021-02-10 Thread James Bottomley
On Wed, 2021-02-10 at 12:01 -0600, Connor Kuehl wrote:
> Hello,
> 
> Does QEMU have an internal API which would allow VM construction to
> wait at a *very specific point* until specific data/QMP message(s)
> are supplied via the QMP socket?

Yes, the -S flag tells qemu to pause before starting the VM but after
setting it up.  It's the flag I use for SEV.

> For some additional context: QEMU supports launching AMD SEV-
> protected guests; in short: encrypted virtual machines. Guest owners
> may participate in attestation to cryptographically verify their
> assumptions about the guest's initial state, the host's platform, and
> the host platform owner's identity. If the guest owner is satisfied
> with the attestation process, a secret can be safely injected into
> the guest's address space over a secure channel.
> 
> Attestation is an unavoidably interactive process.
> 
> It appears that QEMU already exposes most of the API required to
> perform this attestation remotely with a guest owner over QMP, with
> only one exception: starting the attestation session. It looks like
> the session  components (policy, session-file, and dh-cert-file) are
> supplied via command line arguments to QEMU and don't have a message
> type in the QMP spec:
> 
>   -object 
> sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x1,session-
> file=blah.session,dh-cert-file=guest_owner.cert
> 
> I would like to add a message type to QMP which allows guest owners
> to supply this data over a socket and _not_ require these components
> a priori via command line arguments. In doing so, this would allow
> for a 100% remote attestation process over the socket. However, I'm
> not sure how to express this interactive "waiting" for this data to
> become available with internal APIs (assuming it's not supplied as a
> command  line argument).

Well, I never understood why qemu can't deduce the value of cbitpos ...
it even errors out if you get it wrong.  However, other things like the
policy and the session file have to be present at start of day. 
They're not things that can be passed in after qemu starts building the
machine image because they need to be present to begin building it.

> For example, in order to accomplish a 100% remote attestation:
> 
> Somewhere in between sev_guest_init() and sev_launch_start(), the
> guest owner may send the following messages:
> 
> 1. "query-sev" to collect important information about the platform
> state
> 
> 2. "query-sev-capabilities" to independently verify the platform 
> certificate chain and derive a shared secret for establishing a
> secure channel with the AMD SP.
> 
> 3. "sev-launch-start" this is the only message that I think is
> missing from the QMP message types for remote attestation. This is
> how the guest owner would deliver the session components over the
> socket instead of as command line arguments.

The patch for remote attestation (which was only recently added to the
PSP protocol) is here:

https://lore.kernel.org/kvm/20210105163943.30510-1-brijesh.si...@amd.com/

> Then, sometime before the VM is launched and is running, the guest
> owner may send:
> 
> 4. "query-sev-launch-measure" to compare its measurement against the
> AMD SP's measurement
> 
> 5. "sev-inject-launch-secret" if happy with attestation, securely 
> deliver secrets
> 
> 6. Guest owner could send a "cont" command and the VM can launch
> 
> Any advice on how to accomplish adding this degree of interaction to 
> supplying inputs to specific parts of the launch process this is
> greatly appreciated.

I've attached the python script I use to launch sev guests.  However,
it doesn't include the launch bundle because that has to have already
been passed in when qemu was started.

James

---
#!/usr/bin/python3
##
# Python script to inject a secret disk password into a paused SEV VM
#  (to pause the VM start with -S option)
#
# This assumes you've already created the launch bundle using sev-tool
# from https://github.com/AMDESE/sev-tool.git
#
# sev-tool --generate_launch_blob
#
# creates several files, the only one this script needs is the TIK and TEK
# keys which are stored in tmp_tk.bin
#
# Once TIK/TEK are known, the script will probe the VM for the sev
# parameters needed to calculate the launch measure, retrieve the launch
# measure and verify against the measure calculated from the OVMF hash
# and if that matches create the secret bundle and inject it
#
# Tables and chapters refer to the amd 55766.pdf document
#
# https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
##
import sys
import os 
import base64
import hmac
import hashlib
from argparse import ArgumentParser
from uuid import UUID
from Crypto.Cipher import AES
from Crypto.Util import Counter
from git.qemu.python.qemu import qmp

if __name__ == "__main__":
parser = ArgumentParser(description='Inject secret into SEV')
parser.add_argument('--tiktek-file',
help='file where sev-tool stored the 

[PATCH v3 2/2] sev: update sev-inject-launch-secret to make gpa optional

2021-02-04 Thread James Bottomley
If the gpa isn't specified, it's value is extracted from the OVMF
properties table located below the reset vector (and if this doesn't
exist, an error is returned).  OVMF has defined the GUID for the SEV
secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format of
the  is: | where both are uint32_t.  We extract
 and use it as the gpa for the injection.

Note: it is expected that the injected secret will also be GUID
described but since qemu can't interpret it, the format is left
undefined here.

Signed-off-by: James Bottomley 

---

v2: fix line length warning, add more comments about sev area
v2: remove misleading comment
---
 qapi/misc-target.json |  2 +-
 target/i386/monitor.c | 23 ++-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 06ef8757f0..0c7491cd82 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -216,7 +216,7 @@
 #
 ##
 { 'command': 'sev-inject-launch-secret',
-  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa': 'uint64' },
+  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' },
   'if': 'defined(TARGET_I386)' }
 
 ##
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 1bc91442b1..5994408bee 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -34,6 +34,7 @@
 #include "sev_i386.h"
 #include "qapi/qapi-commands-misc-target.h"
 #include "qapi/qapi-commands-misc.h"
+#include "hw/i386/pc.h"
 
 /* Perform linear address sign extension */
 static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
@@ -730,9 +731,29 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
 return sev_get_capabilities(errp);
 }
 
+#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
+struct sev_secret_area {
+uint32_t base;
+uint32_t size;
+};
+
 void qmp_sev_inject_launch_secret(const char *packet_hdr,
-  const char *secret, uint64_t gpa,
+  const char *secret,
+  bool has_gpa, uint64_t gpa,
   Error **errp)
 {
+if (!has_gpa) {
+uint8_t *data;
+struct sev_secret_area *area;
+
+if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, , NULL)) {
+error_setg(errp, "SEV: no secret area found in OVMF,"
+   " gpa must be specified.");
+return;
+}
+area = (struct sev_secret_area *)data;
+gpa = area->base;
+}
+
 sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
 }
-- 
2.26.2




[PATCH v3 1/2] pc: add parser for OVMF reset block

2021-02-04 Thread James Bottomley
OVMF is developing a mechanism for depositing a GUIDed table just
below the known location of the reset vector.  The table goes
backwards in memory so all entries are of the form

|len|

Where  is arbtrary size and type,  is a uint16_t and
describes the entire length of the entry from the beginning of the
data to the end of the guid.

The foot of the table is of this form and  for this case
describes the entire size of the table.  The table foot GUID is
defined by OVMF as 96b582de-1fb2-45f7-baea-a366c55a082d and if the
table is present this GUID is just below the reset vector, 48 bytes
before the end of the firmware file.

Add a parser for the ovmf reset block which takes a copy of the block,
if the table foot guid is found, minus the footer and a function for
later traversal to return the data area of any specified GUIDs.

Signed-off-by: James Bottomley 

---

v2: fix brace warnings and return values
v3: add bounds checking for flash tables
---
 hw/i386/pc_sysfw.c   | 112 +++
 include/hw/i386/pc.h |   4 ++
 2 files changed, 116 insertions(+)

diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 92e90ff013..8ef73dbc3a 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -124,6 +124,113 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
 }
 }
 
+#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
+
+static uint8_t *ovmf_table;
+static int ovmf_table_len;
+
+static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
+{
+uint8_t *ptr;
+QemuUUID guid;
+int tot_len;
+
+/* should only be called once */
+if (ovmf_table) {
+return;
+}
+
+if (flash_size < TARGET_PAGE_SIZE) {
+return;
+}
+
+/*
+ * if this is OVMF there will be a table footer
+ * guid 48 bytes before the end of the flash file.  If it's
+ * not found, silently abort the flash parsing.
+ */
+qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, );
+guid = qemu_uuid_bswap(guid); /* guids are LE */
+ptr = flash_ptr + flash_size - 48;
+if (!qemu_uuid_is_equal((QemuUUID *)ptr, )) {
+return;
+}
+
+/* if found, just before is two byte table length */
+ptr -= sizeof(uint16_t);
+tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);
+
+if (tot_len <= 0) {
+return;
+}
+
+ovmf_table = g_malloc(tot_len);
+ovmf_table_len = tot_len;
+
+/*
+ * ptr is the foot of the table, so copy it all to the newly
+ * allocated ovmf_table and then set the ovmf_table pointer
+ * to the table foot
+ */
+memcpy(ovmf_table, ptr - tot_len, tot_len);
+ovmf_table += tot_len;
+}
+
+bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
+   int *data_len)
+{
+uint8_t *ptr = ovmf_table;
+int tot_len = ovmf_table_len;
+QemuUUID entry_guid;
+
+if (qemu_uuid_parse(entry, _guid) < 0) {
+return false;
+}
+
+if (!ptr) {
+return false;
+}
+
+entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
+while (tot_len >= sizeof(QemuUUID) + sizeof(uint16_t)) {
+int len;
+QemuUUID *guid;
+
+/*
+ * The data structure is
+ *   arbitrary length data
+ *   2 byte length of entire entry
+ *   16 byte guid
+ */
+guid = (QemuUUID *)(ptr - sizeof(QemuUUID));
+len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) -
+sizeof(uint16_t)));
+
+/*
+ * just in case the table is corrupt, wouldn't want to spin in
+ * the zero case
+ */
+if (len < sizeof(QemuUUID) + sizeof(uint16_t)) {
+return false;
+} else if (len > tot_len) {
+return false;
+}
+
+ptr -= len;
+tot_len -= len;
+if (qemu_uuid_is_equal(guid, _guid)) {
+if (data) {
+*data = ptr;
+}
+if (data_len) {
+*data_len = len - sizeof(QemuUUID) - sizeof(uint16_t);
+}
+return true;
+}
+}
+return false;
+}
+
 /*
  * Map the pcms->flash[] from 4GiB downward, and realize.
  * Map them in descending order, i.e. pcms->flash[0] at the top,
@@ -195,6 +302,11 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+/*
+ * OVMF places a GUIDed structures in the flash, so
+ * search for them
+ */
+pc_system_parse_ovmf_flash(flash_ptr, flash_size);
 ret = kvm_memcrypt_encrypt_data(flash_ptr, flash_size);
 if (ret) {
 error_report("failed to encrypt pflash r

[PATCH v3 0/2] sev: enable secret injection to a self described area in OVMF

2021-02-04 Thread James Bottomley
v3: add bounds checking and remove misleading comment

v2: fix build issues and update comments.  Also drop the first patch
which is now merged upstream

The two patches introduce a parser for the optional OVMF description
table which is placed just below the reset vector (the format of the
table is described in the patch itself) and also adds a hook to pull
out the description of the SEV secret area location and use it in
place of the sev-inject-launch-secret gpa.

James

---

James Bottomley (2):
  pc: add parser for OVMF reset block
  sev: update sev-inject-launch-secret to make gpa optional

 hw/i386/pc_sysfw.c| 112 ++
 include/hw/i386/pc.h  |   4 ++
 qapi/misc-target.json |   2 +-
 target/i386/monitor.c |  23 -
 4 files changed, 139 insertions(+), 2 deletions(-)

-- 
2.26.2




Re: [PATCH v2 2/2] sev: update sev-inject-launch-secret to make gpa optional

2021-02-02 Thread James Bottomley
On Tue, 2021-01-26 at 12:32 +, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > If the gpa isn't specified, it's value is extracted from the OVMF
> > properties table located below the reset vector (and if this
> > doesn't
> > exist, an error is returned).  OVMF has defined the GUID for the
> > SEV
> > secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format
> > of
> > the  is: | where both are uint32_t.  We extract
> >  and use it as the gpa for the injection.
> > 
> > Note: it is expected that the injected secret will also be GUID
> > described but since qemu can't interpret it, the format is left
> > undefined here.
> > 
> > Signed-off-by: James Bottomley 
> > 
> > ---
> > 
> > v2: fix line length warning, add more comments about sev area
> > ---
> >  qapi/misc-target.json |  2 +-
> >  target/i386/monitor.c | 27 ++-
> >  2 files changed, 27 insertions(+), 2 deletions(-)
> > 
> > diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> > index 06ef8757f0..0c7491cd82 100644
> > --- a/qapi/misc-target.json
> > +++ b/qapi/misc-target.json
> > @@ -216,7 +216,7 @@
> >  #
> >  ##
> >  { 'command': 'sev-inject-launch-secret',
> > -  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa':
> > 'uint64' },
> > +  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa':
> > 'uint64' },
> >'if': 'defined(TARGET_I386)' }
> >  
> >  ##
> > diff --git a/target/i386/monitor.c b/target/i386/monitor.c
> > index 1bc91442b1..11bdb04155 100644
> > --- a/target/i386/monitor.c
> > +++ b/target/i386/monitor.c
> > @@ -34,6 +34,7 @@
> >  #include "sev_i386.h"
> >  #include "qapi/qapi-commands-misc-target.h"
> >  #include "qapi/qapi-commands-misc.h"
> > +#include "hw/i386/pc.h"
> >  
> >  /* Perform linear address sign extension */
> >  static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
> > @@ -730,9 +731,33 @@ SevCapability
> > *qmp_query_sev_capabilities(Error **errp)
> >  return sev_get_capabilities(errp);
> >  }
> >  
> > +#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
> > +struct sev_secret_area {
> > +uint32_t base;
> > +uint32_t size;
> > +};
> > +
> >  void qmp_sev_inject_launch_secret(const char *packet_hdr,
> > -  const char *secret, uint64_t
> > gpa,
> > +  const char *secret,
> > +  bool has_gpa, uint64_t gpa,
> >Error **errp)
> >  {
> > +if (!has_gpa) {
> > +uint8_t *data;
> > +struct sev_secret_area *area;
> > +
> > +/*
> > + * not checking length means that this area can't be
> > versioned
> > + * by length and would have to be replaced if updated
> > + */
> 
> Can you just explain that a bit more?

It's referring back to the original concept that the reset vector
length would tell you what version of the thing you were using.  So if
you were looking for a property at offset 10 and the length came in as
8 the version was too early.  If it was 18 you had a later version and
your property was present.

The current scheme uses guids which can be versioned by length if you
think you'll add extra properties to them.  This one I don't think
would ever get an extra property, so there's no point checking the
length.  Not checking the length means if I'm wrong and we do need an
extra property it will have to be attached to a new guid.

That's a bit confusing to add to the comment ... how about I just leave
out the comment entirely?

> > +if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, ,
> > NULL)) {
> > +error_setg(errp, "SEV: no secret area found in OVMF,"
> > +   " gpa must be specified.");
> > +return;
> > +}
> > +area = (struct sev_secret_area *)data;
> > +gpa = area->base;
> > +}
> > +
> >  sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
> 
> Other than me not understanding that comment, I think we're fine:

Thanks.

> Reviewed-by: Dr. David Alan Gilbert 
> 
> >  }
> > -- 
> > 2.26.2
> > 
> > 





Re: [PATCH v2 1/2] pc: add parser for OVMF reset block

2021-02-02 Thread James Bottomley
On Tue, 2021-01-26 at 12:22 +, Dr. David Alan Gilbert wrote:
> * James Bottomley (j...@linux.ibm.com) wrote:
> > OVMF is developing a mechanism for depositing a GUIDed table just
> > below the known location of the reset vector.  The table goes
> > backwards in memory so all entries are of the form
> > 
> > |len|
> > 
> > Where  is arbtrary size and type,  is a uint16_t and
> > describes the entire length of the entry from the beginning of the
> > data to the end of the guid.
> > 
> > The foot of the table is of this form and  for this case
> > describes the entire size of the table.  The table foot GUID is
> > defined by OVMF as 96b582de-1fb2-45f7-baea-a366c55a082d and if the
> > table is present this GUID is just below the reset vector, 48 bytes
> > before the end of the firmware file.
> > 
> > Add a parser for the ovmf reset block which takes a copy of the
> > block,
> > if the table foot guid is found, minus the footer and a function
> > for
> > later traversal to return the data area of any specified GUIDs.
> > 
> > Signed-off-by: James Bottomley 
> > 
> > ---
> > 
> > v2: fix brace warnings and return values
> > ---
> >  hw/i386/pc_sysfw.c   | 106
> > +++
> >  include/hw/i386/pc.h |   4 ++
> >  2 files changed, 110 insertions(+)
> > 
> > diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
> > index 92e90ff013..436b78c587 100644
> > --- a/hw/i386/pc_sysfw.c
> > +++ b/hw/i386/pc_sysfw.c
> > @@ -124,6 +124,107 @@ void
> > pc_system_flash_cleanup_unused(PCMachineState *pcms)
> >  }
> >  }
> >  
> > +#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-
> > a366c55a082d"
> > +
> > +static uint8_t *ovmf_table;
> > +static int ovmf_table_len;
> > +
> > +static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, int
> > flash_size)
> 
> Maybe size_t for flash_size?

Heh, sure, who knows how big OVMF will get ...  but I get the point
about an int overflow attack.

> > +{
> > +uint8_t *ptr;
> > +QemuUUID guid;
> > +int tot_len;
> > +
> > +/* should only be called once */
> > +if (ovmf_table) {
> > +return;
> > +}
> > +
> > +/*
> > + * if this is OVMF there will be a table footer
> > + * guid 48 bytes before the end of the flash file.  If it's
> > + * not found, silently abort the flash parsing.
> > + */
> > +qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, );
> > +guid = qemu_uuid_bswap(guid); /* guids are LE */
> > +ptr = flash_ptr + flash_size - 48;
> 
> I think since flash_size is coming from memory_region_size it's
> probably rounded to a page size by now, but perhaps we should always
> check we have enough space before we start moving pointers around

I think OVMF must be at least a page, so I can add that check.

> (Given that the OVMF binary might be provided by the guest owner, we
> have to consider it might be a vector to attack the hypervisor).
> 
> > +if (!qemu_uuid_is_equal((QemuUUID *)ptr, )) {
> > +return;
> > +}
> > +
> > +/* if found, just before is two byte table length */
> > +ptr -= sizeof(uint16_t);
> > +tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) -
> > sizeof(uint16_t);
> > +
> > +if (tot_len <= 0) {
> > +return;
> > +}
> > +
> > +ovmf_table = g_malloc(tot_len);
> > +ovmf_table_len = tot_len;
> > +
> > +/*
> > + * ptr is the foot of the table, so copy it all to the newly
> > + * allocated ovmf_table and then set the ovmf_table pointer
> > + * to the table foot
> > + */
> > +memcpy(ovmf_table, ptr - tot_len, tot_len);
> > +ovmf_table += tot_len;
> > +}
> > +
> > +bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
> > +   int *data_len)
> > +{
> > +uint8_t *ptr = ovmf_table;
> > +int tot_len = ovmf_table_len;
> > +QemuUUID entry_guid;
> > +
> > +if (qemu_uuid_parse(entry, _guid) < 0) {
> > +return false;
> > +}
> > +
> > +if (!ptr) {
> > +return false;
> > +}
> > +
> > +entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
> > +while (tot_len > 0) {
> > +int len;
> > +QemuUUID *guid;
> > +
> > +/*
> > + * The data structure i

Re: [PATCH v2] target/i386/sev: add support to query the attestation report

2021-01-05 Thread James Bottomley
On Tue, 2021-01-05 at 10:39 -0600, Brijesh Singh wrote:
> The SEV FW >= 0.23 added a new command that can be used to query the
> attestation report containing the SHA-256 digest of the guest memory
> and VMSA encrypted with the LAUNCH_UPDATE and sign it with the PEK.
> 
> Note, we already have a command (LAUNCH_MEASURE) that can be used to
> query the SHA-256 digest of the guest memory encrypted through the
> LAUNCH_UPDATE. The main difference between previous and this command
> is that the report is signed with the PEK and unlike the
> LAUNCH_MEASURE
> command the ATTESATION_REPORT command can be called while the guest
> is running.
> 
> Add a QMP interface "query-sev-attestation-report" that can be used
> to get the report encoded in base64.
> 
> Cc: James Bottomley 
> Cc: Tom Lendacky 
> Cc: Eric Blake 
> Cc: Paolo Bonzini 
> Cc: k...@vger.kernel.org
> Signed-off-by: Brijesh Singh 
> ---
> v2:
>   * add trace event.
>   * fix the goto to return NULL on failure.
>   * make the mnonce as a base64 encoded string

Yes, that fixes all my issues, thanks!

Reviewed-by: James Bottomley 
Tested-by: James Bottomley 

I've also attached a python script below which I've used to verify the
attestation.

James

---

#!/usr/bin/python3
##
# Python script get an attestation and verify it with the PEK
#
# This assumes you've already exported the pek.cert with sev-tool
# from https://github.com/AMDESE/sev-tool.git
#
# sev-tool --export_cert_chain
#
# creates several files, the only one this script needs is pek.cert
#
# Tables and chapters refer to the amd 55766.pdf document
#
# https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
##
import sys
import os 
import base64
import hashlib
from argparse import ArgumentParser
from Crypto.PublicKey import ECC
from Crypto.Math.Numbers import Integer
from git.qemu.python.qemu import qmp

if __name__ == "__main__":
parser = ArgumentParser(description='Inject secret into SEV')
parser.add_argument('--pek-cert',
help='The Platform DH certificate in binary form',
default='pek.cert')
parser.add_argument('--socket',
help='Socket to connect to QMP on, defaults to 
localhost:6550',
default='localhost:6550')
args = parser.parse_args()

if (args.socket[0] == '/'):
socket = args.socket
elif (':' in args.socket):
s = args.socket.split(':')
socket = (s[0], int(s[1]))
else:
parse.error('--socket must be : or /path/to/unix')

fh = open(args.pek_cert, 'rb')
pek = bytearray(fh.read())
curve = int.from_bytes(pek[16:20], byteorder='little')
curves = {
1: 'p256',
2: 'p384'
}
Qx = int.from_bytes(bytes(pek[20:92]), byteorder='little')
Qy = int.from_bytes(bytes(pek[92:164]), byteorder='little')

pubkey = ECC.construct(point_x=Qx, point_y=Qy, curve=curves[curve])

Qmp = qmp.QEMUMonitorProtocol(address=socket);
Qmp.connect()
caps = Qmp.command('query-sev')
print('SEV query found API={api-major}.{api-minor} build={build-id} 
policy={policy}\n'.format(**caps))

nonce=os.urandom(16)

report = Qmp.command('query-sev-attestation-report',
 mnonce=base64.b64encode(nonce).decode())

a = base64.b64decode(report['data'])

##
# returned data is formulated as Table 60. Attestation Report Buffer
##
rnonce = a[0:16]
rmeas = a[16:48]

if (nonce != rnonce):
sys.exit('returned nonce doesn\'t match input nonce')

policy = int.from_bytes(a[48:52], byteorder='little')
usage = int.from_bytes(a[52:56], byteorder='little')
algo = int.from_bytes(a[56:60], byteorder='little')

if (policy != caps['policy']):
sys.exit('Policy mismatch:', policy, '!=', caps['policy'])

if (usage != 0x1002):
sys.exit('error PEK is not specified in usage: ', usage)

if (algo == 0x2):
h = hashlib.sha256()
elif (algo == 0x102):
##
# The spec (6.8) says the signature must be ECDSA-SHA256 so this
# should be impossible, but it turns out to be the way our
# current test hardware produces its signature
##
h = hashlib.sha384()
else:
sys.exit('unrecognized signing algorithm: ', algo)

h.update(a[0:52])

sig = a[64:208]
r = int.from_bytes(sig[0:72],byteorder='little')
s = int.from_bytes(sig[72:144],byteorder='little')
##
# subtlety: r and s are little (AMD defined) z is big (crypto requirement)
##
z = int.from_bytes(h.digest(), byteorder='big')

##
# python crypto doesn't have a way of passing in r and s as
# integers and I'm not inclined to wrap them up as a big endian
# binary signature to have Signature.DSS unwrap them again, so
# call the _verify() private interface that does tak

[PATCH v2 2/2] sev: update sev-inject-launch-secret to make gpa optional

2020-12-14 Thread James Bottomley
If the gpa isn't specified, it's value is extracted from the OVMF
properties table located below the reset vector (and if this doesn't
exist, an error is returned).  OVMF has defined the GUID for the SEV
secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format of
the  is: | where both are uint32_t.  We extract
 and use it as the gpa for the injection.

Note: it is expected that the injected secret will also be GUID
described but since qemu can't interpret it, the format is left
undefined here.

Signed-off-by: James Bottomley 

---

v2: fix line length warning, add more comments about sev area
---
 qapi/misc-target.json |  2 +-
 target/i386/monitor.c | 27 ++-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 06ef8757f0..0c7491cd82 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -216,7 +216,7 @@
 #
 ##
 { 'command': 'sev-inject-launch-secret',
-  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa': 'uint64' },
+  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' },
   'if': 'defined(TARGET_I386)' }
 
 ##
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 1bc91442b1..11bdb04155 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -34,6 +34,7 @@
 #include "sev_i386.h"
 #include "qapi/qapi-commands-misc-target.h"
 #include "qapi/qapi-commands-misc.h"
+#include "hw/i386/pc.h"
 
 /* Perform linear address sign extension */
 static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
@@ -730,9 +731,33 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
 return sev_get_capabilities(errp);
 }
 
+#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
+struct sev_secret_area {
+uint32_t base;
+uint32_t size;
+};
+
 void qmp_sev_inject_launch_secret(const char *packet_hdr,
-  const char *secret, uint64_t gpa,
+  const char *secret,
+  bool has_gpa, uint64_t gpa,
   Error **errp)
 {
+if (!has_gpa) {
+uint8_t *data;
+struct sev_secret_area *area;
+
+/*
+ * not checking length means that this area can't be versioned
+ * by length and would have to be replaced if updated
+ */
+if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, , NULL)) {
+error_setg(errp, "SEV: no secret area found in OVMF,"
+   " gpa must be specified.");
+return;
+}
+area = (struct sev_secret_area *)data;
+gpa = area->base;
+}
+
 sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
 }
-- 
2.26.2




[PATCH v2 1/2] pc: add parser for OVMF reset block

2020-12-14 Thread James Bottomley
OVMF is developing a mechanism for depositing a GUIDed table just
below the known location of the reset vector.  The table goes
backwards in memory so all entries are of the form

|len|

Where  is arbtrary size and type,  is a uint16_t and
describes the entire length of the entry from the beginning of the
data to the end of the guid.

The foot of the table is of this form and  for this case
describes the entire size of the table.  The table foot GUID is
defined by OVMF as 96b582de-1fb2-45f7-baea-a366c55a082d and if the
table is present this GUID is just below the reset vector, 48 bytes
before the end of the firmware file.

Add a parser for the ovmf reset block which takes a copy of the block,
if the table foot guid is found, minus the footer and a function for
later traversal to return the data area of any specified GUIDs.

Signed-off-by: James Bottomley 

---

v2: fix brace warnings and return values
---
 hw/i386/pc_sysfw.c   | 106 +++
 include/hw/i386/pc.h |   4 ++
 2 files changed, 110 insertions(+)

diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 92e90ff013..436b78c587 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -124,6 +124,107 @@ void pc_system_flash_cleanup_unused(PCMachineState *pcms)
 }
 }
 
+#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
+
+static uint8_t *ovmf_table;
+static int ovmf_table_len;
+
+static void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, int flash_size)
+{
+uint8_t *ptr;
+QemuUUID guid;
+int tot_len;
+
+/* should only be called once */
+if (ovmf_table) {
+return;
+}
+
+/*
+ * if this is OVMF there will be a table footer
+ * guid 48 bytes before the end of the flash file.  If it's
+ * not found, silently abort the flash parsing.
+ */
+qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, );
+guid = qemu_uuid_bswap(guid); /* guids are LE */
+ptr = flash_ptr + flash_size - 48;
+if (!qemu_uuid_is_equal((QemuUUID *)ptr, )) {
+return;
+}
+
+/* if found, just before is two byte table length */
+ptr -= sizeof(uint16_t);
+tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);
+
+if (tot_len <= 0) {
+return;
+}
+
+ovmf_table = g_malloc(tot_len);
+ovmf_table_len = tot_len;
+
+/*
+ * ptr is the foot of the table, so copy it all to the newly
+ * allocated ovmf_table and then set the ovmf_table pointer
+ * to the table foot
+ */
+memcpy(ovmf_table, ptr - tot_len, tot_len);
+ovmf_table += tot_len;
+}
+
+bool pc_system_ovmf_table_find(const char *entry, uint8_t **data,
+   int *data_len)
+{
+uint8_t *ptr = ovmf_table;
+int tot_len = ovmf_table_len;
+QemuUUID entry_guid;
+
+if (qemu_uuid_parse(entry, _guid) < 0) {
+return false;
+}
+
+if (!ptr) {
+return false;
+}
+
+entry_guid = qemu_uuid_bswap(entry_guid); /* guids are LE */
+while (tot_len > 0) {
+int len;
+QemuUUID *guid;
+
+/*
+ * The data structure is
+ *   arbitrary length data
+ *   2 byte length of entire entry
+ *   16 byte guid
+ */
+guid = (QemuUUID *)(ptr - sizeof(QemuUUID));
+len = le16_to_cpu(*(uint16_t *)(ptr - sizeof(QemuUUID) -
+sizeof(uint16_t)));
+
+/*
+ * just in case the table is corrupt, wouldn't want to spin in
+ * the zero case
+ */
+if (len < sizeof(QemuUUID) + sizeof(uint16_t)) {
+return false;
+}
+
+ptr -= len;
+tot_len -= len;
+if (qemu_uuid_is_equal(guid, _guid)) {
+if (data) {
+*data = ptr;
+}
+if (data_len) {
+*data_len = len - sizeof(QemuUUID) - sizeof(uint16_t);
+}
+return true;
+}
+}
+return false;
+}
+
 /*
  * Map the pcms->flash[] from 4GiB downward, and realize.
  * Map them in descending order, i.e. pcms->flash[0] at the top,
@@ -195,6 +296,11 @@ static void pc_system_flash_map(PCMachineState *pcms,
 if (kvm_memcrypt_enabled()) {
 flash_ptr = memory_region_get_ram_ptr(flash_mem);
 flash_size = memory_region_size(flash_mem);
+/*
+ * OVMF places a GUIDed structures in the flash, so
+ * search for them
+ */
+pc_system_parse_ovmf_flash(flash_ptr, flash_size);
 ret = kvm_memcrypt_encrypt_data(flash_ptr, flash_size);
 if (ret) {
 error_report("failed to encrypt pflash rom");
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 2aa8797c6e..19a53f745f 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -3,6 +3,7 @@
 
 #include "qemu/notify.h"

[PATCH v2 0/2] sev: enable secret injection to a self described area in OVMF

2020-12-14 Thread James Bottomley
v2: fix build issues and update comments.  Also drop the first patch
which is now merged upstream

The two patches introduce a parser for the optional OVMF description
table which is placed just below the reset vector (the format of the
table is described in the patch itself) and also adds a hook to pull
out the description of the SEV secret area location and use it in
place of the sev-inject-launch-secret gpa.

James

---

James Bottomley (2):
  pc: add parser for OVMF reset block
  sev: update sev-inject-launch-secret to make gpa optional

 hw/i386/pc_sysfw.c| 106 ++
 include/hw/i386/pc.h  |   4 ++
 qapi/misc-target.json |   2 +-
 target/i386/monitor.c |  27 ++-
 4 files changed, 137 insertions(+), 2 deletions(-)

-- 
2.26.2




Re: [PATCH 3/3] sev: update sev-inject-launch-secret to make gpa optional

2020-12-11 Thread James Bottomley
On Fri, 2020-12-11 at 16:00 -0600, Tom Lendacky wrote:
> On 12/9/20 11:23 AM, James Bottomley wrote:
> > If the gpa isn't specified, it's value is extracted from the OVMF
> > properties table located below the reset vector (and if this
> > doesn't
> > exist, an error is returned).  OVMF has defined the GUID for the
> > SEV
> > secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format
> > of
> > the  is: | where both are uint32_t.  We extract
> >  and use it as the gpa for the injection.
> > 
> > Note: it is expected that the injected secret will also be GUID
> > described but since qemu can't interpret it, the format is left
> > undefined here.
> > 
> > Signed-off-by: James Bottomley 
> > ---
> >   qapi/misc-target.json |  2 +-
> >   target/i386/monitor.c | 22 +-
> >   2 files changed, 22 insertions(+), 2 deletions(-)
> > 
> > diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> > index 4486a543ae..1ee4e62f85 100644
> > --- a/qapi/misc-target.json
> > +++ b/qapi/misc-target.json
> > @@ -216,7 +216,7 @@
> >   #
> >   ##
> >   { 'command': 'sev-inject-launch-secret',
> > -  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa':
> > 'uint64' },
> > +  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa':
> > 'uint64' },
> > 'if': 'defined(TARGET_I386)' }
> >   
> >   ##
> > diff --git a/target/i386/monitor.c b/target/i386/monitor.c
> > index 1bc91442b1..a99e3dd2b3 100644
> > --- a/target/i386/monitor.c
> > +++ b/target/i386/monitor.c
> > @@ -34,6 +34,7 @@
> >   #include "sev_i386.h"
> >   #include "qapi/qapi-commands-misc-target.h"
> >   #include "qapi/qapi-commands-misc.h"
> > +#include "hw/i386/pc.h"
> >   
> >   /* Perform linear address sign extension */
> >   static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
> > @@ -730,9 +731,28 @@ SevCapability
> > *qmp_query_sev_capabilities(Error **errp)
> >   return sev_get_capabilities(errp);
> >   }
> >   
> > +#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
> > +struct sev_secret_area {
> > +uint32_t base;
> > +uint32_t size;
> > +};
> > +
> 
> Originally, the idea was to allow expanding of these GUID based
> structures by pre-pending data to them, but based on how
> pc_system_ovmf_table_find() returns the pointer to the start of the
> structure (based on the length found in the structure), I believe
> that expansion could be done by appending to the structure, which
> seems more logical. For example, if this structure is ever expanded,
> it can use the third parameter of pc_system_ovmf_table_find() to get
> the length and compare that to the size  of the structure to
> determine if new version of the structure is present in the firmware.

Actually, I don't think it much matters.  It looks like the len it
would return is wrong ... it should be the length of just the returned
data pointer (without the length or guid), so ptr+len would point to
the foot of the data if that's what you want.

> Otherwise you can't do the nice easy assignment below:
>area = (struct sev_secret_area *)data;
> 
> You actually have to do some math:
>area = (struct sev_secret_area *)(data + data_len -
>  sizeof(QemuUUID) -
> sizeof(uint16_t) -
>   sizeof(*area));
> 
> or add the QemuUUID and uint16_t fields to sev_secret_area and:
>area = (struct sev_secret_area *)(data + data_len -
> sizeof(*area));

Right, that's why I think patch 2/3 should do

*data_len = len - sizeof(QemuUUID) - sizeof(uint16_t)

> Or we make the decision that these GUID structs should never change,
> just add a new one to the table if more info is needed.

Actually, the fact that the only guid the table depends on is the table
footer GUID, you can always remove guids and add new ones.  So I think
it's up to whoever is using the GUID to decide the policy.

So for this one I'm not checking the length, which argues it wouldn't
be subject to the added length new data rule and I'd have to use a new
guid for new information.  However, I could also see situations where
you would check the length and thus would have the ability to add
fields (either at the beginning or the end).

> Whatever we decide should probably be documented in both the OVMF
> patches and the Qemu patches.

OK, I can add a comment about my use case and you can add one
documenting your length based use case.

James





Re: [PATCH] target/i386/sev: add the support to query the attestation report

2020-12-10 Thread James Bottomley
On Fri, 2020-12-04 at 15:31 -0600, Brijesh Singh wrote:
> The SEV FW >= 0.23 added a new command that can be used to query the
> attestation report containing the SHA-256 digest of the guest memory
> and VMSA encrypted with the LAUNCH_UPDATE and sign it with the PEK.
> 
> Note, we already have a command (LAUNCH_MEASURE) that can be used to
> query the SHA-256 digest of the guest memory encrypted through the
> LAUNCH_UPDATE. The main difference between previous and this command
> is that the report is signed with the PEK and unlike the
> LAUNCH_MEASURE
> command the ATTESATION_REPORT command can be called while the guest
> is running.
> 
> Add a QMP interface "query-sev-attestation-report" that can be used
> to get the report encoded in base64.
> 
> Cc: James Bottomley 
> Cc: Tom Lendacky 
> Cc: Eric Blake 
> Cc: Paolo Bonzini 
> Cc: k...@vger.kernel.org
> Signed-off-by: Brijesh Singh 
> ---
>  linux-headers/linux/kvm.h |  8 ++
>  qapi/misc-target.json | 38 +++
>  target/i386/monitor.c |  6 +
>  target/i386/sev-stub.c|  7 +
>  target/i386/sev.c | 54
> +++
>  target/i386/sev_i386.h|  2 ++
>  6 files changed, 115 insertions(+)
> 
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index 56ce14ad20..6d0f8101ba 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -1585,6 +1585,8 @@ enum sev_cmd_id {
>   KVM_SEV_DBG_ENCRYPT,
>   /* Guest certificates commands */
>   KVM_SEV_CERT_EXPORT,
> + /* Attestation report */
> + KVM_SEV_GET_ATTESTATION_REPORT,
>  
>   KVM_SEV_NR_MAX,
>  };
> @@ -1637,6 +1639,12 @@ struct kvm_sev_dbg {
>   __u32 len;
>  };
>  
> +struct kvm_sev_attestation_report {
> + __u8 mnonce[16];
> + __u64 uaddr;
> + __u32 len;
> +};
> +
>  #define KVM_DEV_ASSIGN_ENABLE_IOMMU  (1 << 0)
>  #define KVM_DEV_ASSIGN_PCI_2_3   (1 << 1)
>  #define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
> diff --git a/qapi/misc-target.json b/qapi/misc-target.json
> index 1e561fa97b..ec6565e6ef 100644
> --- a/qapi/misc-target.json
> +++ b/qapi/misc-target.json
> @@ -267,3 +267,41 @@
>  ##
>  { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'],
>'if': 'defined(TARGET_ARM)' }
> +
> +
> +##
> +# @SevAttestationReport:
> +#
> +# The struct describes attestation report for a Secure Encrypted
> Virtualization
> +# feature.
> +#
> +# @data:  guest attestation report (base64 encoded)
> +#
> +#
> +# Since: 5.2
> +##
> +{ 'struct': 'SevAttestationReport',
> +  'data': { 'data': 'str'},
> +  'if': 'defined(TARGET_I386)' }
> +
> +##
> +# @query-sev-attestation-report:
> +#
> +# This command is used to get the SEV attestation report, and is
> supported on AMD
> +# X86 platforms only.
> +#
> +# @mnonce: a random 16 bytes of data (it will be included in report)
> +#
> +# Returns: SevAttestationReport objects.
> +#
> +# Since: 5.2
> +#
> +# Example:
> +#
> +# -> { "execute" : "query-sev-attestation-report", "arguments": {
> "mnonce": "aaa" } }
> +# <- { "return" : { "data": "bbbd"} }

It would be nice here, rather than returning a binary blob to break it
up into the actual returned components like query-sev does.

> +##
> +{ 'command': 'query-sev-attestation-report', 'data': { 'mnonce':
> 'str' },
> +  'returns': 'SevAttestationReport',
> +  'if': 'defined(TARGET_I386)' }
[...]
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 93c4d60b82..28958fb71b 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -68,6 +68,7 @@ struct SevGuestState {
>  
>  #define DEFAULT_GUEST_POLICY0x1 /* disable debug */
>  #define DEFAULT_SEV_DEVICE  "/dev/sev"
> +#define DEFAULT_ATTESATION_REPORT_BUF_SIZE  4096
>  
>  static SevGuestState *sev_guest;
>  static Error *sev_mig_blocker;
> @@ -490,6 +491,59 @@ out:
>  return cap;
>  }
>  
> +SevAttestationReport *
> +sev_get_attestation_report(const char *mnonce, Error **errp)
> +{
> +struct kvm_sev_attestation_report input = {};
> +SevGuestState *sev = sev_guest;
> +SevAttestationReport *report;
> +guchar *data;
> +int err = 0, ret;
> +
> +if (!sev_enabled()) {
> +error_setg(errp, "SEV is not enabled");
> +return NULL;
> +}
> +
> +/* Verify that user provided random data length */

There should be a g_base64_decode here, shouldn't there, so we can pass
an arbitrar

Re: [PATCH 0/3] sev: enable seret injection to a self described area in OVMF

2020-12-09 Thread James Bottomley
On Wed, 2020-12-09 at 09:23 -0800, James Bottomley wrote:
> This patch series includes one from Tobin that has already been
> posted
> and reviewed:
> 
> https://lore.kernel.org/qemu-devel/20201027170303.47550-1-to...@linux.ibm.com/
> 
> I'm adding it here because it's a required precursor, but it can be
> dropped from this series if it's already being upstreamed elsewhere.
> 
> The remaining two patches introduce a parser for the optional OVMF
> description table which is placed just below the reset vector (the
> format of the table is described in the patch itself) and also adds a
> hook to pull out the description of the SEV secret area location and
> use it in place of the sev-inject-launch-secret gpa.

For those who want to try this at home (assuming you have a SEV capable
AMD system), you need the amd sev-tool:

https://github.com/AMDESE/sev-tool/

To build the launch bundle (which contains the TIK and TEK key pair). 
Once you have that, you need to pass in both the launch bundle and the
-S flag to get QEMU to pause before starting the VM to allow
measurement and secret injection.  I'm using the python script below to
interact with the paused VM, verify the measurement, inject the secret
and resume the VM.  The below python script uses qmp.py from the qemu
git repository, so you'll have to adjust your path to it.

James

---

#!/usr/bin/python3
##
# Python script to inject a secret disk password into a paused SEV VM
#  (to pause the VM start with -S option)
#
# This assumes you've already created the launch bundle using sev-tool
# from https://github.com/AMDESE/sev-tool.git
#
# sev-tool --generate_launch_blob
#
# creates several files, the only one this script needs is the TIK and TEK
# keys which are stored in tmp_tk.bin
#
# Once TIK/TEK are known, the script will probe the VM for the sev
# parameters needed to calculate the launch measure, retrieve the launch
# measure and verify against the measure calculated from the OVMF hash
# and if that matches create the secret bundle and inject it
#
# Tables and chapters refer to the amd 55766.pdf document
#
# https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
##
import sys
import os 
import base64
import hmac
import hashlib
from argparse import ArgumentParser
from uuid import UUID
from Crypto.Cipher import AES
from Crypto.Util import Counter
from git.qemu.python.qemu import qmp

if __name__ == "__main__":
parser = ArgumentParser(description='Inject secret into SEV')
parser.add_argument('--tiktek-file',
help='file where sev-tool stored the TIK/TEK 
combination, defaults to tmp_tk.bin',
default='tmp_tk.bin')
parser.add_argument('--passwd',
help='Disk Password',
required=True)
parser.add_argument('--ovmf-hash',
help='hash of OVMF firmware blob in hex')
parser.add_argument('--ovmf-file',
help='location of OVMF file to calculate hash from')
parser.add_argument('--socket',
help='Socket to connect to QMP on, defaults to 
localhost:6550',
default='localhost:6550')
args = parser.parse_args()

if (args.ovmf_file):
fh = open (args.ovmf_file, 'rb')
h = hashlib.sha256(fh.read())
ovmf_hash = h.digest()
elif (args.ovmf_hash):
ovmf_hash = bytearray.fromhex(args.ovmf_hash)
else:
parser.error('one of --ovmf-hash or -ovmf-file must be specified')

if (args.socket[0] == '/'):
socket = args.socket
elif (':' in args.socket):
s = args.socket.split(':')
socket = (s[0], int(s[1]))
else:
parse.error('--socket must be : or /path/to/unix')

fh=open(args.tiktek_file, 'rb')
tiktek=bytearray(fh.read())
fh.close()

##
#  tiktek file is just two binary aes128 keys
##
TEK=tiktek[0:16]
TIK=tiktek[16:32]

disk_secret = args.passwd

Qmp = qmp.QEMUMonitorProtocol(address=socket);
Qmp.connect()
caps = Qmp.command('query-sev')
print('SEV query found API={api-major}.{api-minor} build={build-id} 
policy={policy}'.format(**caps))
h = hmac.new(TIK, digestmod='sha256');

##
# calculated per section 6.5.2
##
h.update(bytes([0x04]))
h.update(caps['api-major'].to_bytes(1,byteorder='little'))
h.update(caps['api-minor'].to_bytes(1,byteorder='little'))
h.update(caps['build-id'].to_bytes(1,byteorder='little'))
h.update(caps['policy'].to_bytes(4,byteorder='little'))
h.update(ovmf_hash)

print('\nGetting Launch Measurement')
meas = Qmp.command('query-sev-launch-measure')
launch_measure = base64.b64decode(meas['data'])

##
# returned data per Table 52. LAUNCH_MEASURE Measurement Buffer
##
nonce = launch_measure[32:48]
h.update(nonce)
measure = launch_measure[0:32]

print('Measure:   ', me

[PATCH 3/3] sev: update sev-inject-launch-secret to make gpa optional

2020-12-09 Thread James Bottomley
If the gpa isn't specified, it's value is extracted from the OVMF
properties table located below the reset vector (and if this doesn't
exist, an error is returned).  OVMF has defined the GUID for the SEV
secret area as 4c2eb361-7d9b-4cc3-8081-127c90d3d294 and the format of
the  is: | where both are uint32_t.  We extract
 and use it as the gpa for the injection.

Note: it is expected that the injected secret will also be GUID
described but since qemu can't interpret it, the format is left
undefined here.

Signed-off-by: James Bottomley 
---
 qapi/misc-target.json |  2 +-
 target/i386/monitor.c | 22 +-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 4486a543ae..1ee4e62f85 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -216,7 +216,7 @@
 #
 ##
 { 'command': 'sev-inject-launch-secret',
-  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa': 'uint64' },
+  'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' },
   'if': 'defined(TARGET_I386)' }
 
 ##
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 1bc91442b1..a99e3dd2b3 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -34,6 +34,7 @@
 #include "sev_i386.h"
 #include "qapi/qapi-commands-misc-target.h"
 #include "qapi/qapi-commands-misc.h"
+#include "hw/i386/pc.h"
 
 /* Perform linear address sign extension */
 static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
@@ -730,9 +731,28 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
 return sev_get_capabilities(errp);
 }
 
+#define SEV_SECRET_GUID "4c2eb361-7d9b-4cc3-8081-127c90d3d294"
+struct sev_secret_area {
+uint32_t base;
+uint32_t size;
+};
+
 void qmp_sev_inject_launch_secret(const char *packet_hdr,
-  const char *secret, uint64_t gpa,
+  const char *secret,
+  bool has_gpa, uint64_t gpa,
   Error **errp)
 {
+if (!has_gpa) {
+uint8_t *data;
+struct sev_secret_area *area;
+
+if (!pc_system_ovmf_table_find(SEV_SECRET_GUID, , NULL)) {
+error_setg(errp, "SEV: no secret area found in OVMF, gpa must be 
specified.");
+return;
+}
+area = (struct sev_secret_area *)data;
+gpa = area->base;
+}
+
 sev_inject_launch_secret(packet_hdr, secret, gpa, errp);
 }
-- 
2.26.2




[PATCH 1/3] sev: add sev-inject-launch-secret

2020-12-09 Thread James Bottomley
From: Tobin Feldman-Fitzthum 

AMD SEV allows a guest owner to inject a secret blob
into the memory of a virtual machine. The secret is
encrypted with the SEV Transport Encryption Key and
integrity is guaranteed with the Transport Integrity
Key. Although QEMU facilitates the injection of the
launch secret, it cannot access the secret.

Signed-off-by: Tobin Feldman-Fitzthum 
Reviewed-by: Daniel P. Berrangé 
Reviewed-by: Brijesh Singh 
Signed-off-by: James Bottomley 
---
 include/monitor/monitor.h |  3 ++
 include/sysemu/sev.h  |  2 ++
 monitor/misc.c| 17 +++---
 qapi/misc-target.json | 18 +++
 target/i386/monitor.c |  7 +
 target/i386/sev-stub.c|  5 +++
 target/i386/sev.c | 65 +++
 target/i386/trace-events  |  1 +
 8 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 348bfad3d5..af3887bb71 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -4,6 +4,7 @@
 #include "block/block.h"
 #include "qapi/qapi-types-misc.h"
 #include "qemu/readline.h"
+#include "include/exec/hwaddr.h"
 
 typedef struct MonitorHMP MonitorHMP;
 typedef struct MonitorOptions MonitorOptions;
@@ -37,6 +38,8 @@ void monitor_flush(Monitor *mon);
 int monitor_set_cpu(Monitor *mon, int cpu_index);
 int monitor_get_cpu_index(Monitor *mon);
 
+void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp);
+
 void monitor_read_command(MonitorHMP *mon, int show_prompt);
 int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func,
   void *opaque);
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
index 98c1ec8d38..7ab6e3e31d 100644
--- a/include/sysemu/sev.h
+++ b/include/sysemu/sev.h
@@ -18,4 +18,6 @@
 
 void *sev_guest_init(const char *id);
 int sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len);
+int sev_inject_launch_secret(const char *hdr, const char *secret,
+ uint64_t gpa, Error **errp);
 #endif
diff --git a/monitor/misc.c b/monitor/misc.c
index 398211a034..4e40f7c850 100644
--- a/monitor/misc.c
+++ b/monitor/misc.c
@@ -667,10 +667,11 @@ static void hmp_physical_memory_dump(Monitor *mon, const 
QDict *qdict)
 memory_dump(mon, count, format, size, addr, 1);
 }
 
-static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
+void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, uint64_t size, Error **errp)
 {
+Int128 gpa_region_size;
 MemoryRegionSection mrs = memory_region_find(get_system_memory(),
- addr, 1);
+ addr, size);
 
 if (!mrs.mr) {
 error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, 
addr);
@@ -683,6 +684,14 @@ static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, 
Error **errp)
 return NULL;
 }
 
+gpa_region_size = int128_make64(size);
+if (int128_lt(mrs.size, gpa_region_size)) {
+error_setg(errp, "Size of memory region at 0x%" HWADDR_PRIx
+   " exceeded.", addr);
+memory_region_unref(mrs.mr);
+return NULL;
+}
+
 *p_mr = mrs.mr;
 return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
 }
@@ -694,7 +703,7 @@ static void hmp_gpa2hva(Monitor *mon, const QDict *qdict)
 MemoryRegion *mr = NULL;
 void *ptr;
 
-ptr = gpa2hva(, addr, _err);
+ptr = gpa2hva(, addr, 1, _err);
 if (local_err) {
 error_report_err(local_err);
 return;
@@ -770,7 +779,7 @@ static void hmp_gpa2hpa(Monitor *mon, const QDict *qdict)
 void *ptr;
 uint64_t physaddr;
 
-ptr = gpa2hva(, addr, _err);
+ptr = gpa2hva(, addr, 1, _err);
 if (local_err) {
 error_report_err(local_err);
 return;
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 1e561fa97b..4486a543ae 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -201,6 +201,24 @@
 { 'command': 'query-sev-capabilities', 'returns': 'SevCapability',
   'if': 'defined(TARGET_I386)' }
 
+##
+# @sev-inject-launch-secret:
+#
+# This command injects a secret blob into memory of SEV guest.
+#
+# @packet-header: the launch secret packet header encoded in base64
+#
+# @secret: the launch secret data to be injected encoded in base64
+#
+# @gpa: the guest physical address where secret will be injected.
+#
+# Since: 5.2
+#
+##
+{ 'command': 'sev-inject-launch-secret',
+  'data': { 'packet-header': 'str', 'secret': 'str', 'gpa': 'uint64' },
+  'if': 'defined(TARGET_I386)' }
+
 ##
 # @dump-skeys:
 #
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 9f9e1c42f4..1bc91442b1 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -729,3 +729,10 @@ SevCapability *qmp_query_sev_capabilities(Error **errp)
 {
 return sev_get_capabilit

  1   2   >