[libvirt] [PATCH v2 3/3] qemu: Pass file descriptor when using TPM passthrough

Michal Privoznik mprivozn at redhat.com
Thu Mar 5 15:25:34 UTC 2015


On 03.03.2015 15:40, Stefan Berger wrote:
> Pass the TPM file descriptor to QEMU via command line.
> Instead of passing /dev/tpm0 we now pass /dev/fdset/10 and the additional
> parameters -add-fd set=10,fd=20.
> 
> This addresses the use case when QEMU is started with non-root privileges
> and QEMU cannot open /dev/tpm0 for example.
> 
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> ---
>  src/qemu/qemu_command.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 117 insertions(+), 4 deletions(-)
> 
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index d6bc294..4c6b76d 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -161,6 +161,58 @@ VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
>                "interleave");
>  
>  /**
> + * qemuVirCommandGetFDSet:
> + * @cmd: the command to modify
> + * @fd: fd to reassign to the child
> + *
> + * Get the parameters for the QEMU -add-fd command line option
> + * for the given file descriptor. The file descriptor must previously
> + * have been 'transferred' in a virCommandPassFD() call.
> + * This function for example returns "set=10,fd=20".
> + */
> +static char *
> +qemuVirCommandGetFDSet(virCommandPtr cmd, int fd)
> +{
> +    char *result = NULL;
> +    int idx = virCommandPassFDGetFDIndex(cmd, fd);
> +
> +    if (idx >= 0) {
> +        ignore_value(virAsprintf(&result, "set=%d,fd=%d", idx, fd));
> +    } else {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("file descriptor %d has not been transferred"), fd);
> +    }
> +
> +    return result;
> +}
> +
> +/**
> + * qemuVirCommandGetDevSet:
> + * @cmd: the command to modify
> + * @fd: fd to reassign to the child
> + *
> + * Get the parameters for the QEMU path= parameter where a file
> + * descriptor is accessed via a file descriptor set, for example
> + * /dev/fdset/10. The file descriptor must previously have been
> + * 'transferred' in a virCommandPassFD() call.
> + */
> +static char *
> +qemuVirCommandGetDevSet(virCommandPtr cmd, int fd)
> +{
> +    char *result = NULL;
> +    int idx = virCommandPassFDGetFDIndex(cmd, fd);
> +
> +    if (idx >= 0) {
> +        ignore_value(virAsprintf(&result, "/dev/fdset/%d", idx));
> +    } else {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("file descriptor %d has not been transferred"), fd);
> +    }
> +    return result;
> +}
> +
> +
> +/**
>   * qemuPhysIfaceConnect:
>   * @def: the definition of the VM (needed by 802.1Qbh and audit)
>   * @driver: pointer to the driver instance
> @@ -6321,15 +6373,20 @@ qemuBuildRNGDevStr(virDomainDefPtr def,
>  
>  
>  static char *qemuBuildTPMBackendStr(const virDomainDef *def,
> +                                    virCommandPtr cmd,
>                                      virQEMUCapsPtr qemuCaps,
> -                                    const char *emulator)
> +                                    const char *emulator,
> +                                    int *tpmfd, int *cancelfd)
>  {
>      const virDomainTPMDef *tpm = def->tpm;
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>      const char *type = virDomainTPMBackendTypeToString(tpm->type);
> -    char *cancel_path;
> +    char *cancel_path = NULL, *devset = NULL;
>      const char *tpmdev;
>  
> +    *tpmfd = -1;
> +    *cancelfd = -1;
> +
>      virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias);
>  
>      switch (tpm->type) {
> @@ -6341,11 +6398,42 @@ static char *qemuBuildTPMBackendStr(const virDomainDef *def,
>          if (!(cancel_path = virTPMCreateCancelPath(tpmdev)))
>              goto error;
>  
> +        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ADD_FD)) {
> +            *tpmfd = open(tpmdev, O_RDWR);
> +            if (*tpmfd < 0) {
> +                virReportSystemError(errno, _("Could not open TPM device %s"),
> +                                     tpmdev);
> +                goto error;
> +            }
> +
> +            virCommandPassFD(cmd, *tpmfd,
> +                             VIR_COMMAND_PASS_FD_CLOSE_PARENT);
> +            devset = qemuVirCommandGetDevSet(cmd, *tpmfd);
> +            if (devset == NULL)
> +                goto error;
> +
> +            *cancelfd = open(cancel_path, O_WRONLY);
> +            if (*cancelfd < 0) {
> +                virReportSystemError(errno,
> +                                     _("Could not open TPM device's cancel "
> +                                       "path %s"), cancel_path);
> +                goto error;
> +            }
> +            VIR_FREE(cancel_path);
> +
> +            virCommandPassFD(cmd, *cancelfd,
> +                             VIR_COMMAND_PASS_FD_CLOSE_PARENT);
> +            cancel_path = qemuVirCommandGetDevSet(cmd, *cancelfd);
> +            if (cancel_path == NULL)
> +                goto error;
> +        }

I'm thinking of how to test this code, but those open() complicate the
things. Unless we want to mock them in qemuxml2argvmock.c which would
not be trivial after all.

ACK series.

Michal




More information about the libvir-list mailing list