nspawn: rework how /run/host/ is set up
Let's find the right os-release file on the host side, and only mount the one that matters, i.e. /etc/os-release if it exists and /usr/lib/os-release otherwise. Use the fixed path /run/host/os-release for that. Let's also mount /run/host as a bind mount on itself before we set up /run/host, and let's mount it MS_RDONLY after we are done, so that it remains immutable as a whole.
This commit is contained in:
parent
62b0ee9eb1
commit
d64e32c245
|
@ -563,15 +563,16 @@ int mount_all(const char *dest,
|
||||||
MOUNT_FATAL|MOUNT_MKDIR },
|
MOUNT_FATAL|MOUNT_MKDIR },
|
||||||
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
|
||||||
MOUNT_FATAL|MOUNT_MKDIR },
|
MOUNT_FATAL|MOUNT_MKDIR },
|
||||||
{ "/usr/lib/os-release", "/run/host/usr/lib/os-release", NULL, NULL, MS_BIND,
|
{ "/run/host", "/run/host", NULL, NULL, MS_BIND,
|
||||||
MOUNT_FATAL|MOUNT_MKDIR|MOUNT_TOUCH }, /* As per kernel interface requirements, bind mount first (creating mount points) and make read-only later */
|
MOUNT_FATAL|MOUNT_MKDIR|MOUNT_PREFIX_ROOT }, /* Prepare this so that we can make it read-only when we are done */
|
||||||
{ NULL, "/run/host/usr/lib/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
|
{ "/etc/os-release", "/run/host/os-release", NULL, NULL, MS_BIND,
|
||||||
0 },
|
MOUNT_TOUCH }, /* As per kernel interface requirements, bind mount first (creating mount points) and make read-only later */
|
||||||
{ "/etc/os-release", "/run/host/etc/os-release", NULL, NULL, MS_BIND,
|
{ "/usr/lib/os-release", "/run/host/os-release", NULL, NULL, MS_BIND,
|
||||||
MOUNT_MKDIR|MOUNT_TOUCH },
|
MOUNT_FATAL }, /* If /etc/os-release doesn't exist use the version in /usr/lib as fallback */
|
||||||
{ NULL, "/run/host/etc/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
|
{ NULL, "/run/host/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
|
||||||
0 },
|
MOUNT_FATAL },
|
||||||
|
{ 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
|
#if HAVE_SELINUX
|
||||||
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
|
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
|
||||||
MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
|
MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
|
||||||
|
@ -589,9 +590,9 @@ int mount_all(const char *dest,
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
|
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
|
||||||
_cleanup_free_ char *where = NULL, *options = NULL;
|
_cleanup_free_ char *where = NULL, *options = NULL, *prefixed = NULL;
|
||||||
const char *o;
|
|
||||||
bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL);
|
bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL);
|
||||||
|
const char *o;
|
||||||
|
|
||||||
if (in_userns != FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
|
if (in_userns != FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
|
||||||
continue;
|
continue;
|
||||||
|
@ -616,20 +617,9 @@ int mount_all(const char *dest,
|
||||||
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
|
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Shortcut for optional bind mounts: if the source can't be found skip ahead to avoid creating
|
|
||||||
* empty and unused directories. */
|
|
||||||
if (!fatal && FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR) && FLAGS_SET(mount_table[k].flags, MS_BIND)) {
|
|
||||||
r = access(mount_table[k].what, F_OK);
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno == ENOENT)
|
|
||||||
continue;
|
|
||||||
return log_error_errno(errno, "Failed to stat %s: %m", mount_table[k].what);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR)) {
|
if ((mount_table[k].mount_settings & (MOUNT_MKDIR|MOUNT_TOUCH)) != 0) {
|
||||||
uid_t u = (use_userns && !in_userns) ? uid_shift : UID_INVALID;
|
uid_t u = (use_userns && !in_userns) ? uid_shift : UID_INVALID;
|
||||||
|
|
||||||
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH))
|
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH))
|
||||||
|
@ -647,13 +637,17 @@ int mount_all(const char *dest,
|
||||||
if (r != -EROFS)
|
if (r != -EROFS)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
|
}
|
||||||
r = touch(where);
|
|
||||||
if (r < 0 && r != -EEXIST) {
|
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
|
||||||
if (fatal)
|
r = touch(where);
|
||||||
return log_error_errno(r, "Failed to create mount point %s: %m", where);
|
if (r < 0 && r != -EEXIST) {
|
||||||
log_debug_errno(r, "Failed to create mount point %s: %m", where);
|
if (fatal && r != -EROFS)
|
||||||
}
|
return log_error_errno(r, "Failed to create file %s: %m", where);
|
||||||
|
|
||||||
|
log_debug_errno(r, "Failed to create file %s: %m", where);
|
||||||
|
if (r != -EROFS)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,8 +660,18 @@ int mount_all(const char *dest,
|
||||||
o = options;
|
o = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
* for those. */
|
||||||
|
r = chase_symlinks(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);
|
||||||
|
}
|
||||||
|
|
||||||
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
|
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
|
||||||
mount_table[k].what,
|
prefixed ?: mount_table[k].what,
|
||||||
where,
|
where,
|
||||||
mount_table[k].type,
|
mount_table[k].type,
|
||||||
mount_table[k].flags,
|
mount_table[k].flags,
|
||||||
|
|
|
@ -18,6 +18,7 @@ typedef enum MountSettingsMask {
|
||||||
MOUNT_NON_ROOT_ONLY = 1 << 7, /* if set, only non-root mounts are mounted */
|
MOUNT_NON_ROOT_ONLY = 1 << 7, /* if set, only non-root mounts are mounted */
|
||||||
MOUNT_MKDIR = 1 << 8, /* if set, make directory to mount over first */
|
MOUNT_MKDIR = 1 << 8, /* if set, make directory to mount over first */
|
||||||
MOUNT_TOUCH = 1 << 9, /* if set, touch file to mount over first */
|
MOUNT_TOUCH = 1 << 9, /* if set, touch file to mount over first */
|
||||||
|
MOUNT_PREFIX_ROOT = 1 << 10,/* if set, prefix the source path with the container's root directory */
|
||||||
} MountSettingsMask;
|
} MountSettingsMask;
|
||||||
|
|
||||||
typedef enum CustomMountType {
|
typedef enum CustomMountType {
|
||||||
|
|
|
@ -66,12 +66,25 @@ if [ -n "${ID:+set}" ] && [ "${ID}" != "${container_host_id}" ]; then exit 1; fi
|
||||||
if [ -n "${VERSION_ID:+set}" ] && [ "${VERSION_ID}" != "${container_host_version_id}" ]; then exit 1; fi
|
if [ -n "${VERSION_ID:+set}" ] && [ "${VERSION_ID}" != "${container_host_version_id}" ]; then exit 1; fi
|
||||||
if [ -n "${BUILD_ID:+set}" ] && [ "${BUILD_ID}" != "${container_host_build_id}" ]; then exit 1; fi
|
if [ -n "${BUILD_ID:+set}" ] && [ "${BUILD_ID}" != "${container_host_build_id}" ]; then exit 1; fi
|
||||||
if [ -n "${VARIANT_ID:+set}" ] && [ "${VARIANT_ID}" != "${container_host_variant_id}" ]; then exit 1; fi
|
if [ -n "${VARIANT_ID:+set}" ] && [ "${VARIANT_ID}" != "${container_host_variant_id}" ]; then exit 1; fi
|
||||||
cd /tmp; (cd /run/host/usr/lib; md5sum os-release) | md5sum -c
|
cd /tmp; (cd /run/host; md5sum os-release) | md5sum -c
|
||||||
if echo test >> /run/host/usr/lib/os-release; then exit 1; fi
|
if echo test >> /run/host/os-release; then exit 1; fi
|
||||||
if echo test >> /run/host/etc/os-release; then exit 1; fi
|
|
||||||
'
|
'
|
||||||
|
|
||||||
systemd-nspawn --register=no -D /testsuite-13.nc-container --bind=/etc/os-release:/tmp/os-release /bin/sh -x -e -c "$_cmd"
|
local _os_release_source="/etc/os-release"
|
||||||
|
if [ ! -r "${_os_release_source}" ]; then
|
||||||
|
_os_release_source="/usr/lib/os-release"
|
||||||
|
elif [ -L "${_os_release_source}" ] && rm /etc/os-release; then
|
||||||
|
# Ensure that /etc always wins if available
|
||||||
|
cp /usr/lib/os-release /etc
|
||||||
|
echo MARKER=1 >> /etc/os-release
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemd-nspawn --register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
|
||||||
|
|
||||||
|
if grep -q MARKER /etc/os-release; then
|
||||||
|
rm /etc/os-release
|
||||||
|
ln -s ../usr/lib/os-release /etc/os-release
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function run {
|
function run {
|
||||||
|
|
Loading…
Reference in New Issue