]> git.ipfire.org Git - pakfire.git/commitdiff
jail: Catch any PID events by the event loop
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 5 Oct 2024 17:15:22 +0000 (17:15 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 5 Oct 2024 17:15:22 +0000 (17:15 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/jail.c

index 38d80c6f9e3dc942f466ffad2c9da66db24282cc..a4a0499d6e29ac1a1e5637e669d5484db3cbdfe4 100644 (file)
@@ -161,9 +161,14 @@ struct pakfire_jail {
 };
 
 struct pakfire_jail_exec {
+       struct pakfire_jail* jail;
+
        sd_event* loop;
        int flags;
 
+       // Exit Code
+       int exit;
+
        // PID (of the child)
        pid_t pid;
        int pidfd;
@@ -171,9 +176,6 @@ struct pakfire_jail_exec {
        // Socket to pass FDs
        int socket[2];
 
-       // Process status (from waitid)
-       siginfo_t status;
-
        // FD to notify the client that the parent has finished initialization
        int completed_fd;
 
@@ -1126,9 +1128,6 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
        char garbage[8];
        int r = 0;
 
-       // Fetch file descriptors from context
-       const int pidfd  = ctx->pidfd;
-
        // Fetch the UNIX domain socket
        const int socket_recv = pakfire_jail_get_pipe_to_read(jail, &ctx->socket);
 
@@ -1143,9 +1142,6 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
                // Timer
                { timerfd, EPOLLIN },
 
-               // Child Process
-               { ctx->pidfd, EPOLLIN },
-
                // UNIX Domain Socket
                { socket_recv, EPOLLIN },
 
@@ -1232,21 +1228,6 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
                                        goto ERROR;
                                }
 
-                       // Handle any changes to the PIDFD
-                       } else if (pidfd == fd) {
-                               if (e & EPOLLIN) {
-                                       // Call waidid() and store the result
-                                       r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
-                                       if (r) {
-                                               CTX_ERROR(jail->ctx, "waitid() failed: %m\n");
-                                               goto ERROR;
-                                       }
-
-                                       // Mark that we have ended so that we will process the remaining
-                                       // events from epoll() now, but won't restart the outer loop.
-                                       ended = 1;
-                               }
-
                        // Handle timer events
                        } else if (timerfd == fd) {
                                if (e & EPOLLIN) {
@@ -1265,7 +1246,7 @@ static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec
                                                CTX_DEBUG(jail->ctx, "Terminating process...\n");
 
                                                // Send SIGTERM to the process
-                                               r = pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
+                                               r = pidfd_send_signal(ctx->pidfd, SIGKILL, NULL, 0);
                                                if (r) {
                                                        CTX_ERROR(jail->ctx, "Could not kill process: %m\n");
                                                        goto ERROR;
@@ -1863,12 +1844,47 @@ static int pakfire_jail_wait_for_signal(struct pakfire_jail* jail, int fd) {
        return r;
 }
 
+static int pakfire_jail_exited(sd_event_source* source, const siginfo_t* si, void* data) {
+       struct pakfire_jail_exec* ctx = data;
+       struct pakfire_jail* jail = ctx->jail;
+
+       switch (si->si_code) {
+               case CLD_EXITED:
+                       CTX_DEBUG(jail->ctx, "Process has exited with status code %d\n", si->si_status);
+
+                       // Store the exit code
+                       ctx->exit = si->si_status;
+                       break;
+
+               case CLD_KILLED:
+                       CTX_ERROR(jail->ctx, "Process has been killed by signal %d\n", si->si_signo);
+
+                       // Store the exit code
+                       ctx->exit = 139;
+                       break;
+
+               case CLD_DUMPED:
+                       CTX_ERROR(jail->ctx, "The child process terminated abnormally\n");
+                       break;
+       }
+
+       // Terminate the event loop
+       return sd_event_exit(sd_event_source_get_event(source), 0);
+}
+
 /*
        Performs the initialisation that needs to happen in the parent part
 */
 static int pakfire_jail_parent(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
        int r;
 
+       // Register the PID file descriptor
+       r = sd_event_add_child_pidfd(ctx->loop, NULL, ctx->pidfd, WEXITED, pakfire_jail_exited, ctx);
+       if (r < 0) {
+               CTX_DEBUG(jail->ctx, "Could not register the child process with the event loop: %s\n", strerror(-r));
+               return r;
+       }
+
        // Setup UID mapping
        r = pakfire_jail_setup_uid_mapping(jail, ctx->pid);
        if (r)
@@ -2221,7 +2237,6 @@ static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exe
 
 // Run a command in the jail
 PAKFIRE_EXPORT int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags) {
-       int exit = -1;
        int r;
 
        // Check if argv is valid
@@ -2232,8 +2247,12 @@ PAKFIRE_EXPORT int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv
 
        // Initialize context for this call
        struct pakfire_jail_exec ctx = {
+               .jail  = jail,
                .flags = flags,
 
+               // Exit Code
+               .exit = -1,
+
                .socket = { -1, -1 },
 
                .pidfd = -1,
@@ -2363,31 +2382,6 @@ PAKFIRE_EXPORT int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv
        if (r)
                goto ERROR;
 
-       // Handle exit status
-       switch (ctx.status.si_code) {
-               case CLD_EXITED:
-                       CTX_DEBUG(jail->ctx, "The child process exited with code %d\n",
-                               ctx.status.si_status);
-
-                       // Pass exit code
-                       exit = ctx.status.si_status;
-                       break;
-
-               case CLD_KILLED:
-                       CTX_ERROR(jail->ctx, "The child process was killed\n");
-                       exit = 139;
-                       break;
-
-               case CLD_DUMPED:
-                       CTX_ERROR(jail->ctx, "The child process terminated abnormally\n");
-                       break;
-
-               // Log anything else
-               default:
-                       CTX_ERROR(jail->ctx, "Unknown child exit code: %d\n", ctx.status.si_code);
-                       break;
-       }
-
 ERROR:
        // Reset all callbacks
        pakfire_jail_set_stdin_callback(jail, NULL, NULL);
@@ -2422,7 +2416,7 @@ ERROR:
        if (ctx.loop)
                sd_event_unref(ctx.loop);
 
-       return exit;
+       return ctx.exit;
 }
 
 static int pakfire_jail_exec_interactive(