]> git.ipfire.org Git - people/ms/pakfire.git/commitdiff
jail: Implement first steps of running a command in jail
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Aug 2022 10:35:30 +0000 (10:35 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Aug 2022 10:35:30 +0000 (10:35 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/jail.c
tests/libpakfire/jail.c

index 4dfdb5eb8d6b2d917f2b4a87f734983bc352120b..b65f2bda66be05be0f3ef0048e16c759d9ab393c 100644 (file)
 #############################################################################*/
 
 #include <errno.h>
+#include <linux/sched.h>
+#include <sched.h>
+#include <signal.h>
 #include <stdlib.h>
+#include <syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include <pakfire/logging.h>
 #include <pakfire/jail.h>
@@ -49,6 +55,10 @@ struct pakfire_jail {
        char* env[ENVIRON_SIZE];
 };
 
+static int clone3(struct clone_args* args, size_t size) {
+       return syscall(__NR_clone3, args, size);
+}
+
 static void pakfire_jail_free(struct pakfire_jail* jail) {
        DEBUG(jail->pakfire, "Freeing jail at %p\n", jail);
 
@@ -208,7 +218,63 @@ int pakfire_jail_set_env(struct pakfire_jail* jail, const char* key, const char*
        return 0;
 }
 
+static int pakfire_jail_child(struct pakfire_jail* jail, const char* argv[]) {
+       // XXX do we have to reconfigure logging here?
+
+       DEBUG(jail->pakfire, "Launched child process in jail with PID %d\n", getpid());
+
+       return 0;
+}
+
 // Run a command in the jail
 int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[]) {
-       return 1; // TODO
+       int r;
+
+       DEBUG(jail->pakfire, "Executing jail...\n");
+
+       // Configure child process
+       struct clone_args args = {
+               .flags =
+                       CLONE_NEWCGROUP |
+                       CLONE_NEWIPC |
+                       CLONE_NEWNS |
+                       CLONE_NEWPID |
+                       CLONE_NEWUSER |
+                       CLONE_NEWUTS,
+               .exit_signal = SIGCHLD,
+       };
+
+       // Fork this process
+       pid_t pid = clone3(&args, sizeof(args));
+       if (pid < 0) {
+               ERROR(jail->pakfire, "Could not clone: %m\n");
+               return -1;
+
+       // Child process
+       } else if (pid == 0) {
+               r = pakfire_jail_child(jail, argv);
+               _exit(r);
+       }
+
+       // Set some useful error code
+       int exit;
+       int status = 0;
+
+       DEBUG(jail->pakfire, "Waiting for PID %d to finish its work\n", pid);
+
+       if (!status)
+               waitpid(pid, &status, 0);
+
+       if (WIFEXITED(status)) {
+               exit = WEXITSTATUS(status);
+
+               DEBUG(jail->pakfire, "Child process exited with code: %d\n", exit);
+       } else {
+               ERROR(jail->pakfire, "Could not determine the exit status of process %d\n", pid);
+
+               errno = ESRCH;
+               exit = -1;
+       }
+
+       return exit;
 }
index 48a42db4fd2e06963a9fea7354317b5d286b2881..ec8987393a6663a36740caa0c2e49ac651ebd163 100644 (file)
@@ -75,10 +75,33 @@ FAIL:
        return EXIT_FAILURE;
 }
 
+static int test_exec(const struct test* t) {
+       struct pakfire_jail* jail = NULL;
+
+       const char* argv[] = {
+               "/does-not-exist",
+               NULL,
+       };
+
+       // Create a new jail
+       ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0));
+
+       // Try to execute something
+       ASSERT_SUCCESS(pakfire_jail_exec(jail, argv));
+
+       // Destroy it
+       ASSERT_NULL(pakfire_jail_unref(jail));
+
+       return EXIT_SUCCESS;
+
+FAIL:
+       return EXIT_FAILURE;
+}
 
 int main(int argc, char** argv) {
        testsuite_add_test(test_create);
        testsuite_add_test(test_env);
+       testsuite_add_test(test_exec);
 
        return testsuite_run();
 }