#include <linux/magic.h>
#include "alloc-util.h"
-#include "chase-symlinks.h"
+#include "chase.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
-#include "label.h"
+#include "label-util.h"
#include "mkdir-label.h"
#include "mount-util.h"
#include "mountpoint-util.h"
MOUNT_FATAL }, /* If /etc/os-release doesn't exist use the version in /usr/lib as fallback */
{ NULL, "/run/host/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
MOUNT_FATAL },
+ { NULL, "/run/host/os-release", NULL, NULL, MS_PRIVATE,
+ MOUNT_FATAL }, /* Turn off propagation (we only want that for the mount propagation tunnel dir) */
{ NULL, "/run/host", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
MOUNT_FATAL|MOUNT_IN_USERNS },
#if HAVE_SELINUX
MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
0 }, /* Then, make it r/o (don't mkdir/chown the mount point here, the previous entry already did that) */
+ { NULL, "/sys/fs/selinux", NULL, NULL, MS_PRIVATE,
+ 0 }, /* Turn off propagation (we only want that for the mount propagation tunnel dir) */
#endif
};
if (!tmpfs_tmp && FLAGS_SET(mount_table[k].mount_settings, MOUNT_APPLY_TMPFS_TMP))
continue;
- r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
+ r = chase(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
+ return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].where);
/* Skip this entry if it is not a remount. */
if (mount_table[k].what) {
- r = path_is_mount_point(where, NULL, 0);
+ r = path_is_mount_point(where);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
if (r > 0)
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_PREFIX_ROOT)) {
/* Optionally prefix the mount source with the root dir. This is useful in bind
* mounts to be created within the container image before we transition into it. Note
- * that MOUNT_IN_USERNS is run after we transitioned hence prefixing is not ncessary
+ * that MOUNT_IN_USERNS is run after we transitioned hence prefixing is not necessary
* for those. */
- r = chase_symlinks(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
+ r = chase(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].what);
+ return log_error_errno(r, "Failed to resolve %s%s: %m", strempty(dest), mount_table[k].what);
}
r = mount_verbose_full(
new_idmapping = REMOUNT_IDMAPPING_NONE;
else if (streq(word, "rootidmap"))
new_idmapping = REMOUNT_IDMAPPING_HOST_OWNER;
+ else if (streq(word, "owneridmap"))
+ new_idmapping = REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid bind mount option: %s", word);
_cleanup_free_ char *mount_opts = NULL, *where = NULL;
unsigned long mount_flags = MS_BIND | MS_REC;
struct stat source_st, dest_st;
+ uid_t dest_uid = UID_INVALID;
int r;
RemountIdmapping idmapping = REMOUNT_IDMAPPING_NONE;
if (stat(m->source, &source_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
+ r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r > 0) { /* Path exists already? */
if (stat(where, &dest_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", where);
+ dest_uid = dest_st.st_uid;
+
if (S_ISDIR(source_st.st_mode) && !S_ISDIR(dest_st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot bind mount directory %s on file %s.",
m->source, where);
} else { /* Path doesn't exist yet? */
- r = mkdir_parents_label(where, 0755);
+ r = mkdir_parents_safe_label(dest, where, 0755, uid_shift, uid_shift, MKDIR_IGNORE_EXISTING);
if (r < 0)
return log_error_errno(r, "Failed to make parents of %s: %m", where);
r = touch(where);
if (r < 0)
return log_error_errno(r, "Failed to create mount point %s: %m", where);
+
+ if (chown(where, uid_shift, uid_shift) < 0)
+ return log_error_errno(errno, "Failed to chown %s: %m", where);
+
+ dest_uid = uid_shift;
}
r = mount_nofollow_verbose(LOG_ERR, m->source, where, NULL, mount_flags, mount_opts);
}
if (idmapping != REMOUNT_IDMAPPING_NONE) {
- r = remount_idmap(where, uid_shift, uid_range, source_st.st_uid, idmapping);
+ r = remount_idmap(STRV_MAKE(where), uid_shift, uid_range, source_st.st_uid, dest_uid, idmapping);
if (r < 0)
return log_error_errno(r, "Failed to map ids for bind mount %s: %m", where);
}
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
+ r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
+ r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
assert(dest);
assert(m);
- r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st, NULL);
+ r = chase_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
if (r < 0) {
log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
return m->graceful ? 0 : r;
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
+ r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
_cleanup_close_ int orig_mntns_fd = -EBADF;
int r, rr;
- r = namespace_open(0, NULL, &orig_mntns_fd, NULL, NULL, NULL);
+ r = namespace_open(0,
+ /* ret_pidns_fd = */ NULL,
+ &orig_mntns_fd,
+ /* ret_netns_fd = */ NULL,
+ /* ret_userns_fd = */ NULL,
+ /* ret_root_fd = */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to pin originating mount namespace: %m");
- r = namespace_enter(-EBADF, mntns_fd, -EBADF, -EBADF, -EBADF);
+ r = namespace_enter(/* pidns_fd = */ -EBADF,
+ mntns_fd,
+ /* netns_fd = */ -EBADF,
+ /* userns_fd = */ -EBADF,
+ /* root_fd = */ -EBADF);
if (r < 0)
return log_error_errno(r, "Failed to enter mount namespace: %m");
rr = do_wipe_fully_visible_fs();
- r = namespace_enter(-EBADF, orig_mntns_fd, -EBADF, -EBADF, -EBADF);
+ r = namespace_enter(/* pidns_fd = */ -EBADF,
+ orig_mntns_fd,
+ /* netns_fd = */ -EBADF,
+ /* userns_fd = */ -EBADF,
+ /* root_fd = */ -EBADF);
if (r < 0)
return log_error_errno(r, "Failed to enter original mount namespace: %m");