Then, added explanations for the missing arguments. Also mentioned that
the memfd is sealed by the function.
(cherry picked from commit 20604d980057da1a606339fb7a660242e8d2db02)
sd_bus_message_append_array_memfd() and
sd_bus_message_append_string_memfd() are public functions, hence the
passed fd may be already sealed by the caller. Let's gracefully handle
such case.
(cherry picked from commit 16025762d9055ec56694e4a1d74344029061b7c2)
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)
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)
- 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)
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)
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)
All test cases are covered by TEST-17-UDEV.device-unit-state-transition-netif.sh
added in the previous commit.
(cherry picked from commit 1ac7d20002fe6e94d24c1e652cdffa5515e1461e)
Commit 905a89a219 raised the priority of
events triggered by the device monitor, so that the queue file would not
be removed while the netlink socket in the device monitor still had a
queued uevent.
However, that causes a problem: when udevd receives a flood of uevents,
sigchld and notification events from the workers are postponed. As a
result, the queued events may not be processed during the flood, and
udevd's memory consumption keeps increasing.
Let's lower the priority of these events again. To avoid removing the
queue file while a uevent is still pending on the netlink socket, check
whether the event source corresponding to the device monitor is pending.
Follow-up for 905a89a219.
Fixes#43865.
(cherry picked from commit bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398)
libgcrypt is used only by test-fsprg. We do not add dlopen notes for
unit tests, so the library may not be installed on the system. If systemd
is built with HAVE_GCRYPT but libgcrypt is not installed, the test fails.
There is no need to install libgcrypt solely for test-dlopen-so, so drop
the test case.
(cherry picked from commit 764b9a724925c4167e91fd36311e38aee8c6871a)
This renames BLOCKDEV_LIST_IGNORE_ZRAM to BLOCKDEV_LIST_IGNORE_RAMDISK,
and make it ignores both /dev/ramX and /dev/zramX.
Note, linux-stable by Alpine/postmarketOS has CONFIG_BLK_DEV_RAM=y,
hence the kernel creates /dev/ramX by default. Without this change,
the test case added by 236e7d8a4c fails,
as io.systemd.Repart.ListCandidateDevices varlink method lists the
ramdisks.
(cherry picked from commit 77c51f4e97)
When a DHCP lease is lost or a client is stopped, there may exist
requests not processed yet. We need to cancel them, otherwise an
address or route requested by the lost lease may be configured later.
(cherry picked from commit 830b60ae1f)
If an address with IPv4ACD is requested, then sd_ipv4acd instance for
the address is configured. If the request is cancelled, we should
also disable the IPv4ACD instance.
Note, if the address is already configured, the IPv4ACD instance for the
address will be removed when the address is removed. See address_drop().
(cherry picked from commit c5bf6bac23)
Otherwise, if the timer event source is enabled, a new query may be
invoked by the already removed service.
This also renames dns_remove_service() to dnssd_discovered_service_detach(),
and drops unused DnssdDiscoveredService.query.
(cherry picked from commit 02f65ebead)
When a DnsServiceBrowser object is detached from the manager,
all queries, event sources, and then the reference to Manager should be
dropped. Otherwise, spurious query may be triggered for already
disconnected varlink.
(cherry picked from commit 219abd95ae)
Previously, only sd_nfnl_nft_message_new_setelems() takes the 'add'
flag. Let's all functions take the boolean parameter for consistency.
(cherry picked from commit 534a25c885)
This is especially necessary since GCC 16.x.
=====
$ gcc --version
gcc (GCC) 16.2.1 20260819 (Red Hat 16.2.1-2)
Copyright (C) 2026 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
=====
Without this change, /usr/include/limits.h is not included, hence POSIX
constants are not defined:
=====
$ echo '#include <limits.h>' | gcc -E -H -isystem ~/git/systemd/src/include/musl - 2>&1 >/dev/null | grep '^\..*limit'
. /home/watanabe/git/systemd/src/include/musl/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
... /usr/lib/gcc/x86_64-redhat-linux/16/include/syslimits.h
=====
With this change, /usr/include/limits.h is included, thus POSIX
constants are defined:
=====
$ echo '#include <limits.h>' | gcc -E -H -isystem ~/git/systemd/src/include/musl - 2>&1 >/dev/null | grep '^\..*limit'
. /home/watanabe/git/systemd/src/include/musl/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
... /usr/include/limits.h
...... /usr/include/linux/limits.h
.. /usr/lib/gcc/x86_64-redhat-linux/16/include/limits.h
=====
Replaces #43824.
The _const_ attribute can be only used for functions.
Fixes the following warnings on Fedora rawhide:
```
../src/core/namespace.h:260:75: warning: '__const__' attribute only applies to functions [-Wignored-attributes]
260 | char* bpf_delegate_to_string(uint64_t u, const char * (*parser)(uint64_t) _const_);
| ^
../src/basic/../fundamental/macro.h:80:32: note: expanded from macro '_const_'
80 | #define _const_ __attribute__((__const__))
| ^
In file included from ../src/core/unit.c:24:
../src/shared/condition.h:87:63: warning: '__const__' attribute only applies to functions [-Wignored-attributes]
87 | typedef const char* (*condition_to_string_t)(ConditionType t) _const_;
| ^
../src/basic/../fundamental/macro.h:80:32: note: expanded from macro '_const_'
80 | #define _const_ __attribute__((__const__))
| ^
```
-ENODATA is returned when the message carries no (reply) cookie, but the
text stated the message "carries a reply cookie field". Say it does not
carry one.
- It does not accept NUL for type.
- ret_size is zero and ret_ptr is non-NULL when it returns positive.
- Fixed argument names: ptr -> ret_ptr, size -> ret_size.
Otherwise, UBSAN complains when src is NULL even though the shift is zero:
../src/basic/compress.c:2074:29: runtime error: applying zero offset to null pointer
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()`.
CPU architecture is determined by uname(), rather than the compile time
macros like __i386__, __x86_64__, __aarch64__.
Let's conditionalize with uname_architecture().
Follow-up for d518675741.
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.
Newly allocated new_res variable was left unreferenced if memory
allocation failed in ndisc_option_add_encrypted_dns_internal().
Co-authored-by: Siteshwar Vashisht <svashisht@redhat.com>
We copy linux/magic.h from the kernel source tree and use it when
building systemd. Let's also make the kernel-filesystem-magics test
use the copy in our tree rather than the one installed on the system.
To achieve that now the 'check' command takes both 'cpp' and
'system_include_args' from meson.
The man page udevadm(8) have explicitly documented that the option -V is
a short form of --version. Let's not hide the short form in the help
message.
This introduces OPTION_COMMON_VERSION_WITH_V then use it in udevadm,
udevd, and run0.
Alos, this moves print_version() to build.c, and renames it to
version_only(). Now the function is also used in udevd amd test-libudev.
With this change, the -V option is hidden only in dmi_memory_id and
scsi_id. So, this removes the OPTION_COMMON_VERSION_WITH_HIDDEN_V macro
and explicitly list the hidden option in their code.
As mentioned in a05fe6684a, glibc provides two
wrappers for epoll_pwait2() on 32-bit architectures, and sys/epoll.h,
together with features-time64.h, selects the appropriate one.
To avoid depending on symbols introduced in newer glibc releases, that
commit relied on the glibc internal macro __USE_TIME_BITS64 to determine
which wrapper to use. However, that is incorrect on some architectures.
See:
https://sourceware.org/git/?p=glibc.git;a=commit;h=a4ed0471d71739928a0d0fa3258b3ff3b158e9b9
The above glibc commit introduces a new internal macro,
__USE_TIME64_REDIRECTS, which correctly describes whether the time64
wrapper should be used. However, we cannot rely on it because it was
introduced in glibc 2.40, while our baseline remains glibc 2.34.
Moreover, even after raising the baseline, relying on glibc internal
implementation details is undesirable.
Instead, call the epoll_pwait2 syscall directly. This avoids any
dependency on glibc wrapper selection logic while preserving the original
goal of avoiding newer glibc symbols.
As a side effect, this also enables epoll_pwait2() on musl, which does not
currently provide a libc wrapper for it.
Currently, epoll_pwait2() is only used by sd-event, so this is also the
simplest solution.
Otherwise, test-dlopen-note.py fails when libarchive support is disabled
but libacl support is enabled.
Also, log the dlopen_libarchive() failure at LOG_ERR level, matching how
the other failures are already logged.
Fixes#43530.
Since kernel v6.17, we can set a path to unix socket to core_pattern
(with request mode). See also:
https://lore.kernel.org/all/20250603-work-coredump-socket-protocol-v2-0-05a5f0c18ecc@kernel.org/
This introduces a tiny service that prepares and listens on a UNIX
socket to be passed to the kernel core pattern. When a process is
crashed, the kernel connects to the socket, and sends information
about the crashed process and passes coredump through the socket.
The service accepts the connection, and forks a worker process that
receives coredump from the kernel.
This also renames coredump_context_read_pidfd_info() to
coredump_context_read_code(), as it only reads COREDUMP_CODE.
This does not change anything effectively, as the function is called
only once. Preparation for later change.
Previously, even when the compressed data was truncated, or had
trailing garbage, the decompressor might not detect it.
To fix the issue, update the check if stream is finished.
With this change, now decompressor_push() must be called with
size == 0 to finalize the stream.
This splits coredumpctl.c into small pieces, and fixes several minor
issues such that memleak, unremoved temporary files, and missing
uncompressed core file handling. This also makes `coredumpctl
dump/debug` command accept --json= option that was previously silently
ignored.