]> git.ipfire.org Git - people/ms/pakfire.git/commitdiff
jail: Handle signals in epoll() loop
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Jun 2023 13:32:34 +0000 (13:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 30 Jun 2023 13:32:34 +0000 (13:32 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/jail.c

index fbdf7b3c5ef82049154c1468c598241525bd396d..af7de97dc0ba5bbcbb026888b35f49d4ea102425 100644 (file)
@@ -35,6 +35,7 @@
 #include <sys/personality.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
+#include <sys/signalfd.h>
 #include <sys/timerfd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -495,6 +496,32 @@ ERROR:
        return -1;
 }
 
+// Signals
+
+static int pakfire_jail_handle_signals(struct pakfire_jail* jail) {
+       sigset_t mask;
+       int r;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+
+       // Block signals
+       r = sigprocmask(SIG_BLOCK, &mask, NULL);
+       if (r < 0) {
+               ERROR(jail->pakfire, "Failed to block signals: %m\n");
+               return r;
+       }
+
+       // Create a file descriptor
+       r = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+       if (r < 0) {
+               ERROR(jail->pakfire, "Failed to create signalfd: %m\n");
+               return r;
+       }
+
+       return r;
+}
+
 /*
        This function replaces any logging in the child process.
 
@@ -696,6 +723,7 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
        int epollfd = -1;
        struct epoll_event ev;
        struct epoll_event events[EPOLL_MAX_EVENTS];
+       struct signalfd_siginfo siginfo;
        char garbage[8];
        int r = 0;
 
@@ -713,9 +741,12 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
        const int log_ERROR = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_ERROR);
        const int log_DEBUG = pakfire_jail_get_pipe_to_read(jail, &ctx->pipes.log_DEBUG);
 
+       // Signals
+       const int signalfd = pakfire_jail_handle_signals(jail);
+
        // Make a list of all file descriptors we are interested in
-       int fds[] = {
-               stdin, stdout, stderr, pidfd, timerfd, log_INFO, log_ERROR, log_DEBUG,
+       const int fds[] = {
+               stdin, stdout, stderr, pidfd, timerfd, signalfd, log_INFO, log_ERROR, log_DEBUG,
        };
 
        // Setup epoll
@@ -829,6 +860,37 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
                                        // There is nothing else to do
                                        continue;
 
+                               // Handle signals
+                               } else if (fd == signalfd) {
+                                       // Read the signal
+                                       r = read(signalfd, &siginfo, sizeof(siginfo));
+                                       if (r < 1) {
+                                               ERROR(jail->pakfire, "Could not read signal: %m\n");
+                                               goto ERROR;
+                                       }
+
+                                       DEBUG(jail->pakfire, "Received signal %d\n", siginfo.ssi_signo);
+
+                                       // Handle signals
+                                       switch (siginfo.ssi_signo) {
+                                               // Pass SIGINT down to the child process
+                                               case SIGINT:
+                                                       r = pidfd_send_signal(pidfd, siginfo.ssi_signo, NULL, 0);
+                                                       if (r) {
+                                                               ERROR(jail->pakfire, "Could not send signal to process: %m\n");
+                                                               goto ERROR;
+                                                       }
+                                                       break;
+
+                                               default:
+                                                       ERROR(jail->pakfire, "Received unhandled signal %d\n",
+                                                               siginfo.ssi_signo);
+                                                       break;
+                                       }
+
+                                       // Don't fall through to log processing
+                                       continue;
+
                                // Handle logging messages
                                } else if (fd == log_INFO) {
                                        buffer = &ctx->buffers.log_INFO;
@@ -909,6 +971,8 @@ ERROR:
                close(epollfd);
        if (timerfd > 0)
                close(timerfd);
+       if (signalfd > 0)
+               close(signalfd);
 
        return r;
 }