nspawn: allow disabling os-release check

Introduce a new env variable $SYSTEMD_NSPAWN_CHECK_OS_RELEASE, that can
be used to disable the os-release check for bootable OS trees. Useful
when trying to boot a container with empty /etc/ and bind-mounted /usr/.

Resolves: #29185
This commit is contained in:
Frantisek Sumsal 2023-11-03 09:17:48 +01:00 committed by Luca Boccassi
parent 1af46aecf5
commit d4317fe172
3 changed files with 46 additions and 2 deletions

View file

@ -164,6 +164,10 @@ All tools:
* `$SYSTEMD_NSPAWN_TMPFS_TMP=0` — if set, do not overmount `/tmp/` in the
container with a tmpfs, but leave the directory from the image in place.
* `$SYSTEMD_NSPAWN_CHECK_OS_RELEASE=0` — if set, do not fail when trying to
boot an OS tree without an os-release file (useful when trying to boot a
container with empty `/etc/` and bind-mounted `/usr/`)
* `$SYSTEMD_SUPPRESS_SYNC=1` — if set, all disk synchronization syscalls are
blocked to the container payload (e.g. `sync()`, `fsync()`, `syncfs()`, …)
and the `O_SYNC`/`O_DSYNC` flags are made unavailable to `open()` and

View file

@ -5574,6 +5574,7 @@ static int run(int argc, char *argv[]) {
if (arg_start_mode == START_BOOT) {
_cleanup_free_ char *b = NULL;
const char *p;
int check_os_release, is_os_tree;
if (arg_pivot_root_new) {
b = path_join(arg_directory, arg_pivot_root_new);
@ -5586,7 +5587,16 @@ static int run(int argc, char *argv[]) {
} else
p = arg_directory;
if (path_is_os_tree(p) <= 0) {
check_os_release = getenv_bool("SYSTEMD_NSPAWN_CHECK_OS_RELEASE");
if (check_os_release < 0 && check_os_release != -ENXIO) {
r = log_error_errno(check_os_release, "Failed to parse $SYSTEMD_NSPAWN_CHECK_OS_RELEASE: %m");
goto finish;
}
is_os_tree = path_is_os_tree(p);
if (is_os_tree == 0 && check_os_release == 0)
log_debug("Directory %s is missing an os-release file, continuing anyway.", p);
else if (is_os_tree <= 0) {
r = log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", p);
goto finish;

View file

@ -40,7 +40,7 @@ export SYSTEMD_LOG_TARGET=journal
at_exit() {
set +e
mountpoint -q /var/lib/machines && umount /var/lib/machines
mountpoint -q /var/lib/machines && umount --recursive /var/lib/machines
rm -f /run/systemd/nspawn/*.nspawn
}
@ -841,6 +841,36 @@ matrix_run_one() {
return 0
}
testcase_check_os_release() {
# https://github.com/systemd/systemd/issues/29185
local base common_opts root
base="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release_base.XXX)"
root="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release.XXX)"
create_dummy_container "$base"
cp -d "$base"/{bin,sbin,lib,lib64} "$root/"
common_opts=(
--boot
--register=no
--directory="$root"
--bind-ro="$base/usr:/usr"
)
# Empty /etc/ & /usr/
(! systemd-nspawn "${common_opts[@]}")
(! SYSTEMD_NSPAWN_CHECK_OS_RELEASE=1 systemd-nspawn "${common_opts[@]}")
(! SYSTEMD_NSPAWN_CHECK_OS_RELEASE=foo systemd-nspawn "${common_opts[@]}")
SYSTEMD_NSPAWN_CHECK_OS_RELEASE=0 systemd-nspawn "${common_opts[@]}"
# Empty /usr/ + a broken /etc/os-release -> /usr/os-release symlink
ln -svrf "$root/etc/os-release" "$root/usr/os-release"
(! systemd-nspawn "${common_opts[@]}")
(! SYSTEMD_NSPAWN_CHECK_OS_RELEASE=1 systemd-nspawn "${common_opts[@]}")
SYSTEMD_NSPAWN_CHECK_OS_RELEASE=0 systemd-nspawn "${common_opts[@]}"
rm -fr "$root" "$base"
}
run_testcases
for api_vfs_writable in yes no network; do