From: Christian Brauner Date: Wed, 11 Mar 2020 13:02:40 +0000 (+0100) Subject: start: add ability to detect whether kernel supports pidfds X-Git-Tag: lxc-4.0.0~33^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39293f2213fa1a654309b92f28966e5a353e5212;p=thirdparty%2Flxc.git start: add ability to detect whether kernel supports pidfds Signed-off-by: Christian Brauner --- diff --git a/src/lxc/raw_syscalls.h b/src/lxc/raw_syscalls.h index 65dd31691..0a35408d8 100644 --- a/src/lxc/raw_syscalls.h +++ b/src/lxc/raw_syscalls.h @@ -7,6 +7,7 @@ #define _GNU_SOURCE 1 #endif #include +#include #include #include #include @@ -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 * diff --git a/src/lxc/start.c b/src/lxc/start.c index b8edcdf36..2e6f8c6d4 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -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; diff --git a/src/lxc/utils.c b/src/lxc/utils.c index a3495635a..0fda91762 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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"); +} diff --git a/src/lxc/utils.h b/src/lxc/utils.h index fcaa127a4..1d980f885 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -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 */