From: Michael Tremer Date: Sun, 29 Dec 2024 14:59:17 +0000 (+0000) Subject: jail: Move the environment into an extra object X-Git-Tag: 0.9.30~679 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=716522a822cde30175bf03e935cf8d93aea6c7ff;p=pakfire.git jail: Move the environment into an extra object This allows us to pass a custom environment to each command that we are running. This helps us to keep the environment a lot cleaner. Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 706b3c819..78f100844 100644 --- a/Makefile.am +++ b/Makefile.am @@ -199,6 +199,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/deps.c \ src/libpakfire/digest.c \ src/libpakfire/dist.c \ + src/libpakfire/env.c \ src/libpakfire/fhs.c \ src/libpakfire/file.c \ src/libpakfire/filelist.c \ @@ -254,6 +255,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/deps.h \ src/libpakfire/include/pakfire/digest.h \ src/libpakfire/include/pakfire/dist.h \ + src/libpakfire/include/pakfire/env.h \ src/libpakfire/include/pakfire/fhs.h \ src/libpakfire/include/pakfire/file.h \ src/libpakfire/include/pakfire/filelist.h \ diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index c71732e9c..2421e1c1b 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -1817,7 +1817,7 @@ static int pakfire_archive_handle_systemd_sysusers(struct pakfire_archive* archi goto ERROR; // Run! - r = pakfire_jail_communicate(jail, argv, PAKFIRE_JAIL_NOENT_OK, + r = pakfire_jail_communicate(jail, argv, NULL, PAKFIRE_JAIL_NOENT_OK, pakfire_archive_stream_payload, a, NULL, NULL); ERROR: diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index f53e35ed5..aec2064de 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +91,9 @@ struct pakfire_build { // Jail struct pakfire_jail* jail; + // Environment + struct pakfire_env* env; + // The build repository struct pakfire_repo* repo; @@ -293,7 +297,7 @@ static int pakfire_build_run_script( } // Execute the script - r = pakfire_jail_exec_script(build->jail, script, length, args, + r = pakfire_jail_exec_script(build->jail, script, length, args, build->env, stdin_callback, stdin_data, stdout_callback, stdout_data); if (r) ERROR(build->ctx, "Script '%s' failed with status %d\n", filename, r); @@ -1026,18 +1030,23 @@ ERROR: static int pakfire_build_stage(struct pakfire_build* build, struct pakfire_parser* makefile, const char* stage) { + struct pakfire_env* env = NULL; + char* script = NULL; char template[1024]; + int r; // Prepare template for this stage - int r = pakfire_string_format(template, TEMPLATE, stage); - if (r) + r = pakfire_string_format(template, TEMPLATE, stage); + if (r < 0) return r; // Fetch the environment - char** envp = pakfire_parser_make_environ(makefile); + env = pakfire_parser_make_environ(makefile); + if (!env) + goto ERROR; // Create the build script - char* script = pakfire_parser_expand(makefile, "build", template); + script = pakfire_parser_expand(makefile, "build", template); if (!script) { ERROR(build->ctx, "Could not generate the build script for stage '%s': %m\n", stage); goto ERROR; @@ -1045,26 +1054,17 @@ static int pakfire_build_stage(struct pakfire_build* build, INFO(build->ctx, "Running build stage '%s'\n", stage); - // Import environment - // XXX is this a good idea? - r = pakfire_jail_import_env(build->jail, (const char**)envp); - if (r) { - ERROR(build->ctx, "Could not import environment: %m\n"); - goto ERROR; - } + // XXX merge the basic environment // Run the script - r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, + r = pakfire_jail_exec_script(build->jail, script, strlen(script), NULL, env, NULL, NULL, pakfire_build_output_callback, build); if (r) ERROR(build->ctx, "Build stage '%s' failed with status %d\n", stage, r); ERROR: - if (envp) { - for (char** e = envp; *e; e++) - free(*e); - free(envp); - } + if (env) + pakfire_env_unref(env); if (script) free(script); @@ -1320,6 +1320,8 @@ static void pakfire_build_free(struct pakfire_build* build) { if (build->jail) pakfire_jail_unref(build->jail); + if (build->env) + pakfire_env_unref(build->env); if (build->cgroup) { // Destroy the cgroup @@ -1521,7 +1523,7 @@ static int pakfire_build_setup_ccache(struct pakfire_build* build) { DEBUG(build->ctx, "ccache usage has been disabled for this build\n"); // Set CCACHE_DISABLE=1 so that if ccache is installed, it will disable itself - r = pakfire_jail_set_env(build->jail, "CCACHE_DISABLE", "1"); + r = pakfire_env_set(build->env, "CCACHE_DISABLE", "1"); if (r) { ERROR(build->ctx, "Could not disable ccache: %m\n"); return r; @@ -1531,14 +1533,14 @@ static int pakfire_build_setup_ccache(struct pakfire_build* build) { } // Set CCACHE_DIR - r = pakfire_jail_set_env(build->jail, "CCACHE_DIR", CCACHE_DIR); + r = pakfire_env_set(build->env, "CCACHE_DIR", CCACHE_DIR); if (r) { ERROR(build->ctx, "Could not set ccache directory: %m\n"); return r; } // Set CCACHE_TEMPDIR - r = pakfire_jail_set_env(build->jail, "CCACHE_TEMPDIR", "/tmp"); + r = pakfire_env_set(build->env, "CCACHE_TEMPDIR", "/tmp"); if (r) { ERROR(build->ctx, "Could not set ccache tempdir: %m\n"); return r; @@ -1617,6 +1619,11 @@ PAKFIRE_EXPORT int pakfire_build_create(struct pakfire_build** build, // Copy flags b->flags = flags; + // Create an environment + r = pakfire_env_create(&b->env, b->ctx); + if (r < 0) + goto ERROR; + // Store start time r = pakfire_build_set_time_start(b); if (r) @@ -2537,7 +2544,7 @@ PAKFIRE_EXPORT int pakfire_build_shell(struct pakfire_build* build, const char* // Run the command (if given) if (argv) - return pakfire_jail_exec(build->jail, argv, 0); + return pakfire_jail_exec(build->jail, argv, build->env, 0); // Otherwise run the shell return pakfire_jail_shell(build->jail); diff --git a/src/libpakfire/env.c b/src/libpakfire/env.c new file mode 100644 index 000000000..9d1dcfd12 --- /dev/null +++ b/src/libpakfire/env.c @@ -0,0 +1,189 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2024 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include + +#define ENVIRON_SIZE 128 + +struct pakfire_env { + struct pakfire_ctx* ctx; + int nrefs; + + char* env[ENVIRON_SIZE]; +}; + +static void pakfire_env_free(struct pakfire_env* env) { + // Free environment + for (unsigned int i = 0; env->env[i]; i++) + free(env->env[i]); + + if (env->ctx) + pakfire_ctx_unref(env->ctx); + free(env); +} + +int pakfire_env_create(struct pakfire_env** env, struct pakfire_ctx* ctx) { + struct pakfire_env* e = NULL; + + // Allocate a new environment + e = calloc(1, sizeof(*e)); + if (!e) + return -errno; + + // Store a reference to the context + e->ctx = pakfire_ctx_ref(ctx); + + // Initialize the reference counter + e->nrefs = 1; + + // Return the pointer + *env = e; + + return 0; +} + +struct pakfire_env* pakfire_env_ref(struct pakfire_env* env) { + ++env->nrefs; + + return env; +} + +struct pakfire_env* pakfire_env_unref(struct pakfire_env* env) { + if (--env->nrefs > 0) + return env; + + pakfire_env_free(env); + return NULL; +} + +char** pakfire_env_get_envp(struct pakfire_env* env) { + if (!env->env[0]) + return NULL; + + return env->env; +} + +// Returns the length of the environment +static unsigned int pakfire_env_length(struct pakfire_env* env) { + unsigned int i = 0; + + // Count everything in the environment + for (char** e = env->env; *e; e++) + i++; + + return i; +} + +// Finds an existing environment variable and returns its index or -1 if not found +static int pakfire_env_find(struct pakfire_env* env, const char* key) { + if (!key) + return -EINVAL; + + const size_t length = strlen(key); + + for (unsigned int i = 0; env->env[i]; i++) { + if ((pakfire_string_startswith(env->env[i], key) + && *(env->env[i] + length) == '=')) { + return i; + } + } + + // Nothing found + return -1; +} + +// Returns the value of an environment variable or NULL +const char* pakfire_env_get(struct pakfire_env* env, const char* key) { + int i = pakfire_env_find(env, key); + if (i < 0) + return NULL; + + return env->env[i] + strlen(key) + 1; +} + +// Sets an environment variable +int pakfire_env_set(struct pakfire_env* env, const char* key, const char* value) { + int r; + + // Find the index where to write this value to + int i = pakfire_env_find(env, key); + if (i < 0) + i = pakfire_env_length(env); + + // Return ENOBUFS when the environment is full + if (i >= ENVIRON_SIZE) + return -ENOBUFS; + + // Free any previous value + if (env->env[i]) + free(env->env[i]); + + // Format and set environment variable + r = asprintf(&env->env[i], "%s=%s", key, value); + if (r < 0) { + ERROR(env->ctx, "Could not set environment variable %s: %m\n", key); + return -errno; + } + + DEBUG(env->ctx, "Set environment variable: %s\n", env->env[i]); + + return 0; +} + +// Imports an environment +int pakfire_env_import(struct pakfire_env* env, const char** e) { + char* key = NULL; + char* val = NULL; + int r; + + // Is there anything to import? + if (!e) + return 0; + + // Copy environment variables + for (unsigned int i = 0; e[i]; i++) { + r = pakfire_string_partition(e[i], "=", &key, &val); + if (r < 0) + continue; + + // Set value + r = pakfire_env_set(env, key, val); + + if (key) + free(key); + if (val) + free(val); + + // Break on error + if (r) + return r; + } + + return 0; +} + +int pakfire_env_merge(struct pakfire_env* env1, struct pakfire_env* env2) { + return pakfire_env_import(env1, (const char**)env2->env); +} diff --git a/src/libpakfire/include/pakfire/env.h b/src/libpakfire/include/pakfire/env.h new file mode 100644 index 000000000..882984ef1 --- /dev/null +++ b/src/libpakfire/include/pakfire/env.h @@ -0,0 +1,45 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2024 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_ENV_H +#define PAKFIRE_ENV_H + +#ifdef PAKFIRE_PRIVATE + +#include + +struct pakfire_env; + +int pakfire_env_create(struct pakfire_env** env, struct pakfire_ctx* ctx); + +struct pakfire_env* pakfire_env_ref(struct pakfire_env* env); +struct pakfire_env* pakfire_env_unref(struct pakfire_env* env); + +char** pakfire_env_get_envp(struct pakfire_env* env); + +const char* pakfire_env_get(struct pakfire_env* env, const char* key); +int pakfire_env_set(struct pakfire_env* env, const char* key, const char* value); + +int pakfire_env_import(struct pakfire_env* env, const char** e); + +int pakfire_env_merge(struct pakfire_env* env1, struct pakfire_env* env2); + +#endif /* PAKFIRE_PRIVATE */ +#endif /* PAKFIRE_ENV_H */ diff --git a/src/libpakfire/include/pakfire/jail.h b/src/libpakfire/include/pakfire/jail.h index 6aac94bda..b6ac0015e 100644 --- a/src/libpakfire/include/pakfire/jail.h +++ b/src/libpakfire/include/pakfire/jail.h @@ -24,6 +24,7 @@ #ifdef PAKFIRE_PRIVATE #include +#include #include #include @@ -44,11 +45,6 @@ int pakfire_jail_nice(struct pakfire_jail* jail, int nice); // Timeout int pakfire_jail_set_timeout(struct pakfire_jail* jail, unsigned int timeout); -// Environment -const char* pakfire_jail_get_env(struct pakfire_jail* jail, const char* key); -int pakfire_jail_set_env(struct pakfire_jail* jail, const char* key, const char* value); -int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]); - typedef int (*pakfire_jail_callback)(struct pakfire_jail* jail, void* data); // Standard Input @@ -70,27 +66,28 @@ enum pakfire_jail_exec_flags { PAKFIRE_JAIL_HAS_LOOP_DEVICES = (1 << 3), }; -int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags); +int pakfire_jail_exec(struct pakfire_jail* jail, + const char* argv[], struct pakfire_env* env, int flags); int pakfire_jail_exec_capture_output(struct pakfire_jail* jail, - const char* argv[], int flags, char** output, size_t* length); + const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* length); // Resource limits int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cgroup); int pakfire_jail_communicate( - struct pakfire_jail* jail, const char* argv[], int flags, + struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags, pakfire_pty_stdin_callback stdin_callback, void* stdin_data, pakfire_pty_stdout_callback stdout_callback, void* stdout_data); // Convenience functions int pakfire_jail_run(struct pakfire* pakfire, - const char* argv[], int flags, char** output, size_t* output_length); + const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* output_length); int pakfire_jail_run_script(struct pakfire* pakfire, - const char* script, const size_t length, const char* argv[], int flags); + const char* script, const size_t length, const char* argv[], struct pakfire_env* env, int flags); int pakfire_jail_exec_script(struct pakfire_jail* jail, - const char* script, const size_t size, const char* args[], + const char* script, const size_t size, const char* args[], struct pakfire_env* env, pakfire_pty_stdin_callback stdin_callback, void* stdin_data, pakfire_pty_stdout_callback stdout_callback, void* stdout_data); diff --git a/src/libpakfire/include/pakfire/parser.h b/src/libpakfire/include/pakfire/parser.h index 881ccd5be..f6b2143ea 100644 --- a/src/libpakfire/include/pakfire/parser.h +++ b/src/libpakfire/include/pakfire/parser.h @@ -28,6 +28,7 @@ struct pakfire_parser; +#include #include #include #include @@ -113,7 +114,7 @@ int pakfire_parser_apply_declaration( int pakfire_parser_parse_data(struct pakfire_parser* parent, const char* data, size_t len, struct pakfire_parser_error** error); -char** pakfire_parser_make_environ(struct pakfire_parser* parser); +struct pakfire_env* pakfire_parser_make_environ(struct pakfire_parser* parser); #endif /* PAKFIRE_PRIVATE */ diff --git a/src/libpakfire/jail.c b/src/libpakfire/jail.c index ff620e2e2..9f551bd62 100644 --- a/src/libpakfire/jail.c +++ b/src/libpakfire/jail.c @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -62,7 +63,6 @@ #include #define BUFFER_SIZE 1024 * 64 -#define ENVIRON_SIZE 128 #define MAX_MOUNTPOINTS 8 // The default environment that will be set for every command @@ -106,7 +106,7 @@ struct pakfire_jail { struct pakfire_cgroup* cgroup; // Environment - char* env[ENVIRON_SIZE]; + struct pakfire_env* env; // Mountpoints struct pakfire_jail_mountpoint mountpoints[MAX_MOUNTPOINTS]; @@ -166,14 +166,12 @@ static int pakfire_jail_exec_has_flag( static void pakfire_jail_free(struct pakfire_jail* jail) { DEBUG(jail->ctx, "Freeing jail at %p\n", jail); - // Free environment - for (unsigned int i = 0; jail->env[i]; i++) - free(jail->env[i]); - if (jail->cgroup) pakfire_cgroup_unref(jail->cgroup); if (jail->pakfire) pakfire_unref(jail->pakfire); + if (jail->env) + pakfire_env_unref(jail->env); if (jail->ctx) pakfire_ctx_unref(jail->ctx); free(jail); @@ -210,29 +208,34 @@ int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire) { DEBUG(j->ctx, "Allocated new jail at %p\n", j); + // Create environment + r = pakfire_env_create(&j->env, j->ctx); + if (r < 0) + goto ERROR; + // Set default environment for (const struct environ* e = ENV; e->key; e++) { - r = pakfire_jail_set_env(j, e->key, e->val); - if (r) + r = pakfire_env_set(j->env, e->key, e->val); + if (r < 0) goto ERROR; } // Enable all CPU features that CPU has to offer if (!pakfire_arch_is_supported_by_host(arch)) { - r = pakfire_jail_set_env(j, "QEMU_CPU", "max"); - if (r) + r = pakfire_env_set(j->env, "QEMU_CPU", "max"); + if (r < 0) goto ERROR; } // Set container UUID - r = pakfire_jail_set_env(j, "container_uuid", pakfire_jail_uuid(j)); - if (r) + r = pakfire_env_set(j->env, "container_uuid", pakfire_jail_uuid(j)); + if (r < 0) goto ERROR; // Disable systemctl to talk to systemd if (!pakfire_on_root(j->pakfire)) { - r = pakfire_jail_set_env(j, "SYSTEMD_OFFLINE", "1"); - if (r) + r = pakfire_env_set(j->env, "SYSTEMD_OFFLINE", "1"); + if (r < 0) goto ERROR; } @@ -293,106 +296,6 @@ int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cg return 0; } -// Environment - -// Returns the length of the environment -static unsigned int pakfire_jail_env_length(struct pakfire_jail* jail) { - unsigned int i = 0; - - // Count everything in the environment - for (char** e = jail->env; *e; e++) - i++; - - return i; -} - -// Finds an existing environment variable and returns its index or -1 if not found -static int pakfire_jail_find_env(struct pakfire_jail* jail, const char* key) { - if (!key) { - errno = EINVAL; - return -1; - } - - const size_t length = strlen(key); - - for (unsigned int i = 0; jail->env[i]; i++) { - if ((pakfire_string_startswith(jail->env[i], key) - && *(jail->env[i] + length) == '=')) { - return i; - } - } - - // Nothing found - return -1; -} - -// Returns the value of an environment variable or NULL -const char* pakfire_jail_get_env(struct pakfire_jail* jail, - const char* key) { - int i = pakfire_jail_find_env(jail, key); - if (i < 0) - return NULL; - - return jail->env[i] + strlen(key) + 1; -} - -// Sets an environment variable -int pakfire_jail_set_env(struct pakfire_jail* jail, - const char* key, const char* value) { - // Find the index where to write this value to - int i = pakfire_jail_find_env(jail, key); - if (i < 0) - i = pakfire_jail_env_length(jail); - - // Return -ENOSPC when the environment is full - if (i >= ENVIRON_SIZE) { - errno = ENOSPC; - return -1; - } - - // Free any previous value - if (jail->env[i]) - free(jail->env[i]); - - // Format and set environment variable - asprintf(&jail->env[i], "%s=%s", key, value); - - DEBUG(jail->ctx, "Set environment variable: %s\n", jail->env[i]); - - return 0; -} - -// Imports an environment -int pakfire_jail_import_env(struct pakfire_jail* jail, const char* env[]) { - if (!env) - return 0; - - char* key; - char* val; - int r; - - // Copy environment variables - for (unsigned int i = 0; env[i]; i++) { - r = pakfire_string_partition(env[i], "=", &key, &val); - if (r) - continue; - - // Set value - r = pakfire_jail_set_env(jail, key, val); - - if (key) - free(key); - if (val) - free(val); - - // Break on error - if (r) - return r; - } - - return 0; -} - // Timeout int pakfire_jail_set_timeout( @@ -1069,11 +972,12 @@ static int pakfire_jail_exited(sd_event_source* source, const siginfo_t* si, voi struct pakfire_jail_command { const char** argv; - const char** envp; + struct pakfire_env* env; }; static int pakfire_jail_launch_command(struct pakfire_jail* jail, void* data) { struct pakfire_jail_command* command = data; + char** envp = NULL; int r; // Check if argv is valid @@ -1086,8 +990,15 @@ static int pakfire_jail_launch_command(struct pakfire_jail* jail, void* data) { for (unsigned int i = 0; command->argv[i]; i++) DEBUG(jail->ctx, " argv[%u] = %s\n", i, command->argv[i]); + // Fetch the environment + if (command->env) { + envp = pakfire_env_get_envp(command->env); + if (!envp) + return -ENOTSUP; + } + // exec() command - r = execvpe(command->argv[0], (char**)command->argv, (char**)command->envp); + r = execvpe(command->argv[0], (char**)command->argv, envp); if (r < 0) { // Translate errno into regular exit code switch (errno) { @@ -1624,9 +1535,11 @@ ERROR: return r; } -int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags) { +int pakfire_jail_exec(struct pakfire_jail* jail, + const char* argv[], struct pakfire_env* env, int flags) { struct pakfire_jail_command command = { .argv = argv, + .env = env, }; return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags, @@ -1634,9 +1547,10 @@ int pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[], int flags) } int pakfire_jail_exec_capture_output(struct pakfire_jail* jail, - const char* argv[], int flags, char** output, size_t* length) { + const char* argv[], struct pakfire_env* env, int flags, char** output, size_t* length) { struct pakfire_jail_command command = { .argv = argv, + .env = env, }; return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags, @@ -1644,11 +1558,12 @@ int pakfire_jail_exec_capture_output(struct pakfire_jail* jail, } int pakfire_jail_communicate( - struct pakfire_jail* jail, const char* argv[], int flags, + struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags, pakfire_pty_stdin_callback stdin_callback, void* stdin_data, pakfire_pty_stdout_callback stdout_callback, void* stdout_data) { struct pakfire_jail_command command = { .argv = argv, + .env = env, }; return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags, @@ -1656,7 +1571,7 @@ int pakfire_jail_communicate( } int pakfire_jail_exec_script(struct pakfire_jail* jail, - const char* script, const size_t size, const char* args[], + const char* script, const size_t size, const char* args[], struct pakfire_env* env, pakfire_pty_stdin_callback stdin_callback, void* stdin_data, pakfire_pty_stdout_callback stdout_callback, void* stdout_data) { char path[PATH_MAX]; @@ -1717,7 +1632,7 @@ int pakfire_jail_exec_script(struct pakfire_jail* jail, argv[i] = args[i-1]; // Run the script - r = pakfire_jail_communicate(jail, argv, 0, + r = pakfire_jail_communicate(jail, argv, env, 0, stdin_callback, stdin_data, stdout_callback, stdout_data); ERROR: @@ -1737,8 +1652,8 @@ ERROR: A convenience function that creates a new jail, runs the given command and destroys the jail again. */ -int pakfire_jail_run(struct pakfire* pakfire, - const char* argv[], int flags, char** output, size_t* output_length) { +int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], struct pakfire_env* env, + int flags, char** output, size_t* output_length) { struct pakfire_jail* jail = NULL; int r; @@ -1748,7 +1663,7 @@ int pakfire_jail_run(struct pakfire* pakfire, goto ERROR; // Execute the command - r = pakfire_jail_exec_capture_output(jail, argv, flags, output, output_length); + r = pakfire_jail_exec_capture_output(jail, argv, env, flags, output, output_length); ERROR: if (jail) @@ -1757,8 +1672,8 @@ ERROR: return r; } -int pakfire_jail_run_script(struct pakfire* pakfire, - const char* script, const size_t length, const char* argv[], int flags) { +int pakfire_jail_run_script(struct pakfire* pakfire, const char* script, const size_t length, + const char* argv[], struct pakfire_env* env, int flags) { struct pakfire_jail* jail = NULL; int r; @@ -1768,7 +1683,7 @@ int pakfire_jail_run_script(struct pakfire* pakfire, goto ERROR; // Execute the command - r = pakfire_jail_exec_script(jail, script, length, argv, NULL, NULL, NULL, NULL); + r = pakfire_jail_exec_script(jail, script, length, argv, env, NULL, NULL, NULL, NULL); ERROR: if (jail) @@ -1778,37 +1693,47 @@ ERROR: } int pakfire_jail_shell(struct pakfire_jail* jail) { + struct pakfire_env* env = NULL; int r; const char* argv[] = { "/bin/bash", "--login", NULL, }; + // Create a new environment + r = pakfire_env_create(&env, jail->ctx); + if (r < 0) + goto ERROR; + // Copy TERM char* TERM = secure_getenv("TERM"); if (TERM) { - r = pakfire_jail_set_env(jail, "TERM", TERM); - if (r) - return r; + r = pakfire_env_set(env, "TERM", TERM); + if (r < 0) + goto ERROR; } // Copy LANG char* LANG = secure_getenv("LANG"); if (LANG) { - r = pakfire_jail_set_env(jail, "LANG", LANG); - if (r) - return r; + r = pakfire_env_set(env, "LANG", LANG); + if (r < 0) + goto ERROR; } // Execute /bin/bash - r = pakfire_jail_exec(jail, argv, PAKFIRE_JAIL_INTERACTIVE); - - // Raise any errors + r = pakfire_jail_exec(jail, argv, env, PAKFIRE_JAIL_INTERACTIVE); if (r < 0) - return r; + goto ERROR; // Ignore any return codes from the shell - return 0; + r = 0; + +ERROR: + if (env) + pakfire_env_unref(env); + + return r; } static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** argv) { @@ -1829,7 +1754,7 @@ static int pakfire_jail_run_if_possible(struct pakfire* pakfire, const char** ar goto ERROR; } - r = pakfire_jail_run(pakfire, argv, 0, NULL, NULL); + r = pakfire_jail_run(pakfire, argv, NULL, 0, NULL, NULL); ERROR: if (ctx) diff --git a/src/libpakfire/parser.c b/src/libpakfire/parser.c index ec59ca7fa..0bb42efc3 100644 --- a/src/libpakfire/parser.c +++ b/src/libpakfire/parser.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -479,7 +480,7 @@ static int pakfire_parser_expand_commands(struct pakfire_parser* parser, char** size_t length = 0; // Execute the command inside the Pakfire environment - r = pakfire_jail_run(parser->pakfire, argv, 0, &output, &length); + r = pakfire_jail_run(parser->pakfire, argv, NULL, 0, &output, &length); if (r) { // Just log this and continue DEBUG(parser->ctx, "Command '%s' failed with return code %d\n", command, r); @@ -954,47 +955,40 @@ int pakfire_parser_set_namespace(struct pakfire_parser* parser, const char* name return 0; } -char** pakfire_parser_make_environ(struct pakfire_parser* parser) { - char** envp = NULL; - unsigned int num = 0; +struct pakfire_env* pakfire_parser_make_environ(struct pakfire_parser* parser) { + struct pakfire_parser_declaration* d = NULL; + struct pakfire_env* env = NULL; + char* value = NULL; + int r; + + // Create a new empty environment + r = pakfire_env_create(&env, parser->ctx); + if (r < 0) + goto ERROR; for (unsigned int i = 0; i < parser->num_declarations; i++) { - struct pakfire_parser_declaration* d = parser->declarations[i]; + d = parser->declarations[i]; if (!d) continue; // Is the export flag set? if (d->flags & PAKFIRE_PARSER_DECLARATION_EXPORT) { - char* buffer = NULL; - - char* value = pakfire_parser_expand(parser, d->namespace, d->value); + value = pakfire_parser_expand(parser, d->namespace, d->value); if (!value) goto ERROR; - // Build line - int r = asprintf(&buffer, "%s=%s", d->name, value); - free(value); + // Store the value + r = pakfire_env_set(env, d->name, value); if (r < 0) goto ERROR; - - // Extend the array - envp = reallocarray(envp, num + 2, sizeof(*envp)); - if (!envp) - goto ERROR; - - envp[num++] = buffer; - envp[num] = NULL; } } - return envp; + return env; ERROR: - if (envp) { - for (char** e = envp; *e; e++) - free(*e); - free(envp); - } + if (env) + pakfire_env_unref(env); return NULL; } diff --git a/src/libpakfire/scriptlet.c b/src/libpakfire/scriptlet.c index a28891d8a..a29707e6a 100644 --- a/src/libpakfire/scriptlet.c +++ b/src/libpakfire/scriptlet.c @@ -181,7 +181,7 @@ static int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet int pakfire_scriptlet_execute(struct pakfire_scriptlet* scriptlet, struct pakfire* pakfire) { // Detect what kind of script this is and run it if (pakfire_scriptlet_is_shell_script(scriptlet)) - return pakfire_jail_run_script(pakfire, scriptlet->data, scriptlet->size, NULL, 0); + return pakfire_jail_run_script(pakfire, scriptlet->data, scriptlet->size, NULL, NULL, 0); ERROR(scriptlet->ctx, "Scriptlet is of an unknown kind\n"); return -ENOTSUP; diff --git a/tests/libpakfire/cgroup.c b/tests/libpakfire/cgroup.c index 11ae3a4f3..47429149a 100644 --- a/tests/libpakfire/cgroup.c +++ b/tests/libpakfire/cgroup.c @@ -124,7 +124,7 @@ static int test_stats(const struct test* t) { // Run a few things for (unsigned int i = 0; i < 3; i++) { - ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, 0)); + ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, 0)); } // Try reading the stats into some invalid space diff --git a/tests/libpakfire/jail.c b/tests/libpakfire/jail.c index 819794ffc..d93e20f4e 100644 --- a/tests/libpakfire/jail.c +++ b/tests/libpakfire/jail.c @@ -68,7 +68,7 @@ static int test_exit_code(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); // Check if we receive the correct exit code - ASSERT(pakfire_jail_exec(jail, argv, 0) == 123); + ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 123); // Success r = EXIT_SUCCESS; @@ -92,7 +92,7 @@ static int test_segv(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); // Check if we receive the correct exit code - ASSERT(pakfire_jail_exec(jail, argv, 0) == 139); + ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 139); // Success r = EXIT_SUCCESS; @@ -104,34 +104,6 @@ FAIL: return r; } -static int test_env(const struct test* t) { - struct pakfire_jail* jail = NULL; - - // Create a new jail - ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); - - // Check if the default variables are set - ASSERT(pakfire_jail_get_env(jail, "LANG")); - ASSERT(pakfire_jail_get_env(jail, "TERM")); - - // Fetch a non-existing environment variable - ASSERT_NULL(pakfire_jail_get_env(jail, "VARIABLE")); - - // Set a variable - ASSERT_SUCCESS(pakfire_jail_set_env(jail, "VARIABLE", "VALUE")); - - // Read the value back - ASSERT_STRING_EQUALS(pakfire_jail_get_env(jail, "VARIABLE"), "VALUE"); - - // Destroy it - ASSERT_NULL(pakfire_jail_unref(jail)); - - return EXIT_SUCCESS; - -FAIL: - return EXIT_FAILURE; -} - static int test_exec(const struct test* t) { struct pakfire_jail* jail = NULL; char* output = NULL; @@ -141,7 +113,7 @@ static int test_exec(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); // Try to execute something - ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, cmd_hello_world, 0, &output, &length)); + ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, cmd_hello_world, NULL, 0, &output, &length)); // We should have some output ASSERT_STRING_EQUALS(output, "Hello World!\n"); @@ -171,7 +143,7 @@ static int test_launch_into_cgroup(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_set_cgroup(jail, cgroup)); // Run command - ASSERT(pakfire_jail_exec(jail, cmd_hello_world, 0) == 0); + ASSERT(pakfire_jail_exec(jail, cmd_hello_world, NULL, 0) == 0); r = EXIT_SUCCESS; @@ -206,7 +178,7 @@ static int test_nice(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_nice(jail, 5)); // Check if the nice level has been set - ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, argv, 0, &output, NULL)); + ASSERT_SUCCESS(pakfire_jail_exec_capture_output(jail, argv, NULL, 0, &output, NULL)); ASSERT_STRING_EQUALS(output, "5\n"); // Success @@ -240,10 +212,10 @@ static int test_memory_limit(const struct test* t) { ASSERT_SUCCESS(pakfire_cgroup_set_memory_limit(cgroup, 100 * 1024 * 1024)); // Try to exhaust all memory - ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, 0)); + ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_exhaust_memory, NULL, 0)); // A fork bomb should also exhaust all memory - ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, 0)); + ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, 0)); // Success r = EXIT_SUCCESS; @@ -277,7 +249,7 @@ static int test_pid_limit(const struct test* t) { ASSERT_SUCCESS(pakfire_cgroup_set_pid_limit(cgroup, 100)); // Try to fork as many processes as possible - ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, 0)); + ASSERT_FAILURE(pakfire_jail_exec(jail, cmd_fork_bomb, NULL, 0)); // Success r = EXIT_SUCCESS; @@ -298,7 +270,7 @@ static int test_file_ownership(const struct test* t) { char* output = NULL; // Execute a simple command - ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, 0, &output, NULL)); + ASSERT_SUCCESS(pakfire_jail_run(t->pakfire, cmd_stat_ownership, NULL, 0, &output, NULL)); // Check if the file has been mapped to root/root ASSERT_STRING_EQUALS(output, "uid=0 gid=0\n"); @@ -335,7 +307,7 @@ static int test_bind(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY)); // Check if the mount actually works - ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, 0)); + ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL, 0)); // Success r = EXIT_SUCCESS; @@ -384,7 +356,7 @@ static int test_communicate(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire)); // Check if the mount actually works - ASSERT_SUCCESS(pakfire_jail_communicate(jail, argv, 0, + ASSERT_SUCCESS(pakfire_jail_communicate(jail, argv, NULL, 0, callback_stdin, &lines, NULL, NULL)); // Success @@ -404,7 +376,7 @@ static int test_send_one_signal(const struct test* t, }; // Perform the command - return pakfire_jail_exec(jail, argv, 0); + return pakfire_jail_exec(jail, argv, NULL, 0); } static int test_send_signal(const struct test* t) { @@ -448,7 +420,7 @@ static int test_timeout(const struct test* t) { ASSERT_SUCCESS(pakfire_jail_set_timeout(jail, 1)); // Check if we receive the correct exit code - ASSERT(pakfire_jail_exec(jail, argv, 0) == 139); + ASSERT(pakfire_jail_exec(jail, argv, NULL, 0) == 139); // Success r = EXIT_SUCCESS; @@ -464,7 +436,6 @@ int main(int argc, const char* argv[]) { testsuite_add_test(test_create, TEST_WANTS_PAKFIRE); testsuite_add_test(test_exit_code, TEST_WANTS_PAKFIRE); testsuite_add_test(test_segv, TEST_WANTS_PAKFIRE); - testsuite_add_test(test_env, TEST_WANTS_PAKFIRE); testsuite_add_test(test_exec, TEST_WANTS_PAKFIRE); #if 0 testsuite_add_test(test_launch_into_cgroup, TEST_WANTS_PAKFIRE);