[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