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

Stefan Berger stefanb at linux.vnet.ibm.com
Fri Mar 6 01:07:58 UTC 2015


On 03/05/2015 10:25 AM, Michal Privoznik wrote:
> 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
>
Pushed

     Stefan




More information about the libvir-list mailing list