summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2020-07-08 23:52:13 +0200
committerGitHub <noreply@github.com>2020-07-08 23:52:13 +0200
commit55aacd502b0a80c21aee50bdd0f325d378250261 (patch)
tree5fa0afda7abdb1695a12b56608e1f9602a5cc1fc
parent48c190822b1f0658fd715446a9efe4d91a32411a (diff)
parent73083ca238d8d537e2713378271a316fc6afa350 (diff)
downloadsystemd-55aacd502b0a80c21aee50bdd0f325d378250261.tar.gz
Merge pull request #15891 from bluca/host_os_release
Container Interface: expose the host's os-release metadata to nspawn and portable guests
-rw-r--r--docs/CONTAINER_INTERFACE.md10
-rw-r--r--man/os-release.xml7
-rw-r--r--src/basic/mkdir-label.c5
-rw-r--r--src/basic/mkdir.c42
-rw-r--r--src/basic/mkdir.h8
-rw-r--r--src/nspawn/nspawn-mount.c104
-rw-r--r--src/nspawn/nspawn-mount.h1
-rw-r--r--src/nspawn/nspawn.c12
-rw-r--r--src/portable/portable.c1
-rw-r--r--src/shared/os-util.c30
-rw-r--r--src/shared/os-util.h1
-rwxr-xr-xtest/TEST-13-NSPAWN-SMOKE/test.sh2
-rwxr-xr-xtest/units/testsuite-13.sh14
13 files changed, 153 insertions, 84 deletions
diff --git a/docs/CONTAINER_INTERFACE.md b/docs/CONTAINER_INTERFACE.md
index 71f9185c58..a36d2edc72 100644
--- a/docs/CONTAINER_INTERFACE.md
+++ b/docs/CONTAINER_INTERFACE.md
@@ -121,6 +121,16 @@ manager, please consider supporting the following interfaces.
`container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login
gettys on ptys 7, 8, and 14.
+4. To allow applications to detect the OS version and other metadata of the host
+ running the container manager, if this is considered desirable, please parse
+ the host's `/etc/os-release` and set a `$container_host_<key>=<VALUE>`
+ environment variable for the ID fields described by the [os-release
+ interface](https://www.freedesktop.org/software/systemd/man/os-release.html), eg:
+ `$container_host_id=debian`
+ `$container_host_build_id=2020-06-15`
+ `$container_host_variant_id=server`
+ `$container_host_version_id=10`
+
## Advanced Integration
1. Consider syncing `/etc/localtime` from the host file system into the
diff --git a/man/os-release.xml b/man/os-release.xml
index a2e3d0d8ac..675daf3ede 100644
--- a/man/os-release.xml
+++ b/man/os-release.xml
@@ -339,6 +339,13 @@
name in order to avoid name clashes. Applications
reading this file must ignore unknown fields. Example:
<literal>DEBIAN_BTS="debbugs://bugs.debian.org/"</literal></para>
+
+ <para>Container and sandbox runtime managers may make the host's
+ identification data available to applications by providing the host's
+ <filename>/etc/os-release</filename> and
+ <filename>/usr/lib/os-release</filename> as respectively
+ <filename>/run/host/etc/os-release</filename> and
+ <filename>/run/host/usr/lib/os-release</filename>.</para>
</refsect1>
<refsect1>
diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c
index 0eba7fc514..e844a59806 100644
--- a/src/basic/mkdir-label.c
+++ b/src/basic/mkdir-label.c
@@ -10,6 +10,7 @@
#include "mkdir.h"
#include "selinux-util.h"
#include "smack-util.h"
+#include "user-util.h"
int mkdir_label(const char *path, mode_t mode) {
int r;
@@ -50,9 +51,9 @@ int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirF
}
int mkdir_parents_label(const char *path, mode_t mode) {
- return mkdir_parents_internal(NULL, path, mode, mkdir_label);
+ return mkdir_parents_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdir_label);
}
int mkdir_p_label(const char *path, mode_t mode) {
- return mkdir_p_internal(NULL, path, mode, mkdir_label);
+ return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdir_label);
}
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index ff20cec985..ed5c4546e4 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -93,7 +93,7 @@ int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags f
return mkdir_safe_internal(path, mode, uid, gid, flags, mkdir_errno_wrapper);
}
-int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
+int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) {
const char *p, *e;
int r;
@@ -136,34 +136,54 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mk
if (prefix && path_startswith(prefix, t))
continue;
- r = _mkdir(t, mode);
- if (r < 0 && r != -EEXIST)
- return r;
+ if (uid == UID_INVALID && gid == UID_INVALID && flags == 0) {
+ r = _mkdir(t, mode);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ } else {
+ r = mkdir_safe_internal(t, mode, uid, gid, flags, _mkdir);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
}
}
int mkdir_parents(const char *path, mode_t mode) {
- return mkdir_parents_internal(NULL, path, mode, mkdir_errno_wrapper);
+ return mkdir_parents_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdir_errno_wrapper);
+}
+
+int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
+ return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdir_errno_wrapper);
}
-int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
+int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir) {
int r;
/* Like mkdir -p */
assert(_mkdir != mkdir);
- r = mkdir_parents_internal(prefix, path, mode, _mkdir);
+ r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags, _mkdir);
if (r < 0)
return r;
- r = _mkdir(path, mode);
- if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
- return r;
+ if (uid == UID_INVALID && gid == UID_INVALID && flags == 0) {
+ r = _mkdir(path, mode);
+ if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
+ return r;
+ } else {
+ r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdir);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
return 0;
}
int mkdir_p(const char *path, mode_t mode) {
- return mkdir_p_internal(NULL, path, mode, mkdir_errno_wrapper);
+ return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdir_errno_wrapper);
+}
+
+int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
+ return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdir_errno_wrapper);
}
diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h
index eb54853ea7..8bfaaf405b 100644
--- a/src/basic/mkdir.h
+++ b/src/basic/mkdir.h
@@ -12,15 +12,17 @@ int mkdir_errno_wrapper(const char *pathname, mode_t mode);
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode);
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
int mkdir_parents(const char *path, mode_t mode);
+int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
int mkdir_p(const char *path, mode_t mode);
+int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
/* mandatory access control(MAC) versions */
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
-int mkdir_parents_label(const char *path, mode_t mode);
+int mkdir_parents_label(const char *path, mode_t mod);
int mkdir_p_label(const char *path, mode_t mode);
/* internally used */
typedef int (*mkdir_func_t)(const char *pathname, mode_t mode);
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
-int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir);
-int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir);
+int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
+int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 2fbaf65692..b07a214b61 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -487,59 +487,6 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT|extra_flags, NULL);
}
-static int mkdir_userns(const char *path, mode_t mode, uid_t uid_shift) {
- int r;
-
- assert(path);
-
- r = mkdir_errno_wrapper(path, mode);
- if (r < 0 && r != -EEXIST)
- return r;
-
- if (uid_shift == UID_INVALID)
- return 0;
-
- if (lchown(path, uid_shift, uid_shift) < 0)
- return -errno;
-
- return 0;
-}
-
-static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, uid_t uid_shift) {
- const char *p, *e;
- int r;
-
- assert(path);
-
- if (prefix && !path_startswith(path, prefix))
- return -ENOTDIR;
-
- /* create every parent directory in the path, except the last component */
- p = path + strspn(path, "/");
- for (;;) {
- char t[strlen(path) + 1];
-
- e = p + strcspn(p, "/");
- p = e + strspn(e, "/");
-
- /* Is this the last component? If so, then we're done */
- if (*p == 0)
- break;
-
- memcpy(t, path, e - path);
- t[e-path] = 0;
-
- if (prefix && path_startswith(prefix, t))
- continue;
-
- r = mkdir_userns(t, mode, uid_shift);
- if (r < 0)
- return r;
- }
-
- return mkdir_userns(path, mode, uid_shift);
-}
-
int mount_all(const char *dest,
MountSettingsMask mount_settings,
uid_t uid_shift,
@@ -598,29 +545,33 @@ int mount_all(const char *dest,
PROC_READ_ONLY("/proc/irq"),
PROC_READ_ONLY("/proc/scsi"),
- { "mqueue", "/dev/mqueue", "mqueue", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "mqueue", "/dev/mqueue", "mqueue", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_IN_USERNS|MOUNT_MKDIR },
/* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
- { "tmpfs", "/tmp", "tmpfs", "mode=1777" TMPFS_LIMITS_TMP, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/tmp", "tmpfs", "mode=1777" TMPFS_LIMITS_TMP, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP|MOUNT_MKDIR },
- { "tmpfs", "/sys", "tmpfs", "mode=555" TMPFS_LIMITS_SYS, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "tmpfs", "/sys", "tmpfs", "mode=555" TMPFS_LIMITS_SYS, MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS|MOUNT_MKDIR },
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO|MOUNT_MKDIR }, /* skipped if above was mounted */
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
MOUNT_FATAL|MOUNT_MKDIR }, /* skipped if above was mounted */
- { "tmpfs", "/dev", "tmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_STRICTATIME,
+ { "tmpfs", "/dev", "tmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_STRICTATIME,
MOUNT_FATAL|MOUNT_MKDIR },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777" TMPFS_LIMITS_DEV_SHM, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
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 },
+ { "/usr/lib/os-release", "/run/host/usr/lib/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_MKDIR|MOUNT_TOUCH },
+ { "/etc/os-release", "/run/host/etc/os-release", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_MKDIR|MOUNT_TOUCH },
#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) */
- { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ { 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) */
#endif
};
@@ -636,6 +587,7 @@ int mount_all(const char *dest,
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
_cleanup_free_ char *where = NULL, *options = NULL;
const char *o;
+ struct stat source_st;
bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL);
if (in_userns != FLAGS_SET(mount_table[k].mount_settings, MOUNT_IN_USERNS))
@@ -661,10 +613,26 @@ int mount_all(const char *dest,
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
if (r > 0)
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 = stat(mount_table[k].what, &source_st);
+ 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)) {
- r = mkdir_userns_p(dest, where, 0755, (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))
+ r = mkdir_parents_safe(dest, where, 0755, u, u, 0);
+ else
+ r = mkdir_p_safe(dest, where, 0755, u, u, 0);
if (r < 0 && r != -EEXIST) {
if (fatal && r != -EROFS)
return log_error_errno(r, "Failed to create directory %s: %m", where);
@@ -676,6 +644,14 @@ int mount_all(const char *dest,
if (r != -EROFS)
continue;
}
+ if (FLAGS_SET(mount_table[k].mount_settings, MOUNT_TOUCH)) {
+ r = touch(where);
+ if (r < 0 && r != -EEXIST) {
+ if (fatal)
+ return log_error_errno(r, "Failed to create mount point %s: %m", where);
+ log_debug_errno(r, "Failed to create mount point %s: %m", where);
+ }
+ }
}
o = mount_table[k].options;
diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h
index e8bb903839..062ed8b57d 100644
--- a/src/nspawn/nspawn-mount.h
+++ b/src/nspawn/nspawn-mount.h
@@ -17,6 +17,7 @@ typedef enum MountSettingsMask {
MOUNT_ROOT_ONLY = 1 << 6, /* if set, only 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_TOUCH = 1 << 9, /* if set, touch file to mount over first */
} MountSettingsMask;
typedef enum CustomMountType {
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 0f2d01c0aa..1f321f9ea3 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2931,7 +2931,8 @@ static int inner_child(
int kmsg_socket,
int rtnl_socket,
int master_pty_socket,
- FDSet *fds) {
+ FDSet *fds,
+ char **os_release_pairs) {
_cleanup_free_ char *home = NULL;
char as_uuid[ID128_UUID_STRING_MAX];
@@ -3190,7 +3191,7 @@ static int inner_child(
if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
return log_oom();
- env_use = strv_env_merge(2, envp, arg_setenv);
+ env_use = strv_env_merge(3, envp, arg_setenv, os_release_pairs);
if (!env_use)
return log_oom();
@@ -3316,6 +3317,7 @@ static int outer_child(
FDSet *fds,
int netns_fd) {
+ _cleanup_strv_free_ char **os_release_pairs = NULL;
_cleanup_close_ int fd = -1;
const char *p;
pid_t pid;
@@ -3337,6 +3339,10 @@ static int outer_child(
log_debug("Outer child is initializing.");
+ r = load_os_release_pairs_with_prefix("/", "container_host_", &os_release_pairs);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read os-release from host for container, ignoring: %m");
+
if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
@@ -3602,7 +3608,7 @@ static int outer_child(
return log_error_errno(r, "Failed to join network namespace: %m");
}
- r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds);
+ r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds, os_release_pairs);
if (r < 0)
_exit(EXIT_FAILURE);
diff --git a/src/portable/portable.c b/src/portable/portable.c
index c7c11a48f2..48294d4c49 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -701,6 +701,7 @@ static int install_chroot_dropin(
"[Service]\n",
IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) ? "RootDirectory=" : "RootImage=", image_path, "\n"
"Environment=PORTABLE=", basename(image_path), "\n"
+ "BindReadOnlyPaths=-/etc/os-release:/run/host/etc/os-release /usr/lib/os-release:/run/host/usr/lib/os-release\n"
"LogExtraFields=PORTABLE=", basename(image_path), "\n",
NULL))
diff --git a/src/shared/os-util.c b/src/shared/os-util.c
index eacebc1ea5..7cca59d58a 100644
--- a/src/shared/os-util.c
+++ b/src/shared/os-util.c
@@ -117,3 +117,33 @@ int load_os_release_pairs(const char *root, char ***ret) {
return load_env_file_pairs(f, p, ret);
}
+
+int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret) {
+ _cleanup_strv_free_ char **os_release_pairs = NULL, **os_release_pairs_prefixed = NULL;
+ char **p, **q;
+ int r;
+
+ r = load_os_release_pairs(root, &os_release_pairs);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH_PAIR(p, q, os_release_pairs) {
+ char *line;
+
+ // We strictly return only the four main ID fields and ignore the rest
+ if (!STR_IN_SET(*p, "ID", "VERSION_ID", "BUILD_ID", "VARIANT_ID"))
+ continue;
+
+ ascii_strlower(*p);
+ line = strjoin(prefix, *p, "=", *q);
+ if (!line)
+ return -ENOMEM;
+ r = strv_consume(&os_release_pairs_prefixed, line);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(os_release_pairs_prefixed);
+
+ return 0;
+}
diff --git a/src/shared/os-util.h b/src/shared/os-util.h
index 27ec7ac8d7..b54bb0916d 100644
--- a/src/shared/os-util.h
+++ b/src/shared/os-util.h
@@ -10,3 +10,4 @@ int fopen_os_release(const char *root, char **ret_path, FILE **ret_file);
int parse_os_release(const char *root, ...) _sentinel_;
int load_os_release_pairs(const char *root, char ***ret);
+int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret);
diff --git a/test/TEST-13-NSPAWN-SMOKE/test.sh b/test/TEST-13-NSPAWN-SMOKE/test.sh
index fbe52296ce..236378a380 100755
--- a/test/TEST-13-NSPAWN-SMOKE/test.sh
+++ b/test/TEST-13-NSPAWN-SMOKE/test.sh
@@ -16,7 +16,7 @@ test_create_image() {
mask_supporting_services
../create-busybox-container $initdir/testsuite-13.nc-container
- initdir="$initdir/testsuite-13.nc-container" dracut_install nc ip
+ initdir="$initdir/testsuite-13.nc-container" dracut_install nc ip md5sum
)
}
diff --git a/test/units/testsuite-13.sh b/test/units/testsuite-13.sh
index e374206102..dd1c9575c4 100755
--- a/test/units/testsuite-13.sh
+++ b/test/units/testsuite-13.sh
@@ -60,6 +60,18 @@ function check_notification_socket {
systemd-nspawn --register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd"
}
+function check_os_release {
+ local _cmd='. /tmp/os-release
+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 "${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
+cd /tmp; (cd /run/host/usr/lib; md5sum os-release) | md5sum -c
+'
+
+ systemd-nspawn --register=no -D /testsuite-13.nc-container --bind=/etc/os-release:/tmp/os-release /bin/sh -x -e -c "$_cmd"
+}
+
function run {
if [[ "$1" = "yes" && "$is_v2_supported" = "no" ]]; then
printf "Unified cgroup hierarchy is not supported. Skipping.\n" >&2
@@ -144,6 +156,8 @@ check_norbind
check_notification_socket
+check_os_release
+
for api_vfs_writable in yes no network; do
run no no $api_vfs_writable
run yes no $api_vfs_writable