summaryrefslogtreecommitdiffstats
path: root/src/shared/mount-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/mount-util.c')
-rw-r--r--src/shared/mount-util.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c
index 4f2acce..4ddfb9a 100644
--- a/src/shared/mount-util.c
+++ b/src/shared/mount-util.c
@@ -79,7 +79,9 @@ int umount_recursive_full(const char *prefix, int flags, char **keep) {
continue;
if (prefix && !path_startswith(path, prefix)) {
- log_trace("Not unmounting %s, outside of prefix: %s", path, prefix);
+ // FIXME: This is extremely noisy, we're probably doing something very wrong
+ // to trigger this so often, needs more investigation.
+ // log_trace("Not unmounting %s, outside of prefix: %s", path, prefix);
continue;
}
@@ -347,7 +349,7 @@ int bind_remount_recursive_with_mountinfo(
* think autofs, NFS, FUSE, …), but let's generate useful debug messages at
* the very least. */
- q = path_is_mount_point(x, NULL, 0);
+ q = path_is_mount_point(x);
if (IN_SET(q, 0, -ENOENT)) {
/* Hmm, whaaaa? The mount point is not actually a mount point? Then
* it is either obstructed by a later mount or somebody has been
@@ -453,14 +455,20 @@ int bind_remount_one_with_mountinfo(
return 0;
}
+int bind_remount_one(const char *path, unsigned long new_flags, unsigned long flags_mask) {
+ _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+
+ proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+ if (!proc_self_mountinfo)
+ return log_debug_errno(errno, "Failed to open /proc/self/mountinfo: %m");
+
+ return bind_remount_one_with_mountinfo(path, new_flags, flags_mask, proc_self_mountinfo);
+}
+
static int mount_switch_root_pivot(int fd_newroot, const char *path) {
assert(fd_newroot >= 0);
assert(path);
- /* Change into the new rootfs. */
- if (fchdir(fd_newroot) < 0)
- return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
-
/* Let the kernel tuck the new root under the old one. */
if (pivot_root(".", ".") < 0)
return log_debug_errno(errno, "Failed to pivot root to new rootfs '%s': %m", path);
@@ -477,10 +485,6 @@ static int mount_switch_root_move(int fd_newroot, const char *path) {
assert(fd_newroot >= 0);
assert(path);
- /* Change into the new rootfs. */
- if (fchdir(fd_newroot) < 0)
- return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
-
/* Move the new root fs */
if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
return log_debug_errno(errno, "Failed to move new rootfs '%s': %m", path);
@@ -494,7 +498,7 @@ static int mount_switch_root_move(int fd_newroot, const char *path) {
int mount_switch_root_full(const char *path, unsigned long mount_propagation_flag, bool force_ms_move) {
_cleanup_close_ int fd_newroot = -EBADF;
- int r;
+ int r, is_current_root;
assert(path);
assert(mount_propagation_flag_is_valid(mount_propagation_flag));
@@ -503,19 +507,31 @@ int mount_switch_root_full(const char *path, unsigned long mount_propagation_fla
if (fd_newroot < 0)
return log_debug_errno(errno, "Failed to open new rootfs '%s': %m", path);
- if (!force_ms_move) {
- r = mount_switch_root_pivot(fd_newroot, path);
- if (r < 0) {
- log_debug_errno(r, "Failed to pivot into new rootfs '%s', will try to use MS_MOVE instead: %m", path);
- force_ms_move = true;
+ is_current_root = path_is_root_at(fd_newroot, NULL);
+ if (is_current_root < 0)
+ return log_debug_errno(is_current_root, "Failed to determine if target dir is our root already: %m");
+
+ /* Change into the new rootfs. */
+ if (fchdir(fd_newroot) < 0)
+ return log_debug_errno(errno, "Failed to chdir into new rootfs '%s': %m", path);
+
+ /* Make this a NOP if we are supposed to switch to our current root fs. After all, both pivot_root()
+ * and MS_MOVE don't like that. */
+ if (!is_current_root) {
+ if (!force_ms_move) {
+ r = mount_switch_root_pivot(fd_newroot, path);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to pivot into new rootfs '%s', will try to use MS_MOVE instead: %m", path);
+ force_ms_move = true;
+ }
+ }
+ if (force_ms_move) {
+ /* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the rootfs is
+ * an initramfs in which case pivot_root() isn't supported. */
+ r = mount_switch_root_move(fd_newroot, path);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to switch to new rootfs '%s' with MS_MOVE: %m", path);
}
- }
- if (force_ms_move) {
- /* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the rootfs is
- * an initramfs in which case pivot_root() isn't supported. */
- r = mount_switch_root_move(fd_newroot, path);
- if (r < 0)
- return log_debug_errno(r, "Failed to switch to new rootfs '%s' with MS_MOVE: %m", path);
}
/* Finally, let's establish the requested propagation flags. */
@@ -817,8 +833,8 @@ int mount_option_mangle(
if (!(ent->mask & MNT_INVERT))
mount_flags |= ent->id;
- else if (mount_flags & ent->id)
- mount_flags ^= ent->id;
+ else
+ mount_flags &= ~ent->id;
break;
}
@@ -1096,7 +1112,7 @@ static int mount_in_namespace(
if (!pidref_is_set(target))
return -ESRCH;
- r = namespace_open(target->pid, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
+ r = namespace_open(target->pid, &pidns_fd, &mntns_fd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &root_fd);
if (r < 0)
return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m");
@@ -1200,7 +1216,9 @@ static int mount_in_namespace(
(void) mkdir_parents(dest, 0755);
if (img) {
- DissectImageFlags f = DISSECT_IMAGE_TRY_ATOMIC_MOUNT_EXCHANGE;
+ DissectImageFlags f =
+ DISSECT_IMAGE_TRY_ATOMIC_MOUNT_EXCHANGE |
+ DISSECT_IMAGE_ALLOW_USERSPACE_VERITY;
if (make_file_or_directory)
f |= DISSECT_IMAGE_MKDIR;
@@ -1279,7 +1297,7 @@ int make_mount_point(const char *path) {
/* If 'path' is already a mount point, does nothing and returns 0. If it is not it makes it one, and returns 1. */
- r = path_is_mount_point(path, NULL, 0);
+ r = path_is_mount_point(path);
if (r < 0)
return log_debug_errno(r, "Failed to determine whether '%s' is a mount point: %m", path);
if (r > 0)
@@ -1310,7 +1328,7 @@ int fd_make_mount_point(int fd) {
return 1;
}
-int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping) {
+int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest_owner, RemountIdmapping idmapping) {
_cleanup_close_ int userns_fd = -EBADF;
_cleanup_free_ char *line = NULL;
@@ -1345,8 +1363,20 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping
if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER) {
/* Remap the owner of the bind mounted directory to the root user within the container. This
* way every file written by root within the container to the bind-mounted directory will
- * be owned by the original user. All other user will remain unmapped. */
- if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", owner, uid_shift, 1u) < 0)
+ * be owned by the original user from the host. All other users will remain unmapped. */
+ if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", source_owner, uid_shift, 1u) < 0)
+ return log_oom_debug();
+ }
+
+ if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER) {
+ /* Remap the owner of the bind mounted directory to the owner of the target directory
+ * within the container. This way every file written by target directory owner within the
+ * container to the bind-mounted directory will be owned by the original host user.
+ * All other users will remain unmapped. */
+ if (asprintf(
+ &line,
+ UID_FMT " " UID_FMT " " UID_FMT "\n",
+ source_owner, dest_owner, 1u) < 0)
return log_oom_debug();
}
@@ -1366,7 +1396,7 @@ int remount_idmap_fd(
assert(userns_fd >= 0);
- /* This remounts all specified paths with the specified userns as idmap. It will do so in in the
+ /* This remounts all specified paths with the specified userns as idmap. It will do so in the
* order specified in the strv: the expectation is that the top-level directories are at the
* beginning, and nested directories in the right, so that the tree can be built correctly from left
* to right. */
@@ -1420,10 +1450,10 @@ int remount_idmap_fd(
return 0;
}
-int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping) {
+int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest_owner,RemountIdmapping idmapping) {
_cleanup_close_ int userns_fd = -EBADF;
- userns_fd = make_userns(uid_shift, uid_range, owner, idmapping);
+ userns_fd = make_userns(uid_shift, uid_range, source_owner, dest_owner, idmapping);
if (userns_fd < 0)
return userns_fd;
@@ -1586,7 +1616,7 @@ int bind_mount_submounts(
if (!t)
return -ENOMEM;
- r = path_is_mount_point(t, NULL, 0);
+ r = path_is_mount_point(t);
if (r < 0) {
log_debug_errno(r, "Failed to detect if '%s' already is a mount point, ignoring: %m", t);
continue;