[libvirt] [PATCH v7 07/12] qemu: Add support for external swtpm TPM emulator

Stefan Berger stefanb at linux.vnet.ibm.com
Thu May 24 13:02:40 UTC 2018


This patch adds support for an external swtpm TPM emulator. The XML for
this type of TPM looks as follows:

 <tpm model='tpm-tis'>
   <backend type='emulator'/>
 </tpm>

The XML will currently only start a TPM 1.2.

Upon first start, libvirt will run `swtpm_setup`, which will simulate the
manufacturing of a TPM and create certificates for it and write them into
NVRAM locations of the emulated TPM.

After that libvirt starts the swtpm TPM emulator using the `swtpm` executable.

Once the VM terminates, libvirt uses the swtpm_ioctl executable to gracefully
shut down the `swtpm` in case it is still running (QEMU did not send shutdown)
or clean up the socket file.

The above mentioned executables must be found in the PATH.

The executables can either be run as root or started as root and switch to
the tss user. The requirement for the tss user comes through 'tcsd', which
is used for the simulation of the manufacturing. Which user is used can be
configured through qemu.conf. By default 'tss' is used.

The swtpm writes out state into files. The state is kept in /var/lib/libvirt/swtpm:

[root at localhost libvirt]# ls -lZ | grep swtpm

drwx--x--x. 7 root root unconfined_u:object_r:virt_var_lib_t:s0 4096 Apr  5 16:22 swtpm

The directory /var/lib/libvirt/swtpm maintains per-TPM state directories.
(Using the uuid of the VM for that since the name can change per VM renaming but
 we need a stable directory name.)

[root at localhost swtpm]# ls -lZ
total 4
drwx------. 2 tss  tss  system_u:object_r:virt_var_lib_t:s0          4096 Apr  5 16:46 485d0004-a48f-436a-8457-8a3b73e28568

[root at localhost 485d0004-a48f-436a-8457-8a3b73e28568]# ls -lZ
total 4
drwx------. 2 tss tss system_u:object_r:virt_var_lib_t:s0 4096 Apr 10 21:34 tpm1.2

[root at localhost tpm1.2]# ls -lZ
total 8
-rw-r--r--. 1 tss tss system_u:object_r:virt_var_lib_t:s0 3648 Apr  5 16:46 tpm-00.permall

The directory /var/run/libvirt/qemu/swtpm/ hosts the swtpm.sock that
QEMU uses to communicate with the swtpm:

root at localhost domain-1-testvm]# ls -lZ
total 0
srw-------. 1 qemu qemu system_u:object_r:svirt_image_t:s0:c597,c632  0 Apr  6 10:24 1-testvm-swtpm.sock

The logfile for the swtpm is in /var/log/swtpm/libvirt/qemu:

[root at localhost-3 qemu]# ls -lZ
total 4
-rw-------. 1 tss tss unconfined_u:object_r:var_log_t:s0 2199 Apr  6 14:01 testvm-swtpm.log

The processes are labeled as follows:

[root at localhost 485d0004-a48f-436a-8457-8a3b73e28567]# ps auxZ | grep swtpm | grep socket | grep -v grep
system_u:system_r:virtd_t:s0-s0:c0.c1023 tss 18697 0.0  0.0 28172 3892 ?       Ss   16:46   0:00 /usr/bin/swtpm socket --daemon --ctrl type=unixio,path=/var/run/libvirt/qemu/swtpm/1-testvm-swtpm.sock,mode=0600 --tpmstate dir=/var/lib/libvirt/swtpm/485d0004-a48f-436a-8457-8a3b73e28568/tpm1.2 --log file=/var/log/swtpm/libvirt/qemu/testvm-swtpm.log

[root at localhost 485d0004-a48f-436a-8457-8a3b73e28567]# ps auxZ | grep qemu | grep tpm | grep -v grep
system_u:system_r:svirt_t:s0:c413,c430 qemu 18702 2.5  0.0 3036052 48676 ?     Sl   16:46   0:08 /bin/qemu-system-x86_64 [...]

Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
Reviewed-by: John Ferlan <jferlan at redhat.com>
---
 src/qemu/qemu_command.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8a2f31ef3f..4ce587774a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -9434,17 +9434,27 @@ qemuBuildTPMBackendStr(const virDomainDef *def,
                        virCommandPtr cmd,
                        virQEMUCapsPtr qemuCaps,
                        int *tpmfd,
-                       int *cancelfd)
+                       int *cancelfd,
+                       char **chardev)
 {
     const virDomainTPMDef *tpm = def->tpm;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
-    const char *type = virDomainTPMBackendTypeToString(tpm->type);
+    const char *type = NULL;
     char *cancel_path = NULL, *devset = NULL;
     const char *tpmdev;
 
     *tpmfd = -1;
     *cancelfd = -1;
 
+    switch (tpm->type) {
+    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+    case VIR_DOMAIN_TPM_TYPE_EMULATOR:
+        type = virDomainTPMBackendTypeToString(tpm->type);
+        break;
+    case VIR_DOMAIN_TPM_TYPE_LAST:
+        goto error;
+    }
+
     virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias);
 
     switch (tpm->type) {
@@ -9496,6 +9506,16 @@ qemuBuildTPMBackendStr(const virDomainDef *def,
 
         break;
     case VIR_DOMAIN_TPM_TYPE_EMULATOR:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_TPM_EMULATOR))
+            goto no_support;
+
+        virBufferAddLit(&buf, ",chardev=chrtpm");
+
+        if (virAsprintf(chardev, "socket,id=chrtpm,path=%s",
+                        tpm->data.emulator.source.data.nix.path) < 0)
+            goto error;
+
+        break;
     case VIR_DOMAIN_TPM_TYPE_LAST:
         goto error;
     }
@@ -9526,6 +9546,7 @@ qemuBuildTPMCommandLine(virCommandPtr cmd,
                         virQEMUCapsPtr qemuCaps)
 {
     char *optstr;
+    char *chardev = NULL;
     int tpmfd = -1;
     int cancelfd = -1;
     char *fdset;
@@ -9534,12 +9555,18 @@ qemuBuildTPMCommandLine(virCommandPtr cmd,
         return 0;
 
     if (!(optstr = qemuBuildTPMBackendStr(def, cmd, qemuCaps,
-                                          &tpmfd, &cancelfd)))
+                                          &tpmfd, &cancelfd,
+                                          &chardev)))
         return -1;
 
     virCommandAddArgList(cmd, "-tpmdev", optstr, NULL);
     VIR_FREE(optstr);
 
+    if (chardev) {
+        virCommandAddArgList(cmd, "-chardev", chardev, NULL);
+        VIR_FREE(chardev);
+    }
+
     if (tpmfd >= 0) {
         fdset = qemuVirCommandGetFDSet(cmd, tpmfd);
         if (!fdset)
-- 
2.14.3




More information about the libvir-list mailing list