namespace: port mount_private_apivfs() to fsopen() and friends

This is not just refactoring, but has the big benefit that it makes us
indepdendent from a temporary directory we might not have enough access
to create. (This matters with the new PrivateUsers=managed).
This commit is contained in:
Lennart Poettering
2026-02-19 15:07:19 +01:00
parent 051dfed9b6
commit 26f80a9d33
+47 -13
View File
@@ -1462,16 +1462,45 @@ static int mount_private_apivfs(
assert(entry_path);
assert(bind_source);
bool noprivs = false;
/* First, check if we have enough privileges to mount a new instance. */
_cleanup_close_ int mount_fd = make_fsmount(
LOG_DEBUG,
/* what= */ fstype,
fstype,
MS_NOSUID|MS_NOEXEC|MS_NODEV,
opts,
/* userns_fd= */ -EBADF);
if (ERRNO_IS_NEG_PRIVILEGE(mount_fd))
noprivs = true;
else if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd)) {
/* Fallback for kernels lacking mount_setattr() */
// FIXME: This compatibility code path shall be removed once kernel 5.12
// becomes the new minimal baseline
r = create_temporary_mount_point(scope, &temporary_mount);
if (r < 0)
return r;
r = mount_nofollow_verbose(
LOG_DEBUG,
fstype,
temporary_mount,
fstype,
MS_NOSUID|MS_NOEXEC|MS_NODEV,
opts);
if (ERRNO_IS_NEG_PRIVILEGE(r))
noprivs = true;
else if (r < 0)
return r;
} else if (mount_fd < 0)
return log_debug_errno(mount_fd, "Failed to make file system mount: %m");
(void) mkdir_p_label(entry_path, 0755);
/* First, check if we have enough privileges to mount a new instance. Note, a new sysfs instance
* cannot be mounted on an already existing mount. Let's use a temporary place. */
r = create_temporary_mount_point(scope, &temporary_mount);
if (r < 0)
return r;
r = mount_nofollow_verbose(LOG_DEBUG, fstype, temporary_mount, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
if (ERRNO_IS_NEG_PRIVILEGE(r)) {
if (noprivs) {
/* When we do not have enough privileges to mount a new instance, fall back to use an
* existing mount. */
@@ -1490,8 +1519,6 @@ static int mount_private_apivfs(
return 1;
}
if (r < 0)
return r;
/* OK. We have a new mount instance. Let's clear an existing mount and its submounts. */
r = umount_recursive(entry_path, /* flags= */ 0);
@@ -1499,9 +1526,16 @@ static int mount_private_apivfs(
log_debug_errno(r, "Failed to unmount directories below '%s', ignoring: %m", entry_path);
/* Then, move the new mount instance. */
r = mount_nofollow_verbose(LOG_DEBUG, temporary_mount, entry_path, /* fstype= */ NULL, MS_MOVE, /* options= */ NULL);
if (r < 0)
return r;
if (mount_fd >= 0) {
r = RET_NERRNO(move_mount(mount_fd, "", -EBADF, entry_path, MOVE_MOUNT_F_EMPTY_PATH));
if (r < 0)
return log_debug_errno(r, "Failed to attach '%s' to '%s': %m", fstype, entry_path);
} else if (temporary_mount) {
r = mount_nofollow_verbose(LOG_DEBUG, temporary_mount, entry_path, /* fstype= */ NULL, MS_MOVE, /* options= */ NULL);
if (r < 0)
return r;
} else
assert_not_reached();
/* We mounted a new instance now. Let's bind mount the children over now. This matters for nspawn
* where a bunch of files are overmounted, in particular the boot id. */