Skip to content

Commit e128723

Browse files
authored
Merge pull request systemd#16566 from poettering/nspawn-osrelease-fixes
nspawn: os-release reorganization, second try
2 parents a8bd4ba + 38821a0 commit e128723

File tree

8 files changed

+75
-42
lines changed

8 files changed

+75
-42
lines changed

NEWS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ CHANGES WITH 246:
546546
has been extended by a set of environment variables that expose
547547
select fields from the host's os-release file to the container
548548
payload. Similarly, host's os-release files can be mounted into the
549-
container underneath /run/hosts. Together, those mechanisms provide a
549+
container underneath /run/host. Together, those mechanisms provide a
550550
standardized way to expose information about the host to the
551551
container payload. Both interfaces are implemented in systemd-nspawn.
552552

TODO

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ Janitorial Clean-ups:
1717

1818
Features:
1919

20+
* nspawn: move "incoming mount" directory to /run/host, move "inaccessible"
21+
nodes to /run/host, move notify socket (for sd_notify() between payload and
22+
container manager)
23+
2024
* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it
2125
and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET)
2226

man/os-release.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,9 @@
342342

343343
<para>Container and sandbox runtime managers may make the host's
344344
identification data available to applications by providing the host's
345-
<filename>/etc/os-release</filename> and
346-
<filename>/usr/lib/os-release</filename> as respectively
347-
<filename>/run/host/etc/os-release</filename> and
348-
<filename>/run/host/usr/lib/os-release</filename>.</para>
345+
<filename>/etc/os-release</filename> (if available, otherwise
346+
<filename>/usr/lib/os-release</filename> as a fallback) as
347+
<filename>/run/host/os-release</filename>.</para>
349348
</refsect1>
350349

351350
<refsect1>

src/nspawn/nspawn-def.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* SPDX-License-Identifier: LGPL-2.1+ */
12
#pragma once
23

34
#include <sys/types.h>

src/nspawn/nspawn-mount.c

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -563,15 +563,16 @@ int mount_all(const char *dest,
563563
MOUNT_FATAL|MOUNT_MKDIR },
564564
{ "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
565565
MOUNT_FATAL|MOUNT_MKDIR },
566-
{ "/usr/lib/os-release", "/run/host/usr/lib/os-release", NULL, NULL, MS_BIND,
567-
MOUNT_FATAL|MOUNT_MKDIR|MOUNT_TOUCH }, /* As per kernel interface requirements, bind mount first (creating mount points) and make read-only later */
568-
{ NULL, "/run/host/usr/lib/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
569-
0 },
570-
{ "/etc/os-release", "/run/host/etc/os-release", NULL, NULL, MS_BIND,
571-
MOUNT_MKDIR|MOUNT_TOUCH },
572-
{ NULL, "/run/host/etc/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
573-
0 },
574-
566+
{ "/run/host", "/run/host", NULL, NULL, MS_BIND,
567+
MOUNT_FATAL|MOUNT_MKDIR|MOUNT_PREFIX_ROOT }, /* Prepare this so that we can make it read-only when we are done */
568+
{ "/etc/os-release", "/run/host/os-release", NULL, NULL, MS_BIND,
569+
MOUNT_TOUCH }, /* As per kernel interface requirements, bind mount first (creating mount points) and make read-only later */
570+
{ "/usr/lib/os-release", "/run/host/os-release", NULL, NULL, MS_BIND,
571+
MOUNT_FATAL }, /* If /etc/os-release doesn't exist use the version in /usr/lib as fallback */
572+
{ NULL, "/run/host/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
573+
MOUNT_FATAL },
574+
{ NULL, "/run/host", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
575+
MOUNT_FATAL|MOUNT_IN_USERNS },
575576
#if HAVE_SELINUX
576577
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
577578
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,
589590
int r;
590591

591592
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
592-
_cleanup_free_ char *where = NULL, *options = NULL;
593-
const char *o;
593+
_cleanup_free_ char *where = NULL, *options = NULL, *prefixed = NULL;
594594
bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL);
595+
const char *o;
595596

596597
if (in_userns != FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
597598
continue;
@@ -616,20 +617,9 @@ int mount_all(const char *dest,
616617
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
617618
if (r > 0)
618619
continue;
619-
620-
/* Shortcut for optional bind mounts: if the source can't be found skip ahead to avoid creating
621-
* empty and unused directories. */
622-
if (!fatal && FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR) && FLAGS_SET(mount_table[k].flags, MS_BIND)) {
623-
r = access(mount_table[k].what, F_OK);
624-
if (r < 0) {
625-
if (errno == ENOENT)
626-
continue;
627-
return log_error_errno(errno, "Failed to stat %s: %m", mount_table[k].what);
628-
}
629-
}
630620
}
631621

632-
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_MKDIR)) {
622+
if ((mount_table[k].mount_settings & (MOUNT_MKDIR|MOUNT_TOUCH)) != 0) {
633623
uid_t u = (use_userns && !in_userns) ? uid_shift : UID_INVALID;
634624

635625
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH))
@@ -647,13 +637,17 @@ int mount_all(const char *dest,
647637
if (r != -EROFS)
648638
continue;
649639
}
650-
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
651-
r = touch(where);
652-
if (r < 0 && r != -EEXIST) {
653-
if (fatal)
654-
return log_error_errno(r, "Failed to create mount point %s: %m", where);
655-
log_debug_errno(r, "Failed to create mount point %s: %m", where);
656-
}
640+
}
641+
642+
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
643+
r = touch(where);
644+
if (r < 0 && r != -EEXIST) {
645+
if (fatal && r != -EROFS)
646+
return log_error_errno(r, "Failed to create file %s: %m", where);
647+
648+
log_debug_errno(r, "Failed to create file %s: %m", where);
649+
if (r != -EROFS)
650+
continue;
657651
}
658652
}
659653

@@ -666,8 +660,18 @@ int mount_all(const char *dest,
666660
o = options;
667661
}
668662

663+
if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_PREFIX_ROOT)) {
664+
/* Optionally prefix the mount source with the root dir. This is useful in bind
665+
* mounts to be created within the container image before we transition into it. Note
666+
* that MOUNT_IN_USERNS is run after we transitioned hence prefixing is not ncessary
667+
* for those. */
668+
r = chase_symlinks(mount_table[k].what, dest, CHASE_PREFIX_ROOT, &prefixed, NULL);
669+
if (r < 0)
670+
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].what);
671+
}
672+
669673
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
670-
mount_table[k].what,
674+
prefixed ?: mount_table[k].what,
671675
where,
672676
mount_table[k].type,
673677
mount_table[k].flags,

src/nspawn/nspawn-mount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ typedef enum MountSettingsMask {
1818
MOUNT_NON_ROOT_ONLY = 1 << 7, /* if set, only non-root mounts are mounted */
1919
MOUNT_MKDIR = 1 << 8, /* if set, make directory to mount over first */
2020
MOUNT_TOUCH = 1 << 9, /* if set, touch file to mount over first */
21+
MOUNT_PREFIX_ROOT = 1 << 10,/* if set, prefix the source path with the container's root directory */
2122
} MountSettingsMask;
2223

2324
typedef enum CustomMountType {

src/portable/portable.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -695,17 +695,28 @@ static int install_chroot_dropin(
695695
if (!text)
696696
return -ENOMEM;
697697

698-
if (endswith(m->name, ".service"))
698+
if (endswith(m->name, ".service")) {
699+
const char *os_release_source;
700+
701+
if (access("/etc/os-release", F_OK) < 0) {
702+
if (errno != ENOENT)
703+
return log_debug_errno(errno, "Failed to check if /etc/os-release exists: %m");
704+
705+
os_release_source = "/usr/lib/os-release";
706+
} else
707+
os_release_source = "/etc/os-release";
708+
699709
if (!strextend(&text,
700710
"\n"
701711
"[Service]\n",
702712
IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) ? "RootDirectory=" : "RootImage=", image_path, "\n"
703713
"Environment=PORTABLE=", basename(image_path), "\n"
704-
"BindReadOnlyPaths=-/etc/os-release:/run/host/etc/os-release /usr/lib/os-release:/run/host/usr/lib/os-release\n"
714+
"BindReadOnlyPaths=", os_release_source, ":/run/host/os-release\n"
705715
"LogExtraFields=PORTABLE=", basename(image_path), "\n",
706716
NULL))
707717

708718
return -ENOMEM;
719+
}
709720

710721
r = write_string_file(dropin, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
711722
if (r < 0)

test/units/testsuite-13.sh

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,25 @@ if [ -n "${ID:+set}" ] && [ "${ID}" != "${container_host_id}" ]; then exit 1; fi
6666
if [ -n "${VERSION_ID:+set}" ] && [ "${VERSION_ID}" != "${container_host_version_id}" ]; then exit 1; fi
6767
if [ -n "${BUILD_ID:+set}" ] && [ "${BUILD_ID}" != "${container_host_build_id}" ]; then exit 1; fi
6868
if [ -n "${VARIANT_ID:+set}" ] && [ "${VARIANT_ID}" != "${container_host_variant_id}" ]; then exit 1; fi
69-
cd /tmp; (cd /run/host/usr/lib; md5sum os-release) | md5sum -c
70-
if echo test >> /run/host/usr/lib/os-release; then exit 1; fi
71-
if echo test >> /run/host/etc/os-release; then exit 1; fi
69+
cd /tmp; (cd /run/host; md5sum os-release) | md5sum -c
70+
if echo test >> /run/host/os-release; then exit 1; fi
7271
'
7372

74-
systemd-nspawn --register=no -D /testsuite-13.nc-container --bind=/etc/os-release:/tmp/os-release /bin/sh -x -e -c "$_cmd"
73+
local _os_release_source="/etc/os-release"
74+
if [ ! -r "${_os_release_source}" ]; then
75+
_os_release_source="/usr/lib/os-release"
76+
elif [ -L "${_os_release_source}" ] && rm /etc/os-release; then
77+
# Ensure that /etc always wins if available
78+
cp /usr/lib/os-release /etc
79+
echo MARKER=1 >> /etc/os-release
80+
fi
81+
82+
systemd-nspawn --register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
83+
84+
if grep -q MARKER /etc/os-release; then
85+
rm /etc/os-release
86+
ln -s ../usr/lib/os-release /etc/os-release
87+
fi
7588
}
7689

7790
function run {

0 commit comments

Comments
 (0)