A session leader can join another process group of its session with setpgid(), where Linux returns EPERM (JoinProcessGroup in pkg/sentry/kernel/sessions.go has no session leader check). After the move its process group has another leader, so pidfd_send_signal() with PIDFD_SIGNAL_PROCESS_GROUP on its pidfd fails with EINVAL.
Reproducer
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
pid_t leader = fork();
if (leader == 0) {
setsid();
pid_t child = fork();
if (child == 0) {
pause();
_exit(0);
}
setpgid(child, child);
int ret = setpgid(0, child);
printf("setpgid(0, child) = %d (%s)\n", ret, ret == 0 ? "ok" : strerror(errno));
printf("leader pgid == sid: %s\n", getpgid(0) == getsid(0) ? "yes" : "no");
kill(child, SIGKILL);
return 0;
}
waitpid(leader, NULL, 0);
return 0;
}
Linux prints setpgid(0, child) = -1 (Operation not permitted). runsc prints setpgid(0, child) = 0 (ok).
Proposed fix in #15567.
A session leader can join another process group of its session with setpgid(), where Linux returns EPERM (JoinProcessGroup in pkg/sentry/kernel/sessions.go has no session leader check). After the move its process group has another leader, so pidfd_send_signal() with PIDFD_SIGNAL_PROCESS_GROUP on its pidfd fails with EINVAL.
Reproducer
Linux prints
setpgid(0, child) = -1 (Operation not permitted). runsc printssetpgid(0, child) = 0 (ok).Proposed fix in #15567.