networkctl,networkd: add --no-reconfigure flag to networkctl reload
Add a new --no-reconfigure flag to 'networkctl reload' that reloads
.network and .netdev files from disk without reconfiguring any network
interfaces. This may be useful to avoid reconfiguring multiple interfaces
simultaneously when multiple .network files are updated, or when an updated
.network file is applied to multiple interfaces.
On the networkd side, manager_reload() gains a reconfigure_links parameter
that gates the per-link reconfiguration loop. A new io.systemd.Network.Reload
varlink method is added that exposes this as an optional reconfigureLinks
boolean (defaults to true). Both plain 'networkctl reload' and
'--no-reconfigure' now unconditionally call this method first. If an older
networkd returns MethodNotFound, plain reload falls back to
io.systemd.service.Reload for backward compatibility; '--no-reconfigure'
fails with a clear error in that case.
core/dbus: do not block the manager on GetId during bus (re-)connection
bus_init_api() issued a synchronous GetId call on every API bus
(re-)connection to decide whether saved subscription state could be
coldplugged onto the new connection.
If the D-Bus socket unit is listening while the message bus daemon
behind it is gone, connect() succeeds against the socket backlog but
nothing answers the authentication handshake. The synchronous call
then blocks PID 1 for BUS_AUTH_TIMEOUT (90 seconds by default), and
queued bus operations can trigger repeated reconnection attempts.
This was observed during shutdown as roughly 15 minutes of teardown
progressing only in 90-second intervals.
Query the instance ID asynchronously on every connection. Defer API
setup until the reply is processed, so saved subscriptions are
validated and coldplugged before new subscription requests can arrive.
If the query cannot be queued or its reply is invalid, discard the
unvalidated state and expose the API without blocking the manager.
Reset the live bus ID on every connection and serialize pending bus ID
and subscription state across reload and reexec. During daemon-reload,
preserve state that was already awaiting the asynchronous reply while
discarding the duplicate state produced by the reload itself.
Also remove the now-unused synchronous bus_get_instance_id() helper.
password-quality-util-passwdqc: restore password-quality-util.h include
suggest_passwords() references the N_SUGGESTIONS macro, which is defined in
password-quality-util.h. Commit ff33c8f87d ("Extend test-dlopen-so to also
cover cases when built without support") introduced the per-backend split
headers: for the pwquality backend it added the new
password-quality-util-pwquality.h include while keeping password-quality-util.h,
but for the passwdqc backend it replaced password-quality-util.h with
password-quality-util-passwdqc.h (which only pulls in shared-forward.h). As a
result N_SUGGESTIONS is no longer declared in the passwdqc translation unit and
the build fails when the passwdqc backend is enabled.
The passwdqc backend is not exercised by the default CI, so this went
unnoticed. Add the include back, matching the pwquality backend.
Let's make timer prop handling less special, and more like path/socket
handling. Let's move the checks for at least one OnXYZ= setting to a
common place at the end of parsing, instead of explicit checks for each
property.
Removed note clarifying that portable services are only for system services and not user services, and changed comparisons to "system services" with just "services". With newer systemd versions, `systemd-portabled` can be run as a user service.
dlopen-note: downgrade all dlopen notes in libsystemd.so and libsystemd-shared.so
Since all executables now manage their required dlopen notes directly
within their own source code with explicit priority levels, it is no
longer necessary to declare high-priority dlopen notes in the shared
libraries themselves.
Since 4c0d8d967300fde858f83ec4b361db19e3e257c8, most dlopen notes are
set at the beginning of the executables. Let's manage all dlopen notes
there, rather than setting them where dlopen is called.
Note that the only exceptions are the LIBBPF_NOTE for networkd and
nsresource. Since dlopen_bpf() is wrapped in an `#if` guard, the notes
are instead set within the corresponding functionality.
As a result, the DLOPEN_FOO() wrapper macros are no longer needed and
can be dropped completely.
The purpose of this header was to provide MIT-0 sources that can be copied
and pasted liberally. Including an LGPL-2.1+ header from it deafeats its
purpose. Make it self-standing again.
network: silence false warning about unitialized variable
[1177/3647] Compiling C object systemd-networkd.p/src_network_networkd-bridge-vlan.c.o
In function ‘bridge_vlan_append_set_info’,
inlined from ‘bridge_vlan_set_message’ at ../src/network/networkd-bridge-vlan.c:257:21:
../src/network/networkd-bridge-vlan.c:162:28: warning: ‘untagged’ may be used uninitialized [-Wmaybe-uninitialized]
162 | if (untagged == u)
| ^
../src/network/networkd-bridge-vlan.c: In function ‘bridge_vlan_set_message’:
../src/network/networkd-bridge-vlan.c:111:14: note: ‘untagged’ was declared here
111 | bool untagged, pvid_is_untagged;
| ^~~~~~~~
sysinstall: don't ask whether to erase a disk that contains no partitions
When the target disk carried no partitions, the installer still asked:
Please type 'keep' to install the OS in addition to what the disk
already contains, or 'erase' to erase all data on the disk:
The question is meaningless in that case: there's nothing on the disk
worth preserving, and both answers lead to the same result.
Modify fsystemd-repart to report in the dry-run reply of
io.systemd.Repart.Run() the number of partitions currently on the disk.
The field is only included if the existing partition table was actually
read, i.e. in the 'refuse' and 'allow' empty modes, and omitted
otherwise.
Make systemd-sysinstall skip the erase question if the reply positively
indicates that there are no partitions, proceeding as if 'keep' was
selected.
sysinstall: suppress 'no' prompt to begin installation
The user has to type 'yes', but it doesn't mean that the default of
'no' is ever useful. Suppress it, so the user doesn't have to press
backspace twice.
udev-util: bound leading whitespace skip in udev_replace_whitespace (#42757)
udev_replace_whitespace() is documented to read at most 'len' bytes from
'str':
- the strspn() skip of leading whitespace stops at a non-space byte or
NUL, not at 'len'
- ata_id passes the space padded, non-NUL-terminated ATA IDENTIFY
model/serial/fw fields
- an all-blank field reads off the end of the 512-byte hd_driveid stack
struct
Capped the skip to 'len'; existing outputs are unchanged. Added a
regression test.
discover-image: don't ignore symlinks to raw images
Since 5c6bb289990ba53898cbc62db6e732ecb9dc87ac image_discover() uses
chaseat() to chase the path to the image. This however breaks the raw
image check in image_make() as "path" is now not the symlink itself, but
the symlink target.
The endswith(path, ".raw") check is now performed on "/.../foo.squashfs"
instead of "/.../foo.raw", making it false and thus ignoring the image
symlink completely.
Address this by also checking if the pretty name is set - if so, and the
path is a regular file, the caller must've been image_find() or
image_discover() which already checked if the original path ends in .raw
and is a regular file.
repart: log allocation failure at debug level in Varlink service mode
When systemd-sysinstall probes whether an installation would fit by
calling io.systemd.Repart.Run() in dry-run mode, systemd-repart runs as
a child process sharing sysinstall's stderr. When the requested
partitions didn't fit, context_ponder() logged its failure at LOG_ERR
before vl_method_run() converted it into a structured Varlink error
(InsufficientFreeSpace or DiskTooSmall), which the client then reports
to the user in its own words. The internal message hence appeared
interleaved with the user-facing report:
Can't fit requested partitions into available free space (1.9G), refusing.
The selected disk is not large enough for an OS installation.
The size of the selected disk is 0B, but a minimal size of 15.7G is required.
Log at LOG_DEBUG when running as a Varlink service, and keep LOG_ERR
for CLI invocations, where this message is the primary error report
shown to the user.
repart: report the actual block device size in currentSizeBytes
The io.systemd.Repart interface documents the currentSizeBytes field as
the size of the selected block device, both in the Run() method's
dry-run reply and in the InsufficientFreeSpace and DiskTooSmall errors.
The implementation however filled it in from the "current size"
computed by determine_auto_size(), which means something else entirely:
the size of the image as it currently exists, i.e. the GPT metadata
overhead plus the sizes of all existing partitions — a metric designed
for growing image files with --size=auto. For a disk that is being
partitioned from scratch (i.e. carries no partition table yet) that
value is 0.
As a result, when systemd-sysinstall was pointed at a blank 2G disk
that is too small for the OS installation, it reported:
The selected disk is not large enough for an OS installation.
The size of the selected disk is 0B, but a minimal size of 15.7G is required.
Report context->total instead, i.e. the actual size of the block
device, which is also the value the DiskTooSmall check compares the
required size against. Do this in all three places that send
currentSizeBytes, matching the documented semantics of the field.
repart,dissect: explicitly support DDIs that are both signed *and* encrypted (#43009)
This is a pretty relevant usecase: preparing an image on some trusted
host, submitting it to some other host that authenticates it and
decrypts it, and consumes it only then.
machined: Allow user ids in open_shell for machine-dbus
Previously "machinectl shell --uid=1000 <container>" resulted in a
sucessful drop into a shell in the respective target machine. After
commit a9e9288288567beae57337ae903dd3b6c774001c this is no longer the
case.
udev-util: bound leading whitespace skip in udev_replace_whitespace
The function documents that at most 'len' bytes are read from 'str',
but the leading whitespace skip used strspn(), which is bounded only
by a non-whitespace byte or a NUL. ata_id passes the space padded,
non-NUL-terminated ATA IDENTIFY fields, so an all-blank model reads
past the buffer. Use strnspn() to cap the skip to 'len'.
Like strspn(), but reads at most 'n' bytes from the input. strspn()
is bounded only by a non-matching byte or a NUL, so it over-reads a
buffer that is all matching bytes and not NUL terminated within 'n'.
For various cases it is interesting to both sign and encrypted a file
system, for example to prepare it on one host and provide it to another.
Let's explicitly support preparing this in systemd-repart via setting
both Verity= and Encrypt=.
Pass relax_extension_release_check through the directory extraction
path instead of hardcoding false. Directory extensions now honor the
same --force relaxation as dissected images.
Before:
directory image extraction always used strict extension-release name
checks. --force relaxed other extension paths but still rejected a
renamed directory extension with matching metadata.
sysext: validate work directory metadata before removal
unmerge_hierarchy() joined the persisted work_dir value directly with
--root=. An empty value therefore resolved to the root itself and was passed
to rm_rf().
Require the decoded metadata to name a non-empty, safe, normalized relative
path before constructing the removal target. Add coverage using a disposable
root with deliberately emptied metadata.
shift-uid: close consumed directory fds on early return
recurse_fd() consumes each directory fd passed to it, but it has no
cleanup set up until after take_fdopendir() succeeds.
Errors and skipped procfs, sysfs, or read-only subtrees therefore leak the
incoming fd.
path_is_root_at() returns a negative errno when it cannot determine whether
a target is the root file system. rm_rf_at() treats those errors as a
negative answer and continued with destructive operations.
Propagate root-check errors before modifying the target, while preserving
REMOVE_MISSING_OK for an absent path.
vconsole: reject empty layout during keymap conversion with error
A leading-dash console keymap or leading-comma X11 layout can produce an
empty layout while converting between the two formats. find_converted_keymap()
then asserts on it, allowing malformed input to abort callers such as localed.
Return EINVAL for an empty derived layout instead.
resolved: preserve unchanged question on asymmetric redirect
dns_question_cname_redirect() returns no replacement when a question
already matches a CNAME target or a DNAME does not apply. If only one of
the UTF-8 and IDNA questions redirects, dns_query_cname_redirect() then
installs NULL for the unchanged side.
Keep a reference to the original question on whichever side does not
redirect, and update the existing asymmetric DNAME test to verify it.
MHDDaemonWrapper_free() unconditionally unrefs both event sources, but
setup_microhttpd_server() could return before initializing either pointer.
Zero-initialize the wrapper so cleanup after MHD startup failures safely
unrefs NULL.
journal-remote: remove disabled compression entry before freeing
compression_config_put() frees the COMPRESSION_NONE value when a later
algorithm is selected, but lefts the map entry pointing at it. Remove the
entry first so subsequent parsing, mangling, and teardown cannot access or
free stale memory.
network: cancel netlink calls for detached requests
Store the asynchronous netlink slot in the Request object and release it
when the request is detached. This cancels the pending callback instead of
keeping the request alive until its reply arrives.
The multipath route comparator looks up every nexthop in the first
route and hence compares each entry with itself. Compare both ordered
nexthop sets instead, including weights, as the hash function does.
Paul Meyer [Tue, 14 Jul 2026 11:26:56 +0000 (13:26 +0200)]
tpm2-util: keep the measurement log's torn-write marker intact
The userspace measurement log carries a sticky-bit marker while a writer
is between updating a measurement register and appending the matching
record, so that a writer dying in between leaves the log detectably
incomplete.
However, the next successful writer used to clear the marker again after
appending its own record, erasing the evidence that an earlier writer
had died and the log is still missing a record. Keep the marker set in
that case instead; the new record is appended and synced regardless. The
marker likewise stays set if the measurement itself fails, so that any
non-clean completion remains flagged: a spurious flag on a failed but
harmless measurement is preferable to erasing evidence of a real gap,
and PCR replay stays authoritative either way.
Finally, warn when systemd-pcrlock loads a marked log, so the resulting
PCR validation failures come with a hint at their cause.
Before, the field listing ignored the unit filter and listed unrelated
units, while the normal journal query applied the filter.
sd_journal_query_unique() cannot represent journalctl filters such as
unit, boot, time, cursor, or grep filters. Walking the journal line by
line would make field listing linear in the number of entries and
duplicate unique-value handling.
Keep the scope-option predicate next to add_filters(), and reject field
listings combined with options that actually limit the journal.
Display-only options such as --pager-end are left alone.
The target parameter length is added to two headers and aligned before
allocation. Check each operation and reject payloads that cannot be
represented by the device-mapper ioctl header.
gaih_addrtuple.addr has room for an IPv6 address, while IPv4 uses only
the first struct in_addr. Express the remaining range directly in terms
of that type so static analysis can prove the access remains within the
array.
* 88c420c621 Install new files for upstream build
* 5b7f67b86a Update changelog for 261.1-3 release
* 3f91c8567c NEWS: update about removal of sd-tpm dep
* e13ba94737 Drop obsolete TODO
* b0c5def366 systemd: downgrade systemd-tpm and mount to recommends
* e9eb859a3a systemd-tpm: depend on tpm-udev for rules and tmpfiles.d
* 42f74bb110 Drop obsolete comment from d/control
* fc40986137 debian/extra/network: use NamePolicy=keep mac on USB wifi devices
Kai Lüke [Wed, 15 Jul 2026 07:09:13 +0000 (16:09 +0900)]
oci-util: Don't fall back to default registry for explicit registries
When a reference specifies a registry like ghcr.io or quay.io for which
we don't have a registry config file, the fallback forced the default
registry which is wrong.
Only use the default as fallback when there is no explicit registry.
config_add_entry_loader_auto() returns NULL when the Windows loader
is missing. With reboot-for-bitlocker enabled, the caller still
assigned e->call and could dereference NULL.
This can happen when reboot-for-bitlocker is enabled but the ESP does
not contain EFI/Microsoft/Boot/bootmgfw.efi.
Before:
systemd-boot could dereference NULL while building the menu
Aritra Basu [Sun, 7 Jun 2026 06:04:11 +0000 (02:04 -0400)]
network: add IPv4ProxyARPAddress= and consolidate proxy ARP/NDP handling
This adds an IPv4 counterpart to `IPv6ProxyNDPAddress=` for adding
manual entries to the kernel's IPv4 neighbour proxy table (check via
`ip -4 neighbour show proxy dev <dev>`). systemd-networkd only exposed
`IPv4ProxyARP=` for per-interface `proxy_arp` sysctl (automatic proxy
ARP) with no way to manage manual entries from a .network file.
To avoid duplicating the IPv6 proxy NDP code path, both families are
now combined into a single new `networkd-neighbor-proxy` module. The
IPv6 behaviour is preserved: `IPv6ProxyNDPAddress=` still implies
`IPv6ProxyNDP=yes` unless `IPv6ProxyNDP=` is explicitly disabled and
entries are still dropped if the kernel has no IPv6 support.
The same rule is applied to `IPv4ProxyARPAddress=`. It implies
`IPv4ProxyARP=yes` when the sysctl is not explicitly set and has no
effect if `IPv4ProxyARP=` has been set to false.
This keeps the user model symmetric and predictable across both
families: a single per-address setting that turns on the matching
per-interface sysctl automatically, while still letting system
administrators opt out by setting the boolean explicitly to false.
Note that the IPv4 manual NTF_PROXY entries installed here would
actually function without `proxy_arp` (unlike IPv6, where `proxy_ndp`
gates the manual entries); the implication is kept for symmetry with
`IPv6ProxyNDPAddress=` and is now called out explicitly in the man
page, together with the fact that enabling `proxy_arp` also activates
interface-wide automatic proxy ARP for routed-toward addresses on
connected subnets.
Parser-time validation rejects addresses the kernel would refuse:
the ANY/null address for both families, IPv4 and IPv6 multicast
and the IPv4 limited broadcast 255.255.255.255.
shared/copy: simplify argument convention for reflink_range
reflink_range() would treat size==UINT64_MAX as "copy everything", but
only if the offsets were 0. There are only two callers: one always passes
a fixed size, the other translated size==UINT64_MAX to 0. Make things
more uniform by always treating size==UINT64_MAX the same as size==0.
Paul Meyer [Mon, 13 Jul 2026 07:47:40 +0000 (09:47 +0200)]
tpm2-util: initialize NvPCRs on first extension
Both callers of tpm2_nvpcr_extend_bytes() duplicate the same dance: on
-ENETDOWN, i.e. when the NvPCR isn't anchored yet because
systemd-tpm2-setup hasn't run, they acquire the anchor secret,
initialize the NvPCR, and extend again. Move this into
tpm2_nvpcr_extend_bytes() itself. The only caller-specific bit, whether
the anchor secret shall be synced to /var, is passed in as a parameter.
Before:
SetPoolLimit adjusted the machine image pool while portablectl
reported the portable image pool. The command could succeed without
changing the limit that portable users queried later.
Normalize the image argument for per-image SetImageLimit requests while
leaving the single-argument pool limit mode unchanged. This aligns quota
handling with other path-taking verbs.
Reproducer:
cd /tmp
portablectl set-limit ./portable-repro 1G
Before:
./portable-repro was sent unchanged to portabled and rejected as an
invalid image name/path. Per-image quota changes worked for absolute
paths but not for equivalent relative paths.
Normalize each remove argument with determine_image() before building
the RemoveImage request. Relative paths are converted before reaching
portabled.
Reproducer:
cd /tmp
portablectl remove ./portable-repro
Before:
./portable-repro was sent unchanged to portabled and rejected as an
invalid image name/path. Removing an image by a relative path failed
even though the path referred to a valid local image.
Open unit files with chase_and_openat() rooted at the image instead of
plain openat(). Symlinks are now resolved under the image root and must
end at a regular file.
Before:
inspect followed the absolute symlink on the host and printed host
file contents as image unit metadata. Image inspection could leak or
trust files outside the portable image.
Run read-only image arguments through determine_image() before sending
them over D-Bus. This gives relative paths the same normalized form as
other portablectl image operations.
Reproducer:
cd /tmp
portablectl read-only ./portable-repro true
Before:
./portable-repro was sent unchanged to portabled and rejected as an
invalid image name/path. The same image worked when passed as an
absolute path, so relative paths behaved inconsistently.
Reflinking is a safe optimization whenever the source and destination are
regular, seekable files on a filesystem that supports cloning. Requiring each
caller to opt in through COPY_REFLINK adds flag plumbing without changing the
necessary fallback behavior.
Drop COPY_REFLINK, renumber the remaining flags, and have copy_bytes_full()
unconditionally try FICLONE or FICLONERANGE before entering its normal copy
loop. Isolate the clone attempt and its file-offset bookkeeping in a helper so
copy_bytes_full() only has to handle its cloned, unavailable, and error results.
A successful clone therefore completes in one operation, while an unsupported
or rejected clone falls back to progress-limited copy_file_range(), sendfile(),
or buffered copying. Keep the public reflink helpers for operations that
specifically require clone semantics.
Existing test-copy coverage exercises both bounded and unbounded regular-file
copies through copy_bytes_full().
Parse the WithExtensions metadata block whenever --force selects that
bus method. This keeps the following unit-file array aligned with the
reply layout.
Before:
inspect printed the image metadata but dropped the matching unit
list. Scripts could not see which unit files were selected when
--force was used with the WithExtensions bus reply.
systemd-repart currently forces newly created image files into NOCOW mode.
That prevents files from being reflinked into the image, making image builds
slower and increasing their disk usage on filesystems that support cloning.
Add a tristate --cow= option. By default, leave the filesystem or parent
directory COW policy unchanged. With --cow=yes, explicitly enable COW; with
--cow=no, retain the previous behavior of forcing NOCOW. Add XO_COW as the
counterpart to XO_NOCOW so xopenat_full() applies either policy while retaining
its normal creation-error cleanup.
Document the new option and extend TEST-58-REPART to verify inherited COW and
NOCOW policies as well as explicit COW and NOCOW overrides. Compare the unset
behavior with the filesystem default so the test also works on nodatacow
mounts, and skip it when the inode attribute is unsupported.
Commit 04f19d673587 ("udev: Add /dev/media/by-path symlinks for media
controllers") added the rule file and the feature was announced in the
v256 NEWS, but the file was never added to the rules.d/meson.build
install list, so no build has ever shipped it and the advertised
/dev/media/by-path/ symlinks are never created.
sd-dhcp-relay: fix off-by-one when discarding BOOTREQUEST messages by hops count
According to RFC specifications
```
RFC 1542 section 4.1.1 states:
The relay agent MUST silently discard BOOTREQUEST messages whose 'hops'
field exceeds the value 16."
```
"Exceeds the value 16" means hops > 16, i.e. a message that arrives with
hops == 16 is still valid and must be relayed (after which its hops field
becomes 17). The code used ">= 16", which silently dropped a valid message
that had legitimately traversed exactly 16 relay agents, one hop too early.
This matches the wording of the adjacent comment, which already says
"exceeds the value 16".
resolved: fix spurious BrowseServices add/remove flapping with ifindex=0 (#42982)
## Problem
A `BrowseServices` subscription with `"ifindex":0` (browse all
interfaces) receives a continuous flap of `added`/`removed` events for a
service that is still present — within a second, and with no goodbye
packet involved.
## Root cause
For `ifindex==0`, `mdns_browser_revisit_cache()` looked up each mDNS
scope's cache separately and called `mdns_manage_services_answer()`
**once per scope**. That function derives `removed` events by diffing
the browser's *global* discovered-service list (all interfaces, filtered
only by owner family) against the single answer it's handed. So with ≥2
mDNS-relevant interfaces of the same family, a service present on
interface A isn't in interface B's answer and is spuriously removed
while B is reconciled, then re-added on the next revisit tick.
## Fix
Accumulate the pruned cache answers from every matching mDNS scope into
one combined `DnsAnswer` and reconcile **once**, so removals diff the
global list against the union across interfaces. Items are merged with
`dns_answer_add_full()` (not `dns_answer_extend()`, which defaults each
item's `until` to `USEC_INFINITY` and would skew the RFC 6762 §5.2
TTL-maintenance schedule). The single-interface (`ifindex>0`) path is
unchanged.
## Test
`TEST-89-RESOLVED-MDNS.sh` gains `testcase_browse_ifindex_zero_no_flap`:
it adds a service-less dummy mDNS link to guarantee ≥2 same-family
scopes (the flap precondition), browses `ifindex=0`, waits for
discovery, then asserts **zero** `removed` events while every publisher
stays up. The subscription uses `varlinkctl --timeout=infinity`, since
it sits idle after discovery and the default 45s idle timeout would
sever it (and the assertion) mid-observation.
## Testing status
Builds clean; `shellcheck -x` clean. First CI round: `TEST-89`
(including this testcase) passed on all mkosi platforms; the failing
jobs all traced to unrelated flakes/infra.
U-Boot currently does not implement EFI_MEMORY_ATTRIBUTE_PROTOCOL
even when reporting EFI version >= 2.10. Consequently, systemd-boot
emits a warning on every boot when running on U-Boot firmware.
The absence of EFI_MEMORY_ATTRIBUTE_PROTOCOL is a current
U-Boot limitation and not a condition users can remedy.
Furthermore, the EFI specification does not require all
firmware advertising EFI 2.10 or newer to implement the
protocol. As a result, the warning provides little value on
U-Boot systems while causing log_wait() to impose a 2.5-second
boot delay.
Downgrade the message to LOG_DEBUG, this keeps the diagnostic
available for debugging purposes without penalizing normal
boot time.