From 1147c538bbb6a2d3d5ba2e40f1437bcbeb22b33e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Oct 2021 18:34:57 +0200 Subject: [PATCH] homework: teach luks backend uid mapping 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 | 15 +++++++++++++++ src/home/homework-mount.c | 16 +++++++++++++--- src/home/homework.c | 12 +++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index b579e3be261..d1208e46787 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -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; diff --git a/src/home/homework-mount.c b/src/home/homework-mount.c index 5758e85839d..82b461a9873 100644 --- a/src/home/homework-mount.c +++ b/src/home/homework-mount.c @@ -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; diff --git a/src/home/homework.c b/src/home/homework.c index 7a2d816e59b..a5da4cf54ba 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -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;