diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-09-15 00:28:40 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-09-15 00:32:23 +0200 |
commit | a041f6d920a4ca78e0d24b2fd84a7c7ecb66d9d7 (patch) | |
tree | 850d626c6a1201fc0cd3fd4fbc6b3c3ed720e7e9 /passt.c | |
parent | 7d81b3c646c353924e7bd2ee719522694d212ba7 (diff) | |
download | passt-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.c | 92 |
1 files changed, 83 insertions, 9 deletions
@@ -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) { |