Bug#1063147: 'telinit u' infinitely re-exec's itself inside containers
Daniel P. Berrangé
berrange at redhat.com
Mon Feb 5 11:45:57 GMT 2024
Package: systemd-sysv
Version: 255.3-2
Running 'telinit u' within a podman container results in an infinite
loop as telinit repeatedly re-exec's itself.
This behaviour comes from systemctl.c which has this logic for handling
'telinit':
if (sd_booted() > 0) {
arg_action = _ACTION_INVALID;
return telinit_parse_argv(argc, argv);
} else {
/* Hmm, so some other init system is running, we need to forward this request to it.
*/
arg_action = ACTION_TELINIT;
return 1;
}
Inside a container 'sd_booted()' will (typically) indicate systemd is
NOT running, thus the 'else' clause will be followed. ACTION_TELINIT
instructs the caller to execve() the telinit binary belonging to any
*non-systemd* init impl, if any.
This binary is determined by the 'telinit-path' meson build option,
which defaults to /lib/sysvinit/telinit.
Debian used to override this to /usr/lib/sysvinit/telinit, but a few
months ago in Sid, this was changed to point to /usr/sbin/telinit,
which is a symlink back to /usr/bin/systemctl:
https://salsa.debian.org/systemd-team/systemd/-/commit/da95bc801088a6ab454851cf01addf97dd2c1ab3
IOW, Debian dpkg build has told systemd that the non-systemd telinit
binary is the systemd telinit binary. Hilarity now ensues as it ends
up exec'ing itself for all eternity :-)
You might ask why should anyone hit this scenario ? Well consider that
the 'libc6' package will run 'telinit u' in its postinst script, if it
sees it is in a non-systemd environment.
Not immediately a problem, since libc6 will be pre-installed in any
container or VM disk image and thus the 'postinst' script won't run
[not sure if 'postinst' is run on upgrades too ?].
Debian containers are an execellent environment for testing cross
compiles though, and thus people will install a foreign arch libc6
package in the container which does trigger the postinst script. The
following hangs (well loops forever in execve()):
$ podman run -it debian:sid-slim
# dpkg --add-architecture i386
# apt-get update
# apt-get install systemd-sysv
# apt-get install libc6:i386
Simpler example
$ podman run -it debian:sid-slim
# dpkg --add-architecture i386
# apt-get update
# apt-get install systemd-sysv strace
# strace -e trace=execve telinit u
strace: Process 232065 attached
execve("/usr/sbin/telinit", ["telinit", "u"], 0x7ffd9b26ba00 /* 24 vars */) = 0
execve("/usr/sbin/telinit", ["telinit", "u"], 0x7ffdab55f1d0 /* 24 vars */) = 0
execve("/usr/sbin/telinit", ["telinit", "u"], 0x7ffe79152400 /* 24 vars */) = 0
....1000000's more times....
Even then though, most people won't (knowingly) install the systemd-sysv
dpkg, so won't hit this problem. A few packages will pull in systemd-sysv
behind the scenes, so you can unwittingly hit the problem. For libvirt
CI, we install the open-iscsi and policykit-1 packages which both pull
in systemd-sysv, so this hangs:
$ podman run -it debian:sid-slim
# dpkg --add-architecture i386
# apt-get update
# apt-get install systemd-sysv
# apt-get install open-iscsi:i386
Our foreign arch CI jobs that use Sid are thus suffering broken container
builds right now.
The simple solution appears to be to just remove the '-Dtelinit-path'
option from debian/rules, and leave it on systemd's built-in defaults.
The binary at this default path won't exist, and thus on a non-systemd
execution environment 'telinit u' will simply exit with an error:
# telinit u
Couldn't find an alternative telinit implementation to spawn.
which is a sensible behaviour and what has happened in containers with
Debian until recent Sid. Other distros (eg Fedora) leave the telinit
binary on systemd's default (non-existant) path too.
Possibly the upstream systemctl.c code should be made to protect itself
against such a mis-configuration by setting an env variable it can look
at to detect re-exec of itself.
Possibly libc6 package postinst script should skip running its
'telinit u' action if it detects it is inside a container, though that
could possibly break something if people do have a real in-systemd init
running ? Seems fairly low probability.
With regards,
Daniel
More information about the Pkg-systemd-maintainers
mailing list