]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
start: add ability to detect whether kernel supports pidfds
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 11 Mar 2020 13:02:40 +0000 (14:02 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 11 Mar 2020 14:59:33 +0000 (15:59 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/raw_syscalls.h
src/lxc/start.c
src/lxc/utils.c
src/lxc/utils.h

index 65dd3169136e75c07f051f5691d2d4b31ae7bdf3..0a35408d8ed28c9d7d21da12b3ca8fc75b56491f 100644 (file)
@@ -7,6 +7,7 @@
 #define _GNU_SOURCE 1
 #endif
 #include <sched.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
 #define CLONE_PIDFD 0x00001000
 #endif
 
+/* waitid */
+#ifndef P_PIDFD
+#define P_PIDFD 3
+#endif
+
 /*
  * lxc_raw_clone() - create a new process
  *
index b8edcdf369b187401ac5f4bb1d94e846c9ff8d9b..2e6f8c6d420c7c47161dcc5d0c6ef7ba13263c83 100644 (file)
@@ -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;
index a3495635af4bdd3b79cad81acf8ed68301c0bfc1..0fda91762f0a16d494e205d4cb9874d0fa0d7b79 100644 (file)
@@ -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");
+}
index fcaa127a4575c8f77070afe8eb060d6d2782ffd4..1d980f8855b44806df9e5f8cf277affb855c2125 100644 (file)
@@ -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 */