start: add ability to detect whether kernel supports pidfds

parent fa3621ea
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define _GNU_SOURCE 1 #define _GNU_SOURCE 1
#endif #endif
#include <sched.h> #include <sched.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
...@@ -18,6 +19,11 @@ ...@@ -18,6 +19,11 @@
#define CLONE_PIDFD 0x00001000 #define CLONE_PIDFD 0x00001000
#endif #endif
/* waitid */
#ifndef P_PIDFD
#define P_PIDFD 3
#endif
/* /*
* lxc_raw_clone() - create a new process * lxc_raw_clone() - create a new process
* *
......
...@@ -1659,6 +1659,10 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1659,6 +1659,10 @@ static int lxc_spawn(struct lxc_handler *handler)
} }
TRACE("Cloned child process %d", handler->pid); 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); ret = snprintf(pidstr, 20, "%d", handler->pid);
if (ret < 0 || ret >= 20) if (ret < 0 || ret >= 20)
goto out_delete_net; goto out_delete_net;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <libgen.h> #include <libgen.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -291,6 +292,20 @@ again: ...@@ -291,6 +292,20 @@ again:
return 0; 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 lxc_wait_for_pid_status(pid_t pid)
{ {
int status, ret; int status, ret;
...@@ -1846,3 +1861,38 @@ int lxc_setup_keyring(char *keyring_label) ...@@ -1846,3 +1861,38 @@ int lxc_setup_keyring(char *keyring_label)
return ret; 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) ...@@ -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 wait_for_pid(pid_t pid);
extern int lxc_wait_for_pid_status(pid_t pid); extern int lxc_wait_for_pid_status(pid_t pid);
extern int wait_for_pidfd(int pidfd);
#if HAVE_OPENSSL #if HAVE_OPENSSL
extern int sha1sum_file(char *fnam, unsigned char *md_value, unsigned int *md_len); 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); ...@@ -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 fd_cloexec(int fd, bool cloexec);
extern int recursive_destroy(const char *dirname); extern int recursive_destroy(const char *dirname);
extern int lxc_setup_keyring(char *keyring_label); extern int lxc_setup_keyring(char *keyring_label);
extern bool lxc_can_use_pidfd(int pidfd);
#endif /* __LXC_UTILS_H */ #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