Commit Graph

6430 Commits

Author SHA1 Message Date
Luca Boccassi
f251930d63 test: make TEST-60-MOUNT-RATELIMIT more robust
TEST-60-MOUNT-RATELIMIT sometimes fails as it cannot see the 'left rate limit'
message in the journal. Tests relying on specific log messages are often flaky,
as the journal is lossy.
Change the test case to check for the desired outcome instead, as that also
catches regressions, without being over reliant on the journal.

Fixes https://github.com/systemd/systemd/issues/32712

(cherry picked from commit d0443c6d1a)
(cherry picked from commit 255a6b9acb)
2026-06-26 14:52:28 +01:00
Luca Boccassi
e6337757b5 hwdb: reject overlong fnmatch key instead of passing NULL to fnmatch()
When the accumulated trie key exceeds the fixed-size line buffer,
linebuf_get() returns NULL. trie_fnmatch_f() passed that NULL straight
into fnmatch() as the pattern, causing a SIGSEGV on a crafted hwdb.bin
(reachable now that recursion is capped rather than overflowing the
stack first). Treat the NULL like the other corruption checks and
return -EBADMSG.

Follow-up for 73fea38cf1

Fixes https://github.com/systemd/systemd/issues/42376

Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 3db89cbf0e)
(cherry picked from commit 138565f8d6)
2026-06-26 14:52:28 +01:00
jeffhuang
4089f60df5 pe-binary: bound section data against file size, cap UKI zero-padding hash, validate optional header size
A hostile but structurally valid 382-byte PE32+ "EFI application" with a
single section whose VirtualSize is ~4 GiB and SizeOfRawData is 0 drives
uki_hash() into ~4.17 M iterations of SHA-256 over 1024 bytes of zeros
— wedging the parser for >10 s. Nine more slow-units share the same
shape. A separate MSAN finding from the new fuzzer (CIFuzz, memory
sanitizer) shows pe_load_headers() reading uninitialised heap memory
when SizeOfOptionalHeader is too small to actually contain
NumberOfRvaAndSizes.

Three tightenings in src/shared/pe-binary.c:

  1. In pe_load_sections, reject sections whose PointerToRawData +
     SizeOfRawData exceeds the actual file size. Raw section data must
     fit inside the file; this is the parser-wide invariant
     pe_hash / uki_hash / pe_read_section_data rely on.

  2. In uki_hash, cap the (VirtualSize - SizeOfRawData) zero-padding
     hash loop at 64 MiB. Real UKIs do not pad sections with tens of
     MiB of zero-equivalent data; anything above this cap is a
     malformed PE.

  3. In pe_load_headers, reject a PE whose SizeOfOptionalHeader is too
     small to cover up to NumberOfRvaAndSizes. Without this guard the
     subsequent size-mismatch check reads uninitialised optional-header
     bytes, caught by MSAN under CIFuzz.

Add the 382 B canonical reproducer (plus two structural siblings) and
the MSAN reproducer to test/fuzz/fuzz-pe-binary/. Also add a libFuzzer
harness in src/fuzz/fuzz-pe-binary.c and unit tests in
src/test/test-pe-binary.c that exercise each fix branch in isolation.
The 64 MiB hash boundary test is gated behind SYSTEMD_SLOW_TESTS so it
doesn't slow down emulated-arch CI.

This is a robustness fix, not a security fix: PE binaries consumed by
bootctl / systemd-stub / pcrlock / kernel-install / systemd-measure are
already trusted and signed at the consumer side, so the worst pre-fix
behaviour is wasted CPU on a UKI install / measure / inspect call.

Closes #42344.

Reported-by: AI-assisted libFuzzer campaign
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 0c5cba6420)
(cherry picked from commit 6b0830b25c)
2026-06-26 14:52:28 +01:00
jeffhuang
602aa76cba hwdb: bounds-check trie offsets against the mmap before dereferencing
Fixes a family of OOB reads in the trie walker where attacker-controlled
offsets are loaded from a (possibly hostile) hwdb.bin and added to
hwdb->map without first checking that the resulting pointer stays inside
the mapping. Crash sites:

  - trie_fnmatch_f               sd-hwdb.c:187   (#42340)
  - trie_search_f                sd-hwdb.c:233   (#42341)
  - trie_children_cmp_f /bsearch sd-hwdb.c:94    (#42342)
  - hwdb_add_property            sd-hwdb.c:121   (#42343)
  - trie_node_from_off (UBSAN)   sd-hwdb.c:83
  - trie_fnmatch_f stack overflow on cyclic children (CIFuzz finding)

Commit b45a897edc ("hwdb: reject out-of-bounds fnmatch prefixes")
plugged the first site only at the prefix_off-content level, but the
crash on the read of node->prefix_off itself still happens when node is
already OOB. This is the structural fix: a single hwdb_at() helper
validates that [off, off + size) lies inside the mapping, and
trie_node_from_off() / trie_string() return NULL on OOB; every caller
treats the result as nullable and surfaces -EBADMSG.

trie_fnmatch_f() additionally caps its recursion depth at 2048; without
the cap a corrupt trie whose child offsets form a cycle (or just a deep
linear chain) drives the parser into stack-overflow rather than
returning -EBADMSG (caught by CIFuzz address sanitizer on this branch).

Additions:

  - A fuzz-hwdb libFuzzer harness that drives sd_hwdb_new_from_path,
    sd_hwdb_get, sd_hwdb_seek, and sd_hwdb_enumerate on attacker bytes.
  - Five hand-crafted unit tests in test-sd-hwdb.c (one per crash
    bucket, plus the cyclic-trie recursion case) that build a malformed
    in-memory hwdb.bin and assert -EBADMSG rather than SIGSEGV /
    stack-overflow.
  - Regression corpus files under test/fuzz/fuzz-hwdb/ pinning each
    fixed bucket, including the CIFuzz stack-overflow reproducer.

Closes #42340.
Closes #42341.
Closes #42342.
Closes #42343.

Reported-by: AI-assisted libFuzzer campaign
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 73fea38cf1)
(cherry picked from commit a3189e6e3d)
2026-06-26 14:50:36 +01:00
Chris Patterson
3429506d9b udev: preserve rule-set properties on failed network interface rename
When rename_netif() failed for a reason other than -EBUSY (e.g. -EEXIST
because NAME= conflicts with an existing interface), the revert path
rewrote the on-disk udev database from dev_db_clone (the pre-rules
snapshot) and then returned the error. The caller in
udev_event_execute_rules() bailed out before reaching the final
device_update_db(dev), so every property the rules had attached to the
device during this event (including ENV{}= assignments made alongside
the failing NAME=) was silently dropped from /run/udev/data/.

Persist 'dev' from inside the revert block, after its syspath and
INTERFACE have been restored. The cloned snapshot is still written
first to clear ID_RENAMING/ID_PROCESSING; the subsequent dev write
keeps the rule-applied properties without resurrecting the new name.
Only persist when r < 0, since the -EBUSY path returns success and the
caller will write the DB itself.

Add a TEST-17-UDEV.rename-netif regression test that pre-creates the
rename target, then triggers rules that set three ENV{}= properties
(one on a rule line before the failing NAME=, one on the same line as
NAME=, and one on a rule line after) and asserts all three are still
visible via udevadm info on the source interface. The neighbouring
test_netif_renaming_conflict already exercises the same -EEXIST revert
path but only checks the SYSTEMD_ALIAS broadcast, which is why this
regression went unnoticed.

Verified against unpatched origin/main (b4aff10ac0): the new test
fails, udevadm reports only kernel-supplied fields for the source
interface, and /run/udev/data/n<ifindex> is 0 bytes. With this patch
applied all three properties survive regardless of whether they were
set before, on, or after the failing NAME= rule line.

Downstream impact (NetworkManager managing an interface that rules had
marked NM_UNMANAGED=1): https://redhat.atlassian.net/browse/RHEL-178481

Fixes: https://github.com/systemd/systemd/issues/42331

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 779a3a13ae)
(cherry picked from commit 44275007bd)
2026-06-26 14:50:36 +01:00
Luca Boccassi
8f4d340ccd test: disable ManagedOOMMemoryPressure on /system.slice in TEST-55-OOMD
The systemd-oomd-defaults rpm installed on Fedora/CentOS images via
mkosi/mkosi.conf.d/centos-fedora/mkosi.conf ships
/usr/lib/systemd/system/system.slice.d/10-oomd-per-slice-defaults.conf:

    [Slice]
    ManagedOOMMemoryPressure=kill
    ManagedOOMMemoryPressureLimit=80%

https://gitlab.com/redhat/centos-stream/rpms/systemd/-/blob/c10s/10-oomd-per-slice-defaults.conf

In a recent flaky CI run on centos-10, the following sequence was
recorded in test/journal/TEST-55-OOMD-1.journal:

    [   77.740597] systemd-oomd[659]: Memory pressure for /system.slice is 85.03% > 80.00% for > 2s with reclaim activity
    [   77.745326] TEST-55-OOMD.sh[1292]: + journalctl --sync
    [   77.749125] systemd-oomd[659]: Considered 19 cgroups for killing, top candidates were:
    [   77.749128] systemd-oomd[659]:         Path: /system.slice/systemd-journald.service
    [   77.749134] systemd-oomd[659]:                 Current Memory Usage: 55.5M
    [   77.749597] systemd-oomd[659]: oomd attempting to kill 407 with KILL
    [   77.749670] systemd-oomd[659]: Marked /system.slice/systemd-journald.service for killing due to memory pressure for /system.slice being 85.03% > 80.00% for > 2s with reclaim activity
    [   77.752252] systemd[1]: systemd-journald.service: systemd-oomd killed 1 process(es) in this unit.
    [   77.752293] systemd[1]: systemd-journald.service: Changed running -> stop-sigterm
    [  329.922401] systemd[1]: systemd-journald.service: Main process exited, code=killed, status=9/KILL

PID 1292 (the test script) never logged anything after the
`journalctl --sync` line at [77.745326], and the unit stayed in
stop-sigterm until [329.922401].

Override /system.slice to ManagedOOMMemoryPressure=auto in the test
setup so the test does not rely on whichever per-slice oomd defaults
the distro happens to ship.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 7b79004cce)
(cherry picked from commit 03def5c285)
2026-05-27 12:20:29 +01:00
Luca Boccassi
7b9ce799a2 test: clean up persistent test state at beginning of TEST-64-UDEV-STORAGE too
This test often fails because the VM reboots (eg: kernel panic) and the
previous state is left unclean. Do the cleanups at the beginning too,
to try and reduce flakiness.

(cherry picked from commit 39a2cc966b)
(cherry picked from commit 65449b6013)
2026-05-27 12:20:29 +01:00
Luca Boccassi
10c1694f28 test: skip TEST-55-OOMD entirely if stress-ng is broken on this host
This reverts commit a17efef137 ("test: try to detect SIGILL in stress-ng
and skip TEST-55-OOMD gracefully") and replaces it with a single
check to skip the test cases.

The previous check was not reliable as stress-ng can catch SIGILL
itself and exist with an error:

  stress-ng[1068]: stress-ng: debug: [1068] caught SIGILL, address \
    0x00005632f8330140 (ILL_ILLOPN)
  stress-ng[1068]: stress-ng: debug: [1068] stress-ng: info: \
    0x00005632f8330140:<62>71 fd 48 6f 2d 36 14 1c 00 c5 d1 ef ed 49 29
  ...
  stress-ng[1053]: stress-ng: error: [1053] vm: [1061] terminated \
    with an error, exit status=2 (stressor failed)
  ...
  systemd[1]: TEST-55-OOMD-slowrule.service: Main process exited, \
    code=exited, status=2/INVALIDARGUMENT
  systemd[1]: TEST-55-OOMD-slowrule.service: Failed with result \
    'exit-code'.

Try to detect at the beginning of the test and skip the test case if it
happens.

(cherry picked from commit 4840da2fdf)
(cherry picked from commit a1ef923999)
2026-05-27 12:20:29 +01:00
Luca Boccassi
a94447fff5 test: also check if networkd built with BTF support before BPF test
SUSE does not provide a vmlinux.h so the package is not built with
CO-RE support, hence the test fails. This was previously masked
by the fact that python3-packaging was never installed, so the
test always skipped everywhere as it could not detect the kernel
version.

Follow-up for c310106c15

(cherry picked from commit 9e4248fbbf)
(cherry picked from commit 59fa0010fb)
2026-05-27 12:20:29 +01:00
Luca Boccassi
fed67c1cfc core: do not leak resources when handling stale alias state on reload
The fix for the corrupted state when units become aliased on reload
leaks the now-aliased unit's resources, which become untracked and
essentially lost.

While fixing the state corruption is of course necessary, leaking
processes/etc. is not ideal for a system and service manager, so
instead attempt to keep track of them by creating stub units
on-the-fly as replacements.
This way resources are not leaked, there are clear indications of
where they moved, and all state can be tracked as expected.

Ignore timers/sockets/paths as those are internal resources/triggers.

Follow-up for a77c7a8224

(cherry picked from commit 4f7089f0c7)
(cherry picked from commit 02b3d7381e)
2026-05-27 12:20:29 +01:00
Luca Boccassi
2bcca88e68 test: add reproducer for alias-corruption skip-desync regression
The existing alias-corruption subtest only intermittently caught the
regression where unit_deserialize_state_skip() stopped at the first
empty line and thus failed to consume embedded "job" subsections
(written by job_serialize() when u->job or u->nop_job is non-NULL).
This same skip routine is also used by the pre-scan that builds the set
of serialized unit names (added in a77c7a8224 to detect stale alias
state). When skip terminates early at a job's end marker, the scan
desyncs and every subsequent unit name is dropped from the set,
silently bypassing the alias-corruption protection for those units.

Whether the bug fired depended on:
  1. Whether any unit happened to carry a pending job at the moment of
     reload/reexec (mostly chance, depends on timers, transient units,
     load, etc.).
  2. Hashmap iteration order during serialization (per-boot randomized
     siphash seed) determining if a job-bearing unit was written before
     a sus-NN.service alias.

To try and make the regression deterministic, add a "with_pending_jobs" mode
that creates 50 Type=oneshot services and starts them with
systemctl --no-block. Each remains in "activating" state with u->job
set forever, guaranteeing the serialized stream contains many embedded
job subsections regardless of hashmap order, and that at least one of
them precedes the sus units. Without the fix, the desync drops the
sus-NN entries from the set, the alias-corruption check
set_contains(serialized_units, u->id) returns false for every alias,
and legit.service's MainPID is overwritten on every run.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit a1aed3eae2)
(cherry picked from commit 0316f75782)
2026-05-27 12:20:29 +01:00
Luca Boccassi
dcc1eb9a01 test: try to detect SIGILL in stress-ng and skip TEST-55-OOMD gracefully
The attempt to fix SIGILL in TEST-55-OOMD actually made the test more
flaky, as the chosen stress-ng method generates less pressure, so it
often fails.

Try a different approach: try to detect that SIGILL caused the unit
calling stress-ng to fail, and skip gracefully in that case.

(cherry picked from commit a17efef137)
(cherry picked from commit 0403a44bdc)
2026-05-27 12:20:29 +01:00
Yu Watanabe
ca5bc98359 test-network: fix path to test-ndisc-send
Follow-up for 9dcdf16b25.

Previously, test cases that use test-ndisc-send executable did not
tested in our mkosi CIs...

(cherry picked from commit dece52443c)
(cherry picked from commit 44f512097b)
2026-05-27 12:20:29 +01:00
Yu Watanabe
a8f1e41d51 test-network: fix test case for Neighbor Announcement message handling
After 9142bd5a8e, when NA without router
flag is received, the corresponding redirect route and the default route
is removed, but the other routes are kept.

The corresponding test case was not updated by the commit, and the test
case has been unfortunately skipped...

This fixes the test case, and added more checks.

(cherry picked from commit d9b7fdf06a)
(cherry picked from commit 1538b9505e)
2026-05-27 12:20:29 +01:00
Frantisek Sumsal
6af681dfac test: re-enable sync in TEST-25-IMPORT
Newer tar started using openat2() via open_subdir() to address
CVE-2025-45582 [0]. Now, gnulib, that tar uses, provides the openat2()
syscall in two ways [1]:

1) If glibc doesn't provide openat2(), it provides its own version in
   openat2.c, that tries to call openat2() syscall first, and if it
   returns ENOSYS, it emulates the function in userspace.

2) If glibc provides openat2(), it uses that directly, without providing
   any fallback on ENOSYS.

Quite recently our test suite started calling nspawn with
--suppress-sync=yes. This means that we call seccomp_suppress_sync(),
which eventually calls block_open_flag(), that blocks the openat2()
syscall completely and refuses it with ENOSYS as this syscall can't be
sensibly filtered (see the openat2()-relevant comments in
block_open_flag() and seccomp_restrict_sxid()). And when glibc provides
openat2(), there's no fallback, so the ENOSYS bubbles up to the user as:

TEST-25-IMPORT.sh[163]: + tar xzf /var/tmp/scratch.tar.gz
TEST-25-IMPORT.sh[163]: tar: ./adirectory/athirdfile: Cannot open: Function not implemented
TEST-25-IMPORT.sh[163]: tar: Exiting with failure status due to previous errors

Let's mitigate this by re-enabling sync for TEST-25-IMPORT, at least for
now.

[0] https://cgit.git.savannah.gnu.org/cgit/tar.git/commit/?id=75b03fdff48916bd0654677ed21379bdb0db016d
[1] https://cgit.git.savannah.gnu.org/cgit/gnulib.git/commit/?id=0b97ffdf32bdab909d02449043447237273df75e

(cherry picked from commit c955e24916)
(cherry picked from commit 89512d0606)
2026-05-27 12:20:28 +01:00
Rocker Zhang
3170811d73 test: cover lingering users surviving a soft-reboot in TEST-82
Regression coverage for the soft-reboot linger bug fixed in
9f25feb4ed ("logind: keep lingering users at startup-time GC", #41789):
a lingering user's user@.service was started after a hardware reboot but
not after `systemctl soft-reboot`, because logind GC'd the user at
startup before user_start() ran.

On the first boot, enable lingering for the pre-existing testuser and
wait for its user@UID.service to come up. After the first soft-reboot
(which keeps the same persistent rootfs), assert the service is active
again — this is the regression check. Disable lingering again before the
nextroot switch in the second boot so the lingering user doesn't leak
into the later boots' minimal overlay rootfs.

Verified locally in a qemu/KVM VM: passes with the fix present, and with
the fix reverted the second-boot assertion times out (the lingering user
is GC'd in logind startup and user@UID.service never comes back),
confirming the test exercises the bug.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 1bd2acf193)
(cherry picked from commit 7d88897d8f)
2026-05-27 12:20:28 +01:00
Luca Boccassi
2655cca712 test: fix race in TEST-07-PID1.socket-on-failure.sh
The test waited for the OnFailure= service's filesystem side effect
(`rmdir` of the directory) and then immediately invoked
`systemctl is-active`. Between `rmdir(2)` returning (which causes the
shell loop to exit) and PID1 reaping the child and transitioning the
oneshot service from `activating` to `active`, there is a small window
where `is-active` can observe `activating` and fail the test.

Wait directly on the unit state instead, matching the pattern used a
few lines above for the `is-failed` case.

  [ 1880.326704] TEST-07-PID1.sh[21489]: + timeout --foreground 60 bash -c 'while [[ -d '\''/tmp/TEST-07-PID1-socket-8467/test'\'' ]]; do sleep .5; done'
  [ 1880.330482] TEST-07-PID1.sh[21489]: + [[ ! -e /tmp/TEST-07-PID1-socket-8467/test ]]
  [ 1880.330482] TEST-07-PID1.sh[21489]: + systemctl is-active TEST-07-PID1-socket-OnFailure.service
  [ 1880.347470] TEST-07-PID1.sh[21520]: activating
  [ 1880.349508] TEST-07-PID1.sh[21489]: + at_exit
  [ 1880.349508] TEST-07-PID1.sh[21489]: + systemctl stop TEST-07-PID1-socket-8467.socket
  [ 1880.367331] TEST-07-PID1.sh[107]: Subtest /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.socket-on-failure.sh failed
  [ 1880.367331] TEST-07-PID1.sh[107]: + return 1

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit fc0bd373ef)
(cherry picked from commit 32daa8e76c)
2026-05-27 12:20:20 +01:00
Luca Boccassi
7730881d55 test: add test coverage for homed+fscrypt
Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit a332f3b6ca)
(cherry picked from commit 219fe12661)
2026-05-27 12:20:20 +01:00
Ivan Kruglov
effae8c8c0 test: wait systemd to finish reexec in TEST-74-AUX-UTILS.varlinkctl.sh
(cherry picked from commit e86b49473f)
(cherry picked from commit 7c39452031)
2026-05-27 12:20:20 +01:00
Luca Boccassi
4e2a1e006c test-network: retry networkctl status in wait_operstate()
networkctl status may transiently fail right after start_networkd() because networkd has not yet picked up the freshly-created link from the kernel. The retry loop in wait_operstate() did not catch the resulting subprocess.CalledProcessError, so the test aborted on the first attempt instead of retrying for the configured timeout.

Observed in TEST-85-NETWORK-NetworkdBridgeTests, subtest test_bridge_configure_without_carrier[no-slave]:

  [   19.600156] systemd-networkd-tests.py[526]: Failed to issue io.systemd.Network.Link.Describe() varlink call: Invalid argument
  [   53.124982] systemd[1]: systemd-networkd.service: Changed start -> running
  [   53.336167] systemd-networkd-tests.py[526]: ERROR: test_bridge_configure_without_carrier (__main__.NetworkdBridgeTests.test_bridge_configure_without_carrier) (test='no-slave')
  [   53.336167] systemd-networkd-tests.py[526]:     self.wait_operstate('bridge99', operstate=r'(no-carrier|routable)', setup_state=None, setup_timeout=30)
  [   53.336167] systemd-networkd-tests.py[526]: subprocess.CalledProcessError: Command '['/usr/bin/networkctl', '-n', '0', 'status', 'bridge99']' returned non-zero exit status 1.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 446b0393ff)
(cherry picked from commit eacfec289e)
2026-05-27 12:20:20 +01:00
Daan De Meyer
5daa4240ee TEST-64-UDEV-STORAGE: Drop number of nvme devices to 12
qemu by default only has 30 PCI slots and with vmspawn now reserving
some of those for its hotplug features, we go over the limit for the
nvme test.

Let's drop the number of nvme devices to 12 to fix the conflict.

(cherry picked from commit 74d742fbfc)
(cherry picked from commit 1be9326f54)
2026-05-27 12:20:20 +01:00
Daan De Meyer
e85b9a01bc test: Modernize btrfs tests
Convert test-btrfs to use the test framework and
assertions, merge the physical offset test into it
and beef it up to include what TEST-83-BTRFS does and
finally get rid of TEST-83-BTRFS as it is unneeded now.

(cherry picked from commit 7cc5d161e6)
(cherry picked from commit 1a16a22bb7)
2026-05-27 12:20:20 +01:00
Frantisek Sumsal
4c0983625a sd-bus: handle non-string keys in dictionaries in JSON dump
JSON only supports string keys in objects, but D-Bus specification is a
bit more lenient and allows dict entries to have any basic type as key.
Let's stringify allowed non-string keys so that we can represent them as
JSON objects.

Relevant snippet from the D-Bus specification:

  A DICT_ENTRY works exactly like a struct, but rather than parentheses
  it uses curly braces, and it has more restrictions. The restrictions
  are: it occurs only as an array element type; it has exactly two
  single complete types inside the curly braces; the first single
  complete type (the "key") must be a basic type rather than a container
  type. Implementations must not accept dict entries outside of arrays,
  must not accept dict entries with zero, one, or more than two fields,
  and must not accept dict entries with non-basic-typed keys. A dict
  entry is always a key-value pair.

Resolves: #32904
(cherry picked from commit 7cecff8c99)
(cherry picked from commit 5fff43e7a5)
2026-05-27 12:20:20 +01:00
Luca Boccassi
adb827efb8 test: make TEST-75-RESOLVED robust against journald metadata race
Even after switching the wait loop to a polling `journalctl --grep`, the
test still fails intermittently because the very first messages emitted by
the freshly-spawned systemd-networkd-wait-online process can carry stale
journald metadata. journald associates `_SYSTEMD_UNIT=` (and friends) with
each entry by reading `/proc/$pid/cgroup` of the originating PID; if those
messages are produced before journald notices the cgroup migration into the
new service, they get tagged with `_SYSTEMD_UNIT=init.scope`. The
`-u $unit` filter then fails to match them.

Capture a journal cursor before launching the unit, and grep using
`--after-cursor=` plus `SYSLOG_IDENTIFIER=systemd-networkd-wait-online`
instead of `-u $unit`. SYSLOG_IDENTIFIER is set by the program itself, so
it's not subject to the cgroup-discovery race. The cursor bounds the search
to entries produced by this invocation, so prior wait-online runs in
earlier testcases don't interfere.

Logs from the failing run showing the messages exist but are tagged with
the wrong unit:

  [ 2570.948554] TEST-75-RESOLVED.sh[2178]: + unit=wait-online-dns-ede81407-b93b-459d-8e5d-69292b42d2ae.service
  [ 2571.023162] TEST-75-RESOLVED.sh[2178]: + systemd-run -u wait-online-dns-ede81407-b93b-459d-8e5d-69292b42d2ae.service ...
  [ 2571.049189] TEST-75-RESOLVED.sh[2178]: + timeout 30 bash -c 'until journalctl -b -u wait-online-dns-ede81407-b93b-459d-8e5d-69292b42d2ae.service --grep ...'
  [ 2571.964986] systemd-networkd-wait-online[2190]: dns0: No DNS server is accessible.
  [ 2601.051088] TEST-75-RESOLVED.sh[2178]: ++ cleanup

And for that 2571.964986 entry:

      _SYSTEMD_CGROUP=/init.scope
      _SYSTEMD_UNIT=init.scope
      _EXE=/usr/lib/systemd/systemd-executor
      _CMDLINE=/usr/lib/systemd/systemd-executor --deserialize 68 ...
      SYSLOG_IDENTIFIER=systemd-networkd-wait-online
      MESSAGE=dns0: No DNS server is accessible.

Follow-up for d4bc62713e

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit 9f08885b0e)
(cherry picked from commit 684e2c2b8c)
2026-05-27 12:20:20 +01:00
Luca Boccassi
3a1a647ab2 TEST-67-INTEGRITY: pre-load crypto modules and skip unsupported algorithms
The test occasionally fails on GHA CI when formatting with xxhash64
because dm-integrity's crypto_alloc_shash() -> request_module() path
flakily fails to load the algorithm:

[   29.172664] TEST-67-INTEGRITY.sh[447]: + for a in crc32c crc32 xxhash64 sha1 sha256
[   29.172664] TEST-67-INTEGRITY.sh[447]: + [[ xxhash64 == crc32 ]]
[   29.172664] TEST-67-INTEGRITY.sh[447]: + test_one xxhash64 0
[   29.172664] TEST-67-INTEGRITY.sh[447]: + integritysetup format /dev/loop0 --batch-mode -I xxhash64 ''
[   29.223383] TEST-67-INTEGRITY.sh[1220]: device-mapper: reload ioctl on temporary-cryptsetup-fa8bebe3-1d87-4796-91e8-abc02c487bb5 (254:0) failed: No such file or directory
[   29.226916] kernel: device-mapper: table: 254:0: integrity: Invalid internal hash (-ENOENT)
[   29.227415] kernel: device-mapper: ioctl: error adding target to table
[   29.231586] TEST-67-INTEGRITY.sh[1220]: Cannot format integrity for device /dev/loop0.

Preload each algorithm's crypto module before use, and skip algorithms
that are not registered in /proc/crypto.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit f68fa99a07)
(cherry picked from commit 27fd8e495c)
2026-05-27 12:20:19 +01:00
Luca Boccassi
0c0a86271a test: bump TEST-58-REPART timeouts with sanitizers
The test is flaky under sanitizers as the timeouts seem to be too short,
bump them like we do in other tests to try and make it more robust when
running with sanitizers

(cherry picked from commit 0bf094b763)
(cherry picked from commit 5f3e9be15d)
2026-05-27 12:20:19 +01:00
Luca Boccassi
01791f0675 test: fix flaky TEST-07-PID1.socket-defer.sh
The socket's SubState transitions from 'running' to 'listening' shortly
after the triggered service becomes inactive, so the assert can race and
observe the stale 'running' state:

[ 1882.425335] systemd[1]: TEST-07-PID1-socket-defer-23279.service: Changed dead -> running
[ 1882.495150] TEST-07-PID1.sh[20535]: ++ systemctl show TEST-07-PID1-socket-defer-23279.socket -P SubState
[ 1882.514239] TEST-07-PID1.sh[20509]: + assert_eq running listening
[ 1882.510529] systemd[1]: TEST-07-PID1-socket-defer-23279.socket: Flushing socket before listening.
[ 1882.510559] systemd[1]: TEST-07-PID1-socket-defer-23279.socket: Changed running -> listening

Poll for 30s instead of directly asserting to try and make it more robust

(cherry picked from commit d3f436aa10)
(cherry picked from commit 1d922feb63)
2026-05-27 12:20:19 +01:00
Luca Boccassi
5b7a7e7cbc test: workaroud flaky TEST-53-TIMER.restart-trigger against journald cgroup attribution race
The restart-trigger subtest occasionally fails on CI with:

    + assert_eq 0 1
    FAIL: expected: '1' actual: '0'

even though the timer fires correctly and the echo message is in fact
written to the journal. The failure happens because the test relies on
`journalctl --unit=$UNIT_NAME` to find the message, and that filter is
based on the cgroup journald looks up for the writer PID at the time
the stdout message is received.

For very short-lived processes spawned via systemd-executor (like
`echo`), that lookup is racy: the writer's `/proc/$PID/cgroup` can
still resolve to `/init.scope` (systemd-executor's own cgroup) rather
than the service's cgroup, so the message ends up attributed to
`init.scope` and `--unit=` filtering misses it.

    __CURSOR=s=6f90ff5b6a0e47c3a527a9b4892af965;i=f8ed;b=3dad0cc689a04781879e4dd846d24432;m=17703dc;t=6513be1be2506;x=8d3009a687724b5e
    __REALTIME_TIMESTAMP=1778167492519174
    __MONOTONIC_TIMESTAMP=24576988
    __SEQNUM=63725
    __SEQNUM_ID=6f90ff5b6a0e47c3a527a9b4892af965
    _BOOT_ID=3dad0cc689a04781879e4dd846d24432
    _HOSTNAME=H
    PRIORITY=6
    SYSLOG_FACILITY=3
    _UID=0
    _GID=0
    _CAP_EFFECTIVE=1ffffffffff
    _SYSTEMD_CGROUP=/init.scope
    _SYSTEMD_UNIT=init.scope
    _SYSTEMD_SLICE=-.slice
    _EXE=/usr/lib/systemd/systemd-executor
    _TRANSPORT=stdout
    _COMM=18
    _MACHINE_ID=89ef83adc0bc4a33a83a227201b57203
    _RUNTIME_SCOPE=system
    _PID=816
    _CMDLINE=/usr/lib/systemd/systemd-executor --deserialize 50 --log-level debug,console:info --log-target journal-or-kmsg
    _STREAM_ID=8e8e4166c99e40afaa58bcd04a50a7f4
    SYSLOG_IDENTIFIER=echo
    MESSAGE=Hello from timer 29581

Note _SYSTEMD_UNIT=init.scope / _SYSTEMD_CGROUP=/init.scope on the
echo output: this is what causes `--unit=timer-restart-14362` to
return 0 hits. The test failure logs from the same run confirm this:

    + JOURNAL_TS=1778160292
    + journalctl -p info --since=@1778160292 --unit=timer-restart-14362 '--grep=Hello from timer 29581'
    -- No entries --
    + systemctl restart timer-restart-14362.timer
    ...
    + date '--set=+2 hours'
    Thu May  7 15:24:52 UTC 2026
    + sleep 1
    ...
    echo[816]: Hello from timer 29581
    ...
    ++ journalctl -q -p info --since=@1778160292 --unit=timer-restart-14362 '--grep=Hello from timer 29581'
    ++ wc -l
    + assert_eq 0 1
    FAIL: expected: '1' actual: '0'

For comparison, in a passing local run the same message is attributed
correctly to the service unit (_SYSTEMD_UNIT=timer-restart-24147.service),
so `--unit=` matches.

Work around the underlying journald race in the test by setting an
explicit `SyslogIdentifier=` on the service and matching with `-t` plus
the unique grep pattern: `SyslogIdentifier` is carried over the stdout
stream protocol and is not affected by the cgroup lookup race.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit cd57308303)
(cherry picked from commit fc204f8707)
2026-05-27 12:20:19 +01:00
Luca Boccassi
eb6247b722 test: make TEST-07-PID1.user-namespace-path more robust
The test occasionally fails because lsns returns empty output for
the transient unit, even though the process is running. e.g.:

    [ 1843.556046] TEST-07-PID1.sh[8560]: + systemd-run --unit=newservice --property=Type=exec --property=UserNamespacePath=/proc/8608/ns/user --property=NetworkNamespacePath=/proc/8608/ns/net sleep 3600
    [ 1844.205927] TEST-07-PID1.sh[8616]: ++ systemctl show newservice -p MainPID
    [ 1844.221425] TEST-07-PID1.sh[8618]: ++ lsns -p 8608 -o NS -t net -n
    [ 1844.229653] TEST-07-PID1.sh[8619]: ++ lsns -p 8614 -o NS -t net -n
    [ 1844.235563] TEST-07-PID1.sh[8620]: FAIL: expected: '' actual: '4026532522'

This could be a race, so switch to Type=notify to try and make it more robust.

(cherry picked from commit 7af304d601)
(cherry picked from commit 2cb47e5d89)
2026-05-27 12:20:19 +01:00
Luca Boccassi
574084bddb test: fix flaky testcase_15_wait_online_dns in TEST-75-RESOLVED
The test used `timeout 30 bash -c "journalctl -b -u $unit -f | grep -m1 ..."`
to wait for systemd-networkd-wait-online to log that no DNS server is
accessible. The expected message is actually emitted ~1s after the unit
starts, but `grep -m1` exiting doesn't tear down `journalctl -f`: journalctl
only notices the closed pipe on its next write, which may never happen for
an otherwise idle unit. The pipeline therefore hangs until the 30s timeout
fires, eventually causing the test to fail.

Replace the follow+pipe with a polling `journalctl --grep` loop, which
exits cleanly as soon as the message lands in the journal.

Logs from the failing run:

  [ 2650.871441] systemd-networkd-wait-online[2190]: dns0: No DNS configuration yet
  [ 2651.723180] systemd-networkd-wait-online[2190]: dns0: No DNS server is accessible.
  [ 2680.909048] systemd-networkd-wait-online[2190]: json-stream: Got POLLHUP from socket.
  [ 2680.909092] systemd-networkd-wait-online[2190]: DNS configuration monitor disconnected, reconnecting...
  [ 2680.914368] systemd-networkd-wait-online[2190]: Failed to connect to io.systemd.Resolve.Monitor: Connection refused
  [ 2681.966674] systemd-networkd-wait-online[2190]: dns0: No DNS server is accessible.
  [ 2681.969527] systemd-networkd-wait-online[2190]: Failed to connect to io.systemd.Resolve.Monitor: Connection refused
  [ 2682.077032] systemd[1]: Stopping wait-online-dns-0f9e4f6d-8b34-4cff-b2da-03612ca731e8.service - [systemd-run] /usr/lib/systemd/systemd-networkd-wait-online --timeout=0 --dns --interface=dns0...

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit d4bc62713e)
(cherry picked from commit 7323186da0)
2026-05-27 12:20:19 +01:00
Luca Boccassi
bdcf186d66 test: bump timeout in TEST-07-PID1.socket-on-failure
The timeout is too short so under sanitizers the test sometimes fails:

[ 3502.317855] TEST-07-PID1.sh[16212]: + mkdir -p /tmp/TEST-07-PID1-socket-29942
[ 3502.317855] TEST-07-PID1.sh[16212]: + cat
[ 3502.317855] TEST-07-PID1.sh[16212]: + cat
[ 3502.317855] TEST-07-PID1.sh[16212]: + cat
[ 3502.317855] TEST-07-PID1.sh[16212]: + systemctl start TEST-07-PID1-socket-29942.socket
[ 3502.317855] TEST-07-PID1.sh[16212]: + systemctl is-active TEST-07-PID1-socket-29942.socket
[ 3502.319398] TEST-07-PID1.sh[16221]: active
[ 3502.319758] TEST-07-PID1.sh[16212]: + [[ -S /tmp/TEST-07-PID1-socket-29942/test ]]
[ 3502.319758] TEST-07-PID1.sh[16212]: + systemctl stop TEST-07-PID1-socket-29942.socket
[ 3502.319758] TEST-07-PID1.sh[16212]: + rm /tmp/TEST-07-PID1-socket-29942/test
[ 3502.319758] TEST-07-PID1.sh[16212]: + chattr +i /tmp/TEST-07-PID1-socket-29942
[ 3502.320499] TEST-07-PID1.sh[16227]: + systemctl start TEST-07-PID1-socket-29942.socket
[ 3502.320914] TEST-07-PID1.sh[16228]: Job failed. See "journalctl -xe" for details.
[ 3502.321560] TEST-07-PID1.sh[16212]: + systemctl is-failed TEST-07-PID1-socket-29942.socket
[ 3502.321856] TEST-07-PID1.sh[16230]: failed
[ 3502.322315] TEST-07-PID1.sh[16233]: ++ systemctl show TEST-07-PID1-socket-29942.socket -P SubState
[ 3502.322722] TEST-07-PID1.sh[16212]: + assert_eq failed failed
[ 3502.323111] TEST-07-PID1.sh[16235]: + set +ex
[ 3502.323512] TEST-07-PID1.sh[16212]: + [[ ! -e /tmp/TEST-07-PID1-socket-29942/test ]]
[ 3502.323512] TEST-07-PID1.sh[16212]: + timeout 10 bash -c 'until systemctl is-failed TEST-07-PID1-socket-OnFailure.service; do sleep .5; done'
[ 3502.323949] TEST-07-PID1.sh[16238]: activating
[ 3502.324376] TEST-07-PID1.sh[16241]: activating
[ 3502.324754] TEST-07-PID1.sh[16244]: activating
[ 3502.325164] TEST-07-PID1.sh[16247]: activating
[ 3502.325587] TEST-07-PID1.sh[16250]: activating
[ 3502.325938] TEST-07-PID1.sh[16253]: activating
[ 3502.326393] TEST-07-PID1.sh[16256]: activating
[ 3502.326791] TEST-07-PID1.sh[16259]: activating
[ 3502.327180] TEST-07-PID1.sh[16262]: activating
[ 3502.327558] TEST-07-PID1.sh[16265]: activating
[ 3502.327971] TEST-07-PID1.sh[16268]: activating
[ 3502.328409] TEST-07-PID1.sh[16212]: + at_exit
[ 3502.328409] TEST-07-PID1.sh[16212]: + systemctl stop TEST-07-PID1-socket-29942.socket
[ 3502.328409] TEST-07-PID1.sh[16212]: + rm -f /run/systemd/system/TEST-07-PID1-socket-29942.socket /run/systemd/system/TEST-07-PID1-socket-29942.service /run/systemd/system/TEST-07-PID1-socket-OnFailure.service
[ 3502.328945] TEST-07-PID1.sh[147]: + echo 'Subtest /usr/lib/systemd/tests/testdata/units/TEST-07-PID1.socket-on-failure.sh failed'

Bump from 10s to 60s to try and make it less flaky

(cherry picked from commit e6ee724ac8)
(cherry picked from commit 66182a74a2)
2026-05-27 12:20:19 +01:00
Diego Viola
6ea33358b2 treewide: fix typos in the entire codebase
Signed-off-by: Diego Viola <diego.viola@gmail.com>
(cherry picked from commit 5d17215c7e)
(cherry picked from commit 87019e04e3)
2026-05-27 12:20:19 +01:00
Luca Boccassi
9e27f135eb test: make TEST-64 btrfs_basic cleanup robust against reruns
The LUKS subtest in testcase_btrfs_basic leaves stale LUKS headers on
the underlying SCSI devices, so if the VM is rebooted the test fails
because the LUKS signature is still there and blkid finds it.

[    7.683] + udevadm lock ... mkfs.btrfs -f -L btrfs_root -U deadbeef-dead-dead-beef-000000000000 /dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs0
[    7.729]   Label: btrfs_root
[    7.729]   UUID:  deadbeef-dead-dead-beef-000000000000
[    7.743] + udevadm wait --settle --timeout=30 /dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs0 /dev/disk/by-uuid/deadbeef-dead-dead-beef-000000000000 /dev/disk/by-label/btrfs_root
[    7.788] sda: ... SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}": Added device node symlink "disk/by-label/encdisk0".
[   37.998] Timed out for waiting devices being initialized.
[   38.002] TEST-64-UDEV-STORAGE-btrfs_basic.service: Main process exited, code=exited, status=1/FAILURE

Likewise for the BTRFS UUID:

ERROR: non-unique UUID: deadbeef-dead-dead-beef-000000000001

So wipe that too.

(cherry picked from commit 5d7d54fc30)
(cherry picked from commit 3db7905d60)
2026-05-27 12:20:19 +01:00
Luca Boccassi
d300751768 test: avoid nspawn failure due to scope in use in TEST-06-SELINUX
TEST-06-SELINUX occasionally fails because repeated nspawn invocations use
the same machine name and scope:

TEST-06-SELINUX.sh[598]: Failed to allocate scope: Unit H.scope was already loaded or has a fragment file.

Use a different machine name/scope for each invocation in the test
case to avoid hitting this issue

(cherry picked from commit ae973bb617)
(cherry picked from commit 9aa22f0de6)
2026-05-27 12:20:19 +01:00
Luca Boccassi
7a91c99318 test: skip TEST-07-PID1.DeferReactivation with sanitizers
This test relies on tight timers, and is flaky under sanitizers
as everything slows down a lot. Just skip it.

(cherry picked from commit a551c1bd56)
(cherry picked from commit dd62e56118)
2026-05-27 12:20:19 +01:00
Luca Boccassi
3ce1f84d64 test: suppress PCR public key auto-loading in TEST-70-TPM2 dditest
The dditest block calls systemd-repart with Encrypt=tpm2 but without
--tpm2-public-key-pcrs=. Since systemd-stub drops
/run/systemd/tpm2-pcr-public-key.pem when booting from a signed UKI
systemd-repart auto-loads it and enrolls a signed PCR policy, and
then systemd-cryptsetup tpm2-device=auto has no matching signature file,
so unlock fails.

--tpm2-public-key= is not enough as the default kicks in then.

Follow-up for cd18656d47

(cherry picked from commit 74338c0bb0)
(cherry picked from commit fe917ff684)
2026-05-27 12:20:19 +01:00
Luca Boccassi
4cf847941c test: make TEST-64 mdadm_lvm cleanup robust against reruns
mdadm --zero-superblock only wipes the MD metadata on the underlying
disks, not the LVM PV header that lives in the array data area. When
the VM is restarted and the test re-creates the array with the same
UUID, /dev/md127 exposes the old data including the LVM PV header, so
udev's 69-lvm.rules auto-triggers lvm-activate-mdlvm_vg.service which
races with the test's own pvcreate for exclusive access on /dev/md127.

Wipe the LVM signature off the MD device (and the underlying disks as
a belt-and-braces measure) to avoid the race on re-run, fixing failures
when the VM is rebooted instead of shut down.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
(cherry picked from commit a1d0c58220)
(cherry picked from commit ab49b6eb7f)
2026-05-27 12:20:19 +01:00
Luca Boccassi
85301a772a test: fix flaky TEST-04-JOURNAL.reload.sh due to service name collision
write_to_journal() was called via $(...) command substitution, so
SERVICE_COUNTER++ ran in a subshell and never incremented in the
parent:

[ 1492.668302] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18493.service
[ 1492.725882] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18009.service
[ 1492.739643] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18493.service
[ 1492.774586] TEST-04-JOURNAL.sh[15064]: + local service=test-0-25540.service
[ 1492.815664] TEST-04-JOURNAL.sh[15064]: + local service=test-0-15916.service
[ 1492.867067] TEST-04-JOURNAL.sh[15064]: + local service=test-0-20327.service
[ 1492.899077] TEST-04-JOURNAL.sh[15064]: + local service=test-0-86.service
[ 1497.289715] TEST-04-JOURNAL.sh[15064]: + local service=test-0-10849.service
[ 1497.335791] TEST-04-JOURNAL.sh[15064]: + local service=test-0-18009.service

With 99999 possible unit names collisions are rare but not impossible,
so every now and then a CI run fails.

Have write_to_journal() set a global SERVICE_NAME variable instead and
call it directly so SERVICE_COUNTER actually goes up through the test.

(cherry picked from commit 7e6507c43f)
(cherry picked from commit c00a9926a5)
2026-05-27 12:20:19 +01:00
Vitaly Kuznetsov
5100f56d96 TEST-70-TPM2: Test the key_file + tpm2-device= combo
When key_file is passed along with tpm2-device= to systemd-cryptsetup, the
logic is to try the blob as a TPM blob first, and then fall back to trying the
file as a regular key file. Check that this fallback works.

(cherry picked from commit 4820d57eee)
(cherry picked from commit c719c8a617)
2026-05-27 12:20:19 +01:00
Luca Boccassi
afc689589e test: make TEST-86-MULTI-PROFILE-UKI robust against reruns
When qemu reboots instead of shutting down after the last iteration,
the profile is already set to profile2 but the /root/encrypted.raw is
gone so the test fails. Reset the default boot entry at the end of the
test to make it robust against reruns.

Fixes https://github.com/systemd/systemd/issues/39553

(cherry picked from commit 3ec1a8ab22)
(cherry picked from commit d8368e9926)
2026-05-27 12:20:19 +01:00
Luca Boccassi
3cff9be611 test: make TEST-70-TPM2 robust against reruns
The test leaves a lot of state around, and when the test is re-run,
for example due to the qemu bug that makes a VM reboot instead of
shutting down, it fails.

Do more cleanups in the traps.

[  162.642175] TEST-70-TPM2.sh[2815]: Calculated public key name: 000b2b66edc3a466e81059286aaf38d09ea42a7a9dcdf6ba3b664c62f0cae4ce4f66
[  162.642628] TEST-70-TPM2.sh[2815]: PolicyAuthorize calculated digest: 2caa740101f65734d50395d6abc64fa46015d40d1f5de239434578544e592a92
[  162.643681] TEST-70-TPM2.sh[2815]: Calculated NV index name: 000b439cfa1534815bbe8d33b80c56f5a8d17d36fe94a7782b23a37b50def5fc5eaa
[  162.645111] TEST-70-TPM2.sh[2815]: PolicyAuthorizeNV calculated digest: 69ee0e89fafe6b9df2cd6a5defbf74aa46cf6d92703e645d463549da4ba5e1a4
[  162.645407] TEST-70-TPM2.sh[2815]: Combined signed PCR policies and pcrlock policies cannot be calculated offline, currently.
[  162.649576] TEST-70-TPM2.sh[2815]: Releasing crypt device /dev/loop0 context.
[  162.652433] TEST-70-TPM2.sh[2815]: Releasing device-mapper backend.
[  162.653518] TEST-70-TPM2.sh[2815]: Closing read only fd for /dev/loop0.
[  162.654359] TEST-70-TPM2.sh[2815]: Closing read write fd for /dev/loop0.
[  162.654786] TEST-70-TPM2.sh[2815]: Failed to encrypt device: Operation not supported

Fixes https://github.com/systemd/systemd/issues/38241

(cherry picked from commit 2fc008b9e4)
(cherry picked from commit d258851ffe)
2026-05-27 12:20:19 +01:00
Luca Boccassi
f17e1928f8 test: bump device timeout to 300s for TPM2 tests
Booting with TPM2 has become slower recently so tests are randomly
failing, try to bump the default device timeout in those test VMs

(cherry picked from commit 8fbc93345e)
(cherry picked from commit 5492c0dc2a)
2026-05-27 12:20:19 +01:00
Luca Boccassi
223df01544 test: avoid getting stuck on /dev/fuse
On Fedora Rawhide checking /dev/fuse in the test is getting stuck and timing out:

[   47.930104] TEST-13-NSPAWN.sh[2588]: + testcase_fuse
[   47.930424] TEST-13-NSPAWN.sh[2589]: ++ cat
[   58.772538] audit: type=1131 audit(1777728357.726:778): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-importd comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[  901.882562] audit: type=1131 audit(1777729200.830:782): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=systemd-tmpfiles-clean comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
Finishing after writing 176921 entries
qemu-system-x86_64: terminating on signal 15 from pid 70717 (/usr/bin/python3)

Wrap it with a timeout to avoid getting stuck forever

Follow-up for dc3223919f

(cherry picked from commit afa4a559e1)
(cherry picked from commit 71e40ed5c1)
2026-05-27 12:20:19 +01:00
Frantisek Sumsal
a8c5784437 test: temporarily ignore sanitizer warning about blocked ptrace()
LLVM 22 introduced an additional check [0] for ptrace() syscall when
invoking sanitizers [0] which currently produces a false-positive
warning when running some of our units under sanitizers:

[   47.524680] systemd-timedated[740]: ==740==WARNING: ptrace appears to be blocked (is seccomp enabled?). LeakSanitizer may hang.
[   47.524680] systemd-timedated[740]: ==740==Child exited with signal 15.
...
[ 1555.734223] systemd-oomd[93]: ==93==WARNING: ptrace appears to be blocked (is seccomp enabled?). LeakSanitizer may hang.
[ 1555.734223] systemd-oomd[93]: ==93==Child exited with signal 15.
...

It is a false positive because we disable the seccomp filters
system-wide for our units in the sanitizer jobs.

Now, from what I've seen so far this happens only in
Type=notify(-reload) units that also utilize bus_event_loop_with_idle().
This, combined with the fact that the ptrace()-check child process from
[0] checks only if the child process was killed by _any_ signal, means
that if the systemd unit exits on its own after becoming idle and then
something sends it SIGTERM (either via explicit `systemctl stop` or
during system shutdown), this SIGTERM might hit the ptrace()-check child
process from the sanitizer handler (as we also send the signal to all
processes in the target cgroup), which the parent process then
mistakenly evaluates as a blocked ptrace() syscall, even though the
check process wasn't killed by SIGSYS.

I filed this as [1] to the LLVM project, but let's also temporarily
ignore the warning in the sanitizer report processing, as it currently
causes annoying test fails.

[0] a708b4bf21
[1] https://github.com/llvm/llvm-project/issues/193714

(cherry picked from commit 445f980548)
(cherry picked from commit b094415c5a)
2026-05-27 12:20:19 +01:00
Frantisek Sumsal
be2d065915 test: wrap even more binaries when running with sanitizers
Turns out that the util-linux dep on libsystemd caused more fun than I
originally anticipated:

$ lddtree /usr/bin/dfuzzer
dfuzzer => /usr/bin/dfuzzer (interpreter => /lib64/ld-linux-x86-64.so.2)
    libgio-2.0.so.0 => /lib64/libgio-2.0.so.0
        libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0
        libz.so.1 => /lib64/libz.so.1
        libmount.so.1 => /lib64/libmount.so.1
            libblkid.so.1 => /lib64/libblkid.so.1
            libsystemd.so.0 => /lib64/libsystemd.so.0
                libm.so.6 => /lib64/libm.so.6
                    ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
        libselinux.so.1 => /lib64/libselinux.so.1
            libpcre2-8.so.0 => /lib64/libpcre2-8.so.0
...

Also, the tpm2 utils now depend on libudev through libcurl -> libssh ->
libfido2 dep chain:

$ lddtree /usr/bin/tpm2_pcrread
tpm2_pcrread => /usr/bin/tpm2_pcrread (interpreter => /lib64/ld-linux-x86-64.so.2)
    ...
    libcurl.so.4 => /lib64/libcurl.so.4
    ...
        libssh.so.4 => /lib64/libssh.so.4
            libfido2.so.1 => /lib64/libfido2.so.1
                libcbor.so.0.13 => /lib64/libcbor.so.0.13
                libudev.so.1 => /lib64/libudev.so.1
                    libgcc_s.so.1 => /lib64/libgcc_s.so.1
...

Follow-up for 8030e0b19e.

(cherry picked from commit a8400c8f1a)
(cherry picked from commit 13043ccbd1)
2026-05-27 12:20:19 +01:00
Luca Boccassi
f39c0b11e1 repart: trim NUL bytes from verity sig split artifact
The verity signature partition content is a bare JSON object. Repart
pads it with zeros to fill the GPT partition. But when splitting out
the content as an individual file, the padding remains, so it's not
a valid text file.

jq started rejecting files with NUL bytes to fix a security issue:
6374ae0bcd

Trim the output when writing these files out.

(cherry picked from commit b54ef83414)
(cherry picked from commit dd9029d670)
2026-05-27 12:20:18 +01:00
Frantisek Sumsal
0fb9ccba5e test: avoid using external commands in trap handlers
In #39675 the reported fail was as follows:

5580s [  247.559994] TEST-13-NSPAWN.sh[1858]: Exported 93%.
5580s [  247.659002] TEST-13-NSPAWN.sh[1858]: Exported 95%.
5580s [  247.785893] TEST-13-NSPAWN.sh[1858]: Operation completed successfully.
5580s [  247.923727] TEST-13-NSPAWN.sh[1858]: Exiting.
5580s [  258.300406] TEST-13-NSPAWN.sh[1074]: + machinectl import-raw /var/tmp/container-export.raw container-raw-reimport
5580s [  258.323328] TEST-13-NSPAWN.sh[1884]: The 'machinectl import-raw' command has been replaced by 'importctl -m import-raw'. Redirecting invocation.
5580s [  258.659982] TEST-13-NSPAWN.sh[1884]: Failed to transfer image: Remote peer disconnected
5580s [  258.734218] TEST-13-NSPAWN.sh[1074]: + at_exit

Turns out that the real reason behind this fail is that the machine was
under heavy load due to a busy-loop from the stub init. The cause of
this is a bug in bash, where running commands that fork (i.e. not
built-ins) can cause a permanent busy-loop due to a desync in trap
handling if you send the signals to the bash process _just right_:

[   90.855318] TEST-13-NSPAWN.sh[1074]: + machinectl poweroff long-running long-running long-running
[   90.855318] TEST-13-NSPAWN.sh[1074]: + machinectl reboot long-running long-running long-running
[   90.928980] systemd-nspawn[1679]: ++ touch /poweroff
[   90.928980] systemd-nspawn[1679]: +++ touch /reboot
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + wait
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + wait
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + :
[   90.928980] systemd-nspawn[1679]: + wait
...

$ journalctl --file TEST-13-NSPAWN-1.journal -o short-monotonic --no-hostname --grep "^\+ wait$" | wc -l
349734

So the stub-init was hammering the machine in a tight endless loop,
which then caused systemd-importd to timeout when talking to D-Bus:

[  258.300096] TEST-13-NSPAWN.sh[1074]: + machinectl import-raw /var/tmp/container-export.raw container-raw-reimport
...
[  258.415319] systemd-importd[1859]: Unable to request name, failing connection: Method call timed out
[  258.483662] systemd-importd[1859]: Bus n/a: changing state RUNNING → CLOSING
[  258.605442] systemd-importd[1859]: Bus n/a: changing state CLOSING → CLOSED
[  258.659958] TEST-13-NSPAWN.sh[1884]: Failed to transfer image: Remote peer disconnected

Given this is not our issue, let's work around it by using just
built-ins from the trap handlers, which are not susceptible to this bug.

Resolves: #39675
(cherry picked from commit 4d92c72b81)
(cherry picked from commit d1f98dffb3)
2026-05-27 12:20:18 +01:00
Frantisek Sumsal
b16b357fc1 compress: gracefully handle a truncated ZSTD frame
If a journal file contains a truncated ZSTD frame (i.e. a frame with
Frame_Content_Size > 0, but with not enough data in Data_Block),
ZSTD_decompressStream() would return a non-zero, non-error value. This
would then skip the error path in the ZSTD_isError() branch and we'd hit
the following assert:

$ build-local/journalctl -o cat --file zstd-truncated.journal
Assertion 'output.pos >= prefix_len + 1' failed at src/basic/compress.c:1236, function decompress_startswith_zstd(). Aborting.
Aborted                    (core dumped) build-local/journalctl -o cat --file zstd-truncated.journal

Let's handle this situation gracefully and return EBADMSG instead.

Also, add another journalctl invocation to the corrupted-journals test
that goes through the sd_journal_get_data() -> decompress_startswith_zstd()
code path which, among other things, covers the issue when run on the
provided journal file.

(cherry picked from commit 35eb598af2)
(cherry picked from commit a9cfbed091)
2026-05-27 12:20:18 +01:00
Frantisek Sumsal
eb3e1a9d1b test: append .journal to unpacked corrupted journals
Otherwise `journalctl --directory=` skips over them in the second part of
the test.

(cherry picked from commit e869c83367)
(cherry picked from commit 7a83d5cc3c)
2026-05-27 12:20:18 +01:00
Luca Boccassi
b808894777 machined: gate metadata querying behind inspect-machines/images action
Ensure only privileged users can call the system scope machined's
APIs that get data out of a machine

Follow-up for 1bd979dddb
Follow-up for 9153b02bb5

(cherry picked from commit 3e716178cc)
(cherry picked from commit 6e6aa47f46)
2026-05-27 12:20:18 +01:00