From: Michael Tremer Date: Tue, 2 Aug 2022 07:46:33 +0000 (+0000) Subject: execute: Split creation of namespaces into two steps X-Git-Tag: 0.9.28~649 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76a1373f5ff9de8b1796853940f3ab49cfc9734b;p=pakfire.git execute: Split creation of namespaces into two steps 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 --- diff --git a/src/libpakfire/execute.c b/src/libpakfire/execute.c index e3fc3caf8..30714b75b 100644 --- a/src/libpakfire/execute.c +++ b/src/libpakfire/execute.c @@ -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); }