Commit Graph
107 Commits
Author SHA1 Message Date
Christian Brauner 28741e0c09 fd-util: ignore O_EMPTYPATH in fd_verify_safe_flags()
Linux 7.2 adds O_EMPTYPATH to openat() combined with an empty path it
reopens the fd itself without a detour through /proc/. glibc does not
define the flag yet, provide it from the fcntl.h override.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-11-02 09:21:12 +01:00
Christian Brauner 381d85eda5 fs-util: report a dangling symlink in the way of O_CREAT as -ELOOP
openat_report_new() refuses to create a file through a symlink. When the
symlink is dangling the first open() fails with ENOENT and the create
with EEXIST. So the retry loop runs all seven rounds and reports
-EEXIST.

The first open() also drops O_CREAT to open an existing file. But the
kernel only applies fs.protected_regular and fs.protected_fifos to
O_CREAT opens. So every O_CREAT open that goes through xopenat_full()
silently loses these checks.

So flip the order. Try to create the file with O_EXCL|O_NOFOLLOW first.
If it exists already open it with O_CREAT|O_NOFOLLOW so the kernel does
its checks. If it is a symlink follow it without O_CREAT so we never
create its target and if that fails with ENOENT report -ELOOP right
away. Use -ELOOP just as O_NOFOLLOW does for a symlink.

If the file went away between the two opens the O_CREAT open creates it
after all. Since Linux 6.12 F_CREATED_QUERY tells us whether it did, so
ask it and report the file as newly created in that case. Older kernels
refuse F_CREATED_QUERY and we assume the file still existed.

Do the same for the XO_REGULAR and O_DIRECTORY|O_CREAT paths of
xopenat_full() which reported a dangling symlink as -EEXIST and -ENOENT
respectively.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-11-02 09:21:12 +01:00
Christian Brauner 7603a4a240 include: name the mount() parameters like the man page
The prototypes copied from glibc carry its reserved __names, which
would end up in the argument name comments of every mount() call.
Use the names mount(2) and umount(2) use.
2026-10-30 13:37:01 +01:00
Christian Brauner d8a06551e2 RestrictFileSystemAccess=: answer execveat(AT_EXECVE_CHECK) (#44393)
Since Linux 6.14 execveat() takes AT_EXECVE_CHECK, which asks whether a
file could be executed without executing it. Interpreters use it so that
"sh script.sh" and "./script.sh" get the same answer from the kernel's
execution policy. The check returns right after the bprm_creds_for_exec
hook, before any binfmt handler runs, so our bprm_check_security program
never sees the file. Currently, we say "yes" to every such query, no
matter where the file lives.

So add a program on bprm_creds_for_exec that runs the same trust check
when bprm->is_check is set. Real execs stay with bprm_check_security,
which also sees the interpreters they pull in. The check is gated on
is_check so normal execs aren't evaluated twice, which is what IPE does
as well. is_check only exists since v6.14, so it's read through a CO-RE
flavor and the program is a no-op on older kernels, which don't know the
flag either. No new kernel requirement.

The tenth link changes the serialized link set, so the first patch
teaches PID 1 to accept the set of a v261 or v262 PID 1 as a prefix on
reexec. Without it a daemon-reexec or an initrd to root switch across
the upgrade kills PID 1.

Tested with TEST-90 (enforce, config, dm-verity keyring) on a 7.2
kernel.
2026-10-29 13:43:36 +01:00
Christian Brauner b63eebe166 include: provide AT_EXECVE_CHECK where glibc lacks it
The flag exists since Linux 6.14, not every glibc we support defines it
yet.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-28 10:04:19 +01:00
Andrew Halaney 38c3d82502 include: add SO_PEERPIDFD_THREAD
Kernel v7.4 added SO_PEERPIDFD_THREAD, which works like SO_PEERPIDFD
but returns a pidfd for the specific thread that called connect(),
listen() or socketpair() instead of for its thread-group leader.

Add a fallback definition so we can use it before libc / kernel headers
catch up.

Link: https://git.kernel.org/torvalds/c/e10899b2a098f496af6316a38a107c859b47c2a4
2026-10-27 16:11:06 -05:00
Christian Brauner 24548be0bf keyring-setup: add systemd-keyring-setup
The kernel has various keyrings that early userspace may choose to set
up. Right now it has the .fs-verity and .dm-verity keyrings and in the
next kernel it will also have a .bpf keyring.

All three keyrings accept X.509 certificates in DER form. The
.dm-verity and .bpf keyrings are inactive and restricted by default
unless the respective kernel command line options are passed that leave
them unrestricted. Both keyrings are ignored until they are restricted.
IOW, restricting them causes the kernel to use them for signature
verification.

The .fs-verity keyring has slightly different semantics. It is always
active and is taken into account as soon as it contains a key.

Add systemd-keyring-setup which provisions the keyrings based on the
VOA spec from the kernel-keyring role with the keyring as the context:

  .dm-verity -> kernel-keyring/dm-verity/
  .fs-verity -> kernel-keyring/fs-verity/
  .bpf       -> kernel-keyring/bpf/

Trust anchors are read from the trust-anchor-kernel-keyring/
counterpart. Note that the "trust-anchor-*" prefix is mandated by the
spec.

The systemd-keyring-setup binary reads
<os>/kernel-keyring/<context>/x509/*-certificate.pem and the
trust-anchor-kernel-keyring/ counterpart from all VOA load paths and
enrolls the certificates into the corresponding keyring. Afterwards it
restricts the keyring to certificates signed by an enrolled key and
drops the SetAttr permission. Hence, neither the restriction nor the
mask can be changed anymore.

The binary may run in the initrd and on the host. A second run detects
a sealed keyring by its permission mask, skips certificates that are
enrolled already and enrolls certificates that are signed by an already
enrolled key.

Any unprovisioned keyrings are sealed at the end of a run even when
empty. Failing to enroll a certificate still causes the keyring to be
sealed. We can make this more flexible in the future but I don't think
leaving a keyring open just because enrolling a key failed makes sense.

Note that a file holding more than one certificate is refused.

Note that on a second call to add_key() for a certificate with the same
subject and key the kernel silently replaces the first. We can detect
this by reading the keyring's members before and after enrollment.

The binary exits with EX_DATAERR for input that can be fixed and
EXIT_FAILURE for kernel refusals. --dry-run only shows what would be
enrolled, optionally as JSON. The service isn't enabled by default and
the tool is marked experimental for now.

systemd-keyring-setup is written in Rust on top of the systemd_shared
crate. The VOA lookup, the keyring and X.509 helpers and everything
else it uses stay C in libsystemd-shared. All lookups are anchored at
the root directory which is opened once. The program, its unit and its
man page are only built with Rust support.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-10-26 18:55:53 +01:00
Dimitri Daskalakis 127e2ee52f include: import linux/ethtool_netlink_generated.h from kernel v7.3-rc2
Only the generated header is imported, as everything needed (the genl family name,
commands, attributes and header flags) is defined there, and linux/ethtool_netlink.h
itself would be unused.

Preparation for supporting the ethtool genl family in sd-netlink.
2026-10-21 09:32:43 -07:00
Lennart Poettering 5eb392756d include: import linux/nvme_ioctl.h from v7.3-rc2
It will be used by the upcoming disk health metrics source to issue NVMe
admin commands.
2026-10-16 16:03:23 +02:00
Yu Watanabe 6a131b32e0 include: fix limits.h override
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.
2026-09-22 18:14:12 +09:00
Luca Boccassi 816d1e48cc include: update syscalls lists 2026-09-08 20:47:54 +01:00
Yu Watanabe deef441b03 include: update kernel headers from v7.3-rc2
The only difference from the previous update is that now CONFIGFS_MAGIC
is listed in the magic.h, hence the override is not necessary anymore.
2026-09-07 19:36:29 +09:00
Yu Watanabe 6ce2db8dc2 include: update Linux kernel headers from v7.3-rc1 2026-08-31 19:43:10 +09:00
Yu Watanabe a2de89f622 libc: call epoll_pwait2 syscall directly instead of resolving glibc symbols
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.
2026-08-28 06:19:13 +09:00
Yu Watanabe 059b41654f include: add missing definition of PF_DUMPCORE 2026-08-27 05:50:14 +09:00
Yu Watanabe f807a32125 coredump: do not leak TID in the host to container (#43349)
PID, UID, and GID are converted by sending struct ucred, however, TID
was not converted. Let's convert TID if corresponding pidfd exists, and
discards TID otherwise.

Fixes 4c7af7d9d1.
2026-08-15 01:38:04 +09:00
Skye Soss 89fb28f1d3 include/uapi: add linux/securebits.h 2026-08-13 13:21:28 -05:00
Yu Watanabe 0ce8c68f02 include: use linux/pidfd.h rather than sys/pidfd.h
Since glibc-2.43, sys/pidfd.h defines struct pidfd_info, but its
definition is slightly older compared with linux v6.19. See
https://sourceware.org/git/?p=glibc.git;a=commit;h=c0c9524a11c56889ec5b1de2e0b78112f2ebc0b7
https://lore.kernel.org/all/20251028-work-coredump-signal-v1-0-ca449b7b7aa0@kernel.org/

This imports linux/pidfd.h (and linux/ioctl.h) from the kernel 7.2-rc6,
and make our header that overrides sys/pidfd.h includes linux/pidfd.h.
Then, we can always use uptodate definition of struct pidfd_info.

Note, linux/pidfd.h includes linux/fcntl.h, but it conflicts glibc's
fcntl.h. So, this also replaces linux/fcntl.h with glibc's fcntl.h.
2026-08-11 00:27:15 +09:00
Yu Watanabe ac33190d1f include: update kernel headers from v7.2-rc5
It seems there is no notable changes to us.
2026-08-02 22:06:40 +09:00
Emanuele Rocca 9c0c364b97 include: add hwcaps missing from glibc and musl
Add an override file for all capabilities missing in glibc v2.34 and musl
1.2.6. The constant AT_HWCAP3 is also not in glibc v2.34, ship a glibc-specific
elf.h in order to provide it.

Signed-off-by: Emanuele Rocca <emanuele.rocca@arm.com>
2026-07-10 12:02:01 +02:00
Yu Watanabe 0d06dbabc3 include: do not override kernel headers with libaudit headers
Overriding <linux/audit.h> to implicitly include <libaudit.h> turns out to
be problematic. Because <linux/audit.h> is pulled in by various other kernel
headers, any source file including those kernel headers indirectly ends up
depending on <libaudit.h>, even if the executable or library being built
does not require libaudit at all.

Let's drop the override header and include <libaudit.h> only where explicitly
needed. This also moves the fallback definitions of AUDIT_SERVICE_* and
MAX_AUDIT_MESSAGE_LENGTH to libaudit-util.h.
2026-07-03 17:25:34 +09:00
Luca Boccassi ef5ef5544a Import linux/liveupdate.h UAPI header from 7.2-rc1 2026-06-30 09:15:58 +01:00
Yu Watanabe 25714364a9 locale-util: drop libintl dependency
Both glibc and musl provides dgettext(). Hence it is not necessary to
use libintl.so provided by gettext.

This partially reverts 590e226437,
fully reverts commit e6e65dc261 and
bd19ffd9cb.

Then, introduce minimal libintl.h for musl build, to avoid using
libintl.h by gettext, which is typically installed on musl-based
build systems.
2026-06-29 23:22:41 +09:00
Yu Watanabe da2ed93b65 musl: fix build on 32-bit architecture
```
../src/boot/test-efi-string.c: In function 'test_xvasprintf_status':
../src/boot/test-efi-string.c:744:34: error: format '%zi' expects argument of type 'signed size_t', but argument 4 has type 'long int' [-Werror=format=]
  744 |         test_printf_one("%i %i %zi", INT_MIN, INT_MAX, SSIZE_MAX);
      |                                ~~^
      |                                  |
      |                                  int
      |                                %li
cc1: some warnings being treated as errors
ninja: subcommand failed
```
2026-06-15 14:15:46 +02:00
Daan De Meyer 06e32e4b61 Introduce support for running code in fibers (#39771)
Traditionally, asynchronous programming in systemd has been achieved
using
sd-event along with the asynchronous interfaces of sd-bus and
sd-varlink.
This works well when the system is reacting to events and all code
triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback
can
use the stack as usual, declaring local state and ensuring proper
cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block
execution
within the callback, we can't directly invoke a long-running operation
and
wait for its result without introducing complexities. Instead, we need
to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along
as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope
may
be prematurely cleaned up. Therefore, the struct must store copies of
the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a
loop,
the complexity grows further. We must introduce additional shared state
to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must
track
the lifecycle of each long-running operation in the global Manager
struct,
ensuring proper cleanup even when stack unwinding can no longer manage
the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s
running
synchronously, but with the ability to yield control at predefined
points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while
waiting
for the long-running operation to finish and then "resume" the operation
once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in
a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve
the
handling of complex workflows, making the code easier to write and
maintain.

The implementation is based on ucontext.h's makecontext() (with a
fallback
to the venerable sigaltstack() approach on musl),
sigsetjmp()/siglongjmp()
and sd-event. ucontext.h provides us with alternate stacks that we can
switch
between. We use sigsetjmp()/siglongjmp() instead of swapcontext()
because the
latter forcibly saves/restores a per context signal mask every time it
is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and
maintain
a per thread signal mask, which makes much more sense than having a per
fiber
signal mask.

The default stack size is the same as a regular thread. Because we 
use mmap() to allocate the stack, the memory won't actually be used
until it
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a
deferred
event source which resumes the fiber when enabled. The deferred event
source
is oneshot by default so the fiber will run immediately until it yields
or
suspends. If it yields, the deferred event source is enabled again
(oneshot)
immediately. If it suspends, before it suspends, one or more event
sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for
completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or
any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is
cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the
fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup
to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them
behind
a generic futures interface to represent long-running operations,
regardless of
whether those operations are running on a fiber or not. Aside from
fibers, the
futures library (sd-future) will for example allow waiting for sd-event
sources
and doing sd-bus calls in the background as well. Fibers can suspend
until a
future is ready with sd_fiber_await() or by having the future wake up
the fiber
explicitly in its callback. A future always defaults to waking up the
current
fiber.

Each future kind plugs into the library by providing an sd_future_ops
vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it
via
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to
that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from
a
fiber via sd_fiber_await() (synchronous-looking fiber code).
sd_fiber_await()
is itself built on a "wait future" that resolves when its target
resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber
callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future
impl's
cancel callback, which is responsible for tearing down its work and
ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from
sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new()
—
take a self-reference on their future so they outlive the caller's
scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds
would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal
sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an
unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the
following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of
it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.
2026-05-21 16:21:13 +02:00
Zbigniew Jędrzejewski-Szmek 705a705e85 include/uapi: add linux/openat2.h (#42220)
We include the header through src/include/override/fcntl.h, hence we should
have the latest copy of the header.

(E.g. compilation fails with musl-libc-1.2.5-6.fc44.x86_64 and older kernel
headers.)
2026-05-21 13:29:28 +02:00
Daan De Meyer 8533513aff Introduce support for running code in fibers
Traditionally, asynchronous programming in systemd has been achieved using
sd-event along with the asynchronous interfaces of sd-bus and sd-varlink.
This works well when the system is reacting to events and all code triggered
by those events can run without blocking. In these scenarios, the global
Manager object is passed as userdata to the callback, and the callback can
use the stack as usual, declaring local state and ensuring proper cleanup via
_cleanup_. Control flow structures, such as loops, work as expected, and
everything runs smoothly.

However, challenges arise when the code needs to perform long-running
operations within these callbacks. Since the system cannot block execution
within the callback, we can't directly invoke a long-running operation and
wait for its result without introducing complexities. Instead, we need to
initiate the long-running task, register for completion with sd-event,
sd-bus, or sd-varlink, and provide a callback to be invoked when the
operation completes.

This callback, however, only receives a single userdata pointer, which
forces us to bundle all local variables into a struct and pass it along as
part of the callback. On top of that, after queuing the asynchronous
operation, the caller continues executing. As the caller's stack unwinds
when the function exits, the resources and state within the local scope may
be prematurely cleaned up. Therefore, the struct must store copies of the
local variables or ensure proper reference counting to prevent premature
resource cleanup.

When multiple long-running operations need to be initiated within a loop,
the complexity grows further. We must introduce additional shared state to
track the completion of all operations before we can run any code that
depends on their results.

Furthermore, since the daemon may be shut down at any time, we must track
the lifecycle of each long-running operation in the global Manager struct,
ensuring proper cleanup even when stack unwinding can no longer manage the
resources for us.

Fibers, or green threads, provide a more natural way of handling
asynchronous operations. By enabling cooperative multitasking within a
single thread, fibers allow us to write code that looks like it’s running
synchronously, but with the ability to yield control at predefined points,
such as when waiting for long-running tasks to complete.

With fibers, we can simplify the control flow by running asynchronous
operations within a fiber, allowing us to "pause" execution while waiting
for the long-running operation to finish and then "resume" the operation once
it's complete. This eliminates the need for multiple callback chains,
extensive state tracking, and the potential pitfalls of stack unwinding.

This commit introduces the ability to execute long-running operations in a
non-blocking manner while maintaining the simplicity and readability of
synchronous code. The fiber-based approach will significantly improve the
handling of complex workflows, making the code easier to write and maintain.

The implementation is based on ucontext.h's makecontext() (with a fallback
to the venerable sigaltstack() approach on musl), sigsetjmp()/siglongjmp() 
and sd-event. ucontext.h provides us with alternate stacks that we can switch 
between. We use sigsetjmp()/siglongjmp() instead of swapcontext() because the
latter forcibly saves/restores a per context signal mask every time it is called.
Using sigsetjmp()/siglongjmp(), we can avoid the unnecessary syscall and maintain
a per thread signal mask, which makes much more sense than having a per fiber
signal mask.

The default stack size is the same as a regular thread. Because we 
use mmap() to allocate the stack, the memory won't actually be used until it 
is paged in by the kernel, so we don't actually use 8MB per fiber.

To integrate fibers with the event loop, each fiber is assigned a deferred
event source which resumes the fiber when enabled. The deferred event source
is oneshot by default so the fiber will run immediately until it yields or
suspends. If it yields, the deferred event source is enabled again (oneshot)
immediately. If it suspends, before it suspends, one or more event sources
are registered with sd-event that will enable the deferred event source
(oneshot) to resume the fiber once the operation it is waiting for completes.

Yielding or suspending the fiber is done by calling sd_fiber_yield() or
sd_fiber_suspend() respectively. Both of these return zero on success or any
error value from the async operation that caused the fiber to resume.

This is also how fiber cancellation is implemented. When a fiber is cancelled,
sd_fiber_yield() and sd_fiber_suspend() will return ECANCELED when the fiber
is resumed, allowing the fiber to unwind its stack (which allows cleanup to
happen automatically) and finish.

Instead of having applications work directly with fibers, we hide them behind
a generic futures interface to represent long-running operations, regardless of
whether those operations are running on a fiber or not. Aside from fibers, the
futures library (sd-future) will for example allow waiting for sd-event sources 
and doing sd-bus calls in the background as well. Fibers can suspend until a 
future is ready with sd_fiber_await() or by having the future wake up the fiber
explicitly in its callback. A future always defaults to waking up the current 
fiber.

Each future kind plugs into the library by providing an sd_future_ops vtable
(alloc, free, cancel, set_priority). The library treats the impl pointer
returned by alloc() as a black box. Future Implementations retrieve it via 
sd_future_get_private().

A future starts in SD_FUTURE_PENDING and transitions exactly once to
SD_FUTURE_RESOLVED, carrying an integer result. Consumers can react to that
transition either by installing a one-shot callback with
sd_future_set_callback() (callback-style code) or by waiting on it from a
fiber via sd_fiber_await() (synchronous-looking fiber code). sd_fiber_await()
is itself built on a "wait future" that resolves when its target resolves;
sd_future_new_wait() exposes the same primitive directly so non-fiber callers
can chain futures without involving a fiber.

Cancellation is cooperative: sd_future_cancel() invokes the future impl's 
cancel callback, which is responsible for tearing down its work and ultimately
resolving the promise with -ECANCELED. For fiber futures this is what
surfaces as the ECANCELED return from sd_fiber_yield()/sd_fiber_suspend()
mentioned above.

Fire-and-forget fibers — created by passing a NULL ret to sd_fiber_new() —
take a self-reference on their future so they outlive the caller's scope.
The self-ref is dropped when the fiber resolves. This floating mechanism
(sd_fiber_set_floating()) is restricted to fiber futures because they
uniquely guarantee resolution; allowing it for arbitrary future kinds would
risk silent leaks for kinds that may never resolve.

Note that fiber cleanup depends on the runtime operating normally. Each
fiber's _cleanup_-style cleanups live on the fiber's own stack and run
only when the fiber is resumed and allowed to unwind, which requires a
working event loop to drive it to completion. The exit event source
registered for top-level fibers ensures unwind on a normal sd_event_exit(),
but if the event loop itself terminates abnormally (e.g. an unrecoverable
allocation failure mid-dispatch) before all fibers have resolved, their
stacks never unwind and any resources they own leak.

The code lives in libsystemd as sd-future (not exported) for the following reasons:
- We may want to make this a public libsystemd API in the future
- The code can't live in src/basic as it makes heavy use of sd-event
- The code can't live in src/shared as sd-bus and sd-event make use of it

The log and log-context headers are updated with functions to allow
fibers to have their own log prefix and log context.
2026-05-21 09:55:04 +00:00
Daan De Meyer 74d392ed1b tree-wide: standardize header names across src/fundamental, src/basic and src/shared
Drop the -fundamental suffix from src/fundamental/ headers in favor of names
that match their src/basic/ or src/shared/ counterparts (e.g.
macro-fundamental.h -> macro.h, assert-fundamental.h -> assert-util.h,
cleanup-fundamental.h -> cleanup-util.h). Rename src/basic/{btrfs,label}.{c,h}
to use the -util suffix to match the existing shared/btrfs-util and
shared/label-util siblings. Rename src/shared/mkdir-label.{c,h} to mkdir.{c,h}
and src/shared/tmpfile-util-label.{c,h} to tmpfile-util.{c,h} to match the
corresponding src/basic names.

This saves us from having to come up with separate names for files that do
the same thing across tiers, and it makes it easier to move stuff between
src/fundamental, src/basic and src/shared: consumers just #include "foo.h"
and pick up whichever tier their -I path resolves to first, so call sites
don't need to be updated when an API moves between layers.

Where a higher-tier wrapper exists (e.g. src/basic/macro.h wrapping
src/fundamental/macro.h), the wrapper uses an explicit "../fundamental/foo.h"
or "../basic/foo.h" relative include for the lower-tier header. We can't use
GCC's #include_next directive for this — when the wrapper is reachable both
via same-dir-as-source lookup and via -I (e.g. -Isrc/shared) for the
directory it lives in, #include_next advances by exactly one slot in libcpp's
internal directory chain and lands on the same physical directory it was
already in, never reaching the lower-tier sibling (see make_cpp_dir() in
gcc/libcpp/files.cc:1986).

To make sure the right headers are always picked up, the include directories
are reordered so that e.g. src/shared always takes priority over src/basic and
similar for the other directories.

Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 10:33:03 +09:00
Yu Watanabe ba13cd1245 include: update kernel headers from v7.1-rc4
It seems there is no notable changes to us.
2026-05-21 07:07:37 +09:00
Yu Watanabe 12b9760800 musl: drop several statx definitions
Those dropped definitions have been provided since musl v1.2.6.
2026-05-21 05:06:35 +09:00
Yu Watanabe bc40f6cc32 musl: drop renameat2() wrapper
musl provides renameat2() since v1.2.6:
https://git.musl-libc.org/cgit/musl/commit/?id=05ce67fea99ca09cd4b6625cff7aec9cc222dd5a
2026-05-21 05:06:35 +09:00
Yu Watanabe 5904cee941 include: move several missing definitions to musl
Those moved ones have been defined in glibc <= 2.34, and only
necessary when built with musl.

Follow-up for c8c1bcf194.
2026-05-21 03:51:26 +09:00
Emanuele Rocca c8c1bcf194 signal-util: add signal_code_to_string
Add signal_code_to_string() in signal-util.c and cover the si_code values
defined in libc's siginfo-consts.h. Fall back to the numeric value when no
symbolic name is known.

Co-developed-by: Codex (GPT-5) <noreply@openai.com>
Signed-off-by: Emanuele Rocca <emanuele.rocca@arm.com>
2026-05-19 08:14:36 +00:00
Emanuele Rocca 577f2f975d include: add coredump_code to struct pidfd_info
Linux v7.1 adds coredump_code to struct pidfd_info and defines a few new
constants. Reflect the changes in include/override/sys/pidfd.h too.

Stop including the libc version of sys/pidfd.h to be able to override the
definition of pidfd_info.

Signed-off-by: Emanuele Rocca <emanuele.rocca@arm.com>
2026-05-19 08:14:18 +00:00
Daan De Meyer bdbcff6530 Various dlopen/linking cleanups from #42100 (#42166)
- **bpf-util: rename from bpf-dlopen, unify version-specific symbol
handling**
- **cryptsetup: dlopen libcryptsetup in tokens**
- **tree-wide: dlopen libpam in pam plugins**
- **test-bus-marshal: dlopen() glib and libdbus instead of linking
directly**
- **lock-util: Simplify timeout for lock_generic_with_timeout()**
- **color-util: simplify hsv_to_rgb, fix rgb_to_hsv negative-hue wrap**
- **tree-wide: Use our own macros instead of fabs()/fmax()/fmin()**
- **locale-util: dlopen() libintl instead of linking against it**
- **home: Use log2u64() over log2()**
- **meson: drop libdl, threads, and librt dependencies**
- **libc: Use dlsym() from a constructor instead of weak symbols**
- **libc: Make sure C23 versions of strtol(), sscanf() are not used**
2026-05-19 08:54:27 +02:00
Daan De Meyer 97f81508c5 libc: Make sure C23 versions of strtol(), sscanf() are not used
When _GNU_SOURCE is defined, glibc will always use c23 versions
of strtol(), sscanf() and friends if available (introduced after
glibc 2.34). Which means that any binaries built with headers
from newer glibc won't load on glibc < 2.38. To work around this,
redefine the appropriate constants to zero make sure the c99 
versions are used instead.
2026-05-18 21:17:38 +00:00
Luca Boccassi 20a79f1222 Update syscall numbers
ninja -C build update-syscall-tables update-syscall-header
2026-05-18 12:18:04 +01:00
Yu Watanabe b0a06e2a81 generate-syscall: apply "ruff format" and "ruff check --fix"
Also, this makes opened files closed when not necessary.
2026-05-18 02:44:46 +09:00
Yu Watanabe 5768f1dd6f Final batch of conversions to option and verb macros (#42127) 2026-05-17 03:50:48 +09:00
Zbigniew Jędrzejewski-Szmek d512d3c6d3 treewide: get rid of remaing getopt/getopt_long stuff 2026-05-16 18:37:12 +02:00
Daan De Meyer bce7b82268 nsresourced: detect and clean up registry entries for dead user namespaces (#42070)
The BPF kprobe that fires on user namespace destruction is the only
thing
that triggers registry cleanup, so any time it doesn't run — ring buffer
overflow, kprobe missing, fdstore entry dropped outside our cleanup path
— a registry entry is left behind forever.

Stamp each registry entry with the kernel's unique namespace identifier
(NS_GET_ID, kernel ≥ 6.13) at allocation time. At manager startup, after
the existing fdstore→registry sweep, walk the registry and ask the
kernel
to look each namespace up by id via open_by_handle_at() on nsfs; if the
lookup returns -ESTALE the namespace is gone and we release the entry.
Old entries written before this change carry no identifier and are left
alone.

Add a namespace_open_by_id() helper for the lookup. The kernel restricts
open_by_handle_at() on nsfs to processes in the initial user namespace,
collapsing both permission denials and dead namespaces onto -ESTALE; the
helper refuses early with -EPERM outside the initial user namespace
so callers can tell the two apart.
2026-05-15 21:19:15 +02:00
Daan De Meyer 23f2204718 nsresourced: detect and clean up registry entries for dead user namespaces
The BPF kprobe that fires on user namespace destruction is the only thing
that triggers registry cleanup, so any time it doesn't run — ring buffer
overflow, kprobe missing, fdstore entry dropped outside our cleanup path
— a registry entry is left behind forever.

Stamp each registry entry with the kernel's unique namespace identifier
(NS_GET_ID, kernel ≥ 6.13) at allocation time. At manager startup, after
the existing fdstore→registry sweep, walk the registry and ask the kernel
to look each namespace up by id via open_by_handle_at() on nsfs; if the
lookup returns -ESTALE the namespace is gone and we release the entry.
Old entries written before this change carry no identifier and are left
alone.

Add a namespace_open_by_id() helper for the lookup. The kernel restricts
open_by_handle_at() on nsfs to processes in the initial user namespace,
collapsing both permission denials and dead namespaces onto -ESTALE; the
helper refuses early with -EHOSTDOWN outside the initial user namespace
so callers can tell the two apart.
2026-05-15 18:05:21 +00:00
Luca Boccassi bc1c56543f Import linux/liveupdate.h UAPI header
From kernel 7.0
2026-05-15 13:46:08 +01:00
Daan De Meyer ba1d406f9b include: import linux/nsfs.h from kernel v7.0.0~rc1 2026-05-14 21:30:59 +00:00
Daan De Meyer f795d54591 libc,shared: detect newer library symbols at runtime
For libc syscall wrappers (pidfd_open, fsopen, openat2, etc.) we previously
gated the calls behind build-time HAVE_* checks. Replace these with shim
functions in src/libc/ that fall back to the raw syscall at runtime when the
loaded glibc lacks the symbol. The infrastructure lives in src/libc/libc-shim.h:
DEFINE_SYSCALL_SHIM falls back to a direct syscall, DEFINE_LIBC_SHIM returns
ENOSYS (for posix_spawn-family helpers that have no corresponding syscall), and
DEFINE_LIBC_ERRNO_SHIM sets errno=ENOSYS and returns -1 (for read/write-style
helpers). The weak reference to the libc symbol is bound via __asm__(\"name\")
rename so the bare libc identifier never appears as a C token — this avoids
both #undef boilerplate against override-header redirects and the resulting
-Wredundant-decls warning. Drop the corresponding cc.has_function() loop from
meson.build.

For optional libraries (libcryptsetup, libdw, libarchive), drop the per-symbol
HAVE_* checks. Always declare the prototypes, suppressing the redundant-decl
warnings via DISABLE_WARNING_REDUNDANT_DECLS and NOLINT, and resolve the symbols
after the main dlopen via a new DLSYM_OPTIONAL() helper that only assigns on
success. libcryptsetup's crypt_set_keyring_to_link / crypt_token_set_external_path
and libarchive's *_is_set wrappers use fallback functions as their pointer
initializers (returning -ENOSYS and 0 respectively), so call sites can invoke
the symbol unconditionally and just check for -ENOSYS where the \"not supported\"
distinction matters.

The same shim treatment applies to pidfd_spawn / posix_spawnattr_setcgroup_np
(src/libc/spawn.c) and epoll_pwait2 (src/libc/epoll.c), with corresponding
override headers in src/include/override/spawn.h and
src/include/override/sys/epoll.h. posix_spawn_wrapper() in process-util.c and
epoll_wait_usec() in sd-event.c now detect ENOSYS in the return value instead
of checking the function pointer, falling back to plain posix_spawn() and
epoll_wait() respectively. coredump-config and coredump-submit get a
dlopen_dw_has_dwfl_set_sysroot() helper. The kexec arch gate now uses
defined(__NR_kexec_file_load) directly; pidfd.h uses __has_include_next() to
decide whether to pull in glibc's header.

This lets binaries built against newer glibc / libcryptsetup / libdw /
libarchive headers still load and run on older targets where these symbols are
absent.
2026-05-13 10:29:50 +02:00
Daan De Meyer 5d60cd8539 syscall: add kexec_file_load to the generated override header
This makes __NR_kexec_file_load available on architectures where the kernel
UAPI headers don't define it, matching the runtime fallback path in
src/libc/kexec.c which is gated on #ifdef __NR_kexec_file_load.
2026-05-13 08:51:28 +02:00
Daan De Meyer 8b81e3b751 chase: Use openat2() if available
Let's make use of openat2() if we can in chaseat().
2026-05-12 14:43:39 +02:00
Daan De Meyer 4d91b0366a libc: Add kexec_file_load() syscall wrapper
Allow tabs in UAPI headers in .gitattributes since they are copied
verbatim from the kernel.
2026-04-13 11:13:04 +02:00
Andreas K. Hüttel beef155b12 mips: Fix conditional inclusion of <asm/sgidefs.h>
systemd now has a system call wrapper that does a long series of #ifdef's to
differentiate between architectures and ABIs. This wrapper has two problems.

1. On mips, it needs to differentiate between O32, N32, N64 ABI. It does that
via a code block in src/include/override/sys/generate-syscall.py (and derived
files):

     76 #  elif defined(_MIPS_SIM)
     77 #    if _MIPS_SIM == _MIPS_SIM_ABI32
     78 #      define systemd_NR_{syscall} {nr_mipso32}
     79 #    elif _MIPS_SIM == _MIPS_SIM_NABI32
     80 #      define systemd_NR_{syscall} {nr_mips64n32}
     81 #    elif _MIPS_SIM == _MIPS_SIM_ABI64
     82 #      define systemd_NR_{syscall} {nr_mips64}
     83 #    else
     84 #      error "Unknown MIPS ABI"
     85 #    endif
     86 #  elif defined(__hppa__)

Now the _MIPS_SIM* constants stem from a vendor-specific header file sgidefs.h,
which is included with glibc, but not with musl. It is however always present
in the Linux kernel headers as asm/sgidefs.h ...

2. To work around this, the syscall wrapper already has a block

     47 #ifdef ARCH_MIPS
     48 #include <asm/sgidefs.h>
     49 #endif

Turns out, ARCH_MIPS is defined nowhere in Gentoo, neither on glibc nor on musl.
As a result the code (by accident, probably sgidefs.h is included transitively
somehow) works on glibc, but not on musl.

The simplest fix is to replace line 47 in the generator and the derived file
with

     47 #ifdef __mips__

Two other source code files require a similar fix since they rely on the
constants.

Bug: https://github.com/systemd/systemd/issues/41239
Bug: https://bugs.gentoo.org/971376
Signed-off-by: Andreas K. Hüttel <dilfridge@gentoo.org>
2026-03-22 20:02:13 +01:00
Yu Watanabe c418543a65 include: update kernel headers from v7.0-rc1
In v7.0-rc1, the kernel introduces typelimits.h to define __KERNEL_INT_MIN/_MAX.
Also, NULL_FS_MAGIC has been introduced for immutable rootfs..
2026-02-24 23:08:52 +09:00