From: Michael Tremer Date: Tue, 16 Aug 2022 15:34:26 +0000 (+0000) Subject: jail: Implement bind-mounting anything into the jail X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cc6e2264595d12458d29e264ff41fa1be8fc62fc;p=people%2Fstevee%2Fpakfire.git jail: Implement bind-mounting anything into the jail Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/jail.h b/src/libpakfire/include/pakfire/jail.h index 299f69c3..a9b6531f 100644 --- a/src/libpakfire/include/pakfire/jail.h +++ b/src/libpakfire/include/pakfire/jail.h @@ -42,6 +42,10 @@ struct pakfire_jail* pakfire_jail_unref(struct pakfire_jail* jail); int pakfire_jail_set_log_callback(struct pakfire_jail* jail, pakfire_jail_log_callback callback, void* data); +// Mountpoints +int pakfire_jail_bind(struct pakfire_jail* jail, + const char* source, const char* target, int flags); + // Resource Limits int pakfire_jail_nice(struct pakfire_jail* jail, int nice); diff --git a/src/libpakfire/jail.c b/src/libpakfire/jail.c index 97decaa9..b954c185 100644 --- a/src/libpakfire/jail.c +++ b/src/libpakfire/jail.c @@ -55,6 +55,7 @@ #define BUFFER_SIZE 1024 * 64 #define ENVIRON_SIZE 128 #define EPOLL_MAX_EVENTS 2 +#define MAX_MOUNTPOINTS 8 // The default environment that will be set for every command static const struct environ { @@ -66,6 +67,12 @@ static const struct environ { { NULL, NULL }, }; +struct pakfire_jail_mountpoint { + char source[PATH_MAX]; + char target[PATH_MAX]; + int flags; +}; + struct pakfire_jail { struct pakfire* pakfire; int nrefs; @@ -89,6 +96,10 @@ struct pakfire_jail { // Logging pakfire_jail_log_callback log_callback; void* log_data; + + // Mountpoints + struct pakfire_jail_mountpoint mountpoints[MAX_MOUNTPOINTS]; + unsigned int num_mountpoints; }; struct pakfire_log_buffer { @@ -886,6 +897,80 @@ ERROR: return r; } +// Mountpoints + +int pakfire_jail_bind(struct pakfire_jail* jail, + const char* source, const char* target, int flags) { + struct pakfire_jail_mountpoint* mp = NULL; + int r; + + // Check if there is any space left + if (jail->num_mountpoints >= MAX_MOUNTPOINTS) { + errno = ENOSPC; + return 1; + } + + // Check for valid inputs + if (!source || !target) { + errno = EINVAL; + return 1; + } + + // Select the next free slot + mp = &jail->mountpoints[jail->num_mountpoints]; + + // Copy source + r = pakfire_string_set(mp->source, source); + if (r < 0) { + ERROR(jail->pakfire, "Could not copy source: %m\n"); + return 1; + } + + // Copy target + r = pakfire_string_set(mp->target, target); + if (r < 0) { + ERROR(jail->pakfire, "Could not copy target: %m\n"); + return 1; + } + + // Copy flags + mp->flags = flags; + + // Increment counter + jail->num_mountpoints++; + + return 0; +} + +/* + Mounts everything that we require in the new namespace +*/ +static int pakfire_jail_mount(struct pakfire_jail* jail) { + struct pakfire_jail_mountpoint* mp = NULL; + int r; + + // Mount all default stuff + r = pakfire_mount_all(jail->pakfire); + if (r) + return r; + + // Mount all custom stuff + for (unsigned int i = 0; i < jail->num_mountpoints; i++) { + // Fetch mountpoint + mp = &jail->mountpoints[i]; + + // Mount it + r = pakfire_bind(jail->pakfire, mp->source, mp->target, mp->flags); + if (r) + return r; + } + + // Log all mountpoints + pakfire_mount_list(jail->pakfire); + + return 0; +} + // UID/GID Mapping static int pakfire_jail_write_uidgid_mapping(struct pakfire_jail* jail, @@ -1132,13 +1217,10 @@ static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exe // Change root (unless root is /) if (!pakfire_on_root(jail->pakfire)) { // Mount everything - r = pakfire_mount_all(jail->pakfire); + r = pakfire_jail_mount(jail); if (r) return r; - // Log all mountpoints - pakfire_mount_list(jail->pakfire); - // Call chroot() r = chroot(root); if (r) { diff --git a/src/libpakfire/mount.c b/src/libpakfire/mount.c index c5ef2050..8b602d19 100644 --- a/src/libpakfire/mount.c +++ b/src/libpakfire/mount.c @@ -467,5 +467,5 @@ PAKFIRE_EXPORT int pakfire_bind(struct pakfire* pakfire, const char* src, const } // Perform mount - return pakfire_mount(pakfire, src, mountpoint, NULL, flags|MS_BIND, NULL); + return pakfire_mount(pakfire, src, mountpoint, NULL, flags|MS_REC|MS_BIND, NULL); } diff --git a/tests/libpakfire/jail.c b/tests/libpakfire/jail.c index 008e05ef..d3b0505a 100644 --- a/tests/libpakfire/jail.c +++ b/tests/libpakfire/jail.c @@ -18,6 +18,8 @@ # # #############################################################################*/ +#include + #include #include @@ -263,6 +265,41 @@ FAIL: return r; } +static int test_bind(const struct test* t) { + struct pakfire_jail* jail = NULL; + char* output = NULL; + int r = EXIT_FAILURE; + + const char* source = "/"; + const char* target = "/oldroot"; + + const char* argv[] = { + "/command", "check-mountpoint", target, NULL, + }; + + // Create a new jail + ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire, 0)); + + // Bind-mount nonsense + ASSERT_ERRNO(pakfire_jail_bind(jail, NULL, target, 0), EINVAL); + ASSERT_ERRNO(pakfire_jail_bind(jail, source, NULL, 0), EINVAL); + + // Bind-mount something + ASSERT_SUCCESS(pakfire_jail_bind(jail, source, target, MS_RDONLY)); + + // Check if the mount actually works + ASSERT_SUCCESS(pakfire_jail_exec(jail, argv, NULL)); + + // Success + r = EXIT_SUCCESS; + +FAIL: + if (jail) + pakfire_jail_unref(jail); + + return r; +} + int main(int argc, const char* argv[]) { testsuite_add_test(test_create); testsuite_add_test(test_env); @@ -272,6 +309,7 @@ int main(int argc, const char* argv[]) { testsuite_add_test(test_memory_limit); testsuite_add_test(test_pid_limit); testsuite_add_test(test_file_ownership); + testsuite_add_test(test_bind); return testsuite_run(argc, argv); }