]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
execute: Split creation of namespaces into two steps
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Aug 2022 07:46:33 +0000 (07:46 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Aug 2022 07:46:33 +0000 (07:46 +0000)
This is needed to create a new user namespace first in which we can do
some first stage of initialization. Then, we will start a new process in
that new namespace which will finish initialization.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/execute.c

index e3fc3caf80eba07330cfa2cb02390f6791d66823..30714b75b208a57707526b6f2e34bc1dd9949858 100644 (file)
@@ -539,7 +539,53 @@ static int set_environ(struct pakfire_execute* env, const char* key, const char*
        return 0;
 }
 
-static int pakfire_execute_fork(void* data) {
+static int pakfire_execute_write_uidgid_mapping(struct pakfire* pakfire,
+               const char* path, uid_t mapped_id, size_t length) {
+       int r = 1;
+
+       // Open file for writing
+       FILE* f = fopen(path, "w");
+       if (!f) {
+               ERROR(pakfire, "Could not open %s for writing: %m\n", path);
+               goto ERROR;
+       }
+
+       // Write configuration
+       int bytes_written = fprintf(f, "%d %d %ld\n", 0, mapped_id, length);
+       if (bytes_written < 0) {
+               ERROR(pakfire, "Could not write UID mapping: %m\n");
+               goto ERROR;
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (f)
+               fclose(f);
+
+       return r;
+}
+
+static int pakfire_execute_setup_uid_mapping(struct pakfire* pakfire) {
+       // XXX hard-coded values
+       const uid_t mapped_uid = 100000;
+       const size_t length = 64536;
+
+       return pakfire_execute_write_uidgid_mapping(pakfire,
+               "/proc/self/uid_map", mapped_uid, length);
+}
+
+static int pakfire_execute_setup_gid_mapping(struct pakfire* pakfire) {
+       // XXX hard-coded values
+       const uid_t mapped_gid = 100000;
+       const size_t length = 64536;
+
+       return pakfire_execute_write_uidgid_mapping(pakfire,
+               "/proc/self/gid_map", mapped_gid, length);
+}
+
+static int pakfire_execute_fork2(void* data) {
        struct pakfire_execute* env = (struct pakfire_execute*)data;
        int r;
 
@@ -650,6 +696,63 @@ static int pakfire_execute_fork(void* data) {
        return r;
 }
 
+/*
+       This function is launched in a new process that has its own user namespace.
+
+       It will set up the container.
+*/
+static int pakfire_execute_fork1(struct pakfire_execute* env) {
+       struct pakfire* pakfire = env->pakfire;
+       int r;
+
+       DEBUG(pakfire, "Launched a new container as PID %d\n", getpid());
+
+       // Setup UID mapping
+       r = pakfire_execute_setup_uid_mapping(pakfire);
+       if (r)
+               return r;
+
+       // Setup GID mapping
+       r = pakfire_execute_setup_gid_mapping(pakfire);
+       if (r)
+               return r;
+
+       // Configure child process
+       struct clone_args args = {
+               .flags =
+                       CLONE_NEWCGROUP |
+                       CLONE_NEWIPC |
+                       CLONE_NEWNS |
+                       CLONE_NEWPID |
+                       CLONE_NEWUTS,
+               .exit_signal = SIGCHLD,
+       };
+
+       // Enable network?
+       if (!(env->flags & PAKFIRE_EXECUTE_ENABLE_NETWORK))
+               args.flags |= CLONE_NEWNET;
+
+       // Fork this process
+       pid_t pid = clone3(&args, sizeof(args));
+       if (pid < 0) {
+               ERROR(pakfire, "Could not fork: %m\n");
+               return -errno;
+
+       // Child process
+       } else if (pid == 0) {
+               r = pakfire_execute_fork2(env);
+               _exit(r);
+       }
+
+       int status = 0;
+
+       // Wait until the child process has finished
+       waitpid(pid, &status, 0);
+
+       // Pass the exit code of the child process
+       return WEXITSTATUS(status);
+}
+
 PAKFIRE_EXPORT int pakfire_execute(struct pakfire* pakfire, const char* argv[], char* envp[],
                int flags, pakfire_execute_logging_callback logging_callback, void* data) {
        int r;
@@ -671,25 +774,6 @@ PAKFIRE_EXPORT int pakfire_execute(struct pakfire* pakfire, const char* argv[],
                        goto ERROR;
        }
 
-       if (!logging_callback)
-               logging_callback = &default_logging_callback;
-
-       // Configure child process
-       struct clone_args args = {
-               .flags =
-                       CLONE_VFORK |
-                       CLONE_NEWCGROUP |
-                       CLONE_NEWIPC |
-                       CLONE_NEWNS |
-                       CLONE_NEWPID |
-                       CLONE_NEWUTS,
-               .exit_signal = SIGCHLD,
-       };
-
-       // Enable network?
-       if (!(flags & PAKFIRE_EXECUTE_ENABLE_NETWORK))
-               args.flags |= CLONE_NEWNET;
-
        // Setup interactive environment
        if (flags & PAKFIRE_EXECUTE_INTERACTIVE) {
                // Set environment
@@ -749,6 +833,17 @@ PAKFIRE_EXPORT int pakfire_execute(struct pakfire* pakfire, const char* argv[],
                }
        }
 
+       if (!logging_callback)
+               logging_callback = &default_logging_callback;
+
+       // Lauch a new user namespace
+       struct clone_args args = {
+               .flags =
+                       CLONE_VFORK |
+                       CLONE_NEWUSER,
+               .exit_signal = SIGCHLD,
+       };
+
        // Fork this process
        pid_t pid = clone3(&args, sizeof(args));
        if (pid < 0) {
@@ -757,7 +852,7 @@ PAKFIRE_EXPORT int pakfire_execute(struct pakfire* pakfire, const char* argv[],
 
        // Child process
        } else if (pid == 0) {
-               r = pakfire_execute_fork(&env);
+               r = pakfire_execute_fork1(&env);
                exit(r);
        }