From 5f6e42a2bd684a61b3caae25f13648d44661edab Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 16 Aug 2022 16:25:42 +0000 Subject: [PATCH] jail: Make dropping users into a shell easier Signed-off-by: Michael Tremer --- src/libpakfire/build.c | 216 ++++++++++++++----------- src/libpakfire/include/pakfire/build.h | 3 +- src/libpakfire/include/pakfire/jail.h | 2 +- src/libpakfire/jail.c | 12 +- 4 files changed, 138 insertions(+), 95 deletions(-) diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index f142c63f..51c6e203 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -91,6 +91,95 @@ static int pakfire_build_has_flag(struct pakfire_build* build, int flag) { return build->flags & flag; } +/* + This function enables the local repository so that it can be access by + a pakfire instance running inside the chroot. +*/ +static int pakfire_build_enable_repos(struct pakfire_build* build) { + char repopath[PATH_MAX]; + FILE* f = NULL; + int r = 1; + + // Fetch the local repository + struct pakfire_repo* repo = pakfire_get_repo(build->pakfire, PAKFIRE_REPO_LOCAL); + if (!repo) { + DEBUG(build->pakfire, "Could not find repository '%s': %m\n", PAKFIRE_REPO_LOCAL); + return 0; + } + + // Fetch repository configuration + char* config = pakfire_repo_get_config(repo); + if (!config) { + ERROR(build->pakfire, "Could not generate repository configuration: %m\n"); + goto ERROR; + } + + const char* path = pakfire_repo_get_path(repo); + + // Make sure the source directory exists + r = pakfire_mkdir(path, 0700); + if (r && errno != EEXIST) { + ERROR(build->pakfire, "Could not create repository directory %s: %m\n", path); + goto ERROR; + } + + // Bind-mount the repository data read-only + r = pakfire_bind(build->pakfire, path, NULL, MS_RDONLY); + if (r) { + ERROR(build->pakfire, "Could not bind-mount the repository at %s: %m\n", path); + goto ERROR; + } + + // Make path for configuration file + r = pakfire_make_path(build->pakfire, repopath, + PAKFIRE_CONFIG_DIR "/repos/" PAKFIRE_REPO_LOCAL ".repo"); + if (r < 0) + goto ERROR; + + // Open configuration file for writing + f = fopen(repopath, "w"); + if (!f) { + ERROR(build->pakfire, "Could not open %s for writing: %m\n", path); + r = 1; + goto ERROR; + } + + // Write configuration + size_t bytes_written = fprintf(f, "%s", config); + if (bytes_written < strlen(config)) { + ERROR(build->pakfire, "Could not write repository configuration: %m\n"); + r = 1; + goto ERROR; + } + + // Success + r = 0; + +ERROR: + if (f) + fclose(f); + if (config) + free(config); + pakfire_repo_unref(repo); + + return r; +} + +/* + Drops the user into a shell +*/ +static int pakfire_build_shell(struct pakfire_build* build) { + int r; + + // Export local repository if running in interactive mode + r = pakfire_build_enable_repos(build); + if (r) + return r; + + // Run shell + return pakfire_jail_shell(build->jail); +} + static int pakfire_build_run_script(struct pakfire_build* build, const char* filename, const char* args[], char** output) { char* script = NULL; @@ -712,7 +801,7 @@ static int pakfire_build_makefile(struct pakfire_build* build, const char* path) if (r) { // Drop to a shell for debugging if (pakfire_has_flag(build->pakfire, PAKFIRE_FLAGS_INTERACTIVE)) - pakfire_jail_shell(build->pakfire); + pakfire_build_shell(build); goto ERROR; } @@ -1203,117 +1292,64 @@ ERROR: return r; } -/* - This function enables the local repository so that it can be access by - a pakfire instance running inside the chroot. -*/ -static int pakfire_build_enable_repos(struct pakfire* pakfire) { - char repopath[PATH_MAX]; - FILE* f = NULL; - int r = 1; - - // Fetch the local repository - struct pakfire_repo* repo = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL); - if (!repo) { - DEBUG(pakfire, "Could not find repository '%s': %m\n", PAKFIRE_REPO_LOCAL); - return 0; - } - - // Fetch repository configuration - char* config = pakfire_repo_get_config(repo); - if (!config) { - ERROR(pakfire, "Could not generate repository configuration: %m\n"); - goto ERROR; - } - - const char* path = pakfire_repo_get_path(repo); - - // Make sure the source directory exists - r = pakfire_mkdir(path, 0700); - if (r && errno != EEXIST) { - ERROR(pakfire, "Could not create repository directory %s: %m\n", path); - goto ERROR; - } - - // Bind-mount the repository data read-only - r = pakfire_bind(pakfire, path, NULL, MS_RDONLY); - if (r) { - ERROR(pakfire, "Could not bind-mount the repository at %s: %m\n", path); - goto ERROR; - } - - // Make path for configuration file - r = pakfire_make_path(pakfire, repopath, - PAKFIRE_CONFIG_DIR "/repos/" PAKFIRE_REPO_LOCAL ".repo"); - if (r < 0) - goto ERROR; +int pakfire_build_clean(struct pakfire* pakfire, int flags) { + struct pakfire_repo* local = NULL; + int r = 0; - // Open configuration file for writing - f = fopen(repopath, "w"); - if (!f) { - ERROR(pakfire, "Could not open %s for writing: %m\n", path); - r = 1; + // Fetch local repository + local = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL); + if (!local) { + ERROR(pakfire, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL); goto ERROR; } - // Write configuration - size_t bytes_written = fprintf(f, "%s", config); - if (bytes_written < strlen(config)) { - ERROR(pakfire, "Could not write repository configuration: %m\n"); - r = 1; + // Destroy everything in it + r = pakfire_repo_clean(local, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY); + if (r) goto ERROR; - } - - // Success - r = 0; ERROR: - if (f) - fclose(f); - if (config) - free(config); - pakfire_repo_unref(repo); + if (local) + pakfire_repo_unref(local); return r; } +/* + This is a convenience function that sets up a build environment and + then drops the user into an interactive shell. +*/ PAKFIRE_EXPORT int pakfire_shell(struct pakfire* pakfire, const char** packages) { + struct pakfire_build* build = NULL; int r; - // Install any additional packages - if (packages) { - r = pakfire_install(pakfire, 0, 0, packages, NULL, 0, NULL, NULL, NULL); - if (r) - return r; + // Create a new build environment + r = pakfire_build_create(&build, pakfire, NULL, 0); + if (r) { + ERROR(pakfire, "Could not create build: %m\n"); + goto ERROR; } - // Export local repository if running in interactive mode - r = pakfire_build_enable_repos(pakfire); - if (r) + // Extract the snapshot + r = pakfire_build_extract_snapshot(build); + if (r) { + ERROR(build->pakfire, "Could not extract snapshot: %m\n"); return r; + } - return pakfire_jail_shell(pakfire); -} - -int pakfire_build_clean(struct pakfire* pakfire, int flags) { - struct pakfire_repo* local = NULL; - int r = 0; - - // Fetch local repository - local = pakfire_get_repo(pakfire, PAKFIRE_REPO_LOCAL); - if (!local) { - ERROR(pakfire, "Could not find repository %s: %m\n", PAKFIRE_REPO_LOCAL); - goto ERROR; + // Install any additional packages + if (packages) { + r = pakfire_install(build->pakfire, 0, 0, packages, NULL, 0, NULL, NULL, NULL); + if (r) + return r; } - // Destroy everything in it - r = pakfire_repo_clean(local, PAKFIRE_REPO_CLEAN_FLAGS_DESTROY); - if (r) - goto ERROR; + // Run shell + r = pakfire_build_shell(build); ERROR: - if (local) - pakfire_repo_unref(local); + if (build) + pakfire_build_unref(build); return r; } diff --git a/src/libpakfire/include/pakfire/build.h b/src/libpakfire/include/pakfire/build.h index 55ef5bdc..b7f109e1 100644 --- a/src/libpakfire/include/pakfire/build.h +++ b/src/libpakfire/include/pakfire/build.h @@ -42,7 +42,8 @@ int pakfire_build_exec(struct pakfire_build* build, const char* path); int pakfire_build(struct pakfire* pakfire, const char* path, const char* target, const char* id, int flags); -int pakfire_shell(struct pakfire* pakfire, const char** packages); int pakfire_build_clean(struct pakfire* pakfire, int flags); +int pakfire_shell(struct pakfire* pakfire, const char** packages); + #endif /* PAKFIRE_BUILD_H */ diff --git a/src/libpakfire/include/pakfire/jail.h b/src/libpakfire/include/pakfire/jail.h index a9b6531f..e284c83b 100644 --- a/src/libpakfire/include/pakfire/jail.h +++ b/src/libpakfire/include/pakfire/jail.h @@ -71,7 +71,7 @@ int pakfire_jail_run(struct pakfire* pakfire, const char* argv[], int flags, cha int pakfire_jail_run_script(struct pakfire* pakfire, const char* script, const size_t length, const char* argv[], int flags, char** output); -int pakfire_jail_shell(struct pakfire* pakfire); +int pakfire_jail_shell(struct pakfire_jail* jail); int pakfire_jail_ldconfig(struct pakfire* pakfire); #endif /* PAKFIRE_PRIVATE */ diff --git a/src/libpakfire/jail.c b/src/libpakfire/jail.c index 29d2bb6e..e022ff4f 100644 --- a/src/libpakfire/jail.c +++ b/src/libpakfire/jail.c @@ -1631,14 +1631,20 @@ ERROR: return r; } - -int pakfire_jail_shell(struct pakfire* pakfire) { +int pakfire_jail_shell(struct pakfire_jail* jail) { const char* argv[] = { "/bin/bash", "--login", NULL, }; + // Check if this operation is possible + if (!pakfire_jail_has_flag(jail, PAKFIRE_JAIL_INTERACTIVE)) { + ERROR(jail->pakfire, "You cannot run a shell in a non-interactive jail\n"); + errno = ENOTSUP; + return 1; + } + // Execute /bin/bash - return pakfire_jail_run(pakfire, argv, PAKFIRE_JAIL_INTERACTIVE, NULL); + return pakfire_jail_exec(jail, argv, NULL); } int pakfire_jail_ldconfig(struct pakfire* pakfire) { -- 2.47.3