]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
execute: Use pivot_root instead of chroot
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 21 May 2022 14:15:05 +0000 (14:15 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 21 May 2022 14:15:05 +0000 (14:15 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/execute.c
src/libpakfire/pakfire.c

index b4aab537e32c1202dd92e5b1ba6556b13d9b7cb9..082b04be94be537351802a85d2689928e80145c8 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <sys/capability.h>
 #include <sys/epoll.h>
+#include <sys/mount.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
 #include <sys/types.h>
@@ -82,6 +83,10 @@ struct pakfire_execute_buffer {
 #define __NR_clone3 435
 #endif
 
+static int pivot_root(const char* new_root, const char* put_old) {
+       return syscall(__NR_pivot_root, new_root, put_old);
+}
+
 static int pakfire_execute_buffer_is_full(const struct pakfire_execute_buffer* buffer) {
        return (sizeof(buffer->data) == buffer->used);
 }
@@ -534,12 +539,15 @@ static int set_environ(struct pakfire_execute* env, const char* key, const char*
 
 static int pakfire_execute_fork(void* data) {
        struct pakfire_execute* env = (struct pakfire_execute*)data;
+       int r;
 
        struct pakfire* pakfire = env->pakfire;
 
        const char* root = pakfire_get_path(pakfire);
        const char* arch = pakfire_get_arch(pakfire);
 
+       char oldroot[PATH_MAX];
+
        DEBUG(pakfire, "Execution environment has been forked as PID %d\n", getpid());
        DEBUG(pakfire, "        root    : %s\n", root);
        DEBUG(pakfire, "        cgroup  : %s\n", env->cgroup);
@@ -552,23 +560,53 @@ static int pakfire_execute_fork(void* data) {
 
        // Change root (unless root is /)
        if (strcmp(root, "/") != 0) {
-               int r = chroot(root);
+               r = pakfire_string_format(oldroot, "%s/.oldroot.XXXXXX", root);
+               if (r < 0) {
+                       ERROR(pakfire, "Could not figure out where the old root directory is going: %m\n");
+                       return r;
+               }
+
+               // Create temporary directory
+               if (!pakfire_mkdtemp(oldroot)) {
+                       ERROR(pakfire, "Could not create temporary directory: %m\n");
+                       return r;
+               }
+
+               // Call pivot_root()
+               r = pivot_root(root, oldroot);
                if (r) {
-                       ERROR(pakfire, "chroot() to %s failed: %m\n", root);
+                       ERROR(pakfire, "pivot_root() to %s failed: %m\n", root);
                        return 1;
                }
 
+               // Change directory to /
                r = chdir("/");
                if (r) {
                        ERROR(pakfire, "chdir() after chroot() failed: %m\n");
                        return 1;
                }
+
+               const char* __oldroot = oldroot + strlen(root);
+
+               // Umount the old root directory
+               r = umount2(__oldroot, MNT_DETACH);
+               if (r) {
+                       ERROR(pakfire, "Could not umount old root directory: %m\n");
+                       return r;
+               }
+
+               // Remove the old root directory
+               r = rmdir(__oldroot);
+               if (r) {
+                       ERROR(pakfire, "Could not remove the old root directory: %m\n");
+                       return r;
+               }
        }
 
        // Set personality
        unsigned long persona = pakfire_arch_personality(arch);
        if (persona) {
-               int r = personality(persona);
+               r = personality(persona);
                if (r < 0) {
                        ERROR(pakfire, "Could not set personality (%x)\n", (unsigned int)persona);
 
@@ -598,7 +636,7 @@ static int pakfire_execute_fork(void* data) {
        }
 
        // Reset open file limit (http://0pointer.net/blog/file-descriptor-limits.html)
-       int r = pakfire_rlimit_reset_nofile(pakfire);
+       r = pakfire_rlimit_reset_nofile(pakfire);
        if (r)
                return r;
 
index 7447938874141dd1f793f9bb63163d9d280159df..ea7bf2deb0cae0dd337120c96cd472ff10256506 100644 (file)
@@ -218,6 +218,13 @@ static int pakfire_mount(struct pakfire* pakfire) {
        char target[PATH_MAX];
        int r;
 
+       // Remount / as private
+       r = mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
+       if (r) {
+               ERROR(pakfire, "Could not re-mount / as private: %m\n");
+               return r;
+       }
+
        for (const struct pakfire_mountpoint* mp = mountpoints; mp->source; mp++) {
                // Skip mounting root when a directory has been passed
                if (!*mp->target && !pakfire->mount_tmpfs)