Before #30884, the user state is tied to user@.service (user service
manager). However, #30884 introduced sessions that need no manager,
and we can no longer rely on that.
Consider the following situation:
1. A 'background-light' session '1' is created (i.e. no user service manager
is needed)
2. Session '1' scope unit pulls in user-runtime-dir@.service
3. Session '1' exits. A stop job is enqueued for user-runtime-dir@.service
due to StopWhenUnneeded=yes
4. At the same time, another session '2' which requires user manager is started.
However, session scope units have JobMode=fail, therefore the start job
for user-runtime-dir@.service that was pulled in by session '2' scope job
is deleted as it conflicts with the stop job.
We want session scope units to continue using JobMode=fail, but we still need
the dependencies to be started correctly, i.e. explicitly requested by logind
beforehand. Therefore, let's stop using StopWhenUnneeded=yes for
user-runtime-dir@.service, and track users' `started` and `stopping` state
based on that when user@.service is not needed. Then, for every invocation
of user_start(), we'll recheck if we need the service manager and start it
if so.
Also, the dependency type on user-runtime-dir@.service from user@.service
is upgraded to `BindsTo=`, in order to ensure that when logind stops the
former, the latter is stopped as well.
Let's make sure that user's cannot DoS services for other users so
easily, and enable MaxConnectionsPerSocket= by default for all of them.
Note that this is mostly paranoia for systemd-pcrextend.socket and
systemd-sysext.socket: the socket is only accessible to root anyway,
hence the accounting shouldn#t change anything. But this is just a
safety net, in preparation that we open up some functionality of these
services sooner or later.
Also= lists units which should be enabled/disabled together with the first unit.
But userdbd is independent of homed, we shouldn't e.g. disable it even if homed
is disabled.
To me this is the last major basic functionality that couldn't be
configured via credentials: the network.
We do not invent any new format for this, but simply copy relevant creds
1:1 into /run/systemd/network/ to open up the full functionality of
networkd to VM hosts.
Distributions apparently only compile a subset of TPM2 drivers into the
kernel. For those not compiled it but provided as kmod we need a
synchronization point: we must wait before the first TPM2 interaction
until the driver is available and accessible.
This adds a tpm2.target unit as such a synchronization point. It's
ordered after /dev/tpmrm0, and is pulled in by a generator whenever we
detect that the kernel reported a TPM2 to exist but we have no device
for it yet.
This should solve the issue, but might create problems: if there are TPM
devices supported by firmware that we don't have Linux drivers for we'll
hang for a bit. Hence let's add a kernel cmdline switch to disable (or
alternatively force) this logic.
Fixes: #30164
This extends what systemd-firstboot does and runs on first boots only
and either processes user records passed in via credentials to create,
or asks the user interactively to create one (only if no regular user
exists yet).
The unit will be started or restarted a few times during boot, but but it has
StartLimitBurst = DefaultStartLimitBurst = 5, which means that the fifth
restart will already fail. On my laptop, I have exactly 4 restarts, so I don't
hit the limit, but on a slightly different system we will easily hit the limit.
In https://bugzilla.redhat.com/show_bug.cgi?id=2251394, there are five reloads
and we hit the limit.
Since 6ef512c0bb we propagate the start counter
over switch-root and daemon reloads, so it's easier to hit the limit during
boot.
In principle there might be systems with lots of vtcon devices, so let's just
allow the unit to be restarted without a limit.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2251394.
This implements a "storage target mode", similar to what MacOS provides
since a long time as "Target Disk Mode":
https://en.wikipedia.org/wiki/Target_Disk_Mode
This implementation is relatively simple:
1. a new generic target "storage-target-mode.target" is added, which
when booted into defines the target mode.
2. a small tool and service "systemd-storagetm.service" is added which
exposes a specific device or all devices as NVMe-TCP devices over the
network. NVMe-TCP appears to be hot shit right now how to expose
block devices over the network. And it's really simple to set up via
configs, hence our code is relatively short and neat.
The idea is that systemd-storagetm.target can be extended sooner or
later, for example to expose block devices also as USB mass storage
devices and similar, in case the system has "dual mode" USB controller
that can also work as device, not just as host. (And people could also
plug in sharing as NBD, iSCSI, whatever they want.)
How to use this? Boot into your system with a kernel cmdline of
"rd.systemd.unit=storage-target-mode.target ip=link-local", and you'll see on
screen the precise "nvme connect" command line to make the relevant
block devices available locally on some other machine. This all requires
that the target mode stuff is included in the initrd of course. And the
system will the stay in the initrd forever.
Why bother? Primarily three use-cases:
1. Debug a broken system: with very few dependencies during boot get
access to the raw block device of a broken machine.
2. Migrate from system to another system, by dd'ing the old to the new
directly.
3. Installing an OS remotely on some device (for example via Thunderbolt
networking)
(And there might be more, for example the ability to boot from a
laptop's disk on another system)
Limitations:
1. There's no authentication/encryption. Hence: use this on local links
only.
2. NVMe target mode on Linux supports r/w operation only. Ideally, we'd
have a read-only mode, for security reasons, and default to it.
Future love:
1. We should have another mode, where we simply expose the homed LUKS
home dirs like that.
2. Some lightweight hookup with plymouth, to display a (shortened)
version of the info we write to the console.
To test all this, just run:
mkosi --kernel-command-line-extra="rd.systemd.unit=storage-target-mode.target" qemu
modprobe treats "-" and "_" interchangeably, thereby avoiding frequent
errors because some module names contain dashes and others underscores.
Because modprobe@.service unescapes the instance name, an attempt to
start "modprobe@dm-crypt.service" will run "modprobe -abq dm/crypt",
which is doomed to fail. "modprobe@dm_crypt.service" will work as
expected. Thus unescaping the instance name has surprising side effects.
Use "%i" instead.
When --boot is set, and --keep-unit is not, set CoredumpReceive=yes on
the scope allocated for the container. When --keep-unit is set, nspawn
does not allocate the container's unit, so the existing unit needs to
configure this setting itself.
Since systemd-nspawn@.service sets --boot and --keep-unit, add
CoredumpReceives=yes to that unit.
As systemd-journal-upload deals mostly with remote servers, add
some failsafes to its unit to restart on failures.
```
[Service]
Restart=on-failure
RestartSteps=10
RestartMaxDelaySec=60
```
This is primarily supposed to be a 1st step with varlinkifying our
various command line tools, and excercise in how this might look like
across our codebase one day. However, at AllSystemsGo! 2023 it was
requested that we provide an API to do a PCR measurement along with a
matching event log record, and this provides that.
This adds an explicit service for initializing the TPM2 SRK. This is
implicitly also done by systemd-cryptsetup, hence strictly speaking
redundant, but doing this early has the benefit that we can parallelize
this in a nicer way. This also write a copy of the SRK public key in PEM
format to /run/ + /var/lib/, thus pinning the disk image to the TPM.
Making the SRK public key is also useful for allowing easy offline
encryption for a specific TPM.
Sooner or later we should probably grow what this service does, the
above is just the first step. For example, the service should probably
offer the ability to reset the TPM (clear the owner hierarchy?) on a
factory reset, if such a policy is needed. And we might want to install
some default AK (?).
Fixes: #27986
Also see: #22637
Follow-up for d120ce478d
blockdev@.target is used as a synchronization point between
the mount unit and corresponding systemd-cryptsetup@.service.
After the mentioned commit, it doesn't get a stop job enqueued
during shutdown, and thus the stop job for systemd-cryptsetup@.service
could be run before the mount unit is stopped.
Therefore, let's make blockdev@.target conflict with umount.target,
which is also what systemd-cryptsetup@.service does.
Fixes#29336
So, unfortunately oomd uses "io.system." rather than "io.systemd." as
prefix for its sockets. This is a mistake, and doesn't match the
Varlink interface naming or anything else in oomd.
hence, let's fix that.
Given that this is an internal protocol between PID1 and oomd let's
simply change this without retaining compat.
The tool initially just measured the boot phase, but was subsequently
extended to measure file system and machine IDs, too. At AllSystemsGo
there were request to add more, and make the tool generically
accessible.
Hence, let's rename the binary (but not the pcrphase services), to make
clear the tool is not just measureing the boot phase, but a lot of other
things too.
The tool is located in /usr/lib/ and still relatively new, hence let's
just rename the binary and be done with it, while keeping the unit names
stable.
While we are at it, also move the tool out of src/boot/ and into its own
src/pcrextend/ dir, since it's not really doing boot related stuff
anymore.
When booting from virtiofs, we won't be able to find a root block
device. Let's gracefully handle this similar to how we don't fail
if we can't find a GPT partition table.
Before this commit, the hibernate location logic only exists in
the generator. Also, we compare device nodes (devnode_same()) and
clear EFI variable HibernateLocation in the generator too. This is
not ideal though: when the generator gets to run, udev hasn't yet
started, so effectively devnode_same() always fails. Moreover, if
the boot process is interrupted by e.g. battery-check, the hibernate
information is lost.
Therefore, let's split out the logic of finding hibernate location.
The generator only does the initial validation of system info and
enables systemd-hibernate-resume.service, and when the service
actually runs we validate everything again, which includes comparing
the device nodes and clearing the EFI variable. This should make
things more robust, plus systems that don't utilize a systemd-enabled
initrd can use the exact same logic to resume using the EFI variable.
I.e., systemd-hibernate-resume can be used standalone.
Otherwise the root filesystem might still be readonly and
systemd-userdbd fails to start.
Explicitly pick systemd-remount-fs.service instead of local-fs-pre.target
to prevent a dependency cycle.
- add reference to the service unit in the man page,
- fix several indentation and typos,
- replace '(uint64_t) -1' with 'UINT64_MAX',
- drop unnecessary 'continue'.
This makes tmpfiles, sysusers, and udevd invoked in the following order:
1. systemd-tmpfiles-setup-dev-early.service
Create device nodes gracefully, that is, create device nodes anyway
by ignoring unknown users and groups.
2. systemd-sysusers.service
Create users and groups, to make later invocations of tmpfiles and
udevd can resolve necessary users and groups.
3. systemd-tmpfiles-setup-dev.service
Adjust owners of previously created device nodes.
4. systemd-udevd.service
Process all devices. Especially to make block devices active and can
be mountable.
5. systemd-tmpfiles-setup.service
Setup basic filesystem.
Follow-up for b42482af90.
Fixes#28653.
Replaces #28681 and #28732.
This reverts commits 112a41b6ec,
3178698bb5, and
b768379e8b.
The commit 112a41b6ec introduces #28765,
as systemd-tmpfiles-setup.service has ordering after local-fs.target,
but usually the target requires block devices processed by udevd.
Hence, the service can only start after the block devices timed out.
Fixes#28765.
Follow-up for b42482af90.
The commit makes systemd-tmpfiles-setup.service also updates the
permission or owner of device nodes. However, the service does not have
ordering for systemd-udevd.service. So, the service may set different
permission from the one udevd already set.
Fixes#28653.
Replaces #28681.
If emergency.target is started while initrd-parse-etc.service/start is queued,
the initrd-parse-etc job did not get canceled. In parallel to the emergency
units, it eventually runs the service, which starts initrd-cleanup.service,
which in turn isolates initrd-switch-root.target. This stops the emergency
units and effectively starts the initrd boot process again, which likely
fails again like the initial attempt. The system is thus stuck in an endless
loop, never really reaching emergency.target.
With this conflict added, starting emergency.target automatically cancels
initrd-parse-etc.service/start, avoiding the loop.
Without this change, there are no ordering between udevd and tmpfiles,
and if tmpfiles is invoked later it may discard the permission set by
udevd.
Fixes an issue introduced by b42482af90.
Fixes#28588 and #28653.
In it's latest release, agetty will support reading the agetty.autologin
and login.noauth credentials, so let's make sure we import those in our
getty units so they're available to agetty to read.
Some of the new units using systemd-pcrphase are missing the --graceful
flag which causes them to error if the tpm libraries are not installed.
Add --graceful just like in the other pcrphase units to make systemd-pcrphase
exit gracefully if the tpm libraries are missing.
The service has Type=oneshot, which means that the default value of SuccessExitStatus=0.
When multiple vtcon devices are detected, udev will restart the service after each
one. If this happens quickly enough, the old instance will get SIGTERM while it is
still running:
[ 5.357341] (udev-worker)[593]: vtcon1: /usr/lib/udev/rules.d/90-vconsole.rules:12 RUN '/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service
[ 5.357439] (udev-worker)[593]: vtcon1: Running command "/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service"
[ 5.357485] (udev-worker)[593]: vtcon1: Starting '/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service'
[ 5.357537] (udev-worker)[609]: vtcon0: /usr/lib/udev/rules.d/90-vconsole.rules:12 RUN '/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service
[ 5.357587] (udev-worker)[609]: vtcon0: Running command "/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service"
[ 5.357634] (udev-worker)[609]: vtcon0: Starting '/usr/bin/systemctl --no-block restart systemd-vconsole-setup.service'
...
[ 5.680529] systemd[1]: systemd-vconsole-setup.service: Trying to enqueue job systemd-vconsole-setup.service/restart/replace
[ 5.680565] systemd[1]: systemd-vconsole-setup.service: Merged into running job, re-running: systemd-vconsole-setup.service/restart as 557
[ 5.680600] systemd[1]: systemd-vconsole-setup.service: Enqueued job systemd-vconsole-setup.service/restart as 557
...
[ 5.682334] systemd[1]: Received SIGCHLD from PID 744 ((le-setup)).
[ 5.682377] systemd[1]: Child 744 ((le-setup)) died (code=killed, status=15/TERM)
[ 5.682407] systemd[1]: systemd-vconsole-setup.service: Child 744 belongs to systemd-vconsole-setup.service.
[ 5.682436] systemd[1]: systemd-vconsole-setup.service: Main process exited, code=killed, status=15/TERM
[ 5.682471] systemd[1]: systemd-vconsole-setup.service: Failed with result 'signal'.
[ 5.682518] systemd[1]: systemd-vconsole-setup.service: Service will not restart (manual stop)
[ 5.682552] systemd[1]: systemd-vconsole-setup.service: Changed stop-sigterm -> failed
This is expected and not a problem. Let's treat SIGTERM as success so we don't
get this spurious "failure".
"Setup" is a noun, and the expected order is "<adjective> <noun>".
("Set up" is the verb. But we want a noun here, so that we can say
e.g. "Starting Virtual Console Setup".)
Let's make our units more robust to being added to an initrd:
1. systemd-boot-update only makes sense if sd-boot is available in /usr/
to copy into the ESP. This is generally not the case in initrds, and
even if it was, we shouldn't update the ESP from the initrd, but from
the host instead.
2. The rfkill services save/restore rfkill state, but that information
is only available once /var/ is mounted, which generally happens
after the initrd transition.
3. utmp management is partly in /var/, and legacy anyway, hence don't
bother with it in the initrd.
Let's rename the unit to systemd-battery-check.service. We usually want
to name our own unit files like our tools they wrap, in particular if
they are entirely defined by us (i.e. not just wrappers of foreign
concepts)
While we are at it, also hook this in from initrd.target, and order it
against initrd-root-device.target so that it runs before the root device
is possibly written to (i.e. mounted or fsck'ed).
This is heavily inspired by @aafeijoo-suse's PR #28208, but quite
different ;-)
Follow-ups for e3d4148d50.
- add reference to initrd-battery-check.service in man page, and move
its section from 1 to 8,
- add link to man page in help message,
- introduce ERRNO_IS_NO_PLYMOUTH(),
- propagate error in battery_check_send_plymouth_message(),
- rename battery_check_send_plymouth_message() -> plymouth_send_message(),
- return earlier when the first battery level check passed to reduce
indentation,
- fix potential use of invalid fd on battery restored,
- do not use emoji for /dev/console,
- add simple test (mostly for coverity),
etc, etc...
This also merges two arrays units and in_units, and uses dictionary
for declaring units.
This also fixes the condition handling, that previously only two
conditions were handled and rests were ignored.
This adds a new mechanism for rebooting, a form of "userspace reboot"
hereby dubbed "soft-reboot". It will stop all services as in a usual
shutdown, possibly transition into a new root fs and then issue a fresh
initial transaction. The kernel is not replaced.
File descriptors can be passed over, thus opening the door for leaving
certain resources around between such reboots.
Usecase: this is an extremely quick way to reset userspace fully when
updating image based systems, without going through a full
hardware/firmware/boot loader/kernel/initrd cycle. It minimizes "grayout time"
for OS updates. (In particular when combined with kernel live patching)
We want that cryptsetup/veritysetup devices can stick around until the
very end, as well as the users of them which might depend on
blockdev@.target for the devices. Hence leave the targets around till
the very end.
Note that their runtime is managed via StopWhenUnneeded= anyway, hence
unless their are volumes that actually survive still the very end they
target units will still be stopped.
This mimics what we already have for cryptsetup services: the slice they
are placed in (they have their own slice since that's what we do by
default for instantiated services) shouldn't conflict with
shutdown.target, so that veritysetup services can stay around until the
very end (which is what we want for the root and usr verity volumes).
It's literally just a copy of the same unit we already have for
cryptsetup, just with an updated description string.
local-fs-pre.target is a passive unit, which means that it is supposed to be
pulled in by everything that is ordered before it. We had
Before=local-fs-pre.target, so add Wants= too.
I don't expect this to change anything. Instead, just make things follow the
docs so it's easier to reason about the dependency set.
We may copy files from factory to /etc. The default mkosi config has
factory/etc/vconsole.conf. systemd-firstboot would race with tmpfiles-setup,
and sometimes ask for the keymap, and sometimes not.
I guess that if there are files in factory, we shouldn't ask the user for
the same configuration.
Requested in https://github.com/systemd/systemd/pull/27755#pullrequestreview-1443489520.
I dropped the info message about the job being requested, because we get
fairly verbose logs from starting the unit, and the additional message isn't
useful.
In the unit, the ordering before systemd-vconsole-setup.service is dropped,
because now it needs to happen in parallel, while systemd-firstboot.service
is running. This means that we may potentially execute vconsole-setup twice,
but it's fairly quick, so this doesn't matter much.
Let's explicitly order these against initrd-switch-root.target, so
that they are properly shut down before we switch root. Otherwise,
there's a race condition where networkd might only shut down after
switching root and after we've already we've loaded the unit graph,
meaning it won't be restarted in the rootfs.
Fixes#27718
We would create root account from sysusers or from firstboot, depending on
which one ran earlier. Since firstboot offers more options, in particular can
set the root password, we needed to order it earlier. This created an ugly
ordering requirement:
systemd-sysusers.service > systemd-firstboot.service > ... >
systemd-remount-fs.service > systemd-tmpfiles-setup-dev.service >
systemd-sysusers.service
We want sysusers.service to create basic users, so we can create nodes in dev,
so we can operate on block devices and such, so that we can resize and remount
things. But at the same time, systemd-firstboot.service can only work if it is
run early, before systemd-sysusers.service has created /etc/passwd. We can't
have it both ways: the units that want to have a fully writable root file
system cannot be ordered before units which are required to do file system
preparation.
Instead of trying to order firstboot very early, let's let it do its thing even
if it is started later. Instead of refusing to create to the root account if
/etc/passwd and /etc/shadow exist, actually check if the account is configured.
Now sysusers writes root account with password PASSWORD_UNPROVISIONED
("!unprovisioned"), and then firstboot checks for this, and will configure root
in this case.
This allows sysusers to be executed earlier (or accounts to be set up earlier
in another way).
This effectively reverts b825ab1a99.
We want to call systemd-tmpfiles-setup-dev.service to create /dev/fuse and
other device nodes so that module probing will work. But it is possible that
when we're in first boot, some users or groups need to be created by
systemd-sysusers first. But it is also possible that systemd-sysusers cannot
actually execute configuration because the root partition is not fully writable
yet. So let systemd-tmpfiles-setup-dev.service run earlier, possibly without
all users and groups in place. Since systemd-tmpfiles-setup-dev.service writes
to /dev only, it doesn't care how the root partition is mounted. In this early
run, some some nodes might be created with default permissions (i.e. not
accessible to non-root users or groups). This should be OK for the early boot
phase. Afterwards, we let systemd-tmpfiles-setup.service execute full
configuration. We will configure any files in /dev twice, but considering that
there's only a few of them and that the second run should only adjust ownership
and permissions, this should be OK. This way, we avoid the dependency loop.
As with other units, stopping of the automount requires actual work,
and without the ordering dependency systemd might not execute the stop
job before shutdown.target is reached and units ordered after that are
executed.
I have a system with /usr/lib/repart.d/50-root.conf with GrowFileSystem=yes.
The partition wouldn't be resized in the initrd, because
ConditionDirectoryNotEmpty=|/sysusr/usr/lib/repart.d was evaluated very early,
before /sysroot was mounted. There was no ordering dependency between
systemd-repart.service and sysroot.mount. (There was After=initrd-usr-fs.target,
but it seems to be only referred to by systemd-fstab-generator, which in my
case doesn't even run, because there's no fstab.)
But in fact, we neeed to run systemd-repart in the initrd only in limited
circumstances: when we need to create the root device based on config under
sysusr.mount. If there is config on the root device, it can be executed in
the host system, early during boot. Thus, let's remove the condition on
/sysroot/…. Without an ordering dependency on sysroot.mount, it was subject to
a race condition anyway. (A race condition with a low probability of "winning",
because systemd-repart.service has no dependencies, but sysroot.mount requires
a device to be detected and the mount to happen.)
The other problem was that systemd-repart.service didn't have the ordering wrt.
initrd-switch-root.target, so it was subject to the same race condition that
was fixed for other units in 7c0e2b5559. (If the
systemd-repart.service/stop job is slow, we could end up not restarting
systemd-repart.service in the host system.)
With the changes here, I see systemd-repart.service/start running twice:
in the initrd it is skipped because the conditions fail, and then in the
host system it runs normally.
Note: support for /sysroot is retained in systemd-repart code. I don't see a
strong reason to remove it, since it may still be useful to people invoking
repart in the initrd in other circumstances.