swtpm-util: reap the profile listing child on failure

swtpm_find_best_profile() keeps the swtpm_setup --print-profiles child in
a PidRef that is only closed on return. If the wait fails, the child is
neither killed nor reaped. On a fiber this happens whenever the fiber is
cancelled during the wait.

Kill and reap the child in the cleanup, like other helpers that fork short
lived children do. Drop the PidRef before the cleanup when the wait
reports an exit status, a child killed by a signal, or a child that is
already gone. Otherwise the cleanup would send SIGKILL to a PID that
another process might use by now, if no pidfd was available.
This commit is contained in:
Daan De Meyer authored and Lennart Poettering committed 2026-11-05 18:55:20 +01:00
1 parent fd39acb784
commit 6a02f8893c
1 file changed
+6 -1
+6 -1
View File
@@ -43,7 +43,7 @@ static int swtpm_find_best_profile(const char *swtpm_setup, char **ret) {
log_debug("About to spawn: %s", strnull(cmdline));
}
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork_full(
"(swtpm-lprof)",
(int[]) { -EBADF, mfd, STDERR_FILENO },
@@ -61,6 +61,11 @@ static int swtpm_find_best_profile(const char *swtpm_setup, char **ret) {
}
r = pidref_wait_for_terminate_and_check("(swtpm-lprof)", &pidref, WAIT_LOG_ABNORMAL);
/* An exit status, -EPROTO for a child killed by a signal, and -ECHILD mean that the child is gone.
* The cleanup must not send SIGKILL then, because without a pidfd the PID might belong to another
* process by now. After any other failure the child is not reaped yet, and the cleanup kills it. */
if (r >= 0 || IN_SET(r, -EPROTO, -ECHILD))
pidref_done(&pidref);
if (r < 0)
return r;