Commit Graph
276 Commits
Author SHA1 Message Date
Daan De Meyer f875a8026e core: Don't use TTYPath= for PAM unless StandardInput=tty
Fixes #39334
2025-10-16 13:46:19 +02:00
Lennart Poettering 83b6ef9b62 libselinux: turn into dlopen() dep 2025-09-26 11:12:04 +02:00
Lennart Poettering aaca6bd5d9 libseccomp: turn into dlopen() dependency 2025-09-26 03:30:11 +09:00
Lennart Poettering 882c9ce040 pam: make libpam a dlopen() based dependency 2025-09-20 08:41:20 +02:00
Daan De Meyer 9adb4685df tree-wide: Remove unused includes 2025-09-19 14:46:55 +02:00
Yu Watanabe dac478c44c core: fix typo
Follow-up for b3415f5dae.
2025-08-26 04:54:19 +09:00
Yu WatanabeandLuca Boccassi 4279336618 chase: trigger automount only when explicitly requested
Since c5de7b14ae
file searching implies a new mount api syscall by default,
to trigger automounts.

But, this is not necessary in most cases, e.g. when chasing
syspath in sd-device (actually this causes regression in umockdev,
see https://github.com/martinpitt/umockdev/issues/271).
Another example is reading unit files, especially .network files,
as automount may trigger mounting network filesystems...

Also, when this is used in NSS plugins, programs that load the
plugins may fail because of spuriously configured seccomp. See #38565.

Let's not trigger automount by default, and do only when explicitly
requested.

This introduces CHASE_TRIGGER_AUTOFS, and use it in
- service manager,
- bootctl and finding ESP/xbootldr,
- sysupdate,
- mountfsd,
- systemd-mount.

There may be several more places we should trigger automount, but let's
do that later.

Follow-up for c5de7b14ae.
Fixes #38565.
Replaces #38569.

Co-authored-by: Luca Boccassi <luca.boccassi@gmail.com>
2025-08-20 02:32:02 +09:00
Yu Watanabe 2e7d7e929e Revert "chase: invert CHASE_NO_AUTOFS and only set it where needed"
This reverts commit 490aa05ca1.

As commented https://github.com/systemd/systemd/pull/38569#discussion_r2284978273,
the commit makes autofs check bypassed. Before the commit, when
CHASE_NO_AUTOFS is set, we did not shortcut chasing paths, and refused
any autofs mount points in the path. However, with the commit, the flag
was swapped but even when CHASE_AUTOFS is unset, the autofs check may be
skipped.

To fix the issue, rather than swapping the flag, we should introduce
another flag, say CHASE_TRIGGER_AUTOFS. This revert the commit, and in a
later commit, the new flag will be introduced.
2025-08-20 02:15:36 +09:00
Luca Boccassi 490aa05ca1 chase: invert CHASE_NO_AUTOFS and only set it where needed
Since https://github.com/systemd/systemd/commit/c5de7b14ae2e08d267d8d75bc88934ac6aa7dcd6
file searching implies a new mount api syscall by default,
to trigger automounts.

This is problematic in NSS plugins, as they are dlopen'ed inside
processes by glibc, for two reasons.

First of all, potentially searching on a networked filesystem
automount could lead to nasty surprises, such as the process
responsible for setting up the network filesystem trying to
search on that same filesystem.

More importantly, the new mount api syscall was never part of
the filesystem seccomp filter that we provide by default, and
given mounting/remounting/bind mounting is one of the possible
ways to bypass sandboxing it is very likely not allowed when
custom filters are used in sandboxed processes, if they don't
need to do these operations otherwise.
The filesystem seccomp mask we provide has been updated, however
this only takes effect on the next restart of a service. When
systemd is upgraded via a package upgrade, the new nss plugin is
installed and will be immediately dlopen'ed by glibc when needed,
without waiting for the process to restart, which means the existing
seccomp filter applies, causing the filter to trigger.
Given it's not really possible for any arbitrary program to
predict which NSS modules glibc will load, given programs do not
configure that and instead nsswitch is set up by the sysadmin,
it's impossible to handle at each process level. It's also not
possible to know when it will be triggered, given the plugin
is not linked in each binary tools like need-restart cannot
even pre-emptively restart services that may be affected.

This means in practice, upgrading from systemd << v258 to >= v258
requires a reboot to avoid either subtle or catastrophic system
failures.

By avoiding to trigger automounts in nss-systemd we can avoid
both issues.

userdb drop-ins are searched for in:

/etc/userdb/
/run/userdb/
/run/host/userdb/
/usr/local/lib/userdb/
/usr/lib/userdb/

none of which are supported as automounts anyway.

Note that this happens only when the userdbd service is not running,
as otherwise nss-systemd will go through the varlink IPC, rather than
doing the searches in-process.

So invert CHASE_NO_AUTOFS to CHASE_AUTOFS and set it in the places where
we do want to trigger automounts, like looking for the ESP.

Follow-up for https://github.com/systemd/systemd/commit/c5de7b14ae2e08d267d8d75bc88934ac6aa7dcd6
Fixes https://github.com/systemd/systemd/issues/38565
2025-08-19 16:48:13 +02:00
Yu Watanabe 379d9ae222 core: do not touch tty when StandardOutput=/StandardError=journal+console/kmsg+console 2025-08-13 23:44:42 +09:00
Yu Watanabe da34c27bb1 core: make is_terminal_input() and friends inline
Then, rename them to exec_input_is_terminal() and so on.
2025-08-13 23:43:52 +09:00
Matteo Croce 814bff5e28 core: suppress warning
Avoid definition of `exec_context_get_tty_for_pam` if pam support is
disabled, to avoid the following warning:
```
../src/core/exec-invoke.c:1231:12: warning: ‘exec_context_get_tty_for_pam’ defined but not used [-Wunused-function]
 1231 | static int exec_context_get_tty_for_pam(const ExecContext *context, char **ret) {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
2025-08-12 19:45:04 +01:00
Yu Watanabe 1405d46bf9 core/exec-invoke: fallback to set TTY specified by TTYPath= to PAM
Follow-up for 2b0087e5b1.
Fixes #38486.
2025-08-11 10:26:51 +09:00
Yu Watanabe 1f4e9f6d60 core/exec-invoke: check size of read size
Even though we do not use the read data, it is better to check the size
to prevent something spurious going.

Fixes CID#1612155.
2025-07-26 03:44:49 +09:00
Yu Watanabe 7f6086d530 tree-wide: do not use %m with SYNTHETIC_ERRNO() 2025-07-22 03:05:54 +09:00
Yu Watanabe 9eabf82750 core: it is not necessary to send message after fsconfig() for bpffs
Instead, let's wait for the helper process being finished.
2025-07-18 20:15:25 +09:00
Yu Watanabe 8509ceea10 core/exec-invoke: negative errno needs to be passed to report_errno_and_exit()
Hence, we cannot pass errno as is to report_errno_and_exit().

This splits out bpffs_helper(), which returns negative errno on failure,
and 0 on success. And make the returned value passed to report_errno_and_exit().

Follow-up for #36134.
2025-07-18 20:15:20 +09:00
Mike Yuan db54d1a6b7 core/exec-invoke: pass "/" instead of "" for cgroup root 2025-07-12 17:32:32 +02:00
Yu Watanabe 543a48b653 libc-wrapper: introduce a tiny libc wrapper
Then, move syscall definitions to the wrapper, and prototypes are moved
to relevant headers.

This also adds checks for add_key() and request_key(), as one day
glibc may be going to add some of them separatedly.

The check for fspick in meson.build is dropped, as it is currently
unused in our code.

This also moves
- basic/missing_bpf.h -> include/override/linux/bpf.h,
- basic/missing_keyctl.h -> include/override/linux/keyctl.h.
2025-07-11 13:05:46 +09:00
Matteo Croce ea9826eb94 core: add options to delegate BPFFS token creation
Add four new options BPFDelegate{Commands,Maps,Programs,Attachments}=
in order to delegate to a BPFFS instance the permission to create tokens.

The value is a list of options taken from:
https://github.com/torvalds/linux/blob/v6.14/include/uapi/linux/bpf.h#L922-L1121
The special value "any" means to allow every possible values.

More informations about BPF tokens here:
https://lwn.net/Articles/947173/
2025-07-08 22:35:29 +02:00
Matteo Croce 3a47437fc9 core: Introduce PrivateBPF= to mount a private BPFFS
Add a new option PrivateBPF= to mount a new instance of bpffs within a
namespace.
PrivateBPF= can be set to "no" to use the host bpffs in readonly mode
and "yes" to do a new mount.
The mount is done with the new fsopen()/fsmount() API because in future
we'll hook some commands between the two calls.
2025-07-08 22:33:28 +02:00
Matteo Croce 2c7dabff50 core: split out setup_private_users_child()
Drop support for kernels older than 3.19, as this is where
/proc/<pid>/setgroups was added.

https://github.com/torvalds/linux/commit/9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8
2025-07-08 18:23:46 +02:00
Andres Beltran 26c6f3271a core: add quota support for State, Cache, and Log exec directories 2025-07-07 17:28:47 +00:00
Yu Watanabe 2643cb1ade core: rename ExecContext.ioprio_set -> .ioprio_is_set
To make it not conflict with syscall ioprio_set().
This is important as we have
```
 #define ioprio_set missing_ioprio_set
```
in missing_syscall.h.
2025-07-06 13:31:40 +02:00
Yu Watanabe 237bdd2771 basic: move missing_sched.h -> include/sched.h 2025-07-01 12:29:15 +09:00
Yu Watanabe 4f18ff2e29 tree-wide: include unistd.h where necessary
We use symbols provided by unistd.h without including it. E.g.
open(), close(), read(), write(), access(), symlink(), unlink(), rmdir(),
fsync(), syncfs(), lseek(), ftruncate(), fchown(), dup2(), pipe2(),
getuid(), getgid(), gettid(), getppid(), pipe2(), execv(), _exit(),
environ, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, F_OK, and their
friends and variants, so on.

Currently, unistd.h is indirectly included mainly in the following two paths:
- through missing_syscall.h, which is planned to covert to .c file.
- through signal.h -> bits/sigstksz.h, which is new since glibc-2.34.
  Note, signal.h is included by sd-eevent.h. So, many source files
  indirectly include unistd.h if newer glibc is used.

Currently, our baseline on glibc is 2.31. We need to support glibc older
than 2.34, but unfortunately, we do not have any CI environments with
such old glibc. CIFuzz uses glibc-2.31, but it builds only fuzzers, and
many files are even not compiled.
2025-06-30 09:19:15 +02:00
Lennart Poettering 5584632f40 cpu-set-util: fix null pointer dereference and several cleanups (#37900)
Fixes CID#1611618.
2025-06-27 14:59:25 +02:00
Lennart Poettering 2be3a06bb2 core: when PrivateDevices= is enabled and we need to decrypt TPM2 credentials, go via IPC
Also, if a device ACL list is defined, also go via IPC (instead of
trying to patch it, as before).

The outcome is that the tighter rules continue to apply when configured.

Fixes: #35959
2025-06-24 22:16:01 +02:00
Yu Watanabe 296fe3d511 cpu-set-util: rename cpu_set_reset() -> cpu_set_done()
This also introduces cpu_set_done_and_replace().

No functional change, just refactoring.
2025-06-24 00:20:20 +09:00
Yu Watanabe df77ec5d3a exec-invoke: modernize exec_context_cpu_affinity_from_numa()
- always assign 'ret' on success,
- do not modify previous assignment of 'ret', and simply overwrite it.

No functional change, just refactoring.
2025-06-24 00:20:20 +09:00
Daan De Meyer f8f67eab70 core: Make sure we handle DelegateSubgroup= in combo with cgroupns
Currently, if we use a cgroup namespace together with DelegateSubgroup=,
the subgroup becomes the root of the cgroup namespace because we move the
service process to the subgroup before we unshare the cgroup namespace, and
the current cgroup becomes the root of the cgroup namespace when we unshare
the cgroup namespace.

Let's fix the problem by not moving the service process to the subgroup until
we've unshared the cgroup namespace. Note that this doesn't break the primary use
case of CLONE_INTO_CGROUP since we still use it to immediately clone into the service
main cgroup, just not anymore into the subgroup, but this shouldn't matter in practice.

Additionally, we need special handling for control processes, as those *do*
need to get spawned into the subcgroup immediately if delegation is configured to
avoid violating the cgroupsv2 "no inner processes" rule.

Effectively, this leaves us with the following logic:
- In exec_spawn(), spawn into subgroup if we're spawning a control process
  that needs to be spawned into a subgroup immediately. Otherwise, spawn into
  main service cgroup.
- In exec_invoke(), move into subgroup early if we don't need a cgroup namespace.
  Otherwise, move into subgroup after we've unshared the cgroup namespace.
2025-06-05 12:37:02 +02:00
Daan De Meyer 2d8191f4af core: Disable pid namespacing for control processes
PID namespaces frankly don't make any sense for control processes, so
let's gracefully degrade to no pid namespaces for control processes.
2025-06-05 12:37:02 +02:00
Mike Yuan 6131dc0aad core/exec-invoke: skip query of /dev/console $TERM if we're child of pid1 2025-05-29 21:25:28 +02:00
Mike Yuan 8ffebaaf4d core/exec-invoke: propagate $COLORTERM and $NO_COLOR from pid1 as well
Follow-up for 19aff5f775
2025-05-29 21:16:28 +02:00
Mike Yuan 3235fae685 core/exec-invoke: rework where to apply $TERM fallback logic
Follow-up for 728dbaeffb
and ad6ca4a612

This is inspired by #37538, see the discussion in
https://github.com/systemd/systemd/pull/37538#discussion_r2110229075.

If the user already specifies $TERM (which is actually
quite common if you look at run0), we'd needlessly invoke
the "fallback" logic and
a) possibly issue a DCS query whose result we end up simply
   discarding in strv_env_merge()
b) set $COLORTERM to "truecolor" unconditionally, whereas
   the explicit $TERM value might intend to disable the color output

To address this, the logic of setting fallback $TERM and friends
has been split out of build_environment(), and we'd call into it
only after all envvars have been collected.
2025-05-29 21:16:25 +02:00
Mike Yuan 94f533e305 core: strv_env_clean() modifies in-place, no need to set buf to itself 2025-05-29 21:01:43 +02:00
Mike Yuan c51379e6d8 Use DCS sequence to query terminal name and set $TERM automatically (#37538)
This code seems to work quickly and nicely for a bunch of modern
terminals. Setting $TERM automatically removes an common annoyance for
users. This code will not work for all terminal emulators, but by adding
it in systemd we'll entice maintainers of those terminals to add support
for the sequences. For the terminals that don't support the sequence, we
get a bit of a slowdown of `< 1 ms`, which seems hardly noticeable. The
user can always set TERM explicitly to avoid this if upgrading to a
newer terminal emulator is not possible.

Closes https://github.com/systemd/systemd/issues/36994.
2025-05-29 21:01:01 +02:00
Zbigniew Jędrzejewski-Szmek ad6ca4a612 core: use terminal DCS sequence to set $TERM
query_term_for_tty() is used in two places: in fixup_environment(),
which affects PID1 itself, and in build_environment(), which affects
spawned services. There is obviously some cost to the extra call,
but I think it's worthwhile to do it. When $TERM is set incorrectly,
basic output works OK, but then there are various annoying corner
cases. In particular, we get the support for color (or lack of it)
wrong, and when output is garbled, users are annoyed. Things like
text editors are almost certain to behave incorrectly. Testing in
test-terminal-util indicates that the time required to make a successful
query is on the order of a dozen microseconds, and an unsuccessful
query costs as much as our timeout, i.e. currently 1/3 ms. I think
this is an acceptable tradeoff.

No caching is used, because fixup_environment() is only called once,
and the other place in build_environment(), only affects services
which are connected to a tty, which is only a handful of services,
and often only started in special circumstances.

Fixes https://github.com/systemd/systemd/issues/36994.
2025-05-29 19:20:31 +02:00
Mike Yuan 8b0a0298b7 core/exec-invoke: don't set $TMPDIR if sandboxing is disabled
Follow-up for 6156bec7a4
2025-05-27 22:35:03 +02:00
Daan De Meyer 836e4e7ea8 core: Clean up includes
Split out of #37344.
2025-05-22 09:37:20 +02:00
Mike Yuan 81d5eda6c5 core: accept "|" ExecStart= prefix to spawn target user's shell; teach run0 about the new logic (#37071)
I've always been reluctant to invoke the current user's shell in another
user's context, hence was fully grounded in `sudo -i`. With this bit in
place `run0` will finally be feature-complete on my side ;-)
2025-05-12 16:10:03 +02:00
Yu WatanabeandMike Yuan 6156bec7a4 core: disable mounting disconnected private tmpfs on /var/tmp/ when DefaultDependencies=no
If DefaultDependencies=no, /var/ may not be mounted yet when the service
is being started. Previously, In such case, if the service has
PrivateTmp=disconnected, the service manager created /var/tmp/ on the
root filesystem and mounted the disconnected private tmpfs there. That
poluted the root filesystem and disturbed gpt-auto-generator on next
boot, as /var/ would not be empty anymore. See issue #37258.

This changes PrivateTmp=disconnected as the following:
- If DefaultDependencies=no and RootDirectory=/RootImage= are not set,
  then a private tmpfs is mounted _only_ on /tmp/, and set $TMPDIR=/tmp
  environment variable to suggest the service to use /tmp/.
- If DefaultDependencies=yes and RootDirectory=/RootImage= are not set,
  then implies RequiresMountsFor=/var/, though that is typically
  redundant, but anyway. Hence, we can safely mount /var/tmp/.
- Otherwise, i.e. when one of RootDirectory=/RootImage= is set, behaves
  as the same as the previous, as the private root filesystem for the
  service is explicitly prepared by the service manager, and we can
  safely mount a private tmpfs on /var/tmp/ without any extra
  dependencies.

Fixes #37258.

Co-authored-by: Mike Yuan <me@yhndnzj.com>
2025-05-11 03:33:02 +09:00
Mike Yuan 5b8bcbcf00 core: accept "|" ExecStart= prefix to spawn target user's shell
When switching to another user it's oftentimes desirable to also spawn
the target user's shell. sudo supports this via -i flag, run0 currently
doesn't. We don't want to proactively query NSS ourselves, since
that would fall short when operating remotely. Let's instead teach
the service manager to spawn the command using the user's default shell.

I opted for "|" instead of "." in the end because the latter seems
a bit obscure. But happy to change it to something else if a better option
comes up.
2025-05-07 18:32:19 +02:00
Daan De Meyer fda652117e fs-util: Reduce transitive includes 2025-05-07 22:04:46 +09:00
Daan De Meyer 44d50ba88e execute: Get rid of custom logging macros
We already have LOG_CONTEXT_PUSH_EXEC() which with two additions
does exactly the same as the custom logging macros, so let's get rid
of the custom logging macros and use LOG_CONTEXT_PUSH_EXEC() instead.
2025-04-23 14:48:45 +02:00
Daan De Meyer 4ea4abb651 core: Remove circular dependencies between headers
Currently there are various circular dependencies between headers
in core/. Let's get rid of these by making judicious use of forward
declarations and moving includes into implementation files instead of
having them in header files.

Getting rid of circular header includes simplifies the code and makes
various clang based tooling such as iwyu work much better on our code.

The most important change is getting rid of the manager.h include in
unit.h which is possible thanks to the previous commits. We also move
the OOMPolicy and StatusType enums to unit.h to remove the need for
other unit headers to include manager.h to get access to these enums.
2025-04-23 10:33:35 +02:00
Daan De Meyer 8aa304d313 shared: Remove circular dependency between image-policy.h and dissect-image.h
ImagePolicy can just be a forward declaration in dissect-image.h.
2025-04-23 09:53:43 +02:00
Mike Yuan 418082596c namespace-util: generalize namespace_type_supported() 2025-04-21 16:54:37 +02:00
Stefan Hansson b1236ce38b missing_fcntl: Introduce O_ACCMODE_STRICT
On musl, O_ACCMODE is defined as (03|O_SEARCH), unlike glibc which
defines it as (O_RDONLY|O_WRONLY|O_RDWR). Additionally, O_SEARCH is
simply defined as O_PATH.

This causes problems for systemd on musl, as it changes the
behaviour of open_mkdir_at_full() to return -EINVAL if O_PATH is
included in flags due to the fact that O_ACCMODE includes O_SEARCH
(i.e. O_PATH). Consequently, this makes the test-fs-util test fail.

Upstream musl seems content with this behaviour and doesn't seem
interested in matching glibc's behaviour due to that defining it this
way allows for O_SEARCH to match POSIX better by allowing it to open
directories where read permission is missing. Apparently musl does some
emulation in other places to make this work more consistently as well.

Initially I took the approach of working around this by redefining
O_SEARCH as O_RDONLY if O_SEARCH == O_PATH. This fixes the test and is
the approach taken by both XZ[1] and Gzip[2][3], but was not taken as
redefining system headers potentially could be problematic.

Instead, introduce O_ACCMODE_STRICT which just is a copy of glibc's
O_ACCMODE and use it everywhere. This way we don't have to deal with
unusual definitions of O_ACCMODE from C standard libraries other than
glibc.

 [1]: https://git.tukaani.org/?p=xz.git;a=blob;f=src/xz/file_io.c;h=8c83269b13fa31284f7ea5f3627a1dfbce7d6e14;hb=HEAD#l72
 [2]: https://git.savannah.gnu.org/cgit/gnulib.git/tree/lib/fcntl.in.h
      (lines 380 and 396, commit d7f551b30f3f2a0fa57c1b10c12f4eea41a9b89e)
 [3]: https://lists.gnu.org/archive/html/bug-gzip/2025-01/msg00000.html
2025-04-18 05:22:06 +09:00
Yu Watanabe 188286eec6 cgroup-setup: drop unnecessary controller argument
This also removes unnecessary cg_{create,attach,trim}_everywhere(),
and rename cg_enable_everywhere() -> cg_enable().
2025-04-16 03:56:04 +09:00