]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homework: teach luks backend uid mapping
authorLennart Poettering <lennart@poettering.net>
Tue, 26 Oct 2021 16:34:57 +0000 (18:34 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 28 Oct 2021 06:17:46 +0000 (08:17 +0200)
This teachs the LUKS backend UID mapping, similar to the existing
logic for the "directory", "subvolume" and "fscrypt" backends: the files
will be owned by "nobody" on the fs itself, but will be mapped to
logging in user via uidmapped mounts.

This way LUKS home dirs become truly portable: no local UID info will
leak onto the images anymore, and the need to recursively chown them on
activation goes away. This means activation is always as performant as
it should be.

src/home/homework-luks.c
src/home/homework-mount.c
src/home/homework.c

index b579e3be261fddd550298bd1ff713f49e709c3d3..d1208e4678784cd753ac37d03b5aa2610f7b54f7 100644 (file)
@@ -45,6 +45,7 @@
 #include "strv.h"
 #include "sync-util.h"
 #include "tmpfile-util.h"
+#include "user-util.h"
 
 /* Round down to the nearest 4K size. Given that newer hardware generally prefers 4K sectors, let's align our
  * partitions to that too. In the worst case we'll waste 3.5K per partition that way, but I think I can live
@@ -1989,6 +1990,7 @@ int home_create_luks(
                 host_size = 0, partition_offset = 0, partition_size = 0; /* Unnecessary initialization to appease gcc */
         _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
         sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
+        _cleanup_close_ int mount_fd = -1;
         const char *fstype, *ip;
         struct statfs sfs;
         int r;
@@ -2237,6 +2239,19 @@ int home_create_luks(
         if (setup->root_fd < 0)
                 return log_error_errno(errno, "Failed to open user directory in mounted image file: %m");
 
+        (void) home_shift_uid(setup->root_fd, NULL, UID_NOBODY, h->uid, &mount_fd);
+
+        if (mount_fd >= 0) {
+                /* If we have established a new mount, then we can use that as new root fd to our home directory. */
+                safe_close(setup->root_fd);
+
+                setup->root_fd = fd_reopen(mount_fd, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                if (setup->root_fd < 0)
+                        return log_error_errno(setup->root_fd, "Unable to convert mount fd into proper directory fd: %m");
+
+                mount_fd = safe_close(mount_fd);
+        }
+
         r = home_populate(h, setup->root_fd);
         if (r < 0)
                 return r;
index 5758e85839d7b713902eea556b6ff88010d179d1..82b461a9873616aed05e7ec71a7a78d6f54edbec 100644 (file)
@@ -84,7 +84,17 @@ int home_unshare_and_mount(const char *node, const char *fstype, bool discard, u
         if (r < 0)
                 return r;
 
-        return home_mount_node(node, fstype, discard, flags);
+        r = home_mount_node(node, fstype, discard, flags);
+        if (r < 0)
+                return r;
+
+        r = mount_nofollow_verbose(LOG_ERR, NULL, HOME_RUNTIME_WORK_DIR, NULL, MS_PRIVATE, NULL);
+        if (r < 0) {
+                (void) umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
+                return r;
+        }
+
+        return 0;
 }
 
 int home_move_mount(const char *mount_suffix, const char *target) {
@@ -111,9 +121,9 @@ int home_move_mount(const char *mount_suffix, const char *target) {
         if (r < 0)
                 return r;
 
-        r = umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
+        r = umount_recursive(HOME_RUNTIME_WORK_DIR, 0);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to unmount %s: %m", HOME_RUNTIME_WORK_DIR);
 
         log_info("Moving to final mount point %s completed.", target);
         return 0;
index 7a2d816e59b48ceff6b7629d887f4df8a81b1102..a5da4cf54baa6c191c6a4e438c215ca2b9620dcb 100644 (file)
@@ -306,9 +306,15 @@ int home_setup_undo_mount(HomeSetup *setup, int level) {
         if (!setup->undo_mount)
                 return 0;
 
-        r = umount_verbose(level, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
-        if (r < 0)
-                return r;
+        r = umount_recursive(HOME_RUNTIME_WORK_DIR, 0);
+        if (r < 0) {
+                if (level >= LOG_DEBUG) /* umount_recursive() does debug level logging anyway, no need to
+                                         * repeat that here */
+                        return r;
+
+                /* If a higher log level is requested, the generate a non-debug mesage here too. */
+                return log_full_errno(level, r, "Failed to unmount mount tree below %s: %m", HOME_RUNTIME_WORK_DIR);
+        }
 
         setup->undo_mount = false;
         return 1;