start: add ability to detect whether kernel supports pidfds

parent fa3621ea
......@@ -7,6 +7,7 @@
#define _GNU_SOURCE 1
#endif
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
......@@ -18,6 +19,11 @@
#define CLONE_PIDFD 0x00001000
#endif
/* waitid */
#ifndef P_PIDFD
#define P_PIDFD 3
#endif
/*
* lxc_raw_clone() - create a new process
*
......
......@@ -1659,6 +1659,10 @@ static int lxc_spawn(struct lxc_handler *handler)
}
TRACE("Cloned child process %d", handler->pid);
/* Verify that we can actually make use of pidfds. */
if (!lxc_can_use_pidfd(handler->pidfd))
close_prot_errno_disarm(handler->pidfd);
ret = snprintf(pidstr, 20, "%d", handler->pid);
if (ret < 0 || ret >= 20)
goto out_delete_net;
......
......@@ -12,6 +12,7 @@
#include <inttypes.h>
#include <libgen.h>
#include <pthread.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -291,6 +292,20 @@ again:
return 0;
}
int wait_for_pidfd(int pidfd)
{
int ret;
siginfo_t info = {
.si_signo = 0,
};
do {
ret = waitid(P_PIDFD, pidfd, &info, __WALL | WEXITED);
} while (ret < 0 && errno == EINTR);
return !ret && WIFEXITED(info.si_status) && WEXITSTATUS(info.si_status) == 0;
}
int lxc_wait_for_pid_status(pid_t pid)
{
int status, ret;
......@@ -1846,3 +1861,38 @@ int lxc_setup_keyring(char *keyring_label)
return ret;
}
bool lxc_can_use_pidfd(int pidfd)
{
int ret;
if (pidfd < 0)
return log_error(false, "Kernel does not support pidfds");
ret = lxc_raw_pidfd_send_signal(pidfd, 0, NULL, 0);
if (ret)
return log_error_errno(false, errno, "Kernel does not support sending signals through pidfds");
/*
* We don't care whether or not children were in a waitable state. We
* just care whether waitid() recognizes P_PIDFD.
*
* Btw, while I have your attention, the above waitid() code is an
* excellent example of how _not_ to do flag-based kernel APIs. So if
* you ever go into kernel development or are already and you add this
* kind of flag potpourri even though you have read this comment shame
* on you. May the gods of operating system development have mercy on
* your soul because I won't.
*/
ret = waitid(P_PIDFD, pidfd, NULL,
/* Type of children to wait for. */
__WALL |
/* How to wait for them. */
WNOHANG | WNOWAIT |
/* What state to wait for. */
WEXITED | WSTOPPED | WCONTINUED);
if (ret < 0)
return log_error_errno(false, errno, "Kernel does not support waiting on processes through pidfds");
return log_trace(true, "Kernel supports pidfds");
}
......@@ -85,6 +85,7 @@ static inline void __auto_lxc_pclose__(struct lxc_popen_FILE **f)
*/
extern int wait_for_pid(pid_t pid);
extern int lxc_wait_for_pid_status(pid_t pid);
extern int wait_for_pidfd(int pidfd);
#if HAVE_OPENSSL
extern int sha1sum_file(char *fnam, unsigned char *md_value, unsigned int *md_len);
......@@ -236,5 +237,6 @@ extern int lxc_set_death_signal(int signal, pid_t parent, int parent_status_fd);
extern int fd_cloexec(int fd, bool cloexec);
extern int recursive_destroy(const char *dirname);
extern int lxc_setup_keyring(char *keyring_label);
extern bool lxc_can_use_pidfd(int pidfd);
#endif /* __LXC_UTILS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment