1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-07 17:17:44 +03:00

homework: rework directory backend to set up mounts in /run/systemd/user-home-mount before moving them to /home

This does what we already do for the LUKS backend: instead of mounting
the source directory directly to the final home dir, we instead bind
mount it to /run/systemd/user-home-mount (where /run/ is unshared and
specific to our own mount namespace), then adjust its mount flags and
then bind mount it in a single atomic operation into the final
destination, fully set up.

This doesn't improve much on its own, but it makes things a tiny bit
more correct: this way MS_NODEV/MS_NOEXEC/MS_NOSUID will already be
applied when the bind mount appears in the host mount namespace, instead
of being adjusted after the fact.

Doing things this way also makes things work more like the LUKS backend,
reducing surprises. Most importantly it's preparation for doing
uidmapping for directory homes, added in a later commit.
This commit is contained in:
Lennart Poettering 2021-10-20 22:07:57 +02:00
parent cfef46f5fe
commit 2ba38f78c3

View File

@ -5,6 +5,7 @@
#include "btrfs-util.h"
#include "fd-util.h"
#include "homework-directory.h"
#include "homework-mount.h"
#include "homework-quota.h"
#include "mkdir.h"
#include "mount-util.h"
@ -14,10 +15,38 @@
#include "umask-util.h"
int home_setup_directory(UserRecord *h, HomeSetup *setup) {
const char *ip;
int r;
assert(h);
assert(setup);
assert(setup->root_fd < 0);
setup->root_fd = open(user_record_image_path(h), O_RDONLY|O_CLOEXEC|O_DIRECTORY);
/* We'll bind mount the image directory to a new mount point where we'll start adjusting it. Only
* once that's complete we'll move the thing to its final place eventually. */
r = home_unshare_and_mkdir();
if (r < 0)
return r;
assert_se(ip = user_record_image_path(h));
r = mount_follow_verbose(LOG_ERR, ip, HOME_RUNTIME_WORK_DIR, NULL, MS_BIND, NULL);
if (r < 0)
return r;
setup->undo_mount = true;
/* Turn off any form of propagation for this */
r = mount_nofollow_verbose(LOG_ERR, NULL, HOME_RUNTIME_WORK_DIR, NULL, MS_PRIVATE, NULL);
if (r < 0)
return r;
/* Adjust MS_SUID and similar flags */
r = mount_nofollow_verbose(LOG_ERR, NULL, HOME_RUNTIME_WORK_DIR, NULL, MS_BIND|MS_REMOUNT|user_record_mount_flags(h), NULL);
if (r < 0)
return r;
setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
if (setup->root_fd < 0)
return log_error_errno(errno, "Failed to open home directory: %m");
@ -31,7 +60,7 @@ int home_activate_directory(
UserRecord **ret_home) {
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL, *header_home = NULL;
const char *hdo, *hd, *ipo, *ip;
const char *hd, *hdo;
int r;
assert(h);
@ -39,9 +68,6 @@ int home_activate_directory(
assert(setup);
assert(ret_home);
assert_se(ipo = user_record_image_path(h));
ip = strdupa_safe(ipo); /* copy out, since reconciliation might cause changing of the field */
assert_se(hdo = user_record_home_directory(h));
hd = strdupa_safe(hdo);
@ -57,24 +83,15 @@ int home_activate_directory(
if (r < 0)
return r;
/* Close fd to private mount before moving mount */
setup->root_fd = safe_close(setup->root_fd);
/* Create mount point to mount over if necessary */
if (!path_equal(ip, hd))
(void) mkdir_p(hd, 0700);
/* Create a mount point (even if the directory is already placed correctly), as a way to indicate
* this mount point is now "activated". Moreover, we want to set per-user
* MS_NOSUID/MS_NOEXEC/MS_NODEV. */
r = mount_nofollow_verbose(LOG_ERR, ip, hd, NULL, MS_BIND, NULL);
/* We are now done with everything, move the mount into place */
r = home_move_mount(NULL, hd);
if (r < 0)
return r;
r = mount_nofollow_verbose(LOG_ERR, NULL, hd, NULL, MS_BIND|MS_REMOUNT|user_record_mount_flags(h), NULL);
if (r < 0) {
(void) umount_verbose(LOG_ERR, hd, UMOUNT_NOFOLLOW);
return r;
}
setup->undo_mount = false;
setup->do_drop_caches = false;