network-generator writes generated command line configuration below
the alternate root passed with --root=, but network.* credentials
were copied to fixed host /run paths.
Build the credential target directories with arg_root before passing
them to pick_up_credentials(). This keeps normal boot behavior
unchanged while making credential output land in the requested root.
Fixes#43442.
A `.swap` unit can end up **active but unloadable, with no device**, and
stopping such a unit aborts PID 1.
### What it looks like
```
$ systemctl show 'dev-disk-byx2dpartlabel-primary.swap' -p LoadState,ActiveState,What
LoadState=not-found
ActiveState=active
What= # <-- no device
$ systemctl stop 'dev-disk-byx2dpartlabel-primary.swap'
systemd[1]: About to execute: /usr/sbin/swapoff # <-- no argument
systemd[1]: Caught <ABRT>, from our own process.
systemd[1]: Freezing execution.
```
PID 1 stays alive but frozen, so the machine stops answering `systemctl`
and never reboots.
### How it happens
1. systemd creates one `.swap` unit per udev device link of every device
in `/proc/swaps`.
2. A device link gets repointed at another device while the swap stays
on. `/proc/swaps` doesn't change, so nothing re-examines the unit — it
stays active.
3. The next `daemon-reload` drops all units and rebuilds them.
Enumeration from `/proc/swaps` no longer produces this name, so only the
deserialization brings the unit back: by name, with no fragment on disk.
4. `swap_load()` only calls `swap_add_extras()` for units that loaded a
fragment or are backed by `/proc/swaps`, so this one gets neither a
`What=` nor a patched `ExecContext`.
5. `swap_coldplug()` restores its active state anyway.
6. Shutdown stops it. `unit_stop()` deliberately permits stopping units
whose load failed, so it reaches `exec_spawn()` and trips the
`PrivateVarTmp=` assertion in `exec_context_serialize()`.
Since the D-Bus DNS-SD API was introduced in c3036641f0ed (v236),
`RegisterService()` has created an `sd_bus_track` object to destroy the
registered service when the registering client disconnects from the bus.
However, the track object is a `_cleanup_(sd_bus_track_unrefp)` local in
`bus_method_register_service()` that is never stored anywhere, so it is
destroyed again as soon as the method handler returns. The vanish
handler (`dnssd_registered_service_on_bus_track()`) has thus been dead
code for the past ~8 years.
The observable effect: services registered via D-Bus silently persist
after the client disconnects — unowned, advertised until resolved exits,
and impossible to re-register since the identifier stays taken
(`DNSSD_SERVICE_EXISTS`). At the same time, the registration doesn't
survive a resolved restart, so the current behavior is neither reliably
ephemeral nor reliably persistent. Noticed while reviewing a project
that (unknowingly relying on this bug) registers a service with a
one-shot `gdbus call` and expects it to persist.
This PR:
1. splits the goodbye/zone-removal logic out of
`bus_dnssd_method_unregister()` into a helper — the vanish path needs
the full teardown, not just `dnssd_registered_service_free()`, which
would leave the service's RRs published in the per-link mDNS zones;
2. stores the track object in `DnssdRegisteredService`, making client
tracking work as originally intended;
3. documents the lifetime semantics in `org.freedesktop.resolve1(5)`
(matching the equivalent Avahi D-Bus API, whose entry groups are
likewise bound to the client connection) and points to `*.dnssd` files
for registrations independent of a client's lifetime;
4. adds a TEST-75 case covering the connection-bound lifetime.
Note this is a behavioral change for fire-and-forget clients (one-shot
`busctl`/`gdbus` invocations). Arguably those were never working
reliably (registrations silently vanished on any resolved restart, and
stale entries blocked re-registration), but if this is deemed too risky,
the alternative would be to drop the dead tracking code and codify the
persist-until-exit behavior instead — I'd argue tracking as originally
intended is the better contract.
Verification: code compiles; the new integration test is included.
shellcheck 0.10+ reports SC2329 ("This function is never invoked") for
the per-testcase cleanup() functions in TEST-75-RESOLVED.sh, which are
only invoked indirectly via trap. The existing SC2317 markers don't
cover it, and inserting a new testcase shuffles which definitions the
heuristic fires on, making pre-existing findings show up as new in
differential CI runs. Extend the markers to SC2317,SC2329, matching
what testcase_dot_strict_per_link_verify() in this file and other test
units already do.
Verify that a DNS-SD service registered via the D-Bus RegisterService()
call is bound to the lifetime of the client's bus connection: since
busctl disconnects right after the call returns, the service must be
unregistered again shortly after. Wait for resolved's vanish handler
log message as proof that the client tracking triggered the
unregistration, check that a subsequent UnregisterService() fails
specifically because the service is not known anymore, and verify that
the identifier can be registered again — previously it stayed taken by
the vanished client's service forever, failing with
DNSSD_SERVICE_EXISTS.
A dummy link with mDNS enabled makes sure the per-scope goodbye/zone
teardown path actually runs, and since resolved would be restarted
automatically if it crashed in it, letting the D-Bus level checks pass
vacuously, verify the InvocationID stayed the same throughout.
Currently `RestrictFileSystemAccess` isn't trying hard enough to enforce
W^X and thus there are still places where an executable and writable
mapping can be created:
* `/proc/<pid>/mem` `FOLL_FORCE` writes
* `PTRACE_POKE{TEXT,DATA}` `FOLL_FORCE` writes
* `MAP_PRIVATE | MAP_EXECUTABLE` memory mappings
Let's block all of these mechanisms. Do note that
`RestrictFileSystemAccess` is still in very active development and also
cannot meaningfully be used on general purpose distros and systems.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Make sure the tests can tell the difference between an actual denial and
a probe that simply cannot be run.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
The custom help() is replaced by a COMMAND() description, matching the
other report-sign services. The abstract is now wrapped at 80 columns
in the help output.
Use the new copy timestamp clamping mechanism from the previous commit
to fix unreproducible wall-clock files in the generated images.
That covers both modes: online mode writes through the kernel, and
offline mode stages the tree in a temporary directory before handing it
to mkfs or mcopy. `mcopy -m` then carries the clamped mtimes into the
FAT.
This complements commit 34c3d57474 (directory times) and commit
f191ca982c (FAT insertion order).
Cover all combinations (online/offline, with and without epoch) in the
new `testcase_vfat_reproducibility()`. Update `testcase_make_symlinks()`
to cover the symlink creation/re-fix their parent directory code paths.
Sadly, images are still not reproducible byte for byte. Document
systemd-repart's $SOURCE_DATE_EPOCH handling and remaining
reproducibility issues in the manpage.
systemd-udevd is the same binary as udevadm, so the introspection data
describes both commands, from either name. The COMMAND intentionally
owns no verbs — all of udevadm's verbs are defined in udevadm.c right
after its own COMMAND, so that they are attributed to it.
The -V/--version output (GIT_VERSION) is preserved.
The custom help() is replaced by the common verb help, which derives the
synopsis, abstract, and option list from the verb declaration in
udevadm.c and the "udevadm-control" option namespace. The synopsis
makes use of the new nulstr-argspec functionality:
> udevadm [OPTION…] lock [OPTION…] COMMAND
> udevadm [OPTION…] lock [OPTION…] --print
The custom help() is replaced by the common verb help, which derives the
synopsis, abstract, and option list from the verb declaration in udevadm.c
and the "udevadm-control" option namespace. The new VERB_DEPRECATED flag
is used.
The verbs declare their subcommand option namespaces, so the
introspection data describes the options of every subcommand, nested in
the verb objects.
The bare version number output (a dracut compatibility requirement) is
preserved for --version/-V and the "version" verb.
The "lock" verb's argument specification is simplified to "COMMAND" --
other verbs do not mention their options in the argspec either, and the
subcommand help states where the options may go.
UpdateHomeEx needs to set up the home temporarily so that it can
write the refreshed identity records. Inspect and password changes use
the same setup path for metadata-oriented work.
For LUKS homes with luksDiscard=no, home_setup_luks() fully
allocates the backing image while setting it up. If diskSize=max was
previously written to a sparse image, this can fail with ENOSPC before
the user can disable auto-resize mode again.
Add a setup flag that lets metadata operations skip the full-image
fallocate step. Real create, activate, and resize paths keep the
existing allocation behavior.
Before, reproduced on Ubuntu 26.04 with /home on tmpfs:
homectl create reprohomed \
--storage=luks \
--fs-type=btrfs \
--disk-size=300M \
--auto-resize-mode=shrink-and-grow \
--luks-discard=no
homectl update reprohomed --disk-size=max
dd if=/dev/zero of=/var/tmp/homed-repro/filler bs=1M count=500
systemctl restart systemd-homed.service
homectl update reprohomed --auto-resize-mode=off
Operation on home reprohomed failed:
Not enough disk space for home reprohomed
Fixes#34527
Follow-up for: ab3b6fcb40
When a partition is deleted from a table containing multiple partitions
of the same type, filling the resulting partition-number gap can place
a new partition before an existing partition matched to an earlier
definition. This changes definition matching on the next invocation and
breaks idempotency.
Keep new partitions after existing partitions of the same type. If no
partition table slot is available after them, fall back to the first
unused slot.
Which existing partition is matched to which definition is still
determined by partition type and partition number order, as documented,
and is unchanged by this.
Fixes#43449
When an administrator installed a custom keyring under /etc,
signature verification selected it instead of the vendor keyring
under /usr. That could make vendor-signed system updates stop
verifying after adding local keys.
Collect all readable default keyrings, including the current and
legacy /etc paths, and pass temporary copies to GnuPG with
separate --keyring options. Keep SYSTEMD_OPENPGP_KEYRING as an
explicit override, add regression coverage for keyring
coexistence, override behavior, and current-path signing, and
silence the expected shellcheck false positive in the test
cleanup helper.
Closes: #40702
The transactions-with-cycles subtest starts 20 mutually cyclic
services, reads the manager's TransactionsWithOrderingCycle ids over
varlink, and then requires a journal entry matching "cycle starting
with" for every id. On a fedora rawhide CI run the entry for
transaction id 42 was missing for the entire boot and journalctl
printed "-- No entries --", failing the unit, while the manager had
correctly recorded all 20 ids. In the exported journal of that boot,
transaction 42 kept only its debug-level enqueue line
transaction-cycle12.service: Trying to enqueue job
transaction-cycle12.service/start/replace
while the other 19 transactions each also kept the three messages
that follow it ("Found ordering cycle", "Unable to break cycle
starting with", "unfixable cyclic ordering dependency"), and PID1's
next message, accepted about 2 ms after the enqueue line, shows
journald itself kept ingesting.
The messages were lost, not late. The test VM boots with
systemd.log_level=debug, and the 20 cyclic starts made PID1 emit
about 12,400 debug messages within 30 seconds, 4,100 of them in the
final second, during which journald stalled for 94 ms between two
consecutive entries. PID1 gives its journal socket a 10 ms send
timeout (src/basic/log.c), and a message whose send times out is
either dropped outright, because log_struct() ignores the sendmsg
result and falls back only on formatting errors, or, for the plain
log calls that do fall back to kmsg, reappears as _TRANSPORT=kernel
text stripped of its structured fields, where a TRANSACTION_ID=
match cannot find it. The asserted messages are log_struct() calls,
so they are in the dropped class. Either way the journalctl
assertion comes up empty. This is also why the "journalctl --sync"
added in ed0727fecd does not help here: it only flushes what journald
already received.
Run the whole section, including the daemon-reload, at log level
info, and drain what the earlier subtests queued at debug level with
one "journalctl --sync" before the first start. The daemon-reload is
itself a heavy debug emitter that returns before journald has
drained its burst, so opening the quiet window after it would leave
that backlog competing with the first cycle messages. The two
messages the subtest greps for are emitted at LOG_ERR ("Unable to
break cycle starting with") and LOG_WARNING ("Job ... deleted to
break ordering cycle starting with") in src/core/transaction.c, and
the ids are recorded into transactions_with_cycle on the same code
path directly before them, so the assertion keeps its full strength
while the debug flood that displaced it is gone.
A single at_exit handler installed at the start of the test restores
the boot-time log level when any subtest aborts, and cleans up the
transient unit the aborting subtest had in flight, guarded on the
unit file existing as in TEST-26-SYSTEMCTL.sh. It replaces the
per-subtest restart_randomized_delay_cleanup() handler, so the two
subtests that change the log level share one restore path.
systemd-shutdown parsed a bunch of options, but had no way to print
them. Add the standard --help and --version options and the CLI
introspection.
parse_argv() is moved before the PID 1 check, so that the new options
also work when the binary is invoked manually. As PID 1 we can never
return from main() (the kernel would panic), so in that case parse
errors still freeze(), and the help output is followed by a freeze()
too. Ctrl-Alt-Delete and console reopening are re-enabled before
freezing, so that the freeze can be escaped through the kernel and the
error is visible, as before.
The --help/--version/introspect-cli option names are already listed in
the kernel command line exclusion list in proc-cmdline.c.
--introspect-cli follows the same deferred pattern as --help: parse_argv()
only records the action, and it is executed in the same place where
ACTION_HELP and ACTION_VERSION are handled.
The help is looked up by explicit name: in the multicall configuration
the systemd and systemd-executor commands share one binary, so the
"first COMMAND" default would depend on link order.
The "This program takes no positional arguments." line is dropped from
the help output — the default "[OPTION…]" synopsis already says so.
(And also, this is not quite true. It does take positional args when
called as init.)
This converts systemd-homed, -hostnamed, -importd, -localed, -logind,
-machined, -networkd, -portebled, -resolved, -sysupdated, -timedated,
and -timesyncd.
The service name and description move from service_parse_argv() arguments
into a COMMAND() description that each daemon now defines. The
service_parse_argv() macro captures the calling binary's verb section,
where that COMMAND is found, while the options are still defined and
parsed in libshared, in the new "service" option namespace that each
COMMAND references. (The named namespace makes sure that options defined
by other translation units in libshared can never leak into the
services' parsers.)
The supported features are declared via option group filtering: each
COMMAND lists "Options" plus "Bus introspection" and/or "Runtime scope".
Unsupported options are now rejected by the parser as unknown options
(and are not shown in --help), replacing the runtime "This service does
not support …" errors.
The help output changes slightly: the "Bus introspection" and "Runtime
scope" option groups now get their own headings, and some descriptions
were reworded to the imperative form used elsewhere.
Standard parse_argv() func is added. --version is now accepted
(previously only the help forms were recognized, via argv_looks_like_help()).
The synopsis changes from "systemd-integritysetup COMMAND ..." to the
standard "systemd-integritysetup [OPTION…] COMMAND …", and the help output
gains an Options section. "help" as the first argument keeps working via
the hidden common help verb.
Previously, we'd just print help and exit with success if no arguments
were given. This seems unexpected and wrong. The program now prints the
usual error message:
Command verb required (one of attach, detach, help).
A newly created network namespace may disallow ICMP echo sockets for
unprivileged users even when their GIDs are mapped into the container.
When creating both user and network namespaces, initialize
net.ipv4.ping_group_range using the mapped GID range capped at INT32_MAX.
This follows the system-wide default from sysctl.d/50-default.conf while
respecting the user namespace mapping and the kernel's accepted limit.
Leave externally supplied network namespaces untouched and treat write
failures as non-fatal warnings.
Add regression coverage for the default 64K mapped range using the tools
already available in the minimal container image.
Fixes#41603
This time, various commands with non-trivial requirements are handled.
So the series is shorter, but has a pattern of feature additions and
then those new features being used. The way that --help output is
formatted is changed a bit in various places. Those changes are
described in individual commits.
22 'static int help()' functions left after this.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added.
Options are now in two groups: "Common options" and Mount options". In
--help, for systemd-mount, both groups are shown. For systemd-umount, only
the first. This changes the behaviour a bit: previously, both groups were
shown together as one list. I think the new behaviour is actually a bit
better, because it makes it easier for the user to figure out that the
commands share common options and one of the commands has its private
second group. But if people think that the previous behaviour should
be restored, we could add a display options to squish the groups back
together.
--help now goes through the pager, like other commands with --no-pager.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. --help now goes through the pager, like other
commands with --no-pager.
Also, previously, -h/--help/--version were listed in the "Commands"
section. This was cute, but recreating this in the new scheme would
be complicated. Also, it seems unnecessary. --help/--version and some
other commands terminate the program in all binaries, so they could
be considered "commands" in all cases. But we printed them together
with verbs only in a few cases. So I think it's fine to move them
back to the "Options" section. This makes the description of options
much more consistent between different programs.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The note about invocation as 'installkernel' is
kept as the footer. Verb and option column widths are kept separate, since
the verb table is very wide. --help now goes through the pager, like other
commands with --no-pager.
A separate COMMAND block is included for installkernel, but it is only
used for introspection data.
The custom halt_help() and shutdown_help() are replaced by COMMAND()
descriptions (one per command name, halt/poweroff/reboot sharing the
"halt" option namespace), and --introspect-cli is added to both parsers.
halt/poweroff/reboot now each reference their own man page name.
Create the file with open_tmpfile_linkable_at().
Write the recovery key and trailing newline to the temporary fd.
Set the final mode to 0600 before publishing it.
Link it into place with link_tmpfile_at(..., LINK_TMPFILE_SYNC).
As discussed in the PR, those fields can go down, so they cannot be advertised
as type COUNTER. But the type is shared for the whole family, so we need to
create a new family to keep the other ones as COUNTER and add the new ones
as GAUGE.
kernel/sched/cputime.c says above get_cpu_idle_time_us() and get_cpu_iowait_time_us():
> Note that this is partially broken due to the counter of iowait tasks that
> can be remotely updated without any synchronization. Therefore it is possible
> to observe backward values within two consecutive reads.
steal is apparently also unreliable because it is reported by the hyperviser.
So let's be cautious and report it as gauge too.
Extend the io.systemd.Basic metric families with host-level runtime
metrics: cumulative per-state CPU seconds, memory in use (MemTotal minus
MemAvailable), swap in use, the kernel's 10s pressure stall averages
(cpu/memory/io x some/full). Partitions and stacked devices are excluded
from the disk counters, since their traffic is already accounted for in
the parent device.
Also extend the TEST-74 report subtest with checks for the new metrics.
Network metrics are not added, because the service runs with
PrivateNetwork=yes, and it doesn't make sense to report stats for 'lo'.
After some back-and-forth, I settled on "CPUUsage". We use this scheme of
capitalization in other metric family names: "IPv4Public", "IPv6Public",
IPv4AddressState", "IPv6AddressState", "OSRelease" "SMBIOS" "BootID",
"CPUsOnline", "MachineID", "MachineInfo", "OSRelease",
"SMBIOS.SystemManufacturer", "TPM2.Manufacturer", "TPM2.VendorString",
"IOReadBytes", "IOReadOperations", "CGroup". The exception is
"io.systemd.cgroup.CpuUsage". I think we should treat that one as a
mistake and consider changing it to conform.
The custom help() is replaced by a COMMAND() description, and
--introspect-cli is added. The generic help-verb check in the test is
filtered out, since systemctl's "help" verb shows unit manuals and fails
without arguments.
Arch rolling now ships Nmap 7.991, which contains Nmap commit
b408fc2, titled "Ignore stdin with recv-only"[1].
That change omits stdin from the Ncat descriptor list in recv-only
mode. For a Unix listener, the listening socket is then its sole
descriptor. Ncat enters its listen loop only when that list has more
than one descriptor or a connection already exists, so it exits
immediately after bind and leaves the socket pathname behind.
systemd-oomd sees that stale pathname, tries to invoke the hook, and
gets ECONNREFUSED. The notification output therefore remains empty
and the jq assertion fails. The problem is visible in trunk's CI
failures[2].
Use socat for these one-way Unix listeners. It remains in accept while
waiting for the hook and is already installed in integration images.
[1] https://github.com/nmap/nmap/commit/b408fc243ce26da7ca497595833c14ce36a5e1a4
[2] https://github.com/systemd/systemd/actions/runs/32622985037/job/97153925154
The DBus API already exposes the parsed machine-tags list via the Tags
property but varlink clients needed to parse the raw TAGS= line from
MachineInformationData (which also required implementing tag name
validation if the tags would later be used with SetTags, to avoid
spurious errors).
So, provide the same information that DBus gets (a list of pre-parsed
tags with bad tags gracefully removed) as a new MachineTags field
returned by Describe -- this does mean that the DBus API now exposes the
same data in two ways but making Describe() consistent is more important
and mirrors the OperatingSystem* class of properties.
image_rename() updated the Image object name and path before
computing the source paths for auxiliary files. As a result, the
auxiliary rename loop looked for files with the new image name,
while existing sidecars such as .roothash, .verity, and
.raw.tpmstate still used the old image name.
Delay updating the Image object until after renaming its settings
and auxiliary files. This lets image_auxiliary_path() resolve
existing sidecars from the old image name while
rename_auxiliary_file() assigns the new name.
Extend the import test raw image rename coverage to check
representative sidecars are renamed together with the image.