Commit Graph
91888 Commits
Author SHA1 Message Date
Yu Watanabe 9ad97c1f2e memfd-util: mention that F_SEAL_EXEC is supported since kernel v6.3
(cherry picked from commit f18365107051ce3b8c924f430a189ff027474e3b)
2026-10-16 17:24:51 +01:00
Yu Watanabe c31aa959f3 sd-bus: avoid overflow in sd_bus_message_append_{array,string}_memfd()
This also adds missing size == 0 check, and uses TAKE_FD().

(cherry picked from commit 9e84b6bea4156b8a417419730ff3a04c7e1e0375)
2026-10-16 17:24:51 +01:00
Yu Watanabe e8d4909b44 sd-bus: fix invalid fcntl() argument and error handling
Fixes 40164c2ceb.

(cherry picked from commit 4738dd120dcd4e7ee9c0bb825a41633aad15b0bd)
2026-10-16 17:24:51 +01:00
Yu Watanabe de6055cf6a fuzz: fix error handling of fcntl()
(cherry picked from commit 76f37fd835028177df93d674d9a2f897893af69c)
2026-10-16 17:24:51 +01:00
Yu Watanabe 96be8707ef udev-node: chase devlink on remove event
Previously, readlink_malloc() was used to find the target device.
However, devlink is a relative symbolic link, hence the path obtained by
readlink_malloc() never matched with the one by sd_device_get_devname().
Also path_startswith(target, "/dev/") was always negative.

Let's use chase_and_stat() to obtain the absolute path to the target
device that the devlink currently points to.

Fixes the following spurious logs on remove event:

(udev-worker)[2338]: loop1p1: Processing device (SEQNUM=2231, ACTION=remove)
(udev-worker)[2338]: Notify message sent to '@4814750286313953891': "INOTIFY_WATCH_REMOVE=1"
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/x2' points to '../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/x2', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-diskseq/9-part1' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-diskseq/9-part1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-label/udevtest-b-fs1' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-label/udevtest-b-fs1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-uuid/221d135f-7bf7-45b8-abeb-d9b3afb2c215' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-uuid/221d135f-7bf7-45b8-abeb-d9b3afb2c215', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-partlabel/udevtest-b-part1' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-partlabel/udevtest-b-part1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/b1' points to '../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/b1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/x1' points to '../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/x1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-partuuid/5ef627b6-95f1-a942-8d7a-bd4ac53485ac' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-partuuid/5ef627b6-95f1-a942-8d7a-bd4ac53485ac', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/b3' points to '../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/b3', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-loop-inode/0:36-13-part1' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-loop-inode/0:36-13-part1', removing
(udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-loop-ref/\x2ftmp\x2fudevtest-b.img-part1' points to '../../loop1p1' which is outside of '/dev/', updating it.
(udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-loop-ref/\x2ftmp\x2fudevtest-b.img-part1', removing
(udev-worker)[2338]: loop1p1: Device processed (SEQNUM=2231, ACTION=remove)

(cherry picked from commit 03a65741d77d61929b98977d1bfdf2b470e14b55)
2026-10-16 17:24:51 +01:00
Lennart Poettering 2c4e3b9a6b sysupdate: add PartitionZeroFill= and enable it by default for verity signature partitions
A verity signature partition carries a JSON object that must be followed by
NUL bytes only, up to the end of the partition (dissect refuses anything
else). The split-out artifact repart generates for it however is trimmed of
that padding since b54ef83414, so that it is a plain JSON text file (which
jq nowadays insists on).

sysupdate installs such a file into a partition by simply writing it at the
partition's offset, leaving whatever follows in place. Hence, once a shorter
signature (e.g. after rotating to a different key type) is installed into a
partition that previously held a longer one, the tail of the old signature
survives right after the new JSON object, and the partition becomes
unparsable.

Add a new PartitionZeroFill= boolean setting to the [Target] section, which
makes the importer continue writing zeroes up to the end of the partition
once the payload has been written, by passing --zero-fill= to systemd-import
and systemd-pull. It defaults to off, except for verity signature partitions
(which are tiny, hence this is cheap) where it defaults to on.

Fixes: #43567
(cherry picked from commit d3b6d765a5b320d6d864591c6a7b87e1047d0c78)
2026-10-16 17:24:51 +01:00
Lennart Poettering f9cfc019f9 import,pull: add --zero-fill= switch to fill up the destination range with zeroes
When writing a raw image into a section of an existing file or block device
(i.e. with --offset= and --size-max=, as sysupdate does when updating a
partition), we so far wrote precisely as many bytes as the payload was
large, leaving whatever followed in the destination range untouched. For
some payloads that's a problem: a verity signature partition for example
must carry NUL bytes only after the JSON object, and if a shorter signature
is written over a longer one, the tail of the old one survives.

Add a --zero-fill= boolean switch to both "systemd-import raw" and
"systemd-pull raw", which fills up the remainder of the destination range
(from the end of the payload up to --size-max=) with zeroes once the payload
has been written, via blockdev_zero_out(). It defaults to off, and requires
both --offset= and --size-max= to be specified.

(cherry picked from commit aff5aff407d421fbedc9eb0229c40996ca5570a1)
2026-10-16 17:24:51 +01:00
Lennart Poettering c4e7a0fdfe blockdev-util: add helper for zeroing out a range of a block device
blockdev_zero_out() overwrites a byte range of a block device (or a regular
file, e.g. a disk image) with zeroes. On block devices we try to let the
kernel do the work via BLKZEROOUT, which it might be able to offload to the
device. That ioctl operates on whole sectors only however, hence incomplete
sectors at the beginning and the end of the range are filled with explicit
zeroes, and only the aligned middle part is handed to the ioctl. If that
fails, explicit zeroes are written for that part too. On regular files a
hole is punched instead (which reads back as zeroes and keeps the file
sparse), falling back to explicit zeroes if the file system doesn't support
that.

(cherry picked from commit eb98b03118f27f33d3834ef8322f38391eb2c238)
2026-10-16 17:24:51 +01:00
Lennart Poettering 9752a9ef8f journald: refresh cached client context if stream's unit doesn't match
On kernels lacking CLONE_INTO_CGROUP sd-executor is forked into the
service manager's cgroup, logs a few messages from there, and only then
attaches itself to the unit's cgroup and connects stdout/stderr to
journald. Since we cache client metadata per PID and only refresh it
after 1s, log output on such a stream was attributed to init.scope
rather than to the unit, and hence "journalctl -u" (and thus
"systemd-run -v", "systemctl -v start", "systemctl -v wait") would not
show it.

Hence, if a stream tells us the unit it belongs to, and that doesn't
match what we have cached, refresh the cached data.

(cherry picked from commit 44a9316bf49967164567a7c716b79af7edf53d03)
2026-10-16 17:24:51 +01:00
Martin Pitt cb2f3814bb vmspawn: don't leak the job id if sending blockdev-create fails
The job map owns its keys, but the error path added in commit 1d0a8e5dbd
only frees the value when it unregisters the job. Free the key as well,
like dispatch_pending_job() does.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 67b4f43a54f29b3c0fd5a455b4f956613eae8668)
2026-10-16 17:24:51 +01:00
Martin Pitt fddede73c7 vmspawn: stop the QMP pump on fatal errors
The next commit drains the QMP client before resuming the VM, while
boot-time devices are being set up. Callbacks report fatal setup errors
by logging them and requesting the event loop to exit. As the loop
isn't running yet, the pump would not notice and continue. Stop it
instead, and return the error.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 50063acf50dc81b194780758d3cd2c5fb0a709f4)
2026-10-16 17:24:51 +01:00
Martin Pitt e4c45cae51 vmspawn: factor out the synchronous QMP pump
The upcoming boot-time device setup will need the same synchronous
driving of the QMP client before resuming the VM.

Move the loop into a helper, and generalize the error messages.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 73833bdddfd4e8a1aa003516a8eda53515c9110f)
2026-10-16 17:24:51 +01:00
Martin Pitt ad0f1d66f2 vmspawn: log failures to dismiss completed QMP jobs
Most errors that end the event loop are logged where they happen, except
these two.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 7681db4546d0eb3ef9160e90200ccaf5c9d7edc2)
2026-10-16 17:24:51 +01:00
Martin Pitt 8b54adc7c4 vmspawn: make the QMP job continuation machinery private
Since the previous commit, pending jobs are registered and dispatched
only within vmspawn-qmp.c. Move their types and helpers out of the
header.

No behaviour change, clean code move.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit f1a83ef728923f1cb527724581872d4ae5daf8fc)
2026-10-16 17:24:51 +01:00
Martin Pitt f3f8a96a82 vmspawn: dispatch QMP events in the bridge
The QMP client's userdata (the `VmspawnQmpBridge`, vmspawn's QPM state)
and its event callback were previously only set up in
`vmspawn_varlink_setup()`, after the VM has been resumed. This caused two
problems:

 - Boot-time device setup could not wait for its own completion before
   the VM is resumed, as that needs exactly these replies and events.

 - QMP replies and events that arrive before that were mishandled.
   Command callbacks like `on_qmp_complete()` crashed on a NULL bridge
   assertion. Also, `JOB_STATUS_CHANGE` events were dropped: they drive
   the boot-time blockdev-create continuation for `--ephemeral`.

   This only showed when the varlink setup failed, e.g. with a too long
   runtime directory path. Tearing down the bridge then failed the
   pending commands, and vmspawn aborted with an assertion instead of
   exiting with the error.

Both were introduced with commits 882049362d and 1a7b6fd9dd.

To fix this, set the `userdata` and bind the event callback when
creating the bridge. The bridge itself handles the events that drive its
own state (job continuations, `DEVICE_DELETED`), and forwards the others
to a callback that the varlink server binds for its event subscribers.

Signed-off-by: Martin Pitt <martin@amutable.com>
(cherry picked from commit 2cac293064215d3e4f5ed92a1e898f89e6ac4629)
2026-10-16 17:24:51 +01:00
Yu Watanabe d2b81326ac sd-device: seal object earlier
Previously, the sd_device object was sealed after it was verified. However,
the verifier device_verify() calls device_in_subsystem() which reads the uevent
file if the object is not sealed. Hence, basic information such as
MAJOR=/MINOR=/IFINDEX= and so on were updated by the uevent file,
and the ones passed through netlink were simply discarded.

Seal the device earlier, like we already do in device_clone_with_db().
This ensures all basic information passed through netlink is always honored.

Fixes the following issue:

$ journalctl --no-hostname --file TEST-17-UDEV.journal SEQNUM=2244 DEVNUM=259:1
Oct 12 04:44:22 systemd-udevd[404]: loop1p1: Device is queued (SEQNUM=2244, ACTION=remove)

$ journalctl --no-hostname --file TEST-17-UDEV.journal SEQNUM=2244 DEVNUM=259:2
Oct 12 04:44:22 (udev-worker)[2593]: loop1p1: Processing device (SEQNUM=2244, ACTION=remove)
Oct 12 04:44:22 (udev-worker)[2593]: Notify message sent to '@4814750286313953891': "INOTIFY_WATCH_REMOVE=1"
Oct 12 04:44:22 (udev-worker)[2593]: loop1p1: Device processed (SEQNUM=2244, ACTION=remove)
Oct 12 04:44:22 (udev-worker)[2593]: loop1p1: sd-device-monitor(worker): Passed 325 byte to netlink monitor.
Oct 12 04:44:22 (udev-worker)[2593]: Notify message sent to '@4814750286313953891': "PROCESSED=1"

Here, the main process of udevd receives the uevent with SEQNUM=2244 with
MAJOR=259 and MINOR=1. However, when it is forwarded to the udev worker,
MINOR= is changed to 2. Hence, the worker tries to read a wrong
non-existent database file and cannot remove stale devlinks.

Fixes a regression in ab1bd9daed.

(cherry picked from commit f58a2efc557a740891c5a56c82c971ae9a4e84c1)
2026-10-16 17:24:51 +01:00
Chris Coulson 81795d8826 tpm2: Don't fail NvPCR initialization if there is no initial write policy available
Currently systemd-tpm2-setup will fail if NvPCR initialization doesn't
succeed, either because the currently booted UKI carries no PCR public
key, or it carries no appropriate signed policy (one with the "initrd"
policy reference). In addition to this, systemd-pcrextend will
subsequently fail because it also fails to initialize the NvPCR it is
requested to extend.

This makes systemd-tpm2-setup return EX_CONFIG in these scenarios, with
this marked as a successful exit status in the service unit file. In
addition to this, systemd-pcrextend is updated to only attempt NvPCR
initialization from the initrd (the only place it will succceed), and
when called with --graceful, to not exit with an error code if the
target NvPCR is uninitialized, and can't be initialized because of a
missing PCR public key or appropriate signed policy. When called via
Varlink, it will return the existing "NoSuchNvPCR" error.

Note that I also removed some NvPCR initialization specific exit status
codes from systemd-tpm2-setup.service.in, as these can only be returned
via systemd-tpm2-setup-early.service.

This should address the issues in
https://github.com/systemd/systemd/issues/43848.

(cherry picked from commit e846bbad04d87e58ba9c3e30d8a1087141691715)
2026-10-16 17:24:51 +01:00
Daan De Meyer ef565d78af tree-wide: use pwrite_full() for positioned writes
Several places write a buffer at an offset with a single pwrite() or
pwritev(), and fail if the call writes less than the whole buffer. The
lock file of a dynamic user is then truncated to the bytes written, so
it keeps a cut-off user name. memfd_new_and_seal() fails for data larger
than one write() call accepts, which is about 2 GiB on Linux. The other
callers return -EIO, and lose the error that another write would report,
such as ENOSPC.

Use pwrite_full(), which keeps writing until the whole buffer is written
or a write fails. The lock file of a dynamic user is written from two
buffers and uses pwritev_full() instead.

repart writes the verity signature with lseek() and loop_write(). It
uses pwrite_full() as well, which does not move the file offset.

(cherry picked from commit 2fd17cb9eaca00a4dcb9af85a1f485e6d04bda04)
2026-10-16 17:24:51 +01:00
Daan De Meyer 8b9fb1bbec io-util: add pwritev_full() and pwrite_full()
loop_write() writes one buffer at the file position. To write at an
offset, callers call pwrite() or pwritev() directly and handle short
writes themselves.

Add pwritev_full(), which writes all iovecs at an offset, retries on
EINTR and short writes, splits batches larger than IOV_MAX, and reports
the number of bytes written, also on failure. Add pwrite_full(), which
does the same for one buffer.

(cherry picked from commit 4d36be491a568180dc6336b91b0c496bb8cb6601)
2026-10-16 17:24:51 +01:00
Daan De Meyer fcaf217ab2 journal: reset the offline state if blocking signals fails
journal_file_set_offline() sets OFFLINE_SYNCING before it starts the
offline thread. If the first pthread_sigmask() fails, it returns without
starting the thread and leaves the state at OFFLINE_SYNCING. The next
journal_file_set_offline_thread_join() then calls pthread_join() on a
thread that was never created.

Set OFFLINE_JOINED, as the error path of pthread_create() does.

(cherry picked from commit db2b225a30da26d0939f1f6d6c4b524bd2240900)
2026-10-16 17:24:51 +01:00
Florian Franzen e5197414d9 test: cover case folding of Type #2 entry IDs in TEST-86
Rename the UKI to a mixed case file name with a boot counter before
selecting the first profile, and give the second profile a mixed case
ID, so that both are only reachable if systemd-boot folds the entry IDs
of Type #2 entries with boot counter and of secondary profiles.

The entry IDs passed to bootctl set-default are spelled lower case and
without the counter, like loader.conf(5) documents and bootctl list
shows them.

(cherry picked from commit 3937823293b354d1a3f4a52ba14968eec7c42602)
2026-10-16 17:24:51 +01:00
Florian Franzen 2f53f23355 boot: case fold Type #2 entry IDs with boot counter or profile ID
config_find_entry() matches the case folded patterns from loader.conf and
the LoaderEntry* EFI variables against entry IDs with the case sensitive
efi_fnmatch(), relying on the IDs being lower case already. Type #1
entries fold their ID after the boot counter has been parsed, but Type #2
entries only did so when the file name carried no boot counter, because
boot_entry_parse_tries() rebuilds the ID from the original file name. The
ID of a secondary UKI profile was not folded either, as the profile ID
from the .profile section is appended verbatim.

Hence a UKI like EFI/Linux/Foo+3.efi, or a profile with ID=Profile1,
could never be selected via default, preferred, @saved, bootctl
set-default or systemctl reboot --boot-loader-entry=, while bootctl
(which matches case insensitively) claimed that it was the default.

Fold the ID unconditionally, like Type #1 entries do, and fold the
profile suffix as well. The file names used for renaming the boot
counter keep their case.

Follow-up for 4301ad00ef and
941b91600c.

(cherry picked from commit 1402519771a45745de3f6b7e93d08d7c96d3d65b)
2026-10-16 17:24:51 +01:00
Josh Hoffer 3e95f9bf08 test: add repart testcase for --size=auto with foreign partitions
Adding a partition with --size=auto to an image whose existing
partitions have no definitions used to hit
assert(!PARTITION_IS_FOREIGN(p)). Check that the existing partition
keeps its UUID and label and the new one is appended.

(cherry picked from commit ba56bc4376f24d52479fdf8153132f889a9b00b0)
2026-10-16 17:24:51 +01:00
Josh Hoffer 5fe12bc9de repart: keep foreign partitions' UUID and label across partition table reloads
With --size=auto, repart unloads and reloads the partition table after
context_acquire_partition_uuids_and_labels() ran. The reload recreates the
foreign partitions (those without a definition) with a null new UUID and
no new label, so context_mangle_partitions() sees them as changed and hits
assert(!PARTITION_IS_FOREIGN(p)) when adding a partition to an existing
image:

  Initializing UUID of existing partition 0.
  Setting partition label of existing partition 0.
  Assertion '!PARTITION_IS_FOREIGN(p)' failed.

Set the new UUID and label of a foreign partition when it is loaded, so a
reload keeps them.

(cherry picked from commit 4fc4f6bac772ff3749ba7e0bbcd607175694420c)
2026-10-16 17:24:51 +01:00
Reilly Brogan b2c8372d32 nss-systemd: copy PASSWORD_SEE_SHADOW into the group record buffer
nss_pack_group_record() left gr_passwd pointing at PASSWORD_SEE_SHADOW,
which is part of the module's read-only .rodata. That breaks callers that
modify the returned group before freeing it, in particular
pam_modutil_cleanup_group(), which zeroes gr_passwd when the PAM handle
is torn down and then segfaults on read-only memory.

Copy the placeholder into the caller-provided buffer, as
nss_pack_user_record() already does.

(cherry picked from commit c7a8e871de3427cf654d9a608dc58663874197bb)
2026-10-16 17:24:51 +01:00
Yu Watanabe a70dbe88d4 udev: close inotify fd after disabling the corresponding event source
The event source should be already disabled in manager_exit(),
but for safety.

(cherry picked from commit 02c1be8faf601ec374572446c55c8c5152810fe3)
2026-10-16 17:24:51 +01:00
Yu Watanabe 53eb316e26 TEST-17-UDEV: fix the device watch test
- Match the watch rules against the root block device's kernel name instead
  of a hard-coded 'sda', which is not portable (e.g. 'vda' on virtio).
- The nowatch check used 'test ! -e', but the watch symlinks form a
  bidirectional (circular) pair (ID -> wd -> ID), so dereferencing them with
  -e always fails with ELOOP and 'test ! -e' always succeeds, regardless of
  whether the watch is still present. Use '(! test -L ...)', which does not
  dereference the symlink.
- Drop never worked checks for the 1st and 2nd invocations.
- Drop unnecessary 'function' keyword.
- Drop unnecessary 00-debug.rules.
- Fix broken drop-in config file.
- Restart udevd after the drop-in config file.
- Trigger block devices after rules change to restore the original watches.
- Also verify that the device's inode is listed in the inotify fd's fdinfo.

(cherry picked from commit 8bcd2c8ee03b16ed84b5f5554c02a3bf2e900587)
2026-10-16 17:24:51 +01:00
Lennart Poettering b17f8cd9cc man: explicitly say the NSS is not OK in generators
Inspired by: #44112

(cherry picked from commit 54b24a3855de37e5e19235c44acd113eb6ce6830)
2026-10-16 17:24:51 +01:00
Daan De Meyer d5999b66a2 sbsign: name the input file when hashing it fails
verb_sign() logs argv[0], which is the verb, as the name of the file it
could not hash. Log argv[1], the input file.

(cherry picked from commit 9030bbfc90c646b7c07bbe8d70cfe7ba40b5a25a)
2026-10-16 17:24:51 +01:00
Daan De Meyer cec20dc153 kernel-image: handle errors when reading the .osrel section
uki_read_pretty_name() only handles a missing .osrel section. Any other
error, for example an .osrel section larger than PE_SECTION_READ_MAX,
passes a NULL buffer to parse_env_data(), and "bootctl kernel-inspect"
aborts:

    Assertion 'data' failed at src/basic/env-file.c:429

Return the error instead.

(cherry picked from commit 37717744394b433eb452674f060a4288a8f469bf)
2026-10-16 17:24:51 +01:00
Daan De Meyer 762840e4e0 pe-binary: only read the raw data of a section
pe_read_section_data() reads VirtualSize bytes starting at
PointerToRawData. When VirtualSize is larger than SizeOfRawData, because
the section ends with zero-initialized data, it returns the start of the
next section, or fails with EBADMSG at the end of the file. Read
MIN(VirtualSize, SizeOfRawData) bytes, like systemd-stub and uki_hash()
do.

(cherry picked from commit f219e7e790ec7b1064b71173ad697f48a5d71830)
2026-10-16 17:24:51 +01:00
Daan De Meyer 6f076ff729 pe-binary: add pe_load_headers_and_sections()
Most callers load the PE headers and the section table together, and
only keep the DOS header to pass it to pe_load_sections(). Add a helper
that does both, and use it instead of the private copy in bootspec.c.

(cherry picked from commit 5902fb429f52d75e7b25e6dea4be113e769b2ff8)
2026-10-16 17:24:51 +01:00
Daan De Meyer 899a314271 meson: define EFI_MACHINE_TYPE_NAME when the bootloader is disabled
EFI_MACHINE_TYPE_NAME is empty when systemd-boot is not built. Then
get_efi_arch() returns an empty string, and "bootctl
--print-efi-architecture" prints an empty line. The architecture does not
depend on whether systemd-boot is built, so always set the macro from
efi_arch.

(cherry picked from commit 7d3ca0a8c530ebb71a40298df6c5d4f88b37d7e9)
2026-10-16 17:24:51 +01:00
venkatchalla06 a77d9ebc58 firstboot: fix use-after-free/double-free of the Varlink reply in process_hostname()
ret_parameters (and ret_error_id) returned by sd_varlink_call()/
sd_varlink_callbo() are borrowed from the connection, as documented in
sd-varlink.h, and must not be unreffed by the caller. process_hostname()
declared its reply as _cleanup_(sd_json_variant_unrefp), freeing memory
owned by the Varlink connection and leading to a use-after-free/
double-free (the same bug class and ownership mistake just fixed for
pcrextend_pcr_now()/pcrextend_nvpcr_now() in 76a6dc6d).

(cherry picked from commit c556722826c4892939d2a6239ab00d0a343530a8)
2026-10-16 17:24:51 +01:00
abdurrafay3 088a53dea7 shutdown: copy shutdown verb so shutdown scripts receive $1
The arg_verb was copying the pointer to the shutdown verb, but that
pointer was being overwritten. When the shutdown scripts run, the forked
child calls rename_process() which overwrites argv, so the scripts got
an empty $1 instead of reboot, poweroff, etc.

Make a copy of the verb with strdup() so it is not affected.

Fixes: #44087

Follow-up for: 4927588993

(cherry picked from commit e6b62f2b3a564fcfb282dc4729eb9a5565e87ba9)
2026-10-16 17:24:51 +01:00
Lennart Poettering aaf399e797 sysinstall: fix typo in varlink iface
This is strictly speaking an API break, but given this is output only
and the component so new, I think we should just fix this anyway.

Fix: #44088
(cherry picked from commit fd309374687070ea1ef957d35dffe1e43b4a9c73)
2026-10-16 17:24:51 +01:00
Yu Watanabe 22880ff01c sd-event: coding style fix
(cherry picked from commit c33c5f91dba9bc59c40a227c2a0c728f96a17089)
2026-10-16 17:24:50 +01:00
Yu Watanabe 257d11c731 test: add test case for sd_event_add_inotify() with floating event source
(cherry picked from commit e1514ac3b9a249e08260b895fb64fd919dcc40b0)
2026-10-16 17:24:50 +01:00
Yu Watanabe a32b34813e sd-event: make inotify event source floating if ret is NULL
Otherwise, if sd_event_add_inotify() is called with NULL for ret,
the event source is disabled and never triggered.

Fixes a bug introduced by e67d738a87.

(cherry picked from commit 0582f7cba907eba6d55b686028d145061c38d0b7)
2026-10-16 17:24:50 +01:00
Lennart Poettering 275bae99e3 pretty-print: some more gcc appeasement
(cherry picked from commit b8ac543706cdf3c1c0872889098d171a5774775a)
2026-10-16 17:24:50 +01:00
Egor Ignatov 7476fff8f2 resolve: get the current DNS server before passing the server lists
manager_get_dns_server() may re-read /etc/resolv.conf and replace
m->dns_servers and m->search_domains, but it was passed as an argument
to dns_configuration_json_append() together with those lists, and the
order of evaluation of the arguments is unspecified. gcc with LTO reads
the list heads first, so after a foreign /etc/resolv.conf has changed
the freed lists are walked. Typically the serialization then fails with
EUCLEAN, which makes the SubscribeDNSConfiguration method of
io.systemd.Resolve.Monitor and in turn systemd-networkd-wait-online
--dns fail.

Call manager_get_dns_server() first and store the result in a local
variable.

(cherry picked from commit 04567a3b5e2e29a2252e89be8a3c625c692103d3)
2026-10-16 17:24:50 +01:00
Lennart Poettering c3e01464e7 test-parse-helpers: use ASSERT_STREQ()/ASSERT_EQ() in test_path_simplify_and_warn_one()
Tests exist to test stuff, hence we should not use plain assert(), but
the ASSERT_XYZ() macros, which are never compiled out and print useful
information on failure.

(cherry picked from commit 13bf80491bcf8ffee2b43cf86b16e3d1394300ef)
2026-10-16 17:24:50 +01:00
Lennart Poettering afb572f06e bus-message-util: initialize variables to make gcc happy
gcc 13 on armhf complains with -Wmaybe-uninitialized about family, port
and server_name in bus_message_read_dns_array(), even though they are
always set when bus_message_read_dns_one() returns > 0.

(cherry picked from commit da4052d0037c6bb4981387bb375355f595ab4b1c)
2026-10-16 17:24:50 +01:00
Lennart Poettering 8334118621 test-resolved-packet: use assert_se() for the string comparison
With assert() the comparison is compiled out in NDEBUG builds, leaving
twilio_reply_string unused, which breaks the build with -Werror.

(cherry picked from commit e1577aaed620793fdec39ded861b873e17627f46)
2026-10-16 17:24:50 +01:00
Lennart Poettering 7a45af6e89 test: silence SC2329 for trap-invoked cleanup() in TEST-17-UDEV.sanity-check
cleanup() is only called via 'trap cleanup EXIT', which newer shellcheck
versions report as SC2329 rather than SC2317. Disable both, like the other
test scripts do.

(cherry picked from commit e42ad4c3b60b9bedf59f03901c88062b67a8829d)
2026-10-16 17:24:50 +01:00
Lennart Poettering 686bf67609 test-sd-device: tolerate devices disappearing during enumeration test
On CI (Azure runners) the accelerated networking PCI VF behind the
Hyper-V vmbus PCI bridge may be hot-unplugged while the test runs,
causing sd_device_new_from_syspath() to fail with ENODEV for a device we
just enumerated:

  test_sd_device_one(/sys/devices/LNXSYSTM:00/.../pci7870:00/7870:00:00.0)
  Assertion failed: Expected "sd_device_new_from_syspath(&dev, syspath)"
  to succeed, but got error: -19/ENODEV

Skip devices whose syspath vanished since enumeration rather than
failing.

(cherry picked from commit b43136ffcdbd62b5d11c226df9dd33372cff7823)
2026-10-16 17:24:50 +01:00
Lennart Poettering 9b899b7938 metrics: lift restrictions on fields types
These checks stem from a rework from strv to a proper varlink object,
but the whole rework's point was to allow more expressive field types,
hence drop the unnecessary verification of the string type.

(cherry picked from commit fc38a61894bcc772b2bc8d56be9700335cdba181)
2026-10-16 17:24:50 +01:00
Yu Watanabe c20ee1bfc2 udev: raise priority of post event source above device monitor
The commit bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398 kept the priority of
the post event source at the default (NORMAL), which is lower than the
device monitor (EVENT_PRIORITY_DEVICE_MONITOR, NORMAL-1). Since a pending
device monitor is always dispatched first, on_post() only runs when the
monitor is not pending, hence the sd_event_source_get_pending() check
added in the previous commit could never be true. Moreover, during a
uevent flood on_post() is starved, and as it is the only caller of
event_queue_start(), idle workers no longer get events assigned.

Let's give the post event source a priority above the device monitor, but
below the worker event sources so that worker completions are observed
before the queue is started.

Also, similar to checking whether the device monitor event source is pending,
when synthesizing change uevents, new uevents may come soon. Do not remove
the queue file and do not kill idle workers in that case.

Follow-up for bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398.
Fixes #43865.

(cherry picked from commit a0d25767050d76cfbc1f32dcdde3a0c3da5a7423)
2026-10-16 17:24:50 +01:00
Jonghyun An 6eb23d3526 systemctl: quote command arguments in status output
The Process lines in systemctl status join argv with spaces, making
multi-word arguments ambiguous and empty arguments invisible.

Use quote_command_line() with SHELL_ESCAPE_EMPTY to retain argument
boundaries. Leave the formatted string NULL for an empty argv vector so
that strna() prints n/a. Cover whitespace, empty arguments and literal
dollar signs in TEST-26-SYSTEMCTL.

Fixes #43938.

(cherry picked from commit a83a0d2fc461091b16a699aeba07a82d71545c71)
2026-10-16 17:24:50 +01:00
Bertrand Jacquin 17f3e1fb3b dns-packet: only set mDNS cache-flush bit on mDNS packets
Since 748a548e1b ("resolved: set cache-flush bit on mDNS responses"),
every RR of an mDNS zone, except DNS-SD service enumeration PTRs,
carries DNS_ANSWER_CACHE_FLUSH, and dns_packet_append_key() turns it
into the cache-flush bit regardless of the protocol of the packet.

When a lookup via the DNS stub is answered from our own mDNS zone, e.g.
the reverse lookup of one of our link-local addresses, the RR is sent
with class 0x8001. In unicast DNS bit 15 is part of the class value, so
clients see CLASS32769 instead of IN:

  $ dig +nocmd +nocookie -x fe80::d1f:2970:a730:5ab8 @127.0.0.53
  ;; Warning: Message parser reports malformed message packet.
  ;; Got answer:
  ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30061
  ;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

  ;; OPT PSEUDOSECTION:
  ; EDNS: version: 0, flags:; udp: 65494
  ;; QUESTION SECTION:
  ;8.b.a.5.0.3.7.a.0.7.9.2.f.1.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. IN PTR

  ;; ANSWER SECTION:
  8.b.a.5.0.3.7.a.0.7.9.2.f.1.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. 120 CLASS32769 PTR lady-voodoo.local.

  ;; Query time: 1 msec
  ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
  ;; WHEN: Wed Sep 02 21:40:55 IST 2026
  ;; MSG SIZE  rcvd: 132

The cache-flush bit is defined for mDNS only, hence only set it on mDNS
packets.

See: https://github.com/systemd/systemd/pull/43627
(cherry picked from commit 21159c052bbf28983115d842dbc2597869177d42)
2026-10-16 17:24:50 +01:00