aboutgitcodebugslistschat
path: root/passt.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-09-15 00:28:40 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-09-15 00:32:23 +0200
commita041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7 (patch)
tree850d626c6a1201fc0cd3fd4fbc6b3c3ed720e7e9 /passt.c
parent7d81b3c646c353924e7bd2ee719522694d212ba7 (diff)
downloadpasst-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar.gz
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar.bz2
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar.lz
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar.xz
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.tar.zst
passt-a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7.zip
pasta: Clean up namespace processes on exit, reap zombies from clone()
If pasta created the namespace, it's probably expected that processes started in the same namespace are terminated once pasta exits. Scan procfs namespace links for corresponding processes, send SIGQUIT and SIGKILL (after one second) if found. While at it, make the signal handler reap otherwise-zombies resulting from clone(). Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'passt.c')
-rw-r--r--passt.c92
1 files changed, 83 insertions, 9 deletions
diff --git a/passt.c b/passt.c
index dfd2f9d..3604fa1 100644
--- a/passt.c
+++ b/passt.c
@@ -26,6 +26,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <dirent.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/uio.h>
@@ -138,6 +139,67 @@ void proto_update_l2_buf(unsigned char *eth_d, unsigned char *eth_s,
}
static int pasta_child_pid;
+static char pasta_child_ns[PATH_MAX];
+
+/**
+ * pasta_ns_cleanup() - Look for processes in namespace, terminate them
+ */
+static void pasta_ns_cleanup(void)
+{
+ char proc_path[PATH_MAX], ns_link[PATH_MAX];
+ int recheck = 0, found = 0, waited = 0;
+ struct dirent *dp;
+ DIR *dirp;
+
+ if (!*pasta_child_ns)
+ return;
+
+loop:
+ if (!(dirp = opendir("/proc")))
+ return;
+
+ while ((dp = readdir(dirp))) {
+ pid_t pid;
+
+ errno = 0;
+ pid = strtol(dp->d_name, NULL, 0);
+ if (!pid || errno)
+ continue;
+
+ snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net", pid);
+ if (readlink(proc_path, ns_link, PATH_MAX) < 0)
+ continue;
+
+ if (!strncmp(ns_link, pasta_child_ns, PATH_MAX)) {
+ found = 1;
+ if (waited)
+ kill(pid, SIGKILL);
+ else
+ kill(pid, SIGQUIT);
+ }
+ }
+
+ closedir(dirp);
+
+ if (!found)
+ return;
+
+ if (waited) {
+ if (recheck) {
+ info("Some processes in namespace didn't quit");
+ } else {
+ found = 0;
+ recheck = 1;
+ goto loop;
+ }
+ return;
+ }
+
+ info("Waiting for all processes in namespace to terminate");
+ sleep(1);
+ waited = 1;
+ goto loop;
+}
/**
* pasta_child_handler() - Exit once shell spawned by pasta_start_ns() exits
@@ -149,10 +211,15 @@ static void pasta_child_handler(int signal)
(void)signal;
- if (!waitid(P_PID, pasta_child_pid, &infop, WEXITED | WNOHANG)) {
- if (infop.si_pid == pasta_child_pid)
+ if (pasta_child_pid &&
+ !waitid(P_PID, pasta_child_pid, &infop, WEXITED | WNOHANG)) {
+ if (infop.si_pid == pasta_child_pid) {
+ pasta_ns_cleanup();
exit(EXIT_SUCCESS);
+ }
}
+
+ waitid(P_ALL, 0, NULL, WEXITED | WNOHANG);
}
/**
@@ -175,18 +242,12 @@ static void pasta_start_ns(struct ctx *c)
{
char buf[BUFSIZ], *shell;
int euid = geteuid();
- struct sigaction sa;
int fd;
c->foreground = 1;
if (!c->debug)
c->quiet = 1;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = pasta_child_handler;
- sigaction(SIGCHLD, &sa, NULL);
-
if ((c->pasta_pid = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
@@ -247,6 +308,14 @@ int main(int argc, char **argv)
int nfds, i;
if (strstr(argv[0], "pasta") || strstr(argv[0], "passt4netns")) {
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = pasta_child_handler;
+ sigaction(SIGCHLD, &sa, NULL);
+ signal(SIGPIPE, SIG_IGN);
+
c.mode = MODE_PASTA;
log_name = "pasta";
} else {
@@ -262,8 +331,13 @@ int main(int argc, char **argv)
if (!c.debug && (c.stderr || isatty(fileno(stdout))))
openlog(log_name, LOG_PERROR, LOG_DAEMON);
- if (c.mode == MODE_PASTA && !c.pasta_pid)
+ if (c.mode == MODE_PASTA && !c.pasta_pid) {
+ char proc_path[PATH_MAX];
+
pasta_start_ns(&c);
+ snprintf(proc_path, PATH_MAX, "/proc/%i/ns/net", c.pasta_pid);
+ readlink(proc_path, pasta_child_ns, PATH_MAX);
+ }
c.epollfd = epoll_create1(0);
if (c.epollfd == -1) {