]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
jail: Implement bind-mounting anything into the jail
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 16 Aug 2022 15:34:26 +0000 (15:34 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 16 Aug 2022 15:34:26 +0000 (15:34 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/jail.h
src/libpakfire/jail.c
src/libpakfire/mount.c
tests/libpakfire/jail.c

index 299f69c3e1da98640b4ee7f0b71d1f507190b34a..a9b6531fc94c2bb7422930bc274228736e057ec5 100644 (file)
@@ -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);
 
index 97decaa92c6438a7305c4e494179d3de40889747..b954c185e947b5181eef799f3d5086ed65b9cb57 100644 (file)
@@ -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) {
index c5ef2050a8f5dc01f69d95d2bb6a86f87e1002e7..8b602d19a830dca84a98f53da258ab2867360c6c 100644 (file)
@@ -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);
 }
index 008e05ef7352e575458785775a2ea3d6a4ba6eab..d3b0505a0a14566a8bc4c3bb88b5575b091bbe44 100644 (file)
@@ -18,6 +18,8 @@
 #                                                                             #
 #############################################################################*/
 
+#include <sys/mount.h>
+
 #include <pakfire/cgroup.h>
 #include <pakfire/jail.h>
 
@@ -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);
 }