This also makes initrd-cleanup.service explicitly start
initrd-switch-root.service with replace-irreversibly mode, to avoid
systemd-udevd.service being triggered by kernel events and the start
job of initrd-switch-root.service being cancelled.
Follow-ups for 676fb42aae.
Addresses https://github.com/systemd/systemd/pull/37374#issuecomment-2875990471.
When running with sanitizers:
```
26/95 systemd:integration-tests / TEST-21-DFUZZER OK 1517.75s
40/95 systemd:integration-tests / TEST-85-NETWORK-NetworkdDHCPClientTests OK 779.18s
42/95 systemd:integration-tests / TEST-04-JOURNAL OK 716.17s
```
and without sanitizers:
```
44/95 systemd:integration-tests / TEST-85-NETWORK-NetworkdDHCPClientTests OK 730.33s
29/95 systemd:integration-tests / TEST-64-UDEV-STORAGE-simultaneous_events OK 701.49s
40/95 systemd:integration-tests / TEST-04-JOURNAL OK 348.05s
```
So, let's set higher priorities only on these tests.
Previously, both udevd and logind modifies ACLs of a device node. Hence,
there exists a race something like the following:
1. udevd reads an old state file,
2. logind updates the state file, and apply new ACLs,
3. udevd applies ACLs based on the old state file.
This makes logind not update ACLs but trigger uevents for relevant
devices to make ACLs updated by udevd.
When udevd broadcasts an event for e.g. a graphics device with master-of-seat
tag, then previously manager_process_seat_device() was called twice for
the event.
With this commit, the function is called only once even for an event for
such device.
The kernel sometimes sends uevents in a random order, so previously the
received events were not sorted by their seqnum. We determine which
event is ready for processing by using the assumption that queued events
are sorted by their seqnum. Let's sort the received events before queue
them, to make events processed in a correct ordering.
If DefaultDependencies=no, /var/ may not be mounted yet when the service
is being started. Previously, In such case, if the service has
PrivateTmp=disconnected, the service manager created /var/tmp/ on the
root filesystem and mounted the disconnected private tmpfs there. That
poluted the root filesystem and disturbed gpt-auto-generator on next
boot, as /var/ would not be empty anymore. See issue #37258.
This changes PrivateTmp=disconnected as the following:
- If DefaultDependencies=no and RootDirectory=/RootImage= are not set,
then a private tmpfs is mounted _only_ on /tmp/, and set $TMPDIR=/tmp
environment variable to suggest the service to use /tmp/.
- If DefaultDependencies=yes and RootDirectory=/RootImage= are not set,
then implies RequiresMountsFor=/var/, though that is typically
redundant, but anyway. Hence, we can safely mount /var/tmp/.
- Otherwise, i.e. when one of RootDirectory=/RootImage= is set, behaves
as the same as the previous, as the private root filesystem for the
service is explicitly prepared by the service manager, and we can
safely mount a private tmpfs on /var/tmp/ without any extra
dependencies.
Fixes#37258.
Co-authored-by: Mike Yuan <me@yhndnzj.com>
When the unit is new, then mount_setup_new_unit() adds the unit to the
load queue, and the same dependencies will be anyway added.
When the unit already exists but previously failed to be loaded, then
mount_setup_existing_unit() also adds the unit to the load queue.
Hence it is not necessary to regenerate dependencies here now.
So, we need to regenerate dependencies only when things changed and
the unit has been already loaded.
No functional changes, just optimization.
Unfortunately, the kernel may send events in a random order:
```
[ 25.769624] systemd-udevd[194]: sdi7: Device is queued (SEQNUM=2843, ACTION=add)
[ 25.769893] systemd-udevd[194]: sda5: Device is queued (SEQNUM=2842, ACTION=add)
[ 25.770517] systemd-udevd[194]: sdi8: Device is queued (SEQNUM=2844, ACTION=add)
```
As you can see, udevd receives the event with SEQNUM=2843 earlier than
one with SEQNUM=2842.
Let's make queued events sorted, as our logic of determining which event
is ready for being processed assumes that queued events are sorted.
See event_build_dependencies().
Also, refuse to queue an event if another event with the same seqnum is
already queued.
Previously, when an event for block device is queued or an inotify event
for a block device is triggered, all queued events were checked by
event_queue_assume_block_device_unlocked(), and its cost may be huge
on early boot stage.
This makes locked events are managed in separated prioq and hashmap,
to reduce the cost of event_queue_assume_block_device_unlocked(),
which is now renamed to manager_requeue_locked_events_by_device().
This also changes the clockid of timer events for requeueing and
timeout of retry from CLOCK_BOOTTIME to CLOCK_MONOTONIC. Otherwise,
if the system suspend while an event is locked, the event may be
requeued immediately after come back from the suspend and timed out.
The timeout event sources are enabled only when the event is being
processed by a worker, hence they are not necessary to be owned by the
event.
No effective functional change, just refactoring.
Note, BPF_PROG_TYPE_CGROUP_DEVICE is supported since kernel v4.15.
As our baseline on the kernel is v5.4, we can assume the bpf type is
always supported.
Note, BPF_PROG_TYPE_CGROUP_SKB is supported since kernel v4.10, and
BPF_F_ALLOW_MULTI and program name is supported since kernel v4.15.
As our baseline on the kernel is v5.4, we can assume that the type,
flag, and naming is supported when bpf_program_supported() succeeds.
BPF_PROG_TYPE_CGROUP_SKB is supported since kernel v4.10
(0e33661de493db325435d565a4a722120ae4cbf3) and
BPF_PROG_TYPE_CGROUP_SOCK_ADDR is supported since kernel v4.17
(4fbac77d2d092b475dda9eea66da674369665427).
Our baseline on the kernel is v5.4. The check is not necessary.
After 3988e2489a, the function is a simple
wrapper of bpf_dlopen() with logging. Let's introduce dlopen_bpf_full()
that takes log level, and replace cgroup_bpf_supported() with it.
When the flag is set, even if the specified UID/GID does not exist,
create a synthetic user record for the UID/GID.
Currently, only system UID/GID are supported.
Follow-up for 940441b44c.
With the commit, User=/Group=root was refused and warned that the root
is not a system user. Typically it is not necessary to specify such, but
let's not log confusing warning and honor the setting.
The buffer will be used by a library outside of our code base,
and may not be initialized even on success. Let's initialize
them for safety.
Hopefully fixes the following fuzzer warning:
```
==2039==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f9ad8be3ae6 in _nss_files_getsgnam_r (/lib/x86_64-linux-gnu/libnss_files.so.2+0x8ae6) (BuildId: 013bf05b4846ebbdbebdb05585acc9726c2fabce)
#1 0x7f9ad93e5902 in getsgnam_r (/lib/x86_64-linux-gnu/libc.so.6+0x126902) (BuildId: 0323ab4806bee6f846d9ad4bccfc29afdca49a58)
#2 0x7f9ad9b98153 in nss_sgrp_for_group /work/build/../../src/systemd/src/shared/user-record-nss.c:357:21
#3 0x7f9ad9b98926 in nss_group_record_by_gid /work/build/../../src/systemd/src/shared/user-record-nss.c:431:21
#4 0x7f9ad9bcebd7 in groupdb_by_gid_fallbacks /work/build/../../src/systemd/src/shared/userdb.c:1372:29
Uninitialized value was created by a heap allocation
#0 0x556fd5294302 in malloc /src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cpp:1021:3
#1 0x7f9ad9b9811d in nss_sgrp_for_group /work/build/../../src/systemd/src/shared/user-record-nss.c:353:23
#2 0x7f9ad9b98926 in nss_group_record_by_gid /work/build/../../src/systemd/src/shared/user-record-nss.c:431:21
#3 0x7f9ad9bcebd7 in groupdb_by_gid_fallbacks /work/build/../../src/systemd/src/shared/userdb.c:1372:29
```
Otherwise, initrd-cleanup.service requests isolation thus the socket
is stopped before switching root, and several early events after
switching root may be lost.