When inheriting file descriptors for stdout/stderr (either from stdin
or when making stderr inherit from stdout), we previously just assumed
they would be writable and dup'd them. This could lead to broken setups
if the inherited FD was actually opened read-only.
Before dup'ing any inherited FDs to stdout/stderr, verify they are
actually writable using the new fd_is_writable() helper. If not, fall
back to /dev/null (or reopen the terminal in the TTY case) with a
warning, rather than silently creating a broken setup where output
operations would fail.
$ sudo build/systemd-run --uid=asdf whoami
$ journalctl -e
(whoami)[1007784]: run-p1007782-i5200512.service: Failed to determine user credentials: No such process
(whoami)[1007784]: run-p1007782-i5200512.service: Failed at step USER spawning /usr/sbin/whoami: No such process
systemd[1]: run-p1007782-i5200512.service: Main process exited, code=exited, status=217/USER
systemd[1]: run-p1007782-i5200512.service: Failed with result 'exit-code'.
Now:
(whoami)[1013204]: run-p1013202-i5205932.service: Failed to determine credentials for user 'asdf': Unknown user
(whoami)[1013204]: run-p1013202-i5205932.service: Failed at step USER spawning /usr/sbin/whoami: Invalid argument
systemd[1]: run-p1013202-i5205932.service: Main process exited, code=exited, status=217/USER
systemd[1]: run-p1013202-i5205932.service: Failed with result 'exit-code'.
sys/prctl.h anyway includes linux/prctl.h and actually these .c files
includes sys/prctl.h. Hence, it is not necessary to explicitly include
linux/prctl.h.
Follow-up for 379d9ae222
After the commit, the functions are only used to determine
whether journals shall be forwarded to selected targets,
hence rename as such and remove effectively unused condition
on EXEC_OUTPUT_TTY.
Fixes#38486 again, which was fixed by
1405d46bf9, but regressed again by
f875a8026e.
This also make it use exec_input_is_terminal().
Follow-up for f875a8026e.
Commit 38748596f0 ("core: Make DelegateNamespaces= work for user
managers with CAP_SYS_ADMIN") refactored the logic for when an
unprivileged process should create a new user namespace for sandboxing.
This refactor inadvertently removed a check (`params->runtime_scope !=
RUNTIME_SCOPE_USER`) that differentiated between system services and user
services.
This causes a regression in rootless containers where systemd runs
unprivileged. When starting a system service (like `dbus-broker`) that
uses sandboxing features (eg. with `PrivateTmp=yes`), systemd now
incorrectly creates a new, minimal `PRIVATE_USERS_SELF` namespace.
This new namespace only maps UID/GID 0. When dbus-broker attempts to
drop privileges to the `dbus` user (GID 81), the `setresgid(81, 81, 81)`
call fails because GID 81 is not mapped.
Restore the check to ensure that the special unprivileged sandboxing
logic is only applied to user services, as was the original intent.
System services in a rootless context will now correctly run in the
container's main user namespace, where all necessary UIDs/GIDs are
mapped.
Fixes: https://github.com/systemd/systemd/issues/39563
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2391343
This allows a service to reuse the user namespace created for an
existing service, similarly to NetworkNamespacePath=. The configuration
is the initial user namespace (e.g. ID mapping) is preserved.
RootDirectory= but via a open_tree() file descriptor. This allows
setting up the execution environment for a service by the client in a
mount namespace and then starting a transient unit in that execution
environment using the new property.
We also add --root-directory= and --same-root-dir= to systemd-run to
have it run services within the given root directory. As systemd-run
might be invoked from a different mount namespace than what systemd is
running in, systemd-run opens the given path with open_tree() and then
sends it to systemd using the new RootDirectoryFileDescriptor= property.
RootDirectory= but via a open_tree() file descriptor. This allows
setting up the execution environment for a service by the client in
a mount namespace and then starting a transient unit in that execution
environment using the new property.
We also add --root-directory= and --same-root-dir= to systemd-run to
have it run services within the given root directory. As systemd-run
might be invoked from a different mount namespace than what systemd is
running in, systemd-run opens the given path with open_tree() and then
sends it to systemd using the new RootDirectoryFileDescriptor= property.
Hardcoding total size of the array is error-prone, especially
considering the exeuctable_fd is added far below, so the '4' is
not entirely obvious. Also we seldomly do VLAs.
The distinction between fdstore and extra fds is only meaningful
to struct Service. As far as executor is concerned they're just
some fds to pass to the service. Let's just merge it hence,
for the sake of simplicity.
According to systemd.exec(5):
> The fd:name option connects standard input to a specific, named
> file descriptor provided *by a socket unit*. ...
Currently however we're looking at the whole fd array passed,
fix it.
Previously, we limit the length of process name by 8.
This relax the restriction then at least process comm or
program_invocation_name contains the untrucated process name.
Closes#38367.
Although extremely unlikely, there is a race present in solely checking the
$LISTEN_PID environment variable, due to PID recycling. Fix that by introducing
$LISTEN_PIDFDID, which contains the 64-bit ID of a pidfd for the child process
that is not subject to recycling.
RootDirectory= and other options already implicitly enable PrivateUsers=
since 6ef721cbc7 if they are set in user
units, so that they can work out of the box.
Now with mountfsd support we can do the same for the images settings,
so enable them and document them.
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>
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.
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
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) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
```