[PATCH v2 3/4] qemu_tpm: Get swtpm pid without binary validation

Michal Prívozník mprivozn at redhat.com
Wed Feb 2 10:33:43 UTC 2022


On 1/13/22 13:42, Vasiliy Ulyanov wrote:
> Access to /proc/[pid]/exe may be restricted in certain environments (e.g.
> in containers) and any attempt to stat(2) or readlink(2) the file will
> result in 'permission denied' error if the calling process does not have
> CAP_SYS_PTRACE capability. According to proc(5) manpage:
> 
> Permission to dereference or read (readlink(2)) this symbolic link is
> governed by a ptrace access mode PTRACE_MODE_READ_FSCREDS check; see
> ptrace(2).
> 
> The binary validation in virPidFileReadPathIfAlive may fail with EACCES.
> Therefore instead do only the check that the pidfile is locked by the
> correct process. To ensure this is always the case the daemonization and
> pidfile handling of the swtpm command is now controlled by libvirt.
> 
> Signed-off-by: Vasiliy Ulyanov <vulyanov at suse.de>
> ---
>  src/qemu/qemu_tpm.c | 26 +++++++++++---------------
>  1 file changed, 11 insertions(+), 15 deletions(-)
> 
> diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
> index 7e7b01768e..792ee19bbd 100644
> --- a/src/qemu/qemu_tpm.c
> +++ b/src/qemu/qemu_tpm.c
> @@ -258,13 +258,12 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir,
>                        const char *shortName,
>                        pid_t *pid)
>  {
> -    g_autofree char *swtpm = virTPMGetSwtpm();
>      g_autofree char *pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir,
>                                                                  shortName);
>      if (!pidfile)
>          return -1;
>  
> -    if (virPidFileReadPathIfAlive(pidfile, pid, swtpm) < 0)
> +    if (virPidFileReadPathIfAlive(pidfile, pid, NULL) < 0)
>          return -1;
>  
>      return 0;
> @@ -721,7 +720,7 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
>  
>      virCommandClearCaps(cmd);
>  
> -    virCommandAddArgList(cmd, "socket", "--daemon", "--ctrl", NULL);
> +    virCommandAddArgList(cmd, "socket", "--ctrl", NULL);
>      virCommandAddArgFormat(cmd, "type=unixio,path=%s,mode=0600",
>                             tpm->data.emulator.source->data.nix.path);
>  
> @@ -751,8 +750,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
>      if (!(pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir, shortName)))
>          goto error;
>  
> -    virCommandAddArg(cmd, "--pid");
> -    virCommandAddArgFormat(cmd, "file=%s", pidfile);
> +    virCommandSetPidFile(cmd, pidfile);
> +    virCommandDaemonize(cmd);
>  
>      if (tpm->data.emulator.hassecretuuid) {
>          if (!virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD)) {
> @@ -905,7 +904,6 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver,
>  {
>      g_autoptr(virCommand) cmd = NULL;
>      int exitstatus = 0;
> -    g_autofree char *errbuf = NULL;
>      g_autoptr(virQEMUDriverConfig) cfg = NULL;
>      g_autofree char *shortName = virDomainDefGetShortName(vm->def);
>      int cmdret = 0, timeout, rc;
> @@ -930,8 +928,6 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver,
>      if (qemuExtDeviceLogCommand(driver, vm, cmd, "TPM Emulator") < 0)
>          return -1;
>  
> -    virCommandSetErrorBuffer(cmd, &errbuf);
> -

We can use virCommandSetErrorFD(), which ...

>      if (qemuSecurityStartTPMEmulator(driver, vm, cmd,
>                                       cfg->swtpm_user, cfg->swtpm_group,
>                                       &exitstatus, &cmdret) < 0)
> @@ -939,22 +935,22 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver,
>  
>      if (cmdret < 0 || exitstatus != 0) {
>          virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("Could not start 'swtpm'. exitstatus: %d, "
> -                         "error: %s"), exitstatus, errbuf);
> +                       _("Could not start 'swtpm'. exitstatus: %d"), exitstatus);
>          return -1;
>      }
>  
> -    /* check that the swtpm has written its pid into the file */
> +    /* check that the swtpm has written its pid into the file and the control
> +     * socket has been created. */
> +    rc = qemuTPMEmulatorGetPid(cfg->swtpmStateDir, shortName, &pid);
> +    if ((rc == 0 && pid == (pid_t)-1) || rc < 0)
> +        goto error;
>      timeout = 1000; /* ms */
>      while (timeout > 0) {
> -        rc = qemuTPMEmulatorGetPid(cfg->swtpmStateDir, shortName, &pid);
> -        if (rc < 0) {
> +        if (!virFileExists(tpm->data.emulator.source->data.nix.path)) {
>              timeout -= 50;
>              g_usleep(50 * 1000);
>              continue;
>          }
> -        if (rc == 0 && pid == (pid_t)-1)
> -            goto error;

Can then be used here to report error message that swtpm printed onto
its stderr. Look at qemuProcessStartManagedPRDaemon() which does that.

>          break;
>      }
>      if (timeout <= 0)

Michal




More information about the libvir-list mailing list