[libvirt] [PATCH 06/12] qemu: Extend QEMU with external TPM support
Stefan Berger
stefanb at linux.vnet.ibm.com
Wed May 23 17:59:33 UTC 2018
On 05/23/2018 11:41 AM, Ján Tomko wrote:
> On Tue, May 22, 2018 at 04:44:47PM -0400, Stefan Berger wrote:
>> Implement functions for managing the storage of the external swtpm as
>> well
>> as starting and stopping it. Also implement functions to use
>> swtpm_setup,
>> which simulates the manufacturing of a TPM, which includes creation of
>> certificates for the device.
>>
>> Further, the external TPM needs storage on the host that we need to set
>> up before it can be run. We can clean up the host once the domain is
>> undefined.
>>
>> This patch also implements a small layer for external device support
>> that
>> calls into the TPM device layer if a domain has an attached TPM. This is
>> the layer we will wire up later on.
>>
>
> Later on meaning in other patch series? Adding it for just one device
> seems excessive, but that might be my personal opinion.
>
>> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
>> Reviewed-by: John Ferlan <jferlan at redhat.com>
>> ---
>> src/qemu/Makefile.inc.am | 4 +
>> src/qemu/qemu_domain.c | 2 +
>> src/qemu/qemu_extdevice.c | 154 ++++++++++
>> src/qemu/qemu_extdevice.h | 53 ++++
>> src/qemu/qemu_process.c | 12 +
>> src/qemu/qemu_tpm.c | 751
>> ++++++++++++++++++++++++++++++++++++++++++++++
>> src/qemu/qemu_tpm.h | 50 +++
>> 7 files changed, 1026 insertions(+)
>> create mode 100644 src/qemu/qemu_extdevice.c
>> create mode 100644 src/qemu/qemu_extdevice.h
>> create mode 100644 src/qemu/qemu_tpm.c
>> create mode 100644 src/qemu/qemu_tpm.h
>>
>
>> +/*
>> + * virtTPMGetTPMStorageDir:
>> + *
>> + * @storagepath: directory for swtpm's persistent state
>> + *
>> + * Derive the 'TPMStorageDir' from the storagepath by searching
>> + * for the last '/'.
>> + */
>> +static char *
>> +qemuTPMGetTPMStorageDir(const char *storagepath)
>> +{
>> + const char *tail = strrchr(storagepath, '/');
>> + char *path = NULL;
>> +
>> + if (!tail) {
>> + virReportError(VIR_ERR_INTERNAL_ERROR,
>> + _("Could not get tail of storagedir %s"),
>> + storagepath);
>> + return NULL;
>> + }
>> + ignore_value(VIR_STRNDUP(path, storagepath, tail - storagepath));
>> +
>> + return path;
>> +}
>
> In other places we already use mdir_name from gnulib for this
> functionality.
I didn't know about this API. I will change it to that.
>
>> +/*
>> + * qemuTPMCreateEmulatorStorage
>> + *
>> + * @storagepath: directory for swtpm's persistent state
>> + * @created: a pointer to a bool that will be set to true if the
>> + * storage was created because it did not exist yet
>
> Can't the caller call virFileExists and act accordingly?
We could, except that we have to call this function since it is
adjusting access rights to files for the swtpm_user and swtpm_group.
>
>> + * @swtpm_user: The uid that needs to be able to access the directory
>> + * @swtpm_group: The gid that needs to be able to access the directory
>> + *
>> + * Unless the storage path for the swtpm for the given VM
>> + * already exists, create it and make it accessible for the given
>> userid.
>> + * Adapt ownership of the directory and all swtpm's state files there.
>> + */
>
> [...]
>
>> +static int
>> +qemuTPMEmulatorPrepareHost(virDomainTPMDefPtr tpm,
>> + const char *logDir,
>> + const char *vmname,
>> + uid_t swtpm_user,
>> + gid_t swtpm_group,
>> + const char *swtpmStateDir,
>> + uid_t qemu_user,
>> + const char *shortName)
>> +{
>> + int ret = -1;
>> +
>> + if (qemuTPMEmulatorInit() < 0)
>> + return -1;
>> +
>> + /* create log dir ... allow 'tss' user to cd into it */
>> + if (virFileMakePathWithMode(logDir, 0711) < 0)
>> + return -1;
>> +
>> + /* ... and adjust ownership */
>> + if (virDirCreate(logDir, 0730, swtpm_user, swtpm_group,
>> + VIR_DIR_CREATE_ALLOW_EXIST) < 0)
>> + goto cleanup;
>> +
>> + /* create logfile name ... */
>> + if (!tpm->data.emulator.logfile &&
>> + virAsprintf(&tpm->data.emulator.logfile, "%s/%s-swtpm.log",
>> + logDir, vmname) < 0)
>
> This should also use shortName.
The shortName has the ID of the domain in the name. So for short-lived
logs I would say yes. Though this should be a log like the one for the
VM that gets appended to every time the VM restarts. I'd rather not
change this.
>
>> + goto cleanup;
>> +
>> + /* ... and make sure it can be accessed by swtpm_user */
>> + if (virFileExists(tpm->data.emulator.logfile) &&
>> + chown(tpm->data.emulator.logfile, swtpm_user, swtpm_group) <
>> 0) {
>> + virReportSystemError(errno,
>> + _("Could not chown on swtpm logfile %s"),
>> + tpm->data.emulator.logfile);
>> + goto cleanup;
>> + }
>> +
>> + /*
>> + create our swtpm state dir ...
>> + - QEMU user needs to be able to access the socket there
>> + - swtpm group needs to be able to create files there
>> + - in privileged mode 0570 would be enough, for non-privileged
>> mode
>> + we need 0770
>> + */
>> + if (virDirCreate(swtpmStateDir, 0770, qemu_user, swtpm_group,
>> + VIR_DIR_CREATE_ALLOW_EXIST) < 0)
>> + goto cleanup;
>> +
>> + /* create the socket filename */
>> + if (!tpm->data.emulator.source.data.nix.path &&
>> + !(tpm->data.emulator.source.data.nix.path =
>> + qemuTPMCreateEmulatorSocket(swtpmStateDir, shortName)))
>> + goto cleanup;
>> + tpm->data.emulator.source.type = VIR_DOMAIN_CHR_TYPE_UNIX;
>> +
>> + ret = 0;
>> +
>> + cleanup:
>> +
>> + return ret;
>> +}
>> +
>
> [...]
>
>> +static int
>> +qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
>> + virDomainDefPtr def,
>> + qemuDomainLogContextPtr logCtxt)
>> +{
>> + int ret = -1;
>> + virCommandPtr cmd = NULL;
>> + int exitstatus;
>> + char *errbuf = NULL;
>> + virQEMUDriverConfigPtr cfg;
>> + virDomainTPMDefPtr tpm = def->tpm;
>> + char *shortName = virDomainDefGetShortName(def);
>> +
>> + if (!shortName)
>> + return -1;
>> +
>> + cfg = virQEMUDriverGetConfig(driver);
>> +
>> + /* stop any left-over TPM emulator for this VM */
>> + qemuTPMEmulatorStop(cfg->swtpmStateDir, shortName);
>> +
>> + if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, def->name, def->uuid,
>> + driver->privileged,
>> + cfg->swtpm_user,
>> + cfg->swtpm_group)))
>> + goto cleanup;
>> +
>> + if (qemuExtDeviceLogCommand(logCtxt, cmd, "TPM Emulator") < 0)
>> + goto cleanup;
>> +
>> + virCommandSetErrorBuffer(cmd, &errbuf);
>> +
>> + if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) {
>> + virReportError(VIR_ERR_INTERNAL_ERROR,
>> + _("Could not start 'swtpm'. exitstatus: %d, "
>> + "error: %s"), exitstatus, errbuf);
>
> Indentation is off here ^
Fixed.
>
>> + goto cleanup;
>> + }
>> +
>> + ret = 0;
>> +
>
> Jano
Thanks..
Stefan
More information about the libvir-list
mailing list