1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-08 08:58:27 +03:00

Compare commits

...

102 Commits

Author SHA1 Message Date
Lennart Poettering
2b717a7f14 update TODO 2024-12-20 18:04:01 +01:00
Lennart Poettering
1c0ade2e1f discover-image: introduce per-user image directories
We nowadays support unprivileged invocation of systemd-nspawn +
systemd-vmspawn, but there was no support for discovering suitable disk
images (i.e. no per-user counterpart of /var/lib/machines). Add this
now, and hook it up everywhere.

Instead of hardcoding machined's, importd's, portabled's, sysupdated's
image discovery to RUNTIME_SCOPE_SYSTEM I introduced a field that make
the scope variable, even if this field is always initialized to
RUNTIME_SCOPE_SYSTEM for now. I think these four services should
eventually be updated to support a per-user concept too, this is
preparation for that, even though it doesn't outright add support for
this.

This is for the largest part not user visible, except for in nspawn,
vmspawn and the dissect tool. For the latter I added a pair of
--user/--system switches to select the discovery scope.
2024-12-20 18:04:01 +01:00
Ricky Tigg
06ffa66a5b po: Translated using Weblate (Finnish)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Ricky Tigg <ricky.tigg@gmail.com>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fi/
Translation: systemd/main
2024-12-21 00:51:18 +09:00
Septatrix
33bfa69b2e Add .venv to gitignore
This directory is commonly used for virtual Python environments.
These are useful when developing to install different Python versions
as well as install tooling like mkosi and mypy in an isolated fashion
without influencing the global system.
2024-12-20 15:33:32 +00:00
Lennart Poettering
f108996319
core/device: handle ID_PROCESSING udev property (#35351)
Continuation of #35332.
2024-12-20 10:12:39 +01:00
Daan De Meyer
dec47e58a6
debug-generator: add a kernel cmdline option to pause the boot process (#35410)
Introduce the `systemd.break=` kernel command line option to allow
stopping the boot process at a certain point and spawn a debug shell.
After exiting this shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and
host).
- `pre-basic`: before leaving early boot and regular services start
(initrd and host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 10:04:41 +01:00
Lennart Poettering
cdcb1eeeb8
[RFC] better naming for Azure MANA network devices (#34255)
The Azure MANA folks would like the PCI domain to be suppressed from
naming network interfaces. Let's introduce a somewhat generic way to do
this, without hardcoding anything to Azure.

Specifically: we'll ship a new hwdb entry that sets a new
ID_NET_NAME_INCLUDE_DOMAIN=0 property on relevant MANA devices. Then we
make net_id look for that property, and if it is set we simply suppress
the PCI domain.

(Untested as of now, needs feedback from Azure MANA folks that this
actually works and does what is requested here).
2024-12-20 09:52:40 +01:00
Matteo Croce
77d4a263c1 mkosi: move config options
Move some config option in the right section, fixes the following warning:
```
mkosi.conf: Setting Credentials should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeBuildSources should be configured in [Runtime], not [Host].
mkosi.conf: Setting RuntimeScratch should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSmp should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuSwtpm should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuVsock should be configured in [Runtime], not [Host].
mkosi.conf: Setting QemuKvm should be configured in [Runtime], not [Host].
```
2024-12-20 09:38:11 +01:00
Yu Watanabe
5f29c86ace audit-util: rename output parameter
To make them consistent with in audit-util.c.

Follow-up for 7e02ee98d86702b8e7055f0a6d8e6ea48267ad23.
2024-12-20 09:37:25 +01:00
Yu Watanabe
182ffb5819 TEST-71-HOSTNAME: do not start user session
The user session may trigger hostnamed, and the job of stopping
hostnamed may be cancelled, and the test may fail:
```
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + stop_hostnamed
[ 4633.613578] TEST-71-HOSTNAME.sh[175]: + systemctl stop systemd-hostnamed.service
[ 4633.664670] systemd[1]: Stopping systemd-hostnamed.service - Hostname Service...
[ 4636.022277] systemd-logind[121]: New session c2 of user root.
[ 4636.032532] systemd[1]: Created slice user-0.slice - User Slice of UID 0.
[ 4636.042675] systemd[1]: Starting user-runtime-dir@0.service - User Runtime Directory /run/user/0...
[ 4636.176140] systemd[1]: Finished user-runtime-dir@0.service - User Runtime Directory /run/user/0.
[ 4636.202951] systemd[1]: Starting user@0.service - User Manager for UID 0...
[ 4636.292204] systemd-logind[121]: New session c3 of user root.
[ 4636.300065] (systemd)[268]: pam_unix(systemd-user:session): session opened for user root(uid=0) by root(uid=0)
[ 4636.757667] systemd[268]: Queued start job for default target default.target.
[ 4636.774419] systemd[268]: Created slice app.slice - User Application Slice.
[ 4636.774579] systemd[268]: Started systemd-tmpfiles-clean.timer - Daily Cleanup of User's Temporary Directories.
[ 4636.774747] systemd[268]: Reached target paths.target - Paths.
[ 4636.776418] systemd[268]: Reached target sysinit.target - System Initialization.
[ 4636.776604] systemd[268]: Reached target timers.target - Timers.
[ 4636.784997] systemd[268]: Starting dbus.socket - D-Bus User Message Bus Socket...
[ 4636.799472] systemd[268]: Starting systemd-tmpfiles-setup.service - Create User Files and Directories...
[ 4637.027125] systemd[268]: Finished systemd-tmpfiles-setup.service - Create User Files and Directories.
[ 4637.031721] systemd[268]: Listening on dbus.socket - D-Bus User Message Bus Socket.
[ 4637.036189] systemd[268]: Reached target sockets.target - Sockets.
[ 4637.036373] systemd[268]: Reached target basic.target - Basic System.
[ 4637.036558] systemd[268]: Reached target default.target - Main User Target.
[ 4637.036646] systemd[268]: Startup finished in 702ms.
[ 4637.049075] systemd[1]: Started user@0.service - User Manager for UID 0.
[ 4637.075263] systemd[1]: Started session-c2.scope - Session c2 of User root.
[ 4637.084917] login[136]: pam_unix(login:session): session opened for user root(uid=0) by root(uid=0)
[ 4637.117348] login[136]: ROOT LOGIN ON pts/0
[ 4637.238572] systemctl[261]: Job for systemd-hostnamed.service canceled.
[ 4637.290369] systemd[1]: TEST-71-HOSTNAME.service: Main process exited, code=exited, status=1/FAILURE
```

Fixes #35643.
2024-12-20 09:36:51 +01:00
Antonio Alvarez Feijoo
e9f781a5a4
debug-generator: add a kernel cmdline option to pause the boot process
Introduce the `systemd.break=` kernel command line option to allow stopping the
boot process at a certain point and spawn a debug shell. After exiting this
shell, the system will resume booting.

It accepts the following values:
- `pre-udev`: before starting to process kernel uevents (initrd and host).
- `pre-basic`: before leaving early boot and regular services start (initrd and
host).
- `pre-mount`: before the root filesystem is mounted (initrd).
- `pre-switch-root`: before switching root (initrd).
2024-12-20 08:51:23 +01:00
Antonio Alvarez Feijoo
cb3801a4c9
man/debug-generator: add a section for kernel command line options 2024-12-20 08:48:23 +01:00
Yu Watanabe
8a135111ca
capability-util: generalize helper to acquire local caps (#35403)
This generalizes and modernizes the code to acquire set of local caps,
based on the code for this in the condition logic. Uses PidRef, and
acquires the full quintuplet of caps.

This can be considered preparation to one day maybe build without
libcap.
2024-12-20 11:52:24 +09:00
Yu Watanabe
5e837858e7
analyze: add "chid" verb to display CHIDs of the local system (#35175)
We already have the code for it, expose it in systemd-analyze, because
it's useful.
2024-12-20 11:47:03 +09:00
Yu Watanabe
a3fecea5e2
Small fixes to nspawn and other stuff (#35686)
Split out ouf #35685.
2024-12-20 11:03:59 +09:00
Yu Watanabe
f01132aacf TEST-17: add test case for ID_PROCESSING flag on add uevent
Also, check the state of the device units on change event.
2024-12-20 10:52:57 +09:00
Yu Watanabe
ad920b4cb3 core/device: handle ID_PROCESSING udev property
If an enumerated device has ID_PROCESSING=1 property, and the service
manager does not know if the device has been processed by udevd
previously (that is, Device.deserialized_found does not have
DEVICE_FOUND_UDEV), then drop DEVICE_FOUND_UDEV flag from the device and
make the device not enter the active state.

Follow-up for 405be62f05d76f1845f347737b5972158c79dd3e, which was
reverted by c4fc22c4defc5983e53f4ce048e15ea7d31e6a75.
2024-12-20 10:52:57 +09:00
Yu Watanabe
a7396f8364 core/device: use path_equal() to compare sysfs path
The hashmap Manager.devices_by_sysfs uses path_hash_ops.
Let's consistent compare function.
2024-12-20 10:52:57 +09:00
Yu Watanabe
71ec342d13 core/device: rename output parameters of device_setup_units() to ret_xyz
No functional change, just refactoring.
2024-12-20 10:52:57 +09:00
Yu Watanabe
3b9010b170
udev: support reloading udev.conf (#35458)
This makes systemd-udevd reload udev.conf when explicitly requested by
e.g. `udevadm control --reload`.
2024-12-20 09:00:48 +09:00
Yu Watanabe
cf89e48028 ptyfwd: reset writable/readable flag before shovel() on exit
Follow-up for 12807b5a49d1fe60434d473afe11ff81a4c92306.

Otherwise, if a call of shovel() disabled the flags, the subsequent
calls do nothing even if there is something we need to read or write.

Fixes the following error:
```
Dec 19 02:19:39 run0[5618]: Error on PTY forwarding logic: Too many levels of symbolic links
```
2024-12-20 08:59:41 +09:00
Ivan Kruglov
3cbf00a30c machine: make TEST-13-NSPAWN wqlong-running code more verbose
Need this to debug https://github.com/systemd/systemd/issues/35115
2024-12-19 17:09:04 +00:00
Luca Boccassi
0f67cb3606
Minor fixes in man pages, example scripts, error log (#35683)
No functional changes.
2024-12-19 17:08:13 +00:00
Lennart Poettering
5ceb38cb1e nspawn: switch to read_virtual_file() for reading audit loginuid 2024-12-19 15:37:00 +01:00
Lennart Poettering
312cf91005 nsresource: print nicer error message when trying to acquire an unpriv user ns range where this isn't possible 2024-12-19 15:35:23 +01:00
Lennart Poettering
b1b128d0e2 mount-util: add debug message to make_userns() failure 2024-12-19 15:33:52 +01:00
Lennart Poettering
91cdc8ab0f mount-util: add debug output when we switched root 2024-12-19 15:33:44 +01:00
Lennart Poettering
009a02b263 nspawn: trivial improvements 2024-12-19 15:33:34 +01:00
Lennart Poettering
b83358b87f nspawn: rename pin_fully_visible_fs() → pin_fully_visible_api_fs()
This function pins the *API* FS, i.e. /proc/ + /sys/, not just any fs.
Hence clarify this in the name.

(At least we call these two fs "API (V)FS" in our codebase, hence
continue to do so here)
2024-12-19 15:33:24 +01:00
Lennart Poettering
bf1ef54d30 nspawn: add some additional useful debug logging 2024-12-19 15:33:10 +01:00
Lennart Poettering
8f9ea89ce4 nspawn: make unexpected mkdir() failures fatal
THis is just to make things easier to debug.
2024-12-19 15:33:06 +01:00
Lennart Poettering
5229cd839a nspawn: rename 'fd' variable to something more descriptive 2024-12-19 15:32:50 +01:00
Lennart Poettering
595ca10f37 nspawn: use DEVNUM_FORMAT_STR/DEVNUM_FORMAT_VAL more 2024-12-19 15:32:05 +01:00
Matthias Lisin
6e3f32cc56
man/sysupdate.features: fix typos 2024-12-19 12:39:32 +01:00
Matthias Lisin
1462736c7e
sysupdate: fix args order of formatted error 2024-12-19 12:39:31 +01:00
Matthias Lisin
f441831c9e
man/sysupdate.d: fix wrong PathRelativeTo value 2024-12-19 12:39:31 +01:00
Matthias Lisin
4bc06da775
man: fix args order for udevadm info cmd 2024-12-19 12:39:31 +01:00
Yu Watanabe
ced0ef3b35 TEST-17: use 'udevadm control --reload' or 'systemctl reload systemd-udevd.service' for reloading udev.conf
These should be equivalent. For coverage, one subtest uses systemctl and
another uses udevadm.
2024-12-19 19:00:38 +09:00
Yu Watanabe
e95861d909 udev: also reload udev.conf when explicitly requested
When reloading is explicitly requested, e.g. by 'udevadm control --reload',
then also reload udev.conf.
2024-12-19 18:57:32 +09:00
Yu Watanabe
0f72af536f udev: reload .rules files and builtins only when necessary
Previously, even if e.g. .rules files are unchanged, all .rules files
are reloaded when other kind of config files like .link files or
.hwdb.bin are changed, vice versa.
2024-12-19 18:55:18 +09:00
Yu Watanabe
b5ea69f5ac
udev: move config parsers and related things to udev-config.c (#35624)
No functional change, just refactoring and preparation for later
changes.
2024-12-19 18:41:52 +09:00
Yu Watanabe
04fa5c1580 udev-config: introduce UdevConfig
Then, save configurations by their source: udev.conf, command line
arguments, kernel command line options, and udev control.

Preparation to support reloading udev.conf in a later commit.
2024-12-19 12:28:44 +09:00
Yu Watanabe
394a678aec udev: move parsers for config file, kerenel command line, and positional arguments to udev-config.c
No functional change, just refactoring and preparation for later
commits.
2024-12-19 12:28:44 +09:00
Thomas Hebb
32c3e1379d ukify: Fix regression in --no-sign-kernel flag
The man page says that --sign-kernel and --no-sign-kernel "override the
detection of whether to sign the Linux binary", so we should only
autodetect if neither are specified. But as of commit 02eabaffe98c
("ukify: Add a unified interface for signing tools"), we autodetect even
when --no-sign-kernel is passed, which makes the flag useless.

The sign_kernel option is parsed using argparse.BooleanOptionalAction,
which sets it to either True, False, or None. commit 02eabaffe98c
replaced `sign_kernel is None` with `not sign_kernel`. These are not the
same in Python, as the latter accepts False as well as None.

Restore the original check and fix type annotations accordingly.

Fixes: 02eabaffe98c ("ukify: Add a unified interface for signing tools")
2024-12-19 12:27:27 +09:00
Lennart Poettering
0d1ebcf67d
networkd-sysctl: tweak error handling and log level a bit (#35673) 2024-12-18 18:20:30 +01:00
Lennart Poettering
0e5a83f510 analyze: drop conditioning of --no-legend and --json= on specific verbs
First of all, the list of verbs was badly out of date, in particular for
--no-legend. But second if it, I think such minor switches that alter
some detail of the output should not result in failure when the specific
tweak does not apply on some command. It should be fine for scripts and
suchlike to dumbly always pass --no-legend to all invocations of our
tools without having to consider if a specific subtool of ours actually
supports it or not.
2024-12-18 17:39:22 +01:00
Lennart Poettering
8f114904fc analyze: add verb for showing system's CHIDs
We have the code already, expose it in systemd-analyze too.

This should make it easier to debug the CHID use in the UKIs with
onboard tooling.
2024-12-18 17:38:42 +01:00
Mike Yuan
cffae6e113
networkd-sysctl: tweak error handling and log level a bit
Follow-up for 6d9ef22acdeac4b429efb75164341233955484af

- Downgrade log level for bpf not installed or kernel version
  being too old to LOG_DEBUG. Otherwise, on kernels older than 6.12
  the log becomes quite annoying.
- Always propagate the error and ignore only on caller's side.
  The current style is a messy mix.
2024-12-18 16:38:54 +01:00
Daan De Meyer
a48803fd84 man: Document generator sandbox environment 2024-12-19 00:36:52 +09:00
Mike Yuan
22583a002e
networkd-sysctl: rename functions to match our typical prefixes 2024-12-18 16:36:24 +01:00
Yu Watanabe
be1bcb85ce
ptyfwd: several cleanups (#35663) 2024-12-19 00:35:42 +09:00
Yu Watanabe
85d040dabd update-utmp: do not give up if the first attempt at connecting bus failed
Otherwise, the program exits with failure if the first attempt in run() failed:
```
Dec 18 20:27:37 systemd-update-utmp[254]: Bus n/a: changing state UNSET → OPENING
Dec 18 20:27:37 systemd-update-utmp[254]: sd-bus: starting bus by connecting to /run/systemd/private...
Dec 18 20:27:37 systemd-update-utmp[254]: Bus n/a: changing state OPENING → CLOSED
Dec 18 20:27:37 systemd-update-utmp[254]: Failed to get D-Bus connection: Connection refused
```
2024-12-19 00:34:38 +09:00
Yu Watanabe
67e5622bfe TEST-50-DISSECT: notify message cannot be sent by ncat
Follow-up for d0a63cf0412ccb9b4edd1f6048e25aa7f68b0133.

The command ncat may be already dead when the service manager receives
the notify message. Hence, the service cannot be found by the sender PID,
and the notify message will be ignored.
```
Dec 17 03:26:49 systemd[1]: Cannot find unit for notify message of PID 1159, ignoring.
Dec 17 03:26:49 systemd[1]: Received SIGCHLD from PID 1152 (bash).
Dec 17 03:26:49 systemd[1]: Child 1152 (bash) died (code=exited, status=0/SUCCESS)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Child 1152 belongs to run-p1151-i1451.service.
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Main process exited, code=exited, status=0/SUCCESS (success)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Failed with result 'protocol'.
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Service will not restart (restart setting)
Dec 17 03:26:49 systemd[1]: run-p1151-i1451.service: Changed start -> failed
```

This also drops unnecessary --pipe option and redundant check by 'env' command.
2024-12-18 15:50:02 +01:00
Morten Hauke Solvang
0da73fab56 resolved: if one transaction completes, expect other transactions within candidate to succeed quickly
Fixes #22575, as suggested by poettering in #35514.

Intended as a workaround for some buggy routers, which refuse to send empty
replies. If systemd-resolved starts two DnsTransactions, one for A and one
for AAAA, and the domain in question has no AAAA entry, then the server will
send a reply for A and no reply for AAAA. Correct behavior for the server would
be to send an empty reply for AAAA.

systemd-resolved would previously keep retrying the AAAA transaction, and
eventually timeout the whole query, returning an error to the caller.

Now, if the server replies to one query and not another, we cut short the
timeout and return the partial result. Returning the partial result allows
the rest of the system to keep working. It matches how e.g. glibc libnss_dns
behaves.
2024-12-18 15:43:46 +01:00
Daan De Meyer
1152826e8d test-firewall-util: Migrate to new assertion macros 2024-12-18 22:03:05 +09:00
Yu Watanabe
d6d98a0c01
udev: make builtins take UdevEvent object (#35625)
No functional change, just refactoring.
2024-12-18 22:02:22 +09:00
Yu Watanabe
114453d795 data-fd-util: drop dead code
Also drops unnecessary header inclusions.

Follow-ups for a87a9625f8bde776ece11b8ddb77588cfff73038.
Fixes CID#1568419.
2024-12-18 13:47:35 +01:00
Fabian Vogt
e61032bf47 tpm2-util: Also retry unsealing after policy_pcr returns PCR_CHANGED
It's not just Esys_Unseal that may fail due to PCR changes during the
session, but also Esys_PolicyPCR. Perform a retry in that case as well.

Fixes #35490
2024-12-18 13:34:55 +01:00
Lennart Poettering
9aee971185 tree-wide: use pidref_is_self() at more places 2024-12-18 13:34:35 +01:00
Yu Watanabe
64b504bde3 machinectl: explicitly assign PTY forwarder to sd_bus_slot
No functional change, just refactoring.
2024-12-18 20:28:28 +09:00
Yu Watanabe
12807b5a49 ptyfwd: always flush buffer and disconnect before exit
Then, it is not necessary to manually drain PTY forwarder by the user
side. Also, not necessary to free PTY forwarder earlier explicitly to
make it disconnected.
2024-12-18 20:28:07 +09:00
Yu Watanabe
4a4e7ec0e9 ptyfwd: always write additional line break on stop
Currently we do that in the user of PTY forwarder, e.g. nspawn.
But, let's do that unconditionally in the PTY forwarder.
2024-12-18 20:26:58 +09:00
Yu Watanabe
d517427dff ptyfwd: save the last character before the escape sequence
If we write e.g. a line break and CSI sequence, then it is not necessary
to write another line break on exit.
2024-12-18 19:55:46 +09:00
Yu Watanabe
5e6a48bf99 ptyfwd: do not forward partial escape sequence
Otherwise, if the sender is killed while writing escape sequence,
we may get spurious output.
2024-12-18 19:55:37 +09:00
Yu Watanabe
781c8c3f72 ptyfwd: coding style fix
- replace 'type *func()' -> 'type* func()',
- rename output argument to 'ret'.
2024-12-18 19:45:46 +09:00
Michal Koutný
4c9f242a54 mkosi: Fix tools image package name 2024-12-18 11:08:06 +01:00
Lennart Poettering
7a8556b901
confext/sysext: add initrd-specific units (#35426)
In the rootfs these need to run after /var/lib/ has been set up. In the
initrd we want them to run as soon as possible so that they can be used
to customize setting up the rootfs.
2024-12-18 10:33:38 +01:00
Yu Watanabe
5830d34b40 core: drop unnecessary header inclusion
Follow-up for e76fcd0e40a6910f4818a374c6a8d854d644ff93.
2024-12-18 09:30:25 +01:00
Yu Watanabe
80080f34f3 TEST-07-PID1: fix typo
Follow-up for e76fcd0e40a6910f4818a374c6a8d854d644ff93.
2024-12-18 10:46:51 +09:00
Lennart Poettering
4f6086ceb4
pam_systemd: some refactorings and bugfixes (#35178)
Inspired at #35171 I had another closer look at pam_systemd, and found a
bunch of things to fix, and correct.
2024-12-17 23:02:00 +01:00
Lennart Poettering
be883be6d3
remove fallbacks for memfd-less kernels (#35605)
Let the culling continue: let's remove support for kernels that lack
memfd, i.e. pre-3.17 kernels.

This is a nice simplification of things.
2024-12-17 23:01:29 +01:00
Lennart Poettering
25b1a73f71 journald: get rid of get_process_capeff(), use pidref_get_capability() instead
This does pretty much the same, but is nicer, since it parses things
properly.
2024-12-17 19:06:54 +01:00
Lennart Poettering
a5370d35d6 capability-util: introduce capability_is_set() helper 2024-12-17 19:06:54 +01:00
Lennart Poettering
1184626a26 capability-util: generalize helper to acquire local caps
This generalizes and modernizes the code to acquire set of local caps,
based on the code for this in the condition logic. Uses PidRef, and
acquires the full quintuplet of caps.

This can be considered preparation to one day maybe build without
libcap.
2024-12-17 19:06:54 +01:00
Lennart Poettering
3ee8082947 update TODO 2024-12-17 18:26:15 +01:00
Lennart Poettering
6db5a6e799 doc: document new baseline requires memfd_create() 2024-12-17 18:26:15 +01:00
Lennart Poettering
4dac692094 fuzz-journal-remote: use memfd_new_and_seal() where appropriate
This means we can drop memfd_new_and_map() and results in generally
shorter code.
2024-12-17 18:26:15 +01:00
Lennart Poettering
65d9ef40f2 pid1: drop check that ensures /run/ has plenty space before reexec/reload
Now that we only support serialization into a memfd (rather than a file
in /run/) there's no point to check the free space in /run/. Let's drop it.

One error scenario gone. Yay.
2024-12-17 18:26:15 +01:00
Lennart Poettering
d54bbc4cdc memfd-util: trivial modernizations 2024-12-17 18:26:15 +01:00
Lennart Poettering
5d1e57b820 serialize: add explicit calls for finishing serialization
These new calls will do three things:

1. in case of FILE* stuff: flush any pending bytes onto the fd, just in
   case
2. seal the backing memfd
3. seek back to the beginning.

Note that this adds sealing to serialization: once we serialized fully,
we'll seal the thing off for further modifications, before we pass the
fd over to the target process. This should add a bit of robustness, and
maybe finds a bug or two one day, if we accidentally write to a
serialization that is complete.
2024-12-17 18:26:15 +01:00
Lennart Poettering
4d98709cb2 memfd-util: introduce memfd_new_full() helper
This is just like memfd_new(), but allows fine grained control of the
sealing flags.

This switches over all uses of memfd_new() where we actually want
sealing to use memfd_new_full().

This then allows use to use memfd_new() for two further calls, where we
previously used the more lowlevel memfd_create_wrapper().
2024-12-17 18:26:15 +01:00
Lennart Poettering
9b1d97cccd memfd-util: explain what memfd_create_wrapper() is for in a comment 2024-12-17 18:26:15 +01:00
Lennart Poettering
caf1436ee8 memfd-util: use TASK_COMM_LEN at one more place
Note this corrects the size of the array from 17 to 16, as the 16
already includes space for a trailing NUL.
2024-12-17 18:26:15 +01:00
Lennart Poettering
ce66a2f2bb sd-journal: drop memfd fallback 2024-12-17 18:26:15 +01:00
Lennart Poettering
52cd287933 serialize: drop memfd fallback when serializing 2024-12-17 18:26:15 +01:00
Lennart Poettering
e1c52c9238 memfd-util: short memfd_clone_fd() 2024-12-17 18:26:15 +01:00
Lennart Poettering
db5381c49c memfd-util: simplify memfd_new_and_seal()
Let's use pwrite() to write the contents of the memfd. This has the
benefit of not moving the file offset, which means we don't have to
reset it after at all.
2024-12-17 18:26:15 +01:00
Lennart Poettering
a87a9625f8 tree-wide: drop acquire_data_fd_full() helper
Let's drop support systems lacking memfds, i.e. pre kernel 3.17 systems.
This allows us to drastically simplify the "data fd" concept, so far
that we can remove it entirely.

This replaces acquire_data_fd() with a specialized call to
memfd_new_and_seal(), not that memfds can be the only implementation of
the concept.
2024-12-17 18:26:15 +01:00
Lennart Poettering
f07fe275d5 pam_systemd: introduce pam_get_data_many() helper and make use of it
This is to pam_get_data() what pam_get_item() is to pam_get_item_many().
2024-12-17 17:52:23 +01:00
Lennart Poettering
7f471bd3b2 pam_systemd: fix error code confusion when prepping D-Bus message
We got confused by the error codes here, and sometimes return PAM errors
where the caller propagated them unconverted as negative errno errors. Fix that.
2024-12-17 17:52:21 +01:00
Lennart Poettering
32580792df pam_systemd: split pam_sm_open_session() into more digestable blocks
Let's separate four different parts of pam_sm_open_session():

1. Acquiring of our various parameters from pam env, pam data, pam items
2. Mangling of that data to clean it up
3. Registering of the service with logind
4. Importing shell credentials into environment variables
5. Enforcement of user record data

This makes the code a lot more readable, and gets rid of an ugly goto
label.

It also corrects things: if step 3 doesnt work because logind is not
around, we'll now still do step 4, which we previously erroneously
skipped.

Besides that no real code changes.
2024-12-17 17:52:18 +01:00
Lennart Poettering
166a678fea pam_systemd: split out setting of shell env vars from credentials and move it later
Let's shorten the code of pam_sm_open_session() a bit, and also make
sure the importing of the env vars from the creds also happens if the
session registration with logind is skipped.
2024-12-17 17:52:14 +01:00
Lennart Poettering
5e782e4de3 pam_systemd: drop "uid" field from SessionContext
Let's instead just pass over the UserRecord, it's a much more useful
object with lots more information we'll sooner or later need
(preparation for later commits).
2024-12-17 17:52:11 +01:00
Lennart Poettering
014d23c395 pam_systemd: drop "pid" field from SessionContext
We never use the field and this is not going to change...

This addresses a weird asymmetry, as create_session_message() always
went to the process' own PID when doing pidfds but otherwise (i.e.
without pidfds) would honour the PID specified as function parameter.
2024-12-17 17:52:08 +01:00
Lennart Poettering
6082ccf792 pam_systemd: normalize parsing of XDG_VTNR
Let's make it more like the parsing of the "incomplete" boolean env var,
to streamline things.
2024-12-17 17:51:57 +01:00
Yu Watanabe
ab70e42999 udev/net: make Link object take reference to UdevEvent
No functional change, just refactoring.
2024-12-15 09:21:46 +09:00
Yu Watanabe
4a90166488 udev: introduce reference counter for UdevEvent
No functional change, preparation for later commits.
2024-12-15 09:20:45 +09:00
Yu Watanabe
036c75ded3 udev-builtin: make udev_builtin_add_property() and friends take UdevEvent*
No functional change, just refactoring.
2024-12-15 09:20:43 +09:00
Lennart Poettering
9311c28b34 hwdb: disable inclusion of the PCI domain in MANA network interface naming 2024-12-11 16:38:25 +01:00
Lennart Poettering
19491cc90f net_id: depending on new udev prop, include/exclude PCI domain from netif names 2024-12-11 16:37:59 +01:00
Luca Boccassi
d21b42b463 sysext: add initrd-specific unit
In the initrd we want to run as early as possible, before
any of the filesystems are set up, so that users can use
sysexts to customize kernel modules, firmware, etc. But
in the root fs it needs to run after /var/ has been set
up. Split the unit, and have an initrd-specific one that
runs very early.
2024-12-01 12:17:21 +00:00
Luca Boccassi
e813252378 confext: add initrd-specific unit
In the initrd we want to run as early as possible, before
any of the filesystems are set up, so that users can use
confexts to customize fstab/veritytab/crypttab/etc. But
in the root fs it needs to run after /var/ has been set
up. Split the unit, and have an initrd-specific one that
runs very early.
2024-12-01 12:16:54 +00:00
172 changed files with 3078 additions and 2031 deletions

View File

@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@07ef37c4c0dad5dfc6cec86c967a7600df1cd88c
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -64,7 +64,7 @@ jobs:
MESON_OPTIONS=--werror
COVERAGE=1
[Host]
[Runtime]
QemuMem=4G
EOF

View File

@ -113,7 +113,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@c4bbf3b71a3e2cf947995caedf10f69da3c4957a
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -171,7 +171,7 @@ jobs:
[Content]
SELinuxRelabel=${{ matrix.relabel }}
[Host]
[Runtime]
QemuMem=4G
EOF

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
.config.args
.gdb_history
.deps/
.venv/
.mypy_cache/
__pycache__/
/*.gcda

2
README
View File

@ -43,7 +43,7 @@ REQUIREMENTS:
⛔ Kernel versions below 4.3 ("minimum baseline") are not supported at
all, and are missing required functionality (e.g. CLOCK_BOOTTIME
support for timerfd_create() or ambient capabilities).
support for timerfd_create(), ambient capabilities, or memfd_create()).
⚠️ Kernel versions below 5.4 ("recommended baseline") have significant
gaps in functionality and are not recommended for use with this version

19
TODO
View File

@ -101,9 +101,6 @@ Deprecations and removals:
and then rework cgroupsv2 support around fds, i.e. keep one fd per active
unit around, and always operate on that, instead of cgroup fs paths.
* drop support for kernels lacking memfd_create() (i.e. make 3.17 new
baseline), then drop all pipe() based fallbacks.
* drop support for getrandom()-less kernels. (GRND_INSECURE means once kernel
5.6 becomes our baseline). See
https://github.com/systemd/systemd/pull/24101#issuecomment-1193966468 for
@ -125,6 +122,18 @@ Deprecations and removals:
Features:
* importd: introduce a per-user instance, that downloads into per-user DDI dirs
* sysupdated: similar
* portabled: similar
* machined: implement a per-user instance, that manages per-user DDI dirs for
images. systemd-nspawn/systemd-vmspawn should probably register with both the
system and the user scoped machined instance. The former to get the machine
name registered as hostname, and the latter so that the image stuff is nicely
per-user managed.
* resolved: make resolved process DNR DHCP info
* Teach systemd-ssh-generator to generated an /run/issue.d/ drop-in telling
@ -394,8 +403,6 @@ Features:
the bg via vmspawn/nspawn if not done so yet and then requests a shell inside
it for the invoking user.
* importd/…: define per-user dirs for container/VM images too.
* add a new specifier to unit files that figures out the DDI the unit file is
from, tracing through overlayfs, DM, loopback block device.
@ -798,7 +805,7 @@ Features:
* udevd: extend memory pressure logic: also kill any idle worker processes
* udevadm: to make symlink querying with udevadm nicer:
- do not enable the pager for queries like 'udevadm info -q -r symlink'
- do not enable the pager for queries like 'udevadm info -q symlink -r'
- add mode with newlines instead of spaces (for grep)?
* SIGRTMIN+18 and memory pressure handling should still be added to: hostnamed,

View File

@ -3,3 +3,7 @@
# Dell iDRAC Virtual USB NIC
usb:v413CpA102*
ID_NET_NAME_FROM_DATABASE=idrac
# Disable inclusion of PCI domain in interface names on Azure MANA
pci:v00001414d000000BA*
ID_NET_NAME_INCLUDE_DOMAIN=0

View File

@ -10,7 +10,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - fido2-device=auto
# If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link:
udevadm info -q -r symlink /dev/sdXn
udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - fido2-device=auto" >>/etc/crypttab'

View File

@ -97,6 +97,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem>
<para>Parameters understood by
<citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
to pause the boot process at a certain point and spawn a debug shell.</para>
<xi:include href="version-info.xml" xpointer="v258"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.run=</varname></term>
<term><varname>systemd.run_success_action=</varname></term>

View File

@ -1093,7 +1093,11 @@ manpages = [
['systemd-sysctl.service', '8', ['systemd-sysctl'], ''],
['systemd-sysext',
'8',
['systemd-confext', 'systemd-confext.service', 'systemd-sysext.service'],
['systemd-confext',
'systemd-confext-initrd.service',
'systemd-confext.service',
'systemd-sysext-initrd.service',
'systemd-sysext.service'],
'ENABLE_SYSEXT'],
['systemd-system-update-generator', '8', [], ''],
['systemd-system.conf',

View File

@ -205,6 +205,11 @@
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">smbios11</arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">chid</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@ -1084,6 +1089,37 @@ io.systemd.credential:vmm.notify_socket=vsock-stream:2:254570042
<xi:include href="version-info.xml" xpointer="v257"/>
</refsect2>
<refsect2>
<title><command>systemd-analyze chid</command></title>
<para>Shows a list of Computer Hardware IDs (CHIDs) of the local system. These IDs identify the
system's computer hardware, based on SMBIOS data. See <ulink
url="https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/using-chids">Using Computer
Hardware IDs (CHIDs)</ulink> for details about CHIDs.</para>
<example>
<title>Example output</title>
<programlisting>$ systemd-analyze chid
TYPE INPUT CHID
3 MFPSmp 520537c0-3b59-504f-b062-9682ea236b21
4 MFPS-- edf05dc8-a53d-5b2c-8023-630bca2a2463
5 MFP--- ebc6a4d9-ec48-537a-916b-c69fa4fdd814
6 M--Smp 5ebe4bba-f598-5e90-9ff2-9fd0d3211465
7 M--S-- 1a3fb835-b42a-5f9c-a38c-eff5bfd5c41d
8 M-P-mp 2a831dce-8163-5bad-8406-435b8c752dd8
9 M-P--- 7c21c878-4a75-50f7-9816-21e811588da0
10 MF--mp 9a003537-bcc5-500e-b10a-8d8892e4fc64
11 MF---- bb9122bb-8a5c-50d2-a742-a85beb719909
13 M---mp bfc36935-5032-5987-a0a3-6311f01de33a
LEGEND: M → sys_vendor (LENOVO) ┄ F → product_family (ThinkPad X1 Carbon Gen 9) ┄ P → product_name (20XW0055GE)
S → product_sku (LENOVO_MT_20XW_BU_Think_FM_ThinkPad X1 Carbon Gen 9) ┄ m → board_vendor (LENOVO)
p → board_name (20XW0055GE)</programlisting>
</example>
<xi:include href="version-info.xml" xpointer="v258"/>
</refsect2>
</refsect1>
<refsect1>

View File

@ -31,45 +31,131 @@
<refsect1>
<title>Description</title>
<para><filename>systemd-debug-generator</filename> is a generator
that reads the kernel command line and understands three
options:</para>
<para><command>systemd-debug-generator</command> is a generator that provides some debugging
functionality.</para>
<para>If the <option>systemd.mask=</option> or <option>rd.systemd.mask=</option>
option is specified and followed by a unit name, this unit is
masked for the runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with
certain units removed from the initial boot transaction for
debugging system startup. May be specified more than once.
<option>rd.systemd.mask=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.mask=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.wants=</option> or
<option>rd.systemd.wants=</option> option is specified
and followed by a unit name, a start job for this unit is added to
the initial transaction. This is useful to start one or more
additional units at boot. May be specified more than once.
<option>rd.systemd.wants=</option> is honored only by initial
RAM disk (initrd) while <option>systemd.wants=</option> is
honored only in the main system.</para>
<para>If the <option>systemd.debug_shell</option> or <option>rd.systemd.debug_shell</option> option is
specified, the debug shell service <literal>debug-shell.service</literal> is pulled into the boot
transaction and a debug shell will be spawned during early boot. By default,
<filename>&DEBUGTTY;</filename> is used, but a specific tty can also be specified, either with or without
the <filename>/dev/</filename> prefix. To set the tty to use without enabling the debug shell, the
<option>systemd.default_debug_tty=</option> option can be used which also takes a tty with or without the
<filename>/dev/</filename> prefix. Note that the shell may also be turned on persistently by enabling it
with <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. <option>rd.systemd.debug_shell</option> is honored only by initial
RAM disk (initrd) while <option>systemd.debug_shell</option> is honored only in the main system.</para>
<para><filename>systemd-debug-generator</filename> implements
<para><command>systemd-debug-generator</command> implements
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title>Kernel Command Line</title>
<para><command>systemd-debug-generator</command> understands the following kernel command line
parameters:</para>
<variablelist class='kernel-commandline-options'>
<varlistentry>
<term><varname>systemd.mask=</varname></term>
<term><varname>rd.systemd.mask=</varname></term>
<listitem><para>These options take a unit name as argument. The unit specified is masked for the
runtime (i.e. for this session — from boot to shutdown), similarly to the effect of
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>mask</command> command. This is useful to boot with certain units removed from the initial
boot transaction for debugging system startup. May be specified more than once. The option prefixed
with <literal>rd.</literal> is honored only in the initrd, while the one without prefix is only
honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.wants=</varname></term>
<term><varname>rd.systemd.wants=</varname></term>
<listitem><para>These options take a unit name as argument. A start job for this unit is added to the
initial transaction. This is useful to start one or more additional units at boot. May be specified
more than once. The option prefixed with <literal>rd.</literal> is honored only in the initrd, while
the one that is not prefixed only in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.debug_shell</varname></term>
<term><varname>rd.systemd.debug_shell</varname></term>
<term><varname>systemd.default_debug_tty=</varname></term>
<term><varname>rd.systemd.default_debug_tty=</varname></term>
<listitem><para>If the <option>systemd.debug_shell</option> or
<option>rd.systemd.debug_shell</option> option is specified, the debug shell service
<literal>debug-shell.service</literal> is pulled into the boot transaction and a debug shell will be
spawned during early boot. By default, <filename>&DEBUGTTY;</filename> is used, but a specific tty
can also be specified, either with or without the <filename>/dev/</filename> prefix. To set the tty
to use without enabling the debug shell, the <option>systemd.default_debug_tty=</option> option can
be used which also takes a tty with or without the <filename>/dev/</filename> prefix. Note that the
shell may also be turned on persistently by enabling it with
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command. The options prefixed with <literal>rd.</literal> are honored only
in the initrd, while the ones without prefix are only honored in the main system.</para>
<xi:include href="version-info.xml" xpointer="v215"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.break=</varname></term>
<term><varname>rd.systemd.break=</varname></term>
<listitem><para>Takes one of <option>pre-udev</option>, <option>pre-basic</option>,
<option>pre-mount</option>, or <option>pre-switch-root</option> (the default for the
<literal>rd.</literal> option). It also accepts multiple values separated by comma
(<literal>,</literal>). These options allow to pause the boot process at a certain point and spawn a
debug shell. After exiting this shell, the system will resume booting. The option prefixed with
<literal>rd.</literal> is honored only in the initrd, while the one without prefix is only honored in
the main system.</para>
<table>
<title>Available breakpoints</title>
<tgroup cols='4'>
<colspec colname='breakpoint' />
<colspec colname='description' />
<colspec colname='initrd' />
<colspec colname='main' />
<thead>
<row>
<entry>Breakpoints</entry>
<entry>Description</entry>
<entry>Can be used in the initrd</entry>
<entry>Can be used in the main system</entry>
</row>
</thead>
<tbody>
<row>
<entry><option>pre-udev</option></entry>
<entry>Before starting to process kernel uevents, i.e., before <filename>systemd-udevd.service</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-basic</option></entry>
<entry>Before leaving early boot and regular services start, i.e., before <filename>basic.target</filename> is reached.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-mount</option></entry>
<entry>Before the root filesystem is mounted, i.e., before <filename>sysroot.mount</filename> starts.</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry><option>pre-switch-root</option></entry>
<entry>Before switching from the initrd to the real root.</entry>
<entry></entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</table>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>System Credentials</title>
@ -108,6 +194,8 @@
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -503,6 +503,17 @@
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--system</option></term>
<term><option>--user</option></term>
<listitem><para>When used together with <option>--discover</option> controls whether to search for
images installed system-wide or in the user's directories in <varname>$HOME</varname>. If neither
switch is specified, will search within both scopes.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="image-policy-open" />
<xi:include href="standard-options.xml" xpointer="no-pager" />
<xi:include href="standard-options.xml" xpointer="no-legend" />

View File

@ -19,8 +19,10 @@
<refnamediv>
<refname>systemd-sysext</refname>
<refname>systemd-sysext.service</refname>
<refname>systemd-sysext-initrd.service</refname>
<refname>systemd-confext</refname>
<refname>systemd-confext.service</refname>
<refname>systemd-confext-initrd.service</refname>
<refpurpose>Activates System Extension Images</refpurpose>
</refnamediv>

View File

@ -64,6 +64,10 @@
override existing definitions. For tests, generators may be called with just one argument; the generator
should assume that all three paths are the same in that case.</para>
<para>Generators executed by the system manager are invoked in a sandbox with a private writable
<filename>/tmp/</filename> directory and where most of the file system is read-only except for the
generator output directories.</para>
<para>Directory paths for generator output differ by priority: <filename>…/generator.early</filename> has
priority higher than the admin configuration in <filename>/etc/</filename>, while
<filename>…/generator</filename> has lower priority than <filename>/etc/</filename> but higher than

View File

@ -672,7 +672,7 @@
<listitem><para>Specifies what anchor point <varname>Path=</varname> should be relative to. Takes one
of <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,
<constant>boot</constant> or <constant>directory</constant>. If unspecified, defaults to
<constant>boot</constant> or <constant>explicit</constant>. If unspecified, defaults to
<constant>root</constant>.</para>
<para>If set to <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,

View File

@ -93,7 +93,7 @@
XML file.
This may be used by software centers (such as GNOME Software or KDE Discover) to present rich
metadata about this feature.
This includes display names, chagnelogs, icons, and more.
This includes display names, changelogs, icons, and more.
This setting supports specifier expansion; see below for details on supported specifiers.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
@ -177,7 +177,7 @@ Enabled=false
</programlisting></para>
<para>The above defines the <literal>devel</literal> feature, and disables it by default.
Now let's a define a transfer that's associated with this feature:</para>
Now let's define a transfer that's associated with this feature:</para>
<para><programlisting># /usr/lib/sysupdate.d/50-devel.transfer
[Transfer]

View File

@ -10,7 +10,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - tpm2-device=auto
# If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link:
udevadm info -q -r symlink /dev/sdXn
udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - tpm2-device=auto" >>/etc/crypttab'

View File

@ -26,7 +26,7 @@ sudo systemd-cryptsetup attach mytest /dev/sdXn - pkcs11-uri=auto
# If that worked, let's now add the same line persistently to /etc/crypttab,
# for the future. We don't want to use the (unstable) /dev/sdX name, so let's
# figure out a stable link:
udevadm info -q -r symlink /dev/sdXn
udevadm info -q symlink -r /dev/sdXn
# Now add the line using the by-uuid symlink to /etc/crypttab:
sudo bash -c 'echo "mytest /dev/disk/by-uuid/... - pkcs11-uri=auto" >>/etc/crypttab'

View File

@ -130,7 +130,7 @@ Packages=
zsh
zstd
[Host]
[Runtime]
Credentials=
journal.storage=persistent
tty.serial.hvc0.agetty.autologin=root

View File

@ -15,7 +15,7 @@ ToolsTreePackages=
pkgconfig(libmicrohttpd)
pkgconfig(mount)
python3-ruff
tss2-devel
tpm2-0-tss-devel
python3-jinja2
python3-pytest
ShellCheck

View File

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-28 18:16+0900\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>\n"
"PO-Revision-Date: 2024-12-20 15:38+0000\n"
"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n"
"Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
"main/fi/>\n"
"Language: fi\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.8.2\n"
"X-Generator: Weblate 5.9.1\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -1176,9 +1176,8 @@ msgid "Manage optional features"
msgstr "Hallitse valinnaisia ominaisuuksia"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
#, fuzzy
msgid "Authentication is required to manage optional features."
msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan"
msgstr "Todennus vaaditaan valinnaisten ominaisuuksien hallintaan."
#: src/timedate/org.freedesktop.timedate1.policy:22
msgid "Set system time"

View File

@ -67,7 +67,7 @@ _systemd_analyze() {
)
local -A VERBS=(
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11'
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2 smbios11 chid'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[DUMP]='dump'

View File

@ -29,6 +29,8 @@ _systemd_dissect() {
local cur=${COMP_WORDS[COMP_CWORD]} prev_1=${COMP_WORDS[COMP_CWORD-1]} prev_2=${COMP_WORDS[COMP_CWORD-2]} words cword
local -A OPTS=(
[STANDALONE]='-h --help --version
--user
--system
--discover
--no-pager
--no-legend

224
src/analyze/analyze-chid.c Normal file
View File

@ -0,0 +1,224 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "analyze.h"
#include "analyze-chid.h"
#include "chid-fundamental.h"
#include "efi-api.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "parse-util.h"
#include "strv.h"
#include "utf8.h"
#include "virt.h"
static int parse_chid_type(const char *s, size_t *ret) {
unsigned u;
int r;
assert(s);
r = safe_atou(s, &u);
if (r < 0)
return r;
if (u >= CHID_TYPES_MAX)
return -ERANGE;
if (ret)
*ret = u;
return 0;
}
static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = 'M',
[CHID_SMBIOS_FAMILY] = 'F',
[CHID_SMBIOS_PRODUCT_NAME] = 'P',
[CHID_SMBIOS_PRODUCT_SKU] = 'S',
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = 'm',
[CHID_SMBIOS_BASEBOARD_PRODUCT] = 'p',
};
static char *chid_smbios_fields_string(uint32_t combination) {
_cleanup_free_ char *s = NULL;
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
char c;
c = (combination & (UINT32_C(1) << f)) ? chid_smbios_fields_char[f] : '-';
if (!strextend(&s, CHAR_TO_STR(c)))
return NULL;
}
return TAKE_PTR(s);
}
static int add_chid(Table *table, const EFI_GUID guids[static CHID_TYPES_MAX], size_t t) {
int r;
assert(table);
assert(guids);
assert(t < CHID_TYPES_MAX);
sd_id128_t id = efi_guid_to_id128(guids + t);
if (sd_id128_is_null(id))
return 0;
_cleanup_free_ char *flags = chid_smbios_fields_string(chid_smbios_table[t]);
if (!flags)
return log_oom();
r = table_add_many(table,
TABLE_UINT, (unsigned) t,
TABLE_STRING, flags,
TABLE_UUID, id);
if (r < 0)
return table_log_add_error(r);
return 0;
}
static void smbios_fields_free(char16_t *(*fields)[_CHID_SMBIOS_FIELDS_MAX]) {
assert(fields);
FOREACH_ARRAY(i, *fields, _CHID_SMBIOS_FIELDS_MAX)
free(*i);
}
int verb_chid(int argc, char *argv[], void *userdata) {
static const char *const smbios_files[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = "sys_vendor",
[CHID_SMBIOS_FAMILY] = "product_family",
[CHID_SMBIOS_PRODUCT_NAME] = "product_name",
[CHID_SMBIOS_PRODUCT_SKU] = "product_sku",
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "board_vendor",
[CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name",
};
_cleanup_(table_unrefp) Table *table = NULL;
int r;
if (detect_container() > 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Container environments do not have SMBIOS.");
table = table_new("type", "input", "chid");
if (!table)
return log_oom();
(void) table_set_align_percent(table, table_get_cell(table, 0, 0), 100);
(void) table_set_align_percent(table, table_get_cell(table, 0, 1), 50);
_cleanup_close_ int smbios_fd = open("/sys/class/dmi/id", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (smbios_fd < 0)
return log_error_errno(errno, "Failed to open SMBIOS sysfs object: %m");
_cleanup_(smbios_fields_free) char16_t* smbios_fields[_CHID_SMBIOS_FIELDS_MAX] = {};
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
_cleanup_free_ char *buf = NULL;
size_t size;
r = read_virtual_file_at(smbios_fd, smbios_files[f], SIZE_MAX, &buf, &size);
if (r < 0)
return log_error_errno(r, "Failed to read SMBIOS field '%s': %m", smbios_files[f]);
if (size < 1 || buf[size-1] != '\n')
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected SMBIOS field '%s' to end in newline, but it doesn't, refusing.", smbios_files[f]);
size--;
smbios_fields[f] = utf8_to_utf16(buf, size);
if (!smbios_fields[f])
return log_oom();
}
EFI_GUID chids[CHID_TYPES_MAX] = {};
chid_calculate((const char16_t* const*) smbios_fields, chids);
if (strv_isempty(strv_skip(argv, 1)))
for (size_t t = 0; t < CHID_TYPES_MAX; t++) {
r = add_chid(table, chids, t);
if (r < 0)
return r;
}
else {
STRV_FOREACH(as, strv_skip(argv, 1)) {
size_t t;
r = parse_chid_type(*as, &t);
if (r < 0)
return log_error_errno(r, "Failed to pare CHID type: %s", *as);
r = add_chid(table, chids, t);
if (r < 0)
return r;
}
(void) table_set_sort(table, (size_t) 0);
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
if (!sd_json_format_enabled(arg_json_format_flags)) {
_cleanup_free_ char *legend = NULL;
bool separator = false;
size_t w = 0;
legend = strjoin(ansi_grey(), "LEGEND: ", ansi_normal());
if (!legend)
return log_oom();
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
_cleanup_free_ char *c = utf16_to_utf8(smbios_fields[f], SIZE_MAX);
if (!c)
return log_oom();
if (!strextend(&legend,
ansi_grey(),
separator ? " " : "",
separator ? special_glyph(SPECIAL_GLYPH_HORIZONTAL_DOTTED) : "",
separator ? " " : "",
ansi_normal(),
CHAR_TO_STR(chid_smbios_fields_char[f]),
ansi_grey(),
" ",
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
" ",
ansi_normal(),
smbios_files[f],
ansi_grey(),
" (",
ansi_highlight(),
c,
ansi_grey(),
")",
ansi_normal()))
return log_oom();
w += separator * 3 +
4 +
utf8_console_width(smbios_files[f]) +
2 +
utf8_console_width(c) +
1;
if (w > 79) {
if (!strextend(&legend, "\n "))
return log_oom();
separator = false;
w = 8;
} else
separator = true;
}
putchar('\n');
puts(legend);
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int verb_chid(int argc, char *argv[], void *userdata);

View File

@ -18,6 +18,7 @@
#include "analyze-calendar.h"
#include "analyze-capability.h"
#include "analyze-cat-config.h"
#include "analyze-chid.h"
#include "analyze-compare-versions.h"
#include "analyze-condition.h"
#include "analyze-critical-chain.h"
@ -219,6 +220,7 @@ static int help(int argc, char *argv[], void *userdata) {
" filesystems [NAME...] List known filesystems\n"
" architectures [NAME...] List known architectures\n"
" smbios11 List strings passed via SMBIOS Type #11\n"
" chid List local CHIDs\n"
"\n%3$sExpression Evaluation:%4$s\n"
" condition CONDITION... Evaluate conditions and asserts\n"
" compare-versions VERSION1 [OP] VERSION2\n"
@ -593,10 +595,6 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= requires one or more units to perform a security review.");
if (sd_json_format_enabled(arg_json_format_flags) && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore", "pcrs", "architectures", "capability", "exit-status"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security, inspect-elf, plot, fdstore, pcrs, architectures, capability, exit-status right now.");
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now.");
@ -631,10 +629,6 @@ static int parse_argv(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used.");
if ((!arg_legend && !STRPTR_IN_SET(argv[optind], "plot", "architectures")) ||
(streq_ptr(argv[optind], "plot") && !arg_legend && !arg_table && !sd_json_format_enabled(arg_json_format_flags)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --no-legend is only supported for plot with either --table or --json=.");
if (arg_table && !streq_ptr(argv[optind], "plot"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --table is only supported for plot right now.");
@ -691,6 +685,7 @@ static int run(int argc, char *argv[]) {
{ "srk", VERB_ANY, 1, 0, verb_srk },
{ "architectures", VERB_ANY, VERB_ANY, 0, verb_architectures },
{ "smbios11", VERB_ANY, 1, 0, verb_smbios11 },
{ "chid", VERB_ANY, VERB_ANY, 0, verb_chid },
{}
};

View File

@ -6,6 +6,7 @@ systemd_analyze_sources = files(
'analyze-calendar.c',
'analyze-capability.c',
'analyze-cat-config.c',
'analyze-chid.c',
'analyze-compare-versions.c',
'analyze-condition.c',
'analyze-critical-chain.c',

View File

@ -9,8 +9,8 @@
#define AUDIT_SESSION_INVALID UINT32_MAX
int audit_session_from_pid(const PidRef *pid, uint32_t *id);
int audit_loginuid_from_pid(const PidRef *pid, uid_t *uid);
int audit_session_from_pid(const PidRef *pid, uint32_t *ret_id);
int audit_loginuid_from_pid(const PidRef *pid, uid_t *ret_uid);
bool use_audit(void);

View File

@ -8,8 +8,9 @@
#include <unistd.h>
#include "alloc-util.h"
#include "capability-util.h"
#include "cap-list.h"
#include "capability-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "logarithm.h"
@ -17,6 +18,8 @@
#include "missing_prctl.h"
#include "missing_threads.h"
#include "parse-util.h"
#include "pidref.h"
#include "stat-util.h"
#include "user-util.h"
int have_effective_cap(int value) {
@ -607,3 +610,78 @@ int capability_get_ambient(uint64_t *ret) {
*ret = a;
return 1;
}
int pidref_get_capability(const PidRef *pidref, CapabilityQuintet *ret) {
int r;
if (!pidref_is_set(pidref))
return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
const char *path = procfs_file_alloca(pidref->pid, "status");
_cleanup_fclose_ FILE *f = fopen(path, "re");
if (!f) {
if (errno == ENOENT && proc_mounted() == 0)
return -ENOSYS;
return -errno;
}
CapabilityQuintet q = CAPABILITY_QUINTET_NULL;
for (;;) {
_cleanup_free_ char *line = NULL;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0)
break;
static const struct {
const char *field;
size_t offset;
} fields[] = {
{ "CapBnd:", offsetof(CapabilityQuintet, bounding) },
{ "CapInh:", offsetof(CapabilityQuintet, inheritable) },
{ "CapPrm:", offsetof(CapabilityQuintet, permitted) },
{ "CapEff:", offsetof(CapabilityQuintet, effective) },
{ "CapAmb:", offsetof(CapabilityQuintet, ambient) },
};
FOREACH_ELEMENT(i, fields) {
const char *p = first_word(line, i->field);
if (!p)
continue;
uint64_t *v = (uint64_t*) ((uint8_t*) &q + i->offset);
if (*v != CAP_MASK_UNSET)
return -EBADMSG;
r = safe_atoux64(p, v);
if (r < 0)
return r;
if (*v == CAP_MASK_UNSET)
return -EBADMSG;
}
}
if (q.effective == CAP_MASK_UNSET ||
q.inheritable == CAP_MASK_UNSET ||
q.permitted == CAP_MASK_UNSET ||
q.effective == CAP_MASK_UNSET ||
q.ambient == CAP_MASK_UNSET)
return -EBADMSG;
r = pidref_verify(pidref);
if (r < 0)
return r;
if (ret)
*ret = q;
return 0;
}

View File

@ -8,6 +8,7 @@
#include "macro.h"
#include "missing_capability.h"
#include "pidref.h"
/* Special marker used when storing a capabilities mask as "unset" */
#define CAP_MASK_UNSET UINT64_MAX
@ -66,14 +67,18 @@ typedef struct CapabilityQuintet {
assert_cc(CAP_LAST_CAP < 64);
#define CAPABILITY_QUINTET_NULL { CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET }
#define CAPABILITY_QUINTET_NULL (CapabilityQuintet) { CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET, CAP_MASK_UNSET }
static inline bool capability_is_set(uint64_t v) {
return v != CAP_MASK_UNSET;
}
static inline bool capability_quintet_is_set(const CapabilityQuintet *q) {
return q->effective != CAP_MASK_UNSET ||
q->bounding != CAP_MASK_UNSET ||
q->inheritable != CAP_MASK_UNSET ||
q->permitted != CAP_MASK_UNSET ||
q->ambient != CAP_MASK_UNSET;
return capability_is_set(q->effective) ||
capability_is_set(q->bounding) ||
capability_is_set(q->inheritable) ||
capability_is_set(q->permitted) ||
capability_is_set(q->ambient);
}
/* Mangles the specified caps quintet taking the current bounding set into account:
@ -84,3 +89,5 @@ bool capability_quintet_mangle(CapabilityQuintet *q);
int capability_quintet_enforce(const CapabilityQuintet *q);
int capability_get_ambient(uint64_t *ret);
int pidref_get_capability(const PidRef *pidref, CapabilityQuintet *ret);

View File

@ -24,6 +24,11 @@ int memfd_create_wrapper(const char *name, unsigned mode) {
unsigned mode_compat;
int mfd;
assert(name);
/* Wrapper around memfd_create() which adds compat with older kernels where memfd_create() didn't
* support MFD_EXEC/MFD_NOEXEC_SEAL. (kernel 6.3+) */
mfd = RET_NERRNO(memfd_create(name, mode));
if (mfd != -EINVAL)
return mfd;
@ -36,11 +41,11 @@ int memfd_create_wrapper(const char *name, unsigned mode) {
return RET_NERRNO(memfd_create(name, mode_compat));
}
int memfd_new(const char *name) {
int memfd_new_full(const char *name, unsigned extra_flags) {
_cleanup_free_ char *g = NULL;
if (!name) {
char pr[17] = {};
char pr[TASK_COMM_LEN] = {};
/* If no name is specified we generate one. We include
* a hint indicating our library implementation, and
@ -65,16 +70,18 @@ int memfd_new(const char *name) {
}
}
return memfd_create_wrapper(name, MFD_ALLOW_SEALING | MFD_CLOEXEC | MFD_NOEXEC_SEAL);
return memfd_create_wrapper(
name,
MFD_CLOEXEC | MFD_NOEXEC_SEAL | extra_flags);
}
int memfd_add_seals(int fd, unsigned int seals) {
int memfd_add_seals(int fd, unsigned seals) {
assert(fd >= 0);
return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals));
}
int memfd_get_seals(int fd, unsigned int *ret_seals) {
int memfd_get_seals(int fd, unsigned *ret_seals) {
int r;
assert(fd >= 0);
@ -88,30 +95,6 @@ int memfd_get_seals(int fd, unsigned int *ret_seals) {
return 0;
}
int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
unsigned int seals;
void *q;
int r;
assert(fd >= 0);
assert(size > 0);
assert(p);
r = memfd_get_seals(fd, &seals);
if (r < 0)
return r;
if (seals & F_SEAL_WRITE)
q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
else
q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
if (q == MAP_FAILED)
return -errno;
*p = q;
return 0;
}
int memfd_set_sealed(int fd) {
return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
}
@ -128,16 +111,16 @@ int memfd_get_sealed(int fd) {
return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
}
int memfd_get_size(int fd, uint64_t *sz) {
int memfd_get_size(int fd, uint64_t *ret) {
struct stat stat;
assert(fd >= 0);
assert(sz);
assert(ret);
if (fstat(fd, &stat) < 0)
return -errno;
*sz = stat.st_size;
*ret = stat.st_size;
return 0;
}
@ -147,50 +130,25 @@ int memfd_set_size(int fd, uint64_t sz) {
return RET_NERRNO(ftruncate(fd, sz));
}
int memfd_new_and_map(const char *name, size_t sz, void **p) {
_cleanup_close_ int fd = -EBADF;
int r;
assert(sz > 0);
assert(p);
fd = memfd_new(name);
if (fd < 0)
return fd;
r = memfd_set_size(fd, sz);
if (r < 0)
return r;
r = memfd_map(fd, 0, sz, p);
if (r < 0)
return r;
return TAKE_FD(fd);
}
int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
_cleanup_close_ int fd = -EBADF;
ssize_t n;
off_t f;
int r;
assert(data || sz == 0);
fd = memfd_new(name);
if (sz == SIZE_MAX)
sz = strlen(data);
fd = memfd_new_full(name, MFD_ALLOW_SEALING);
if (fd < 0)
return fd;
if (sz > 0) {
n = write(fd, data, sz);
ssize_t n = pwrite(fd, data, sz, 0);
if (n < 0)
return -errno;
if ((size_t) n != sz)
return -EIO;
f = lseek(fd, 0, SEEK_SET);
if (f != 0)
return -errno;
}
r = memfd_set_sealed(fd);

View File

@ -8,16 +8,21 @@
int memfd_create_wrapper(const char *name, unsigned mode);
int memfd_new(const char *name);
int memfd_new_and_map(const char *name, size_t sz, void **p);
int memfd_new_and_seal(const char *name, const void *data, size_t sz);
int memfd_new_full(const char *name, unsigned extra_flags);
static inline int memfd_new(const char *name) {
return memfd_new_full(name, 0);
}
int memfd_add_seals(int fd, unsigned int seals);
int memfd_get_seals(int fd, unsigned int *ret_seals);
int memfd_map(int fd, uint64_t offset, size_t size, void **p);
int memfd_new_and_seal(const char *name, const void *data, size_t sz);
static inline int memfd_new_and_seal_string(const char *name, const char *s) {
return memfd_new_and_seal(name, s, SIZE_MAX);
}
int memfd_add_seals(int fd, unsigned seals);
int memfd_get_seals(int fd, unsigned *ret_seals);
int memfd_set_sealed(int fd);
int memfd_get_sealed(int fd);
int memfd_get_size(int fd, uint64_t *sz);
int memfd_get_size(int fd, uint64_t *ret);
int memfd_set_size(int fd, uint64_t sz);

View File

@ -429,7 +429,7 @@ int pidref_wait(const PidRef *pidref, siginfo_t *ret, int options) {
if (pidref_is_remote(pidref))
return -EREMOTE;
if (pidref->pid == 1 || pidref->pid == getpid_cached())
if (pidref->pid == 1 || pidref_is_self(pidref))
return -ECHILD;
siginfo_t si = {};

View File

@ -500,22 +500,6 @@ int pidref_is_kernel_thread(const PidRef *pid) {
return result;
}
int get_process_capeff(pid_t pid, char **ret) {
const char *p;
int r;
assert(pid >= 0);
assert(ret);
p = procfs_file_alloca(pid, "status");
r = get_proc_field(p, "CapEff", WHITESPACE, ret);
if (r == -ENOENT)
return -ESRCH;
return r;
}
static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) {
const char *p;
int r;

View File

@ -50,7 +50,6 @@ int get_process_exe(pid_t pid, char **ret);
int pid_get_uid(pid_t pid, uid_t *ret);
int pidref_get_uid(const PidRef *pid, uid_t *ret);
int get_process_gid(pid_t pid, gid_t *ret);
int get_process_capeff(pid_t pid, char **ret);
int get_process_cwd(pid_t pid, char **ret);
int get_process_root(pid_t pid, char **ret);
int get_process_environ(pid_t pid, char **ret);

View File

@ -13,7 +13,6 @@
#include "creds-util.h"
#include "dbus-execute.h"
#include "dbus-util.h"
#include "dns-domain.h"
#include "env-util.h"
#include "errno-list.h"
#include "escape.h"

View File

@ -14,7 +14,6 @@
#include "bus-util.h"
#include "chase.h"
#include "confidential-virt.h"
#include "data-fd-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-job.h"
@ -33,6 +32,7 @@
#include "locale-util.h"
#include "log.h"
#include "manager-dump.h"
#include "memfd-util.h"
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
@ -48,10 +48,6 @@
#include "virt.h"
#include "watchdog.h"
/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state
* there, and if we can't we'll fail badly. */
#define RELOAD_DISK_SPACE_MIN (UINT64_C(16) * UINT64_C(1024) * UINT64_C(1024))
static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) {
return (runtime ? UNIT_FILE_RUNTIME : 0) |
(force ? UNIT_FILE_FORCE : 0);
@ -1447,7 +1443,7 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er
static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
_cleanup_close_ int fd = -EBADF;
fd = acquire_data_fd(dump);
fd = memfd_new_and_seal_string("dump", dump);
if (fd < 0)
return fd;
@ -1485,73 +1481,6 @@ static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
}
static int get_run_space(uint64_t *ret, sd_bus_error *error) {
struct statvfs svfs;
assert(ret);
if (statvfs("/run/systemd", &svfs) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to statvfs(/run/systemd): %m");
*ret = (uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize;
return 0;
}
static int verify_run_space(const char *message, sd_bus_error *error) {
uint64_t available = 0; /* unnecessary, but used to trick out gcc's incorrect maybe-uninitialized warning */
int r;
assert(message);
r = get_run_space(&available, error);
if (r < 0)
return r;
if (available < RELOAD_DISK_SPACE_MIN)
return sd_bus_error_setf(error,
BUS_ERROR_DISK_FULL,
"%s, not enough space available on /run/systemd/. "
"Currently, %s are free, but a safety buffer of %s is enforced.",
message,
FORMAT_BYTES(available),
FORMAT_BYTES(RELOAD_DISK_SPACE_MIN));
return 0;
}
int verify_run_space_and_log(const char *message) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(message);
r = verify_run_space(message, &error);
if (r < 0)
return log_error_errno(r, "%s", bus_error_message(&error, r));
return 0;
}
static int verify_run_space_permissive(const char *message, sd_bus_error *error) {
uint64_t available = 0; /* unnecessary, but used to trick out gcc's incorrect maybe-uninitialized warning */
int r;
assert(message);
r = get_run_space(&available, error);
if (r < 0)
return r;
if (available < RELOAD_DISK_SPACE_MIN)
log_warning("Dangerously low amount of free space on /run/systemd/, %s.\n"
"Currently, %s are free, but %s are suggested. Proceeding anyway.",
message,
FORMAT_BYTES(available),
FORMAT_BYTES(RELOAD_DISK_SPACE_MIN));
return 0;
}
static void log_caller(sd_bus_message *message, Manager *manager, const char *method) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
@ -1585,10 +1514,6 @@ static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *
assert(message);
r = verify_run_space("Refusing to reload", error);
if (r < 0)
return r;
r = mac_selinux_access_check(message, "reload", error);
if (r < 0)
return r;
@ -1631,10 +1556,6 @@ static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_erro
assert(message);
r = verify_run_space("Refusing to reexecute", error);
if (r < 0)
return r;
r = mac_selinux_access_check(message, "reload", error);
if (r < 0)
return r;
@ -1718,10 +1639,6 @@ static int method_soft_reboot(sd_bus_message *message, void *userdata, sd_bus_er
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
"Soft reboot is only supported by system manager.");
r = verify_run_space_permissive("soft reboot may fail", error);
if (r < 0)
return r;
r = mac_selinux_access_check(message, "reboot", error);
if (r < 0)
return r;
@ -1826,10 +1743,6 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED,
"Root switching is only supported by system manager.");
r = verify_run_space_permissive("root switching may fail", error);
if (r < 0)
return r;
r = mac_selinux_access_check(message, "reboot", error);
if (r < 0)
return r;

View File

@ -85,7 +85,9 @@ static int device_set_sysfs(Device *d, const char *sysfs) {
Unit *u = UNIT(ASSERT_PTR(d));
int r;
if (streq_ptr(d->sysfs, sysfs))
assert(sysfs);
if (path_equal(d->sysfs, sysfs))
return 0;
Hashmap **devices = &u->manager->devices_by_sysfs;
@ -332,6 +334,20 @@ static void device_catchup(Unit *u) {
Device *d = ASSERT_PTR(DEVICE(u));
/* Second, let's update the state with the enumerated state */
/* If Device.found (set from Device.deserialized_found) does not have DEVICE_FOUND_UDEV, and the
* device has not been processed by udevd while enumeration, it indicates the unit was never active
* before reexecution, hence we can safely drop the flag from Device.enumerated_found. The device
* will be set up later when udev finishes processing (see also comment in
* device_setup_devlink_unit_one()).
*
* NB: 💣💣💣 If Device.found already contains udev, i.e. the unit was fully ready before
* reexecution, do not unset the flag. Otherwise, e.g. if systemd-udev-trigger.service is started
* just before reexec, reload, and so on, devices being reprocessed (carrying ID_PROCESSING=1
* property) on enumeration and will enter dead state. See issue #35329. */
if (!FLAGS_SET(d->found, DEVICE_FOUND_UDEV) && !d->processed)
d->enumerated_found &= ~DEVICE_FOUND_UDEV;
device_update_found_one(d, d->enumerated_found, _DEVICE_FOUND_MASK);
}
@ -777,8 +793,16 @@ static int device_setup_devlink_unit_one(Manager *m, const char *devlink, Set **
assert(ready_units);
assert(not_ready_units);
if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev))
if (sd_device_new_from_devname(&dev, devlink) >= 0 && device_is_ready(dev)) {
if (MANAGER_IS_RUNNING(m) && device_is_processed(dev) <= 0)
/* The device is being processed by udevd. We will receive relevant uevent for the
* device later when completed. Let's ignore the device now. */
return 0;
/* Note, even if the device is being processed by udevd, setup the unit on enumerate.
* See also the comments in device_catchup(). */
return device_setup_unit(m, dev, devlink, /* main = */ false, ready_units);
}
/* the devlink is already removed or not ready */
if (device_by_path(m, devlink, &u) < 0)
@ -874,14 +898,15 @@ static int device_setup_extra_units(Manager *m, sd_device *dev, Set **ready_unit
return 0;
}
static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set **not_ready_units) {
static int device_setup_units(Manager *m, sd_device *dev, Set **ret_ready_units, Set **ret_not_ready_units) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath, *devname = NULL;
int r;
assert(m);
assert(dev);
assert(ready_units);
assert(not_ready_units);
assert(ret_ready_units);
assert(ret_not_ready_units);
r = sd_device_get_syspath(dev, &syspath);
if (r < 0)
@ -901,13 +926,13 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* Add the main unit named after the syspath. If this one fails, don't bother with the rest,
* as this one shall be the main device unit the others just follow. (Compare with how
* device_following() is implemented, see below, which looks for the sysfs device.) */
r = device_setup_unit(m, dev, syspath, /* main = */ true, ready_units);
r = device_setup_unit(m, dev, syspath, /* main = */ true, &ready_units);
if (r < 0)
return r;
/* Add an additional unit for the device node */
if (sd_device_get_devname(dev, &devname) >= 0)
(void) device_setup_unit(m, dev, devname, /* main = */ false, ready_units);
(void) device_setup_unit(m, dev, devname, /* main = */ false, &ready_units);
} else {
Unit *u;
@ -915,28 +940,30 @@ static int device_setup_units(Manager *m, sd_device *dev, Set **ready_units, Set
/* If the device exists but not ready, then save the units and unset udev bits later. */
if (device_by_path(m, syspath, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u));
r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
}
if (sd_device_get_devname(dev, &devname) >= 0 &&
device_by_path(m, devname, &u) >= 0) {
r = set_ensure_put(not_ready_units, NULL, DEVICE(u));
r = set_ensure_put(&not_ready_units, NULL, DEVICE(u));
if (r < 0)
log_unit_debug_errno(u, r, "Failed to store unit, ignoring: %m");
}
}
/* Next, add/update additional .device units point to aliases and symlinks. */
(void) device_setup_extra_units(m, dev, ready_units, not_ready_units);
(void) device_setup_extra_units(m, dev, &ready_units, &not_ready_units);
/* Safety check: no unit should be in ready_units and not_ready_units simultaneously. */
Unit *u;
SET_FOREACH(u, *not_ready_units)
if (set_remove(*ready_units, u))
SET_FOREACH(u, not_ready_units)
if (set_remove(ready_units, u))
log_unit_error(u, "Cannot activate and deactivate the unit simultaneously. Deactivating.");
*ret_ready_units = TAKE_PTR(ready_units);
*ret_not_ready_units = TAKE_PTR(not_ready_units);
return 0;
}
@ -1046,13 +1073,32 @@ static void device_enumerate(Manager *m) {
FOREACH_DEVICE(e, dev) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
const char *syspath;
bool processed;
Device *d;
r = sd_device_get_syspath(dev, &syspath);
if (r < 0) {
log_device_debug_errno(dev, r, "Failed to get syspath of enumerated device, ignoring: %m");
continue;
}
r = device_is_processed(dev);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to check if device is processed by udevd, assuming not: %m");
processed = r > 0;
if (device_setup_units(m, dev, &ready_units, &not_ready_units) < 0)
continue;
SET_FOREACH(d, ready_units)
SET_FOREACH(d, ready_units) {
device_update_found_one(d, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
/* Why we need to check the syspath here? Because the device unit may be generated by
* a devlink, and the syspath may be different from the one of the original device. */
if (path_equal(d->sysfs, syspath))
d->processed = processed;
}
SET_FOREACH(d, not_ready_units)
device_update_found_one(d, DEVICE_NOT_FOUND, DEVICE_FOUND_UDEV);
}
@ -1097,7 +1143,6 @@ static void device_remove_old_on_move(Manager *m, sd_device *dev) {
}
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
Manager *m = ASSERT_PTR(userdata);
sd_device_action_t action;
const char *sysfs;
@ -1150,6 +1195,7 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
* change events */
ready = device_is_ready(dev);
_cleanup_set_free_ Set *ready_units = NULL, *not_ready_units = NULL;
(void) device_setup_units(m, dev, &ready_units, &not_ready_units);
if (action == SD_DEVICE_REMOVE) {

View File

@ -29,7 +29,9 @@ struct Device {
DeviceState state, deserialized_state;
DeviceFound found, deserialized_found, enumerated_found;
bool processed; /* Whether udevd has done processing the device, i.e. the device has database and
* ID_PROCESSING=1 udev property is not set. This is used only by enumeration and
* subsequent catchup process. */
bool bind_mounts;
/* The SYSTEMD_WANTS udev property for this device the last time we saw it */

View File

@ -31,7 +31,6 @@
#include "chattr-util.h"
#include "chown-recursive.h"
#include "copy.h"
#include "data-fd-util.h"
#include "env-util.h"
#include "escape.h"
#include "exec-credential.h"
@ -44,6 +43,7 @@
#include "io-util.h"
#include "iovec-util.h"
#include "journal-send.h"
#include "memfd-util.h"
#include "missing_ioprio.h"
#include "missing_prctl.h"
#include "missing_sched.h"
@ -406,7 +406,7 @@ static int setup_input(
case EXEC_INPUT_DATA: {
int fd;
fd = acquire_data_fd_full(context->stdin_data, context->stdin_data_size, /* flags = */ 0);
fd = memfd_new_and_seal("exec-input", context->stdin_data, context->stdin_data_size);
if (fd < 0)
return fd;

View File

@ -516,8 +516,9 @@ int exec_spawn(
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
if (fseeko(f, 0, SEEK_SET) < 0)
return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
r = finish_serialization_file(f);
if (r < 0)
return log_unit_error_errno(unit, r, "Failed to finish serialization stream: %m");
r = fd_cloexec(fileno(f), false);
if (r < 0)

View File

@ -34,12 +34,12 @@
#include "clock-warp.h"
#include "conf-parser.h"
#include "confidential-virt.h"
#include "constants.h"
#include "copy.h"
#include "cpu-set-util.h"
#include "crash-handler.h"
#include "dbus-manager.h"
#include "dbus.h"
#include "constants.h"
#include "dev-setup.h"
#include "efi-random.h"
#include "efivars.h"
@ -87,6 +87,7 @@
#include "seccomp-util.h"
#include "selinux-setup.h"
#include "selinux-util.h"
#include "serialize.h"
#include "signal-util.h"
#include "smack-setup.h"
#include "special.h"
@ -1233,14 +1234,14 @@ static int prepare_reexecute(
assert(ret_f);
assert(ret_fds);
r = manager_open_serialization(m, &f);
if (r < 0)
return log_error_errno(r, "Failed to create serialization file: %m");
/* Make sure nothing is really destructed when we shut down */
m->n_reloading++;
bus_manager_send_reloading(m, true);
r = manager_open_serialization(m, &f);
if (r < 0)
return log_error_errno(r, "Failed to create serialization file: %m");
fds = fdset_new();
if (!fds)
return log_oom();
@ -1249,8 +1250,9 @@ static int prepare_reexecute(
if (r < 0)
return r;
if (fseeko(f, 0, SEEK_SET) < 0)
return log_error_errno(errno, "Failed to rewind serialization fd: %m");
r = finish_serialization_file(f);
if (r < 0)
return log_error_errno(r, "Failed to finish serialization file: %m");
r = fd_cloexec(fileno(f), false);
if (r < 0)

View File

@ -186,10 +186,6 @@ int manager_serialize(
return r;
}
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to flush serialization: %m");
r = bus_fdset_add_all(m, fds);
if (r < 0)
return log_error_errno(r, "Failed to add bus sockets to serialization: %m");

View File

@ -80,6 +80,7 @@
#include "rlimit-util.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "serialize.h"
#include "signal-util.h"
#include "socket-util.h"
#include "special.h"
@ -3123,9 +3124,6 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
case SIGTERM:
if (MANAGER_IS_SYSTEM(m)) {
/* This is for compatibility with the original sysvinit */
if (verify_run_space_and_log("Refusing to reexecute") < 0)
break;
m->objective = MANAGER_REEXECUTE;
break;
}
@ -3179,9 +3177,6 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
case SIGHUP:
if (verify_run_space_and_log("Refusing to reload") < 0)
break;
m->objective = MANAGER_RELOAD;
break;
@ -3762,8 +3757,9 @@ int manager_reload(Manager *m) {
if (r < 0)
return r;
if (fseeko(f, 0, SEEK_SET) < 0)
return log_error_errno(errno, "Failed to seek to beginning of serialization: %m");
r = finish_serialization_file(f);
if (r < 0)
return log_error_errno(r, "Failed to finish serialization: %m");
/* 💀 This is the point of no return, from here on there is no way back. 💀 */
reloading = NULL;

View File

@ -3,9 +3,11 @@
#include <unistd.h>
#include "alloc-util.h"
#include "bitfield.h"
#include "creds-util.h"
#include "dropin.h"
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
#include "generator.h"
@ -27,6 +29,7 @@ static char **arg_wants = NULL;
static bool arg_debug_shell = false;
static char *arg_debug_tty = NULL;
static char *arg_default_debug_tty = NULL;
static uint32_t arg_breakpoints = 0;
STATIC_DESTRUCTOR_REGISTER(arg_default_unit, freep);
STATIC_DESTRUCTOR_REGISTER(arg_mask, strv_freep);
@ -34,6 +37,91 @@ STATIC_DESTRUCTOR_REGISTER(arg_wants, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_debug_tty, freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_debug_tty, freep);
typedef enum BreakpointType {
BREAKPOINT_PRE_UDEV,
BREAKPOINT_PRE_BASIC,
BREAKPOINT_PRE_SYSROOT_MOUNT,
BREAKPOINT_PRE_SWITCH_ROOT,
_BREAKPOINT_TYPE_MAX,
_BREAKPOINT_TYPE_INVALID = -EINVAL,
} BreakpointType;
typedef enum BreakpointValidity {
BREAKPOINT_DEFAULT = 1 << 0,
BREAKPOINT_IN_INITRD = 1 << 1,
BREAKPOINT_ON_HOST = 1 << 2,
} BreakpointValidity;
typedef struct BreakpointInfo {
BreakpointType type;
const char *name;
const char *unit;
BreakpointValidity validity;
} BreakpointInfo;
static const struct BreakpointInfo breakpoint_info_table[_BREAKPOINT_TYPE_MAX] = {
{ BREAKPOINT_PRE_UDEV, "pre-udev", "breakpoint-pre-udev.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_BASIC, "pre-basic", "breakpoint-pre-basic.service", BREAKPOINT_IN_INITRD | BREAKPOINT_ON_HOST },
{ BREAKPOINT_PRE_SYSROOT_MOUNT, "pre-mount", "breakpoint-pre-mount.service", BREAKPOINT_IN_INITRD },
{ BREAKPOINT_PRE_SWITCH_ROOT, "pre-switch-root", "breakpoint-pre-switch-root.service", BREAKPOINT_IN_INITRD | BREAKPOINT_DEFAULT },
};
static BreakpointType parse_breakpoint_from_string_one(const char *s) {
assert(s);
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (streq(i->name, s))
return i->type;
return _BREAKPOINT_TYPE_INVALID;
}
static int parse_breakpoint_from_string(const char *s, uint32_t *ret_breakpoints) {
uint32_t breakpoints = 0;
int r;
assert(ret_breakpoints);
/* Empty value? set default breakpoint */
if (isempty(s)) {
if (in_initrd()) {
FOREACH_ARRAY(i, breakpoint_info_table, ELEMENTSOF(breakpoint_info_table))
if (i->validity & BREAKPOINT_DEFAULT) {
breakpoints |= 1 << i->type;
break;
}
} else
log_warning("No default breakpoint defined on the host, ignoring breakpoint request from kernel command line.");
} else
for (;;) {
_cleanup_free_ char *t = NULL;
BreakpointType tt;
r = extract_first_word(&s, &t, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
break;
tt = parse_breakpoint_from_string_one(t);
if (tt < 0) {
log_warning("Invalid breakpoint value '%s', ignoring.", t);
continue;
}
if (in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_IN_INITRD))
log_warning("Breakpoint '%s' not valid in the initrd, ignoring.", t);
else if (!in_initrd() && !FLAGS_SET(breakpoint_info_table[tt].validity, BREAKPOINT_ON_HOST))
log_warning("Breakpoint '%s' not valid on the host, ignoring.", t);
else
breakpoints |= 1 << tt;
}
*ret_breakpoints = breakpoints;
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@ -88,6 +176,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return free_and_strdup_warn(&arg_default_unit, value);
} else if (streq(key, "systemd.break")) {
uint32_t breakpoints = 0;
r = parse_breakpoint_from_string(value, &breakpoints);
if (r < 0)
return log_warning_errno(r, "Failed to parse breakpoint value '%s': %m", value);
arg_breakpoints |= breakpoints;
} else if (!value) {
const char *target;
@ -269,6 +366,10 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
RET_GATHER(r, install_debug_shell_dropin());
}
BIT_FOREACH(i, arg_breakpoints)
if (strv_extend(&arg_wants, breakpoint_info_table[i].unit) < 0)
return log_oom();
if (get_credentials_dir(&credentials_dir) >= 0)
RET_GATHER(r, process_unit_credentials(credentials_dir));

View File

@ -95,6 +95,7 @@ static char *arg_loop_ref = NULL;
static ImagePolicy *arg_image_policy = NULL;
static bool arg_mtree_hash = true;
static bool arg_via_service = false;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
@ -151,6 +152,8 @@ static int help(void) {
" Generate JSON output\n"
" --loop-ref=NAME Set reference string for loopback device\n"
" --mtree-hash=BOOL Whether to include SHA256 hash in the mtree output\n"
" --user Discover user images\n"
" --system Discover system images\n"
"\n%3$sCommands:%4$s\n"
" -h --help Show this help\n"
" --version Show package version\n"
@ -274,6 +277,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VALIDATE,
ARG_MTREE_HASH,
ARG_MAKE_ARCHIVE,
ARG_SYSTEM,
ARG_USER,
};
static const struct option options[] = {
@ -307,10 +312,13 @@ static int parse_argv(int argc, char *argv[]) {
{ "validate", no_argument, NULL, ARG_VALIDATE },
{ "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
{ "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "user", no_argument, NULL, ARG_USER },
{}
};
_cleanup_free_ char **buf = NULL; /* we use free(), not strv_free() here, as we don't copy the strings here */
bool system_scope_requested = false, user_scope_requested = false;
int c, r;
assert(argc >= 0);
@ -531,7 +539,6 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_MAKE_ARCHIVE:
r = dlopen_libarchive();
if (r < 0)
return log_error_errno(r, "Archive support not available (compiled without libarchive, or libarchive not installed?).");
@ -539,6 +546,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_MAKE_ARCHIVE;
break;
case ARG_SYSTEM:
system_scope_requested = true;
break;
case ARG_USER:
user_scope_requested = true;
break;
case '?':
return -EINVAL;
@ -547,6 +562,10 @@ static int parse_argv(int argc, char *argv[]) {
}
}
if (system_scope_requested || user_scope_requested)
arg_runtime_scope = system_scope_requested && user_scope_requested ? _RUNTIME_SCOPE_INVALID :
system_scope_requested ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
switch (arg_action) {
case ACTION_DISSECT:
@ -1851,7 +1870,7 @@ static int action_discover(void) {
return log_oom();
for (ImageClass cl = 0; cl < _IMAGE_CLASS_MAX; cl++) {
r = image_discover(cl, NULL, images);
r = image_discover(arg_runtime_scope, cl, NULL, images);
if (r < 0)
return log_error_errno(r, "Failed to discover images: %m");
}

View File

@ -61,7 +61,7 @@ static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIE
ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80);
}
static const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |

View File

@ -23,5 +23,7 @@ typedef enum ChidSmbiosFields {
_CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields;
extern const uint32_t chid_smbios_table[CHID_TYPES_MAX];
/* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]);

View File

@ -13,7 +13,6 @@
#include "build-path.h"
#include "bus-common-errors.h"
#include "bus-locator.h"
#include "data-fd-util.h"
#include "env-util.h"
#include "errno-list.h"
#include "errno-util.h"
@ -1266,13 +1265,13 @@ static int home_start_work(
if (r < 0)
return r;
stdin_fd = acquire_data_fd(formatted);
stdin_fd = memfd_new_and_seal_string("request", formatted);
if (stdin_fd < 0)
return stdin_fd;
log_debug("Sending to worker: %s", formatted);
stdout_fd = memfd_create_wrapper("homework-stdout", MFD_CLOEXEC | MFD_NOEXEC_SEAL);
stdout_fd = memfd_new("homework-stdout");
if (stdout_fd < 0)
return stdout_fd;

View File

@ -5,7 +5,6 @@
#include <linux/fs.h>
#endif
#include "data-fd-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -13,6 +12,7 @@
#include "fs-util.h"
#include "homework-cifs.h"
#include "homework-mount.h"
#include "memfd-util.h"
#include "mkdir.h"
#include "mount-util.h"
#include "process-util.h"
@ -76,7 +76,7 @@ int home_setup_cifs(
pid_t mount_pid;
int exit_status;
passwd_fd = acquire_data_fd(*pw);
passwd_fd = memfd_new_and_seal_string("cifspw", *pw);
if (passwd_fd < 0)
return log_error_errno(passwd_fd, "Failed to create data FD for password: %m");

View File

@ -25,6 +25,7 @@
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
static void determine_compression_from_filename(const char *p) {
@ -66,7 +67,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
local = argv[1];
if (image_name_is_valid(local)) {
r = image_find(arg_class, local, NULL, &image);
r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
if (r == -ENOENT)
return log_error_errno(r, "Image %s not found.", local);
if (r < 0)
@ -139,7 +140,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
local = argv[1];
if (image_name_is_valid(local)) {
r = image_find(arg_class, local, NULL, &image);
r = image_find(arg_runtime_scope, arg_class, local, NULL, &image);
if (r == -ENOENT)
return log_error_errno(r, "Image %s not found.", local);
if (r < 0)

View File

@ -34,6 +34,7 @@ static bool arg_sync = true;
static bool arg_direct = false;
static const char *arg_image_root = NULL;
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
typedef struct ProgressInfo {
RateLimit limit;
@ -145,7 +146,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
return log_oom();
if (!arg_force) {
r = image_find(arg_class, local, NULL, NULL);
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);

View File

@ -30,6 +30,7 @@ static const char *arg_image_root = NULL;
static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
static int normalize_local(const char *local, char **ret) {
_cleanup_free_ char *ll = NULL;
@ -63,7 +64,7 @@ static int normalize_local(const char *local, char **ret) {
local = "imported";
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
r = image_find(arg_class, local, NULL, NULL);
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);

View File

@ -111,6 +111,8 @@ struct Manager {
bool use_btrfs_subvol;
bool use_btrfs_quota;
RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
};
#define TRANSFERS_MAX 64
@ -721,6 +723,7 @@ static int manager_new(Manager **ret) {
*m = (Manager) {
.use_btrfs_subvol = true,
.use_btrfs_quota = true,
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
};
r = sd_event_default(&m->event);
@ -1332,6 +1335,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ImageClass class = _IMAGE_CLASS_INVALID;
Manager *m = ASSERT_PTR(userdata);
int r;
assert(msg);
@ -1372,7 +1376,7 @@ static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error
if (!h)
return -ENOMEM;
r = image_discover(c, /* root= */ NULL, h);
r = image_discover(m->runtime_scope, c, /* root= */ NULL, h);
if (r < 0) {
if (class >= 0)
return r;

View File

@ -33,6 +33,7 @@ static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHAS
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
static char *arg_checksum = NULL;
static ImageClass arg_class = IMAGE_MACHINE;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
@ -66,7 +67,7 @@ static int normalize_local(const char *local, const char *url, char **ret) {
local);
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
r = image_find(arg_class, local, NULL, NULL);
r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);

View File

@ -24,7 +24,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_(unlink_and_freep) char *name = NULL;
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
void *mem;
int fdin, r;
if (outside_size_range(size, 3, 65536))
@ -35,13 +34,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(mkdtemp_malloc("/tmp/fuzz-journal-remote-XXXXXX", &tmp) >= 0);
assert_se(name = path_join(tmp, "fuzz-journal-remote.XXXXXX.journal"));
fdin = fdin_close = memfd_new_and_map("fuzz-journal-remote", size, &mem);
fdin = fdin_close = memfd_new_and_seal("fuzz-journal-remote", data, size);
if (fdin < 0)
return log_error_errno(fdin, "memfd_new_and_map() failed: %m");
memcpy(mem, data, size);
assert_se(munmap(mem, size) == 0);
fdout = mkostemps(name, STRLEN(".journal"), O_CLOEXEC);
if (fdout < 0)
return log_error_errno(errno, "mkostemps() failed: %m");

View File

@ -132,6 +132,7 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
.log_level_max = -1,
.log_ratelimit_interval = s->ratelimit_interval,
.log_ratelimit_burst = s->ratelimit_burst,
.capability_quintet = CAPABILITY_QUINTET_NULL,
};
r = hashmap_ensure_put(&s->client_contexts, NULL, PID_TO_PTR(pid), c);
@ -154,7 +155,6 @@ static void client_context_reset(Server *s, ClientContext *c) {
c->comm = mfree(c->comm);
c->exe = mfree(c->exe);
c->cmdline = mfree(c->cmdline);
c->capeff = mfree(c->capeff);
c->auditid = AUDIT_SESSION_INVALID;
c->loginuid = UID_INVALID;
@ -184,6 +184,8 @@ static void client_context_reset(Server *s, ClientContext *c) {
c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns);
c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns);
c->capability_quintet = CAPABILITY_QUINTET_NULL;
}
static ClientContext* client_context_free(Server *s, ClientContext *c) {
@ -233,8 +235,7 @@ static void client_context_read_basic(ClientContext *c) {
if (pid_get_cmdline(c->pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &t) >= 0)
free_and_replace(c->cmdline, t);
if (get_process_capeff(c->pid, &t) >= 0)
free_and_replace(c->capeff, t);
(void) pidref_get_capability(&PIDREF_MAKE_FROM_PID(c->pid), &c->capability_quintet);
}
static int client_context_read_label(

View File

@ -7,6 +7,7 @@
#include "sd-id128.h"
#include "capability-util.h"
#include "set.h"
#include "time-util.h"
@ -27,7 +28,7 @@ struct ClientContext {
char *comm;
char *exe;
char *cmdline;
char *capeff;
CapabilityQuintet capability_quintet;
uint32_t auditid;
uid_t loginuid;

View File

@ -1109,7 +1109,7 @@ static void server_dispatch_message_real(
* Let's use a heap allocation for this one. */
cmdline1 = set_iovec_string_field(iovec, &n, "_CMDLINE=", c->cmdline);
IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE"); /* Read from /proc/.../status */
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "_CAP_EFFECTIVE");
IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID");
@ -1144,7 +1144,7 @@ static void server_dispatch_message_real(
if (o->cmdline)
cmdline2 = set_iovec_string_field(iovec, &n, "OBJECT_CMDLINE=", o->cmdline);
IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->capability_quintet.effective, uint64_t, capability_is_set, "%" PRIx64, "OBJECT_CAP_EFFECTIVE");
IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION");
IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID");

View File

@ -32,7 +32,6 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH),
SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH),
SD_BUS_ERROR_MAP(BUS_ERROR_DISK_FULL, ENOSPC),
SD_BUS_ERROR_MAP(BUS_ERROR_FILE_DESCRIPTOR_STORE_DISABLED,
EHOSTDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_FROZEN_BY_PARENT, EDEADLK),

View File

@ -28,7 +28,6 @@
#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning"
#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser"
#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced"
#define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull"
#define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean"
#define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy"
#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive"

View File

@ -81,7 +81,7 @@ static void *server(void *p) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
assert_se(pidref_set_pidfd_take(&pidref, pidfd) >= 0);
assert_se(pidref.pid == getpid_cached());
assert_se(pidref_is_self(&pidref));
}
const gid_t *gl = NULL;

View File

@ -22,6 +22,7 @@
#include "iovec-util.h"
#include "journal-send.h"
#include "memfd-util.h"
#include "missing_mman.h"
#include "missing_syscall.h"
#include "process-util.h"
#include "socket-util.h"
@ -233,7 +234,6 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
};
ssize_t k;
bool have_syslog_identifier = false;
bool seal = true;
assert_return(iov, -EINVAL);
assert_return(n > 0, -EINVAL);
@ -312,35 +312,19 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
if (!IN_SET(errno, EMSGSIZE, ENOBUFS, EAGAIN))
return -errno;
/* Message doesn't fit... Let's dump the data in a memfd or
* temporary file and just pass a file descriptor of it to the
* other side.
*
* For the temporary files we use /dev/shm instead of /tmp
* here, since we want this to be a tmpfs, and one that is
* available from early boot on and where unprivileged users
* can create files. */
buffer_fd = memfd_new(NULL);
if (buffer_fd < 0) {
if (buffer_fd == -ENOSYS) {
buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
if (buffer_fd < 0)
return buffer_fd;
seal = false;
} else
return buffer_fd;
}
/* Message doesn't fit... Let's dump the data in a memfd or temporary file and just pass a file
* descriptor of it to the other side. */
buffer_fd = memfd_new_full("journal-data", MFD_ALLOW_SEALING);
if (buffer_fd < 0)
return buffer_fd;
n = writev(buffer_fd, w, j);
if (n < 0)
return -errno;
if (seal) {
r = memfd_set_sealed(buffer_fd);
if (r < 0)
return r;
}
r = memfd_set_sealed(buffer_fd);
if (r < 0)
return r;
r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0);
if (r == -ENOENT)

View File

@ -879,7 +879,7 @@ static int create_session(
if (r < 0)
return r;
if (leader.pid == 1 || leader.pid == getpid_cached())
if (leader.pid == 1 || pidref_is_self(&leader))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (isempty(type))

View File

@ -390,116 +390,107 @@ static int export_legacy_dbus_address(
}
static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
assert(handle);
assert(m);
if (isempty(limit))
return PAM_SUCCESS;
return 0;
if (streq(limit, "infinity")) {
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", UINT64_MAX);
if (r < 0)
return pam_bus_log_create_error(handle, r);
return PAM_SUCCESS;
}
if (streq(limit, "infinity"))
return sd_bus_message_append(m, "(sv)", "MemoryMax", "t", UINT64_MAX);
r = parse_permyriad(limit);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return pam_bus_log_create_error(handle, r);
return PAM_SUCCESS;
}
if (r >= 0)
return sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r));
uint64_t val;
r = parse_size(limit, 1024, &val);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit);
return PAM_SUCCESS;
}
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.memory_max, ignoring: %s", limit);
return PAM_SUCCESS;
return sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
}
static int append_session_runtime_max_sec(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
usec_t val;
int r;
assert(handle);
assert(m);
/* No need to parse "infinity" here, it will be set by default later in scope_init() */
if (isempty(limit) || streq(limit, "infinity"))
return PAM_SUCCESS;
return 0;
usec_t val;
r = parse_sec(limit, &val);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "RuntimeMaxUSec", "t", (uint64_t) val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} else
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.runtime_max_sec: %s, ignoring.", limit);
return 0;
}
return PAM_SUCCESS;
return sd_bus_message_append(m, "(sv)", "RuntimeMaxUSec", "t", (uint64_t) val);
}
static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
assert(handle);
assert(m);
/* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */
if (isempty(limit) || streq(limit, "infinity"))
return PAM_SUCCESS;
return 0;
uint64_t val;
r = safe_atou64(limit, &val);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} else
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.tasks_max, ignoring: %s", limit);
return 0;
}
return PAM_SUCCESS;
return sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
}
static int append_session_cpu_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
if (isempty(limit))
return PAM_SUCCESS;
assert(handle);
assert(m);
if (isempty(limit))
return 0;
uint64_t val;
r = cg_cpu_weight_parse(limit, &val);
if (r < 0)
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit);
else {
r = sd_bus_message_append(m, "(sv)", "CPUWeight", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
return 0;
}
return PAM_SUCCESS;
return sd_bus_message_append(m, "(sv)", "CPUWeight", "t", val);
}
static int append_session_io_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
uint64_t val;
int r;
if (isempty(limit))
return PAM_SUCCESS;
assert(handle);
assert(m);
if (isempty(limit))
return 0;
uint64_t val;
r = cg_weight_parse(limit, &val);
if (r < 0)
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit);
else {
r = sd_bus_message_append(m, "(sv)", "IOWeight", "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
return 0;
}
return PAM_SUCCESS;
return sd_bus_message_append(m, "(sv)", "IOWeight", "t", val);
}
static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) {
@ -542,13 +533,33 @@ static bool getenv_harder_bool(pam_handle_t *handle, const char *key, bool fallb
r = parse_boolean(v);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Boolean environment variable value of '%s' is not valid: %s", key, v);
pam_syslog(handle, LOG_WARNING, "Failed to parse environment variable value '%s' of '%s', falling back to using '%s'.", v, key, true_false(fallback));
return fallback;
}
return r;
}
static uint32_t getenv_harder_uint32(pam_handle_t *handle, const char *key, uint32_t fallback) {
int r;
assert(handle);
assert(key);
const char *v = getenv_harder(handle, key, NULL);
if (isempty(v))
return fallback;
uint32_t u;
r = safe_atou32(v, &u);
if (r < 0) {
pam_syslog(handle, LOG_WARNING, "Failed to parse environment variable value '%s' of '%s' as unsigned integer, falling back to using %" PRIu32 ".", v, key, fallback);
return fallback;
}
return u;
}
static int update_environment(pam_handle_t *handle, const char *key, const char *value) {
int r;
@ -826,17 +837,15 @@ static uint64_t pick_default_capability_ambient_set(
}
typedef struct SessionContext {
const uid_t uid;
const pid_t pid;
const char *service;
const char *type;
const char *class;
const char *desktop;
const char *seat;
const uint32_t vtnr;
uint32_t vtnr;
const char *tty;
const char *display;
const bool remote;
bool remote;
const char *remote_user;
const char *remote_host;
const char *memory_max;
@ -844,11 +853,13 @@ typedef struct SessionContext {
const char *cpu_weight;
const char *io_weight;
const char *runtime_max_sec;
bool incomplete;
} SessionContext;
static int create_session_message(
sd_bus *bus,
pam_handle_t *handle,
UserRecord *ur,
const SessionContext *context,
bool avoid_pidfd,
sd_bus_message **ret) {
@ -859,6 +870,7 @@ static int create_session_message(
assert(bus);
assert(handle);
assert(ur);
assert(context);
assert(ret);
@ -872,21 +884,22 @@ static int create_session_message(
if (r < 0)
return r;
r = sd_bus_message_append(m,
pidfd >= 0 ? "uhsssssussbss" : "uusssssussbss",
(uint32_t) context->uid,
pidfd >= 0 ? pidfd : context->pid,
context->service,
context->type,
context->class,
context->desktop,
context->seat,
context->vtnr,
context->tty,
context->display,
context->remote,
context->remote_user,
context->remote_host);
r = sd_bus_message_append(
m,
pidfd >= 0 ? "uhsssssussbss" : "uusssssussbss",
(uint32_t) ur->uid,
pidfd >= 0 ? pidfd : 0,
context->service,
context->type,
context->class,
context->desktop,
context->seat,
context->vtnr,
context->tty,
context->display,
context->remote,
context->remote_user,
context->remote_host);
if (r < 0)
return r;
@ -901,23 +914,23 @@ static int create_session_message(
return r;
r = append_session_memory_max(handle, m, context->memory_max);
if (r != PAM_SUCCESS)
if (r < 0)
return r;
r = append_session_runtime_max_sec(handle, m, context->runtime_max_sec);
if (r != PAM_SUCCESS)
if (r < 0)
return r;
r = append_session_tasks_max(handle, m, context->tasks_max);
if (r != PAM_SUCCESS)
if (r < 0)
return r;
r = append_session_cpu_weight(handle, m, context->cpu_weight);
if (r != PAM_SUCCESS)
if (r < 0)
return r;
r = append_session_io_weight(handle, m, context->io_weight);
if (r != PAM_SUCCESS)
if (r < 0)
return r;
r = sd_bus_message_close_container(m);
@ -928,10 +941,93 @@ static int create_session_message(
return 0;
}
_public_ PAM_EXTERN int pam_sm_open_session(
static void session_context_mangle(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
SessionContext *c,
UserRecord *ur,
bool debug) {
assert(handle);
assert(c);
assert(ur);
if (streq_ptr(c->service, "systemd-user")) {
/* If we detect that we are running in the "systemd-user" PAM stack, then let's patch the class to
* 'manager' if not set, simply for robustness reasons. */
c->type = "unspecified";
c->class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
"manager-early" : "manager";
c->tty = NULL;
} else if (c->tty && strchr(c->tty, ':')) {
/* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
* and don't pretend that an X display was a tty. */
if (isempty(c->display))
c->display = c->tty;
c->tty = NULL;
} else if (streq_ptr(c->tty, "cron")) {
/* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
* probably because it wants to set it to something as pam_time/pam_access/ require PAM_TTY to be set
* (as they otherwise even try to update it!) but cron doesn't actually allocate a TTY for its forked
* off processes.) */
c->type = "unspecified";
c->class = "background";
c->tty = NULL;
} else if (streq_ptr(c->tty, "ssh")) {
/* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
* details look for "PAM_TTY_KLUDGE" in the openssh sources). */
c->type = "tty";
c->class = "user";
c->tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though
* usually associated with a pty won't be tracked by their tty in
* logind. This is because ssh does the PAM session registration early for new
* connections, and registers a pty only much later (this is because it doesn't
* know yet if it needs one at all, as whether to register a pty or not is
* negotiated much later in the protocol). */
} else if (c->tty)
/* Chop off leading /dev prefix that some clients specify, but others do not. */
c->tty = skip_dev_prefix(c->tty);
if (!isempty(c->display) && !c->vtnr) {
if (isempty(c->seat))
(void) get_seat_from_display(c->display, &c->seat, &c->vtnr);
else if (streq(c->seat, "seat0"))
(void) get_seat_from_display(c->display, /* seat= */ NULL, &c->vtnr);
}
if (c->seat && !streq(c->seat, "seat0") && c->vtnr != 0) {
pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", c->vtnr, c->seat);
c->vtnr = 0;
}
if (isempty(c->type))
c->type = !isempty(c->display) ? "x11" :
!isempty(c->tty) ? "tty" : "unspecified";
if (isempty(c->class))
c->class = streq(c->type, "unspecified") ? "background" :
((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
streq(c->type, "tty")) ? "user-early" : "user");
if (c->incomplete) {
if (streq(c->class, "user"))
c->class = "user-incomplete";
else
pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", c->class);
}
c->remote = !isempty(c->remote_host) && !is_localhost(c->remote_host);
}
static int register_session(
pam_handle_t *handle,
SessionContext *c,
UserRecord *ur,
bool debug,
char **ret_seat) {
/* Let's release the D-Bus connection once this function exits, after all the session might live
* quite a long time, and we are not going to process the bus connection in that time, so let's
@ -939,152 +1035,17 @@ _public_ PAM_EXTERN int pam_sm_open_session(
_cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
const char
*id, *object_path, *runtime_path,
*service = NULL,
*tty = NULL, *display = NULL,
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
*class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL, *desktop_pam = NULL,
*memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL, *runtime_max_sec = NULL;
uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
int session_fd = -EBADF, existing, r;
bool debug = false, remote, incomplete;
uint32_t vtnr = 0;
uid_t original_uid;
int r;
assert(handle);
pam_log_setup();
if (parse_argv(handle,
argc, argv,
&class_pam,
&type_pam,
&desktop_pam,
&debug,
&default_capability_bounding_set,
&default_capability_ambient_set) < 0)
return PAM_SESSION_ERR;
pam_debug_syslog(handle, debug, "pam-systemd initializing");
r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS)
return r;
assert(c);
assert(ur);
assert(ret_seat);
/* Make most of this a NOP on non-logind systems */
if (!logind_running())
goto success;
r = pam_get_item_many(
handle,
PAM_SERVICE, &service,
PAM_XDISPLAY, &display,
PAM_TTY, &tty,
PAM_RUSER, &remote_user,
PAM_RHOST, &remote_host);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
seat = getenv_harder(handle, "XDG_SEAT", NULL);
cvtnr = getenv_harder(handle, "XDG_VTNR", NULL);
type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
if (streq_ptr(service, "systemd-user")) {
/* If we detect that we are running in the "systemd-user" PAM stack, then let's patch the class to
* 'manager' if not set, simply for robustness reasons. */
type = "unspecified";
class = IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) ?
"manager-early" : "manager";
tty = NULL;
} else if (tty && strchr(tty, ':')) {
/* A tty with a colon is usually an X11 display, placed there to show up in utmp. We rearrange things
* and don't pretend that an X display was a tty. */
if (isempty(display))
display = tty;
tty = NULL;
} else if (streq_ptr(tty, "cron")) {
/* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but
* probably because it wants to set it to something as pam_time/pam_access/ require PAM_TTY to be set
* (as they otherwise even try to update it!) but cron doesn't actually allocate a TTY for its forked
* off processes.) */
type = "unspecified";
class = "background";
tty = NULL;
} else if (streq_ptr(tty, "ssh")) {
/* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further
* details look for "PAM_TTY_KLUDGE" in the openssh sources). */
type = "tty";
class = "user";
tty = NULL; /* This one is particularly sad, as this means that ssh sessions — even though usually
* associated with a pty won't be tracked by their tty in logind. This is because ssh
* does the PAM session registration early for new connections, and registers a pty only
* much later (this is because it doesn't know yet if it needs one at all, as whether to
* register a pty or not is negotiated much later in the protocol). */
} else if (tty)
/* Chop off leading /dev prefix that some clients specify, but others do not. */
tty = skip_dev_prefix(tty);
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
(void) safe_atou32(cvtnr, &vtnr);
if (!isempty(display) && !vtnr) {
if (isempty(seat))
(void) get_seat_from_display(display, &seat, &vtnr);
else if (streq(seat, "seat0"))
(void) get_seat_from_display(display, NULL, &vtnr);
}
if (seat && !streq(seat, "seat0") && vtnr != 0) {
pam_debug_syslog(handle, debug, "Ignoring vtnr %"PRIu32" for %s which is not seat0", vtnr, seat);
vtnr = 0;
}
if (isempty(type))
type = !isempty(display) ? "x11" :
!isempty(tty) ? "tty" : "unspecified";
if (isempty(class))
class = streq(type, "unspecified") ? "background" :
((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
streq(type, "tty")) ? "user-early" : "user");
if (incomplete) {
if (streq(class, "user"))
class = "user-incomplete";
else
pam_syslog_pam_error(handle, LOG_WARNING, 0, "PAM session of class '%s' is incomplete, which is not supported, ignoring.", class);
}
remote = !isempty(remote_host) && !is_localhost(remote_host);
r = pam_get_data(handle, "systemd.memory_max", (const void **)&memory_max);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.memory_max data: @PAMERR@");
r = pam_get_data(handle, "systemd.tasks_max", (const void **)&tasks_max);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.tasks_max data: @PAMERR@");
r = pam_get_data(handle, "systemd.cpu_weight", (const void **)&cpu_weight);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.cpu_weight data: @PAMERR@");
r = pam_get_data(handle, "systemd.io_weight", (const void **)&io_weight);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.io_weight data: @PAMERR@");
r = pam_get_data(handle, "systemd.runtime_max_sec", (const void **)&runtime_max_sec);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM systemd.runtime_max_sec data: @PAMERR@");
goto skip;
/* Talk to logind over the message bus */
r = pam_acquire_bus_connection(handle, "pam-systemd", debug, &bus, &d);
@ -1095,41 +1056,22 @@ _public_ PAM_EXTERN int pam_sm_open_session(
"Asking logind to create session: "
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
ur->uid, getpid_cached(),
strempty(service),
type, class, strempty(desktop),
strempty(seat), vtnr, strempty(tty), strempty(display),
yes_no(remote), strempty(remote_user), strempty(remote_host));
strempty(c->service),
c->type, c->class, strempty(c->desktop),
strempty(c->seat), c->vtnr, strempty(c->tty), strempty(c->display),
yes_no(c->remote), strempty(c->remote_user), strempty(c->remote_host));
pam_debug_syslog(handle, debug,
"Session limits: "
"memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s runtime_max_sec=%s",
strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight), strna(runtime_max_sec));
strna(c->memory_max), strna(c->tasks_max), strna(c->cpu_weight), strna(c->io_weight), strna(c->runtime_max_sec));
const SessionContext context = {
.uid = ur->uid,
.pid = 0,
.service = service,
.type = type,
.class = class,
.desktop = desktop,
.seat = seat,
.vtnr = vtnr,
.tty = tty,
.display = display,
.remote = remote,
.remote_user = remote_user,
.remote_host = remote_host,
.memory_max = memory_max,
.tasks_max = tasks_max,
.cpu_weight = cpu_weight,
.io_weight = io_weight,
.runtime_max_sec = runtime_max_sec,
};
r = create_session_message(bus,
handle,
&context,
/* avoid_pidfd = */ false,
&m);
r = create_session_message(
bus,
handle,
ur,
c,
/* avoid_pidfd = */ false,
&m);
if (r < 0)
return pam_bus_log_create_error(handle, r);
@ -1142,7 +1084,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
m = sd_bus_message_unref(m);
r = create_session_message(bus,
handle,
&context,
ur,
c,
/* avoid_pidfd = */ true,
&m);
if (r < 0)
@ -1155,7 +1098,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
/* We are already in a session, don't do anything */
pam_debug_syslog(handle, debug,
"Not creating session: %s", bus_error_message(&error, r));
goto success;
goto skip;
}
pam_syslog(handle, LOG_ERR,
@ -1163,23 +1106,27 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return PAM_SESSION_ERR;
}
r = sd_bus_message_read(reply,
"soshusub",
&id,
&object_path,
&runtime_path,
&session_fd,
&original_uid,
&seat,
&vtnr,
&existing);
const char *id, *object_path, *runtime_path, *real_seat;
int session_fd = -EBADF, existing;
uint32_t original_uid, real_vtnr;
r = sd_bus_message_read(
reply,
"soshusub",
&id,
&object_path,
&runtime_path,
&session_fd,
&original_uid,
&real_seat,
&real_vtnr,
&existing);
if (r < 0)
return pam_bus_log_parse_error(handle, r);
pam_debug_syslog(handle, debug,
"Reply from logind: "
"id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u",
id, object_path, runtime_path, session_fd, seat, vtnr, original_uid);
id, object_path, runtime_path, session_fd, real_seat, real_vtnr, original_uid);
/* Please update manager_default_environment() in core/manager.c accordingly if more session envvars
* shall be added. */
@ -1202,38 +1149,25 @@ _public_ PAM_EXTERN int pam_sm_open_session(
* somewhere else (for example PAM module parameters). Let's now update the environment variables, so that this
* data is inherited into the session processes, and programs can rely on them to be initialized. */
r = update_environment(handle, "XDG_SESSION_TYPE", type);
r = update_environment(handle, "XDG_SESSION_TYPE", c->type);
if (r != PAM_SUCCESS)
return r;
r = update_environment(handle, "XDG_SESSION_CLASS", class);
r = update_environment(handle, "XDG_SESSION_CLASS", c->class);
if (r != PAM_SUCCESS)
return r;
r = update_environment(handle, "XDG_SESSION_DESKTOP", desktop);
r = update_environment(handle, "XDG_SESSION_DESKTOP", c->desktop);
if (r != PAM_SUCCESS)
return r;
r = update_environment(handle, "XDG_SEAT", seat);
r = update_environment(handle, "XDG_SEAT", real_seat);
if (r != PAM_SUCCESS)
return r;
static const char *const propagate[] = {
"shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
"shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
"shell.welcome", "SHELL_WELCOME",
NULL
};
STRV_FOREACH_PAIR(k, v, propagate) {
r = propagate_credential_to_environment(handle, *k, *v);
if (r != PAM_SUCCESS)
return r;
}
if (vtnr > 0) {
char buf[DECIMAL_STR_MAX(vtnr)];
sprintf(buf, "%u", vtnr);
if (real_vtnr > 0) {
char buf[DECIMAL_STR_MAX(real_vtnr)];
xsprintf(buf, "%u", real_vtnr);
r = update_environment(handle, "XDG_VTNR", buf);
if (r != PAM_SUCCESS)
@ -1255,9 +1189,115 @@ _public_ PAM_EXTERN int pam_sm_open_session(
TAKE_FD(fd);
}
success:
/* Everything worked, hence let's patch in the data we learned. Since 'real_set' points into the
* D-Bus message, let's copy it and return it as a buffer */
char *rs = strdup(real_seat);
if (!rs)
return pam_log_oom(handle);
c->seat = *ret_seat = rs;
c->vtnr = real_vtnr;
return PAM_SUCCESS;
skip:
*ret_seat = NULL;
return PAM_SUCCESS;
}
static int import_shell_credentials(pam_handle_t *handle) {
static const char *const propagate[] = {
"shell.prompt.prefix", "SHELL_PROMPT_PREFIX",
"shell.prompt.suffix", "SHELL_PROMPT_SUFFIX",
"shell.welcome", "SHELL_WELCOME",
NULL
};
int r;
assert(handle);
STRV_FOREACH_PAIR(k, v, propagate) {
r = propagate_credential_to_environment(handle, *k, *v);
if (r != PAM_SUCCESS)
return r;
}
return PAM_SUCCESS;
}
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
int r;
assert(handle);
pam_log_setup();
uint64_t default_capability_bounding_set = UINT64_MAX, default_capability_ambient_set = UINT64_MAX;
const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL;
bool debug = false;
if (parse_argv(handle,
argc, argv,
&class_pam,
&type_pam,
&desktop_pam,
&debug,
&default_capability_bounding_set,
&default_capability_ambient_set) < 0)
return PAM_SESSION_ERR;
pam_debug_syslog(handle, debug, "pam-systemd initializing");
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
r = acquire_user_record(handle, &ur);
if (r != PAM_SUCCESS)
return r;
SessionContext c = {};
r = pam_get_item_many(
handle,
PAM_SERVICE, &c.service,
PAM_XDISPLAY, &c.display,
PAM_TTY, &c.tty,
PAM_RUSER, &c.remote_user,
PAM_RHOST, &c.remote_host);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM items: @PAMERR@");
c.seat = getenv_harder(handle, "XDG_SEAT", NULL);
c.vtnr = getenv_harder_uint32(handle, "XDG_VTNR", 0);
c.type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam);
c.class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam);
c.desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", desktop_pam);
c.incomplete = getenv_harder_bool(handle, "XDG_SESSION_INCOMPLETE", false);
r = pam_get_data_many(
handle,
"systemd.memory_max", &c.memory_max,
"systemd.tasks_max", &c.tasks_max,
"systemd.cpu_weight", &c.cpu_weight,
"systemd.io_weight", &c.io_weight,
"systemd.runtime_max_sec", &c.runtime_max_sec);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get PAM data: @PAMERR@");
session_context_mangle(handle, &c, ur, debug);
_cleanup_free_ char *seat_buffer = NULL;
r = register_session(handle, &c, ur, debug, &seat_buffer);
if (r != PAM_SUCCESS)
return r;
r = import_shell_credentials(handle);
if (r != PAM_SUCCESS)
return r;
if (default_capability_ambient_set == UINT64_MAX)
default_capability_ambient_set = pick_default_capability_ambient_set(ur, service, seat);
default_capability_ambient_set = pick_default_capability_ambient_set(ur, c.service, c.seat);
return apply_user_record_settings(handle, ur, debug, default_capability_bounding_set, default_capability_ambient_set);
}

View File

@ -178,7 +178,7 @@ int bus_image_method_clone(
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
r = image_clone(image, new_name, read_only);
r = image_clone(image, new_name, read_only, m->runtime_scope);
report_errno_and_exit(errno_pipe_fd[1], r);
}
@ -402,6 +402,7 @@ char* image_bus_path(const char *name) {
static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_hashmap_free_ Hashmap *images = NULL;
_cleanup_strv_free_ char **l = NULL;
Manager *m = ASSERT_PTR(userdata);
Image *image;
int r;
@ -413,7 +414,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata,
if (!images)
return -ENOMEM;
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
if (r < 0)
return r;

View File

@ -148,7 +148,7 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl
return log_debug_errno(r, "Failed to fork: %m");
if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
r = image_clone(image, p.new_name, p.read_only > 0);
r = image_clone(image, p.new_name, p.read_only > 0, manager->runtime_scope);
report_errno_and_exit(errno_pipe_fd[1], r);
}

View File

@ -1188,35 +1188,29 @@ static int bind_mount(int argc, char *argv[], void *userdata) {
}
static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
PTYForward ** forward = (PTYForward**) userdata;
PTYForward *forward = ASSERT_PTR(userdata);
int r;
assert(m);
assert(forward);
if (*forward) {
/* If the forwarder is already initialized, tell it to
* exit on the next vhangup(), so that we still flush
* out what might be queued and exit then. */
r = pty_forward_set_ignore_vhangup(*forward, false);
if (r >= 0)
return 0;
/* Tell the forwarder to exit on the next vhangup(), so that we still flush out what might be queued
* and exit then. */
r = pty_forward_set_ignore_vhangup(forward, false);
if (r < 0) {
/* On error, quit immediately. */
log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
(void) sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
}
/* On error, or when the forwarder is not initialized yet, quit immediately */
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
return 0;
}
static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
char last_char = 0;
bool machine_died;
static int process_forward(sd_event *event, sd_bus_slot *machine_removed_slot, int master, PTYForwardFlags flags, const char *name) {
int r;
assert(event);
assert(machine_removed_slot);
assert(master >= 0);
assert(name);
@ -1231,24 +1225,21 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT
if (r < 0)
return log_error_errno(r, "Failed to enable SIGINT/SITERM handling: %m");
r = pty_forward_new(event, master, flags, forward);
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
r = pty_forward_new(event, master, flags, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
/* No userdata should not set previously. */
assert_se(!sd_bus_slot_set_userdata(machine_removed_slot, forward));
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
pty_forward_get_last_char(*forward, &last_char);
machine_died =
bool machine_died =
(flags & PTY_FORWARD_IGNORE_VHANGUP) &&
pty_forward_get_ignore_vhangup(*forward) == 0;
*forward = pty_forward_free(*forward);
if (last_char != '\n')
fputc('\n', stdout);
pty_forward_get_ignore_vhangup(forward) == 0;
if (!arg_quiet) {
if (machine_died)
@ -1300,7 +1291,6 @@ static int parse_machine_uid(const char *spec, const char **machine, char **uid)
static int login_machine(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int master = -1, r;
@ -1334,7 +1324,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved',"
"arg0='", machine, "'");
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m");
@ -1346,13 +1336,12 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
return process_forward(event, slot, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
}
static int shell_machine(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int master = -1, r;
@ -1396,7 +1385,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
"member='MachineRemoved',"
"arg0='", machine, "'");
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, &forward);
r = sd_bus_add_match_async(bus, &slot, match, on_machine_removed, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request machine removal match: %m");
@ -1426,7 +1415,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
return process_forward(event, &forward, master, 0, machine);
return process_forward(event, slot, master, /* flags = */ 0, machine);
}
static int normalize_nspawn_filename(const char *name, char **ret_file) {

View File

@ -440,7 +440,7 @@ int manager_acquire_image(Manager *m, const char *name, Image **ret) {
return log_debug_errno(r, "Failed to enable source: %m") ;
_cleanup_(image_unrefp) Image *image = NULL;
r = image_find(IMAGE_MACHINE, name, NULL, &image);
r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, &image);
if (r < 0)
return log_debug_errno(r, "Failed to find image: %m");
@ -467,7 +467,7 @@ int rename_image_and_update_cache(Manager *m, Image *image, const char* new_name
/* The image is cached with its name, hence it is necessary to remove from the cache before renaming. */
assert_se(hashmap_remove_value(m->image_cache, image->name, image));
r = image_rename(image, new_name);
r = image_rename(image, new_name, m->runtime_scope);
if (r < 0) {
image = image_unref(image);
return r;

View File

@ -123,7 +123,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, name, NULL, NULL);
r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, NULL);
if (r == -ENOENT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
if (r < 0)
@ -476,7 +476,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
if (!images)
return -ENOMEM;
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
if (r < 0)
return r;
@ -753,7 +753,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
goto child_fail;
}
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images);
if (r < 0)
goto child_fail;

View File

@ -641,6 +641,7 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image
}
static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
struct params {
const char *image_name;
AcquireMetadata acquire_metadata;
@ -667,7 +668,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
if (!image_name_is_valid(p.image_name))
return sd_varlink_error_invalid_parameter_name(link, "name");
r = image_find(IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found);
r = image_find(m->runtime_scope, IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found);
if (r == -ENOENT)
return sd_varlink_error(link, "io.systemd.MachineImage.NoSuchImage", NULL);
if (r < 0)
@ -683,7 +684,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters,
if (!images)
return -ENOMEM;
r = image_discover(IMAGE_MACHINE, /* root = */ NULL, images);
r = image_discover(m->runtime_scope, IMAGE_MACHINE, /* root = */ NULL, images);
if (r < 0)
return log_debug_errno(r, "Failed to discover images: %m");

View File

@ -40,10 +40,14 @@ static int manager_new(Manager **ret) {
assert(ret);
m = new0(Manager, 1);
m = new(Manager, 1);
if (!m)
return -ENOMEM;
*m = (Manager) {
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
};
m->machines = hashmap_new(&machine_hash_ops);
if (!m->machines)
return -ENOMEM;

View File

@ -42,6 +42,8 @@ struct Manager {
sd_varlink_server *varlink_userdb_server;
sd_varlink_server *varlink_machine_server;
RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */
};
int manager_add_machine(Manager *m, const char *name, Machine **ret);

View File

@ -252,7 +252,7 @@ static void link_free_engines(Link *link) {
static Link *link_free(Link *link) {
assert(link);
(void) sysctl_clear_link_shadows(link);
(void) link_clear_sysctl_shadows(link);
link_ntp_settings_clear(link);
link_dns_settings_clear(link);

View File

@ -666,7 +666,7 @@ Manager* manager_free(Manager *m) {
if (!m)
return NULL;
sysctl_remove_monitor(m);
manager_remove_sysctl_monitor(m);
free(m->state_file);
@ -742,7 +742,7 @@ int manager_start(Manager *m) {
log_debug("Starting...");
(void) sysctl_add_monitor(m);
(void) manager_install_sysctl_monitor(m);
/* Loading BPF programs requires CAP_SYS_ADMIN and CAP_BPF.
* Drop the capabilities here, regardless if the load succeeds or not. */

View File

@ -2,11 +2,11 @@
#include "af-list.h"
#include "daemon-util.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "iovec-util.h"
#include "json-util.h"
#include "memfd-util.h"
#include "networkd-address.h"
#include "networkd-json.h"
#include "networkd-link.h"
@ -69,7 +69,7 @@ int manager_serialize(Manager *manager) {
return r;
_cleanup_close_ int fd = -EBADF;
fd = acquire_data_fd(dump);
fd = memfd_new_and_seal_string("serialization", dump);
if (fd < 0)
return fd;

View File

@ -47,7 +47,7 @@ static int sysctl_event_handler(void *ctx, void *data, size_t data_sz) {
* so do it only in case of a fatal error like a version mismatch. */
if (we->version != 1)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"Unexpected sysctl event, disabling sysctl monitoring: %d", we->version);
"Unexpected sysctl event, disabling sysctl monitoring: %d", we->version);
if (we->errorcode != 0) {
log_warning_errno(we->errorcode, "Sysctl monitor BPF returned error: %m");
@ -56,7 +56,7 @@ static int sysctl_event_handler(void *ctx, void *data, size_t data_sz) {
path = path_join("/proc/sys", we->path);
if (!path) {
log_oom();
log_oom_warning();
return 0;
}
@ -91,7 +91,7 @@ static int on_ringbuf_io(sd_event_source *s, int fd, uint32_t revents, void *use
return 0;
}
int sysctl_add_monitor(Manager *manager) {
int manager_install_sysctl_monitor(Manager *manager) {
_cleanup_(sysctl_monitor_bpf_freep) struct sysctl_monitor_bpf *obj = NULL;
_cleanup_(bpf_link_freep) struct bpf_link *sysctl_link = NULL;
_cleanup_(bpf_ring_buffer_freep) struct ring_buffer *sysctl_buffer = NULL;
@ -102,10 +102,10 @@ int sysctl_add_monitor(Manager *manager) {
assert(manager);
r = dlopen_bpf();
if (r < 0) {
log_info_errno(r, "sysctl monitor disabled, as BPF support is not available.");
return 0;
}
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
return log_debug_errno(r, "sysctl monitor disabled, as BPF support is not available.");
if (r < 0)
return log_warning_errno(r, "Failed to load libbpf, not installing sysctl monitor: %m");
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0)
@ -113,13 +113,12 @@ int sysctl_add_monitor(Manager *manager) {
root_cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, "/");
if (root_cgroup_fd < 0)
return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m.");
return log_warning_errno(root_cgroup_fd, "Failed to open cgroup, ignoring: %m");
obj = sysctl_monitor_bpf__open_and_load();
if (!obj) {
log_info_errno(errno, "Unable to load sysctl monitor BPF program, ignoring: %m.");
return 0;
}
if (!obj)
return log_full_errno(errno == EINVAL ? LOG_DEBUG : LOG_INFO, errno,
"Unable to load sysctl monitor BPF program, ignoring: %m");
cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, cgroup);
if (cgroup_fd < 0)
@ -130,10 +129,8 @@ int sysctl_add_monitor(Manager *manager) {
sysctl_link = sym_bpf_program__attach_cgroup(obj->progs.sysctl_monitor, root_cgroup_fd);
r = bpf_get_error_translated(sysctl_link);
if (r < 0) {
log_info_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m.");
return 0;
}
if (r < 0)
return log_warning_errno(r, "Unable to attach sysctl monitor BPF program to cgroup, ignoring: %m");
fd = sym_bpf_map__fd(obj->maps.written_sysctls);
if (fd < 0)
@ -160,7 +157,7 @@ int sysctl_add_monitor(Manager *manager) {
return 0;
}
void sysctl_remove_monitor(Manager *manager) {
void manager_remove_sysctl_monitor(Manager *manager) {
assert(manager);
manager->sysctl_event_source = sd_event_source_disable_unref(manager->sysctl_event_source);
@ -171,7 +168,7 @@ void sysctl_remove_monitor(Manager *manager) {
manager->sysctl_shadow = hashmap_free(manager->sysctl_shadow);
}
int sysctl_clear_link_shadows(Link *link) {
int link_clear_sysctl_shadows(Link *link) {
_cleanup_free_ char *ipv4 = NULL, *ipv6 = NULL;
char *key = NULL, *value = NULL;
@ -188,7 +185,7 @@ int sysctl_clear_link_shadows(Link *link) {
HASHMAP_FOREACH_KEY(value, key, link->manager->sysctl_shadow)
if (path_startswith(key, ipv4) || path_startswith(key, ipv6)) {
assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value) == value);
assert_se(hashmap_remove_value(link->manager->sysctl_shadow, key, value));
free(key);
free(value);
}

View File

@ -28,13 +28,13 @@ typedef enum IPReversePathFilter {
} IPReversePathFilter;
#if HAVE_VMLINUX_H
int sysctl_add_monitor(Manager *manager);
void sysctl_remove_monitor(Manager *manager);
int sysctl_clear_link_shadows(Link *link);
int manager_install_sysctl_monitor(Manager *manager);
void manager_remove_sysctl_monitor(Manager *manager);
int link_clear_sysctl_shadows(Link *link);
#else
static inline int sysctl_add_monitor(Manager *manager) { return 0; }
static inline void sysctl_remove_monitor(Manager *manager) { }
static inline int sysctl_clear_link_shadows(Link *link) { return 0; }
static inline int manager_install_sysctl_monitor(Manager *manager) { return 0; }
static inline void manager_remove_sysctl_monitor(Manager *manager) { }
static inline int link_clear_sysctl_shadows(Link *link) { return 0; }
#endif
void manager_set_sysctl(Manager *manager);

View File

@ -475,7 +475,8 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
if (!full)
return log_oom();
(void) mkdir(full, 0755);
if (mkdir(full, 0755) < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create directory '%s': %m", full);
if (FLAGS_SET(mount_settings, MOUNT_APPLY_APIVFS_RO))
extra_flags |= MS_RDONLY;
@ -1405,9 +1406,11 @@ done:
#define NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS "/run/host/proc"
#define NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS "/run/host/sys"
int pin_fully_visible_fs(void) {
int pin_fully_visible_api_fs(void) {
int r;
log_debug("Pinning fully visible API FS");
(void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, 0755);
(void) mkdir_p(NSPAWN_PRIVATE_FULLY_VISIBLE_SYSFS, 0755);
@ -1422,7 +1425,7 @@ int pin_fully_visible_fs(void) {
return 0;
}
static int do_wipe_fully_visible_fs(void) {
static int do_wipe_fully_visible_api_fs(void) {
if (umount2(NSPAWN_PRIVATE_FULLY_VISIBLE_PROCFS, MNT_DETACH) < 0)
return log_error_errno(errno, "Failed to unmount temporary proc: %m");
@ -1438,10 +1441,12 @@ static int do_wipe_fully_visible_fs(void) {
return 0;
}
int wipe_fully_visible_fs(int mntns_fd) {
int wipe_fully_visible_api_fs(int mntns_fd) {
_cleanup_close_ int orig_mntns_fd = -EBADF;
int r, rr;
log_debug("Wiping fully visible API FS");
r = namespace_open(0,
/* ret_pidns_fd = */ NULL,
&orig_mntns_fd,
@ -1459,7 +1464,7 @@ int wipe_fully_visible_fs(int mntns_fd) {
if (r < 0)
return log_error_errno(r, "Failed to enter mount namespace: %m");
rr = do_wipe_fully_visible_fs();
rr = do_wipe_fully_visible_api_fs();
r = namespace_enter(/* pidns_fd = */ -EBADF,
orig_mntns_fd,

View File

@ -73,5 +73,6 @@ int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s
int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
int tmpfs_patch_options(const char *options,uid_t uid_shift, const char *selinux_apifs_context, char **ret);
int pin_fully_visible_fs(void);
int wipe_fully_visible_fs(int mntns_fd);
int pin_fully_visible_api_fs(void);
int wipe_fully_visible_api_fs(int mntns_fd);

View File

@ -42,6 +42,7 @@
#include "copy.h"
#include "cpu-set-util.h"
#include "dev-setup.h"
#include "devnum-util.h"
#include "discover-image.h"
#include "dissect-image.h"
#include "env-util.h"
@ -1250,7 +1251,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_uid_range = UINT32_C(0x10000);
} else if (streq(optarg, "identity")) {
/* identity: User namespaces on, UID range is map the 0…0xFFFF range to
/* identity: User namespaces on, UID range is map of the 0…0xFFFF range to
* itself, i.e. we don't actually map anything, but do take benefit of
* isolation of capability sets. */
arg_userns_mode = USER_NAMESPACE_FIXED;
@ -2323,7 +2324,7 @@ static int copy_devnode_one(const char *dest, const char *node, bool ignore_mkno
return log_error_errno(r, "Failed to create '%s': %m", dn);
_cleanup_free_ char *sl = NULL;
if (asprintf(&sl, "%s/%u:%u", dn, major(st.st_rdev), minor(st.st_rdev)) < 0)
if (asprintf(&sl, "%s/" DEVNUM_FORMAT_STR, dn, DEVNUM_FORMAT_VAL(st.st_rdev)) < 0)
return log_oom();
_cleanup_free_ char *prefixed = path_join(dest, sl);
@ -2847,7 +2848,7 @@ static int reset_audit_loginuid(void) {
if (!arg_privileged)
return 0;
r = read_one_line_file("/proc/self/loginuid", &p);
r = read_virtual_file("/proc/self/loginuid", SIZE_MAX, &p, /* ret_size= */ NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -3166,7 +3167,8 @@ static int determine_names(void) {
if (arg_machine) {
_cleanup_(image_unrefp) Image *i = NULL;
r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i);
r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
IMAGE_MACHINE, arg_machine, NULL, &i);
if (r == -ENOENT)
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
if (r < 0)
@ -3254,6 +3256,7 @@ static int chase_and_update(char **p, unsigned flags) {
}
static int determine_uid_shift(const char *directory) {
assert(directory);
if (arg_userns_mode == USER_NAMESPACE_NO) {
arg_uid_shift = 0;
@ -3932,7 +3935,7 @@ static int outer_child(
_cleanup_(bind_user_context_freep) BindUserContext *bind_user_context = NULL;
_cleanup_strv_free_ char **os_release_pairs = NULL;
_cleanup_close_ int fd = -EBADF, mntns_fd = -EBADF;
_cleanup_close_ int mntns_fd = -EBADF;
bool idmap = false, enable_fuse;
const char *p;
pid_t pid;
@ -4325,6 +4328,7 @@ static int outer_child(
* visible. Hence there we do it the other way round: we first allocate a new set of namespaces
* (and fork for it) for which we then mount sysfs/procfs, and only then switch root. */
_cleanup_close_ int notify_fd = -EBADF;
if (arg_privileged) {
/* Mark everything as shared so our mounts get propagated down. This is required to make new
* bind mounts available in systemd services inside the container that create a new mount
@ -4355,16 +4359,16 @@ static int outer_child(
* Note, the inner child wouldn't be able to unmount the instances on its own since
* it doesn't own the originating mount namespace. IOW, the outer child needs to do
* this. */
r = pin_fully_visible_fs();
r = pin_fully_visible_api_fs();
if (r < 0)
return r;
}
fd = setup_notify_child(NULL);
notify_fd = setup_notify_child(NULL);
} else
fd = setup_notify_child(directory);
if (fd < 0)
return fd;
notify_fd = setup_notify_child(directory);
if (notify_fd < 0)
return notify_fd;
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
arg_clone_ns_flags |
@ -4429,7 +4433,7 @@ static int outer_child(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Short write while sending machine ID.");
l = send_one_fd(fd_outer_socket, fd, 0);
l = send_one_fd(fd_outer_socket, notify_fd, 0);
if (l < 0)
return log_error_errno(l, "Failed to send notify fd: %m");
@ -5623,7 +5627,7 @@ static int run_container(
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early.");
if (arg_userns_mode != USER_NAMESPACE_NO) {
r = wipe_fully_visible_fs(mntns_fd);
r = wipe_fully_visible_api_fs(mntns_fd);
if (r < 0)
return r;
mntns_fd = safe_close(mntns_fd);
@ -5740,16 +5744,6 @@ static int run_container(
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (forward) {
char last_char = 0;
(void) pty_forward_get_last_char(forward, &last_char);
forward = pty_forward_free(forward);
if (!arg_quiet && last_char != '\n')
putc('\n', stdout);
}
/* Kill if it is not dead yet anyway */
if (!arg_register && !arg_keep_unit && bus)
terminate_scope(bus, arg_machine);

View File

@ -4,8 +4,8 @@
#include "bus-common-errors.h"
#include "bus-polkit.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "memfd-util.h"
#include "oomd-manager-bus.h"
#include "oomd-manager.h"
#include "user-util.h"
@ -22,7 +22,7 @@ static int bus_method_dump_by_fd(sd_bus_message *message, void *userdata, sd_bus
if (r < 0)
return r;
fd = acquire_data_fd(dump);
fd = memfd_new_and_seal_string("oomd-dump", dump);
if (fd < 0)
return fd;

View File

@ -173,6 +173,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char,
PortableMetadata, portable_metadata_unref);
static int extract_now(
RuntimeScope scope,
const char *where,
char **matches,
const char *image_name,
@ -199,6 +200,7 @@ static int extract_now(
* parent. To handle both cases in one call this function also gets a 'socket_fd' parameter, which when >= 0 is
* used to send the data to the parent. */
assert(scope < _RUNTIME_SCOPE_MAX);
assert(where);
/* First, find os-release/extension-release and send it upstream (or just save it). */
@ -248,7 +250,7 @@ static int extract_now(
/* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
* discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as the
* image might have a legacy split-usr layout. */
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
r = lookup_paths_init(&paths, scope, LOOKUP_PATHS_SPLIT_USR, where);
if (r < 0)
return log_debug_errno(r, "Failed to acquire lookup paths: %m");
@ -348,6 +350,7 @@ static int extract_now(
}
static int portable_extract_by_path(
RuntimeScope scope,
const char *path,
bool path_is_extension,
bool relax_extension_release_check,
@ -381,7 +384,7 @@ static int portable_extract_by_path(
if (r < 0)
return log_error_errno(r, "Failed to extract image name from path '%s': %m", path);
r = extract_now(path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files);
r = extract_now(scope, path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files);
if (r < 0)
return r;
@ -458,7 +461,7 @@ static int portable_extract_by_path(
goto child_finish;
}
r = extract_now(tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL);
r = extract_now(scope, tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL);
child_finish:
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
@ -549,6 +552,7 @@ static int portable_extract_by_path(
}
static int extract_image_and_extensions(
RuntimeScope scope,
const char *name_or_path,
char **matches,
char **extension_image_paths,
@ -595,7 +599,7 @@ static int extract_image_and_extensions(
name_or_path = result.path;
}
r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
r = image_find_harder(scope, IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image);
if (r < 0)
return r;
@ -633,7 +637,7 @@ static int extract_image_and_extensions(
path = ext_result.path;
}
r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new);
r = image_find_harder(scope, IMAGE_PORTABLE, path, NULL, &new);
if (r < 0)
return r;
@ -645,6 +649,7 @@ static int extract_image_and_extensions(
}
r = portable_extract_by_path(
scope,
image->path,
/* path_is_extension= */ false,
/* relax_extension_release_check= */ false,
@ -687,6 +692,7 @@ static int extract_image_and_extensions(
const char *e;
r = portable_extract_by_path(
scope,
ext->path,
/* path_is_extension= */ true,
relax_extension_release_check,
@ -754,6 +760,7 @@ static int extract_image_and_extensions(
}
int portable_extract(
RuntimeScope scope,
const char *name_or_path,
char **matches,
char **extension_image_paths,
@ -775,6 +782,7 @@ int portable_extract(
assert(name_or_path);
r = extract_image_and_extensions(
scope,
name_or_path,
matches,
extension_image_paths,
@ -1426,6 +1434,7 @@ static int image_target_path(
}
static int install_image(
RuntimeScope scope,
const char *image_path,
PortableFlags flags,
PortableChange **changes,
@ -1434,13 +1443,14 @@ static int install_image(
_cleanup_free_ char *target = NULL;
int r;
assert(scope < _RUNTIME_SCOPE_MAX);
assert(image_path);
/* If the image is outside of the image search also link it into it, so that it can be found with
* short image names and is listed among the images. If we are operating in mixed mode, the image is
* copied instead. */
if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path))
if (image_in_search_path(scope, IMAGE_PORTABLE, NULL, image_path))
return 0;
r = image_target_path(image_path, flags, &target);
@ -1485,6 +1495,7 @@ static int install_image(
}
static int install_image_and_extensions(
RuntimeScope scope,
const Image *image,
OrderedHashmap *extension_images,
PortableFlags flags,
@ -1497,12 +1508,12 @@ static int install_image_and_extensions(
assert(image);
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
r = install_image(ext->path, flags, changes, n_changes);
r = install_image(scope, ext->path, flags, changes, n_changes);
if (r < 0)
return r;
}
r = install_image(image->path, flags, changes, n_changes);
r = install_image(scope, image->path, flags, changes, n_changes);
if (r < 0)
return r;
@ -1595,6 +1606,7 @@ static void log_portable_verb(
}
int portable_attach(
RuntimeScope scope,
sd_bus *bus,
const char *name_or_path,
char **matches,
@ -1615,7 +1627,10 @@ int portable_attach(
PortableMetadata *item;
int r;
assert(scope < _RUNTIME_SCOPE_MAX);
r = extract_image_and_extensions(
scope,
name_or_path,
matches,
extension_image_paths,
@ -1672,13 +1687,13 @@ int portable_attach(
strempty(extensions_joined));
}
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
if (r < 0)
return r;
if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE_ATTACH))
HASHMAP_FOREACH(item, unit_files) {
r = unit_file_exists(RUNTIME_SCOPE_SYSTEM, &paths, item->name);
r = unit_file_exists(scope, &paths, item->name);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
if (r > 0)
@ -1700,7 +1715,7 @@ int portable_attach(
/* We don't care too much for the image symlink/copy, it's just a convenience thing, it's not necessary for
* proper operation otherwise. */
(void) install_image_and_extensions(image, extension_images, flags, changes, n_changes);
(void) install_image_and_extensions(scope, image, extension_images, flags, changes, n_changes);
log_portable_verb(
"attached",
@ -1844,6 +1859,7 @@ static int test_chroot_dropin(
}
int portable_detach(
RuntimeScope scope,
sd_bus *bus,
const char *name_or_path,
char **extension_image_paths,
@ -1857,12 +1873,12 @@ int portable_detach(
_cleanup_free_ char *extensions = NULL;
_cleanup_closedir_ DIR *d = NULL;
const char *where, *item;
int ret = 0;
int r;
int r, ret = 0;
assert(scope < _RUNTIME_SCOPE_MAX);
assert(name_or_path);
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
if (r < 0)
return r;
@ -1930,7 +1946,7 @@ int portable_detach(
if (r == 0)
break;
if (path_is_absolute(image) && !image_in_search_path(IMAGE_PORTABLE, NULL, image)) {
if (path_is_absolute(image) && !image_in_search_path(scope, IMAGE_PORTABLE, NULL, image)) {
r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(image));
if (r < 0)
return r;
@ -2031,6 +2047,7 @@ not_found:
}
static int portable_get_state_internal(
RuntimeScope scope,
sd_bus *bus,
const char *name_or_path,
char **extension_image_paths,
@ -2045,10 +2062,11 @@ static int portable_get_state_internal(
const char *where;
int r;
assert(scope < _RUNTIME_SCOPE_MAX);
assert(name_or_path);
assert(ret);
r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL);
r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL);
if (r < 0)
return r;
@ -2084,7 +2102,7 @@ static int portable_get_state_internal(
if (r == 0)
continue;
r = unit_file_lookup_state(RUNTIME_SCOPE_SYSTEM, &paths, de->d_name, &state);
r = unit_file_lookup_state(scope, &paths, de->d_name, &state);
if (r < 0)
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME))
@ -2109,6 +2127,7 @@ static int portable_get_state_internal(
}
int portable_get_state(
RuntimeScope scope,
sd_bus *bus,
const char *name_or_path,
char **extension_image_paths,
@ -2125,12 +2144,19 @@ int portable_get_state(
/* We look for matching units twice: once in the regular directories, and once in the runtime directories — but
* the latter only if we didn't find anything in the former. */
r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags & ~PORTABLE_RUNTIME, &state, error);
r = portable_get_state_internal(
scope,
bus,
name_or_path,
extension_image_paths,
flags & ~PORTABLE_RUNTIME,
&state,
error);
if (r < 0)
return r;
if (state == PORTABLE_DETACHED) {
r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error);
r = portable_get_state_internal(scope, bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error);
if (r < 0)
return r;
}

View File

@ -6,6 +6,7 @@
#include "dissect-image.h"
#include "hashmap.h"
#include "macro.h"
#include "runtime-scope.h"
#include "set.h"
#include "string-util.h"
@ -69,12 +70,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(PortableMetadata*, portable_metadata_unref);
int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret);
int portable_extract(const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error);
int portable_extract(RuntimeScope scope, const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error);
int portable_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
int portable_detach(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
int portable_attach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
int portable_detach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
int portable_get_state(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error);
int portable_get_state(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error);
int portable_get_profiles(char ***ret);

View File

@ -165,6 +165,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
return r;
r = portable_get_state(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
NULL,
@ -225,6 +226,7 @@ static int method_get_image_metadata(sd_bus_message *message, void *userdata, sd
static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **extension_images = NULL;
Manager *m = ASSERT_PTR(userdata);
const char *name_or_path;
PortableState state;
int r;
@ -254,6 +256,7 @@ static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bu
}
r = portable_get_state(
m->runtime_scope,
sd_bus_message_get_bus(message),
name_or_path,
extension_images,
@ -330,6 +333,7 @@ static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_e
return 1; /* Will call us back */
r = portable_detach(
m->runtime_scope,
sd_bus_message_get_bus(message),
name_or_path,
extension_images,

View File

@ -114,10 +114,8 @@ int bus_image_common_get_metadata(
assert(name_or_path || image);
assert(message);
if (!m) {
assert(image);
m = image->userdata;
}
if (!m)
m = ASSERT_PTR(ASSERT_PTR(image)->userdata);
bool have_exti = sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions");
@ -160,6 +158,7 @@ int bus_image_common_get_metadata(
return 1;
r = portable_extract(
m->runtime_scope,
image->path,
matches,
extension_images,
@ -264,6 +263,7 @@ static int bus_image_method_get_state(
_cleanup_strv_free_ char **extension_images = NULL;
Image *image = ASSERT_PTR(userdata);
Manager *m = ASSERT_PTR(image->userdata);
PortableState state;
int r;
@ -288,6 +288,7 @@ static int bus_image_method_get_state(
}
r = portable_get_state(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
extension_images,
@ -385,6 +386,7 @@ int bus_image_common_attach(
return 1;
r = portable_attach(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
matches,
@ -463,6 +465,7 @@ static int bus_image_method_detach(
return 1; /* Will call us back */
r = portable_detach(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
extension_images,
@ -513,6 +516,7 @@ int bus_image_common_remove(
return 1; /* Will call us back */
r = portable_get_state(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
NULL,
@ -716,6 +720,7 @@ int bus_image_common_reattach(
return 1;
r = portable_detach(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
extension_images,
@ -727,6 +732,7 @@ int bus_image_common_reattach(
return r;
r = portable_attach(
m->runtime_scope,
sd_bus_message_get_bus(message),
image->path,
matches,
@ -1039,7 +1045,7 @@ int bus_image_acquire(
if (image_name_is_valid(name_or_path)) {
/* If it's a short name, let's search for it */
r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded);
r = image_find(m->runtime_scope, IMAGE_PORTABLE, name_or_path, NULL, &loaded);
if (r == -ENOENT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE,
"No image '%s' found.", name_or_path);

View File

@ -91,7 +91,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro
/* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for
* finding attached images). */
r = image_discover(IMAGE_PORTABLE, NULL, images);
r = image_discover(m->runtime_scope, IMAGE_PORTABLE, NULL, images);
if (r < 0)
return r;

View File

@ -28,10 +28,14 @@ static int manager_new(Manager **ret) {
assert(ret);
m = new0(Manager, 1);
m = new(Manager, 1);
if (!m)
return -ENOMEM;
*m = (Manager) {
.runtime_scope = RUNTIME_SCOPE_SYSTEM,
};
r = sd_event_default(&m->event);
if (r < 0)
return r;

View File

@ -7,6 +7,7 @@
#include "bus-object.h"
#include "hashmap.h"
#include "list.h"
#include "runtime-scope.h"
typedef struct Manager Manager;
@ -23,6 +24,8 @@ struct Manager {
LIST_HEAD(Operation, operations);
unsigned n_operations;
RuntimeScope runtime_scope; /* for now always RUNTIME_SCOPE_SYSTEM */
};
extern const BusObjectImplementation manager_object;

View File

@ -10,6 +10,7 @@
#include "resolved-dns-query.h"
#include "resolved-dns-synthesize.h"
#include "resolved-etc-hosts.h"
#include "resolved-timeouts.h"
#include "string-util.h"
#define QUERIES_MAX 2048
@ -48,6 +49,8 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
assert(c);
(void) event_source_disable(c->timeout_event_source);
/* Detach all the DnsTransactions attached to this query */
while ((t = set_steal_first(c->transactions))) {
@ -62,6 +65,8 @@ static void dns_query_candidate_abandon(DnsQueryCandidate *c) {
assert(c);
(void) event_source_disable(c->timeout_event_source);
/* Abandon all the DnsTransactions attached to this query */
while ((t = set_steal_first(c->transactions))) {
@ -94,6 +99,8 @@ static DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
if (!c)
return NULL;
c->timeout_event_source = sd_event_source_disable_unref(c->timeout_event_source);
dns_query_candidate_stop(c);
dns_query_candidate_unlink(c);
@ -312,6 +319,30 @@ fail:
return r;
}
static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c);
static int on_candidate_timeout(sd_event_source *s, usec_t usec, void *userdata) {
DnsQueryCandidate *c = userdata;
assert(s);
assert(c);
log_debug("Accepting incomplete query candidate after expedited timeout on partial success.");
dns_query_accept(c->query, c);
return 0;
}
static bool dns_query_candidate_has_partially_succeeded(DnsQueryCandidate *c) {
DnsTransaction *t;
SET_FOREACH(t, c->transactions)
if (t->state == DNS_TRANSACTION_SUCCESS)
return true;
return false;
}
void dns_query_candidate_notify(DnsQueryCandidate *c) {
DnsTransactionState state;
int r;
@ -323,11 +354,24 @@ void dns_query_candidate_notify(DnsQueryCandidate *c) {
state = dns_query_candidate_state(c);
if (DNS_TRANSACTION_IS_LIVE(state))
if (DNS_TRANSACTION_IS_LIVE(state)) {
if (dns_query_candidate_has_partially_succeeded(c))
(void) event_reset_time_relative(
c->query->manager->event,
&c->timeout_event_source,
CLOCK_BOOTTIME,
CANDIDATE_EXPEDITED_TIMEOUT_USEC, /* accuracy_usec= */ 0,
on_candidate_timeout, c,
/* priority= */ 0, "candidate-timeout",
/* force_reset= */ false);
return;
}
if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) {
(void) event_source_disable(c->timeout_event_source);
r = dns_query_candidate_next_search_domain(c);
if (r < 0)
goto fail;

View File

@ -25,6 +25,7 @@ struct DnsQueryCandidate {
DnsSearchDomain *search_domain;
Set *transactions;
sd_event_source *timeout_event_source;
LIST_FIELDS(DnsQueryCandidate, candidates_by_query);
LIST_FIELDS(DnsQueryCandidate, candidates_by_scope);

View File

@ -16,6 +16,7 @@
#include "resolved-dns-zone.h"
#include "resolved-llmnr.h"
#include "resolved-mdns.h"
#include "resolved-timeouts.h"
#include "socket-util.h"
#include "strv.h"

View File

@ -14,13 +14,10 @@
#include "resolved-dns-transaction.h"
#include "resolved-dnstls.h"
#include "resolved-llmnr.h"
#include "resolved-timeouts.h"
#include "string-table.h"
#define TRANSACTIONS_MAX 4096
#define TRANSACTION_TCP_TIMEOUT_USEC (10U*USEC_PER_SEC)
/* After how much time to repeat classic DNS requests */
#define DNS_TIMEOUT_USEC (SD_RESOLVED_QUERY_TIMEOUT_USEC / DNS_TRANSACTION_ATTEMPTS_MAX)
static void dns_transaction_reset_answer(DnsTransaction *t) {
assert(t);
@ -1632,13 +1629,10 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
case DNS_PROTOCOL_DNS:
/* When we do TCP, grant a much longer timeout, as in this case there's no need for us to quickly
* resend, as the kernel does that anyway for us, and we really don't want to interrupt it in that
* needlessly. */
if (t->stream)
return TRANSACTION_TCP_TIMEOUT_USEC;
return DNS_TIMEOUT_USEC;
return TRANSACTION_UDP_TIMEOUT_USEC;
case DNS_PROTOCOL_MDNS:
if (t->probing)

View File

@ -203,24 +203,3 @@ DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
const char* dns_transaction_source_to_string(DnsTransactionSource p) _const_;
DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
/* mDNS probing interval, see RFC 6762 Section 8.1 */
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
/* Maximum attempts to send DNS requests, across all DNS servers */
#define DNS_TRANSACTION_ATTEMPTS_MAX 24
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? \
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
(p) == DNS_PROTOCOL_MDNS ? \
MDNS_TRANSACTION_ATTEMPTS_MAX : \
DNS_TRANSACTION_ATTEMPTS_MAX)

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "time-util.h"
#include "resolved-def.h"
/* LLMNR Jitter interval, see RFC 4795 Section 7 */
#define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC)
/* mDNS probing interval, see RFC 6762 Section 8.1 */
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
/* Maximum attempts to send DNS requests, across all DNS servers */
#define DNS_TRANSACTION_ATTEMPTS_MAX 24
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
#define TRANSACTION_ATTEMPTS_MAX(p) (\
(p) == DNS_PROTOCOL_LLMNR ? \
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
(p) == DNS_PROTOCOL_MDNS ? \
MDNS_TRANSACTION_ATTEMPTS_MAX : \
DNS_TRANSACTION_ATTEMPTS_MAX)
/* After how much time to repeat classic DNS requests */
#define TRANSACTION_UDP_TIMEOUT_USEC (SD_RESOLVED_QUERY_TIMEOUT_USEC / DNS_TRANSACTION_ATTEMPTS_MAX)
/* When we do TCP, grant a much longer timeout, as in this case there's no need for us to quickly
* resend, as the kernel does that anyway for us, and we really don't want to interrupt it in that
* needlessly. */
#define TRANSACTION_TCP_TIMEOUT_USEC (10 * USEC_PER_SEC)
/* Should be longer than transaction timeout for a single UDP transaction, so we get at least
* one transaction retry before timeouting the whole candidate */
#define CANDIDATE_EXPEDITED_TIMEOUT_USEC (TRANSACTION_UDP_TIMEOUT_USEC + 1 * USEC_PER_SEC)

View File

@ -1555,16 +1555,9 @@ static int run_context_reconnect(RunContext *c) {
}
static void run_context_check_done(RunContext *c) {
bool done;
assert(c);
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
done = pty_forward_drain(c->forward);
if (done)
if (STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job)
(void) sd_event_exit(c->event, EXIT_SUCCESS);
}
@ -2094,21 +2087,8 @@ static int start_transient_service(sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (c.forward) {
char last_char = 0;
r = pty_forward_get_last_char(c.forward, &last_char);
if (r >= 0 && !arg_quiet && last_char != '\n')
fputc('\n', stdout);
}
if (arg_wait && !arg_quiet) {
/* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, with its
* original settings (i.e. proper line breaks), so that we can show the summary in a pretty
* way. */
c.forward = pty_forward_free(c.forward);
if (!isempty(c.result))
log_info("Finished with result: %s", strna(c.result));

View File

@ -21,10 +21,10 @@
#include "capsule-util.h"
#include "chase.h"
#include "daemon-util.h"
#include "data-fd-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "memfd-util.h"
#include "memstream-util.h"
#include "path-util.h"
#include "socket-util.h"
@ -803,7 +803,7 @@ static int method_dump_memory_state_by_fd(sd_bus_message *message, void *userdat
if (r < 0)
return r;
fd = acquire_data_fd_full(dump, dump_size, /* flags = */ 0);
fd = memfd_new_and_seal("malloc-info", dump, dump_size);
if (fd < 0)
return fd;

View File

@ -21,6 +21,7 @@
#include "battery-util.h"
#include "blockdev-util.h"
#include "cap-list.h"
#include "capability-util.h"
#include "cgroup-util.h"
#include "compare-operator.h"
#include "condition.h"
@ -701,45 +702,23 @@ static int condition_test_security(Condition *c, char **env) {
}
static int condition_test_capability(Condition *c, char **env) {
unsigned long long capabilities = (unsigned long long) -1;
_cleanup_fclose_ FILE *f = NULL;
int value, r;
int r;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_CAPABILITY);
/* If it's an invalid capability, we don't have it */
value = capability_from_name(c->parameter);
int value = capability_from_name(c->parameter);
if (value < 0)
return -EINVAL;
/* If it's a valid capability we default to assume
* that we have it */
CapabilityQuintet q;
r = pidref_get_capability(&PIDREF_MAKE_FROM_PID(getpid_cached()), &q);
if (r < 0)
return r;
f = fopen("/proc/self/status", "re");
if (!f)
return -errno;
for (;;) {
_cleanup_free_ char *line = NULL;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0)
break;
const char *p = startswith(line, "CapBnd:");
if (p) {
if (sscanf(p, "%llx", &capabilities) != 1)
return -EIO;
break;
}
}
return !!(capabilities & (1ULL << value));
return !!(q.bounding & ((UINT64_C(1) << value)));
}
static int condition_test_needs_update(Condition *c, char **env) {

View File

@ -1,168 +1,30 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#if HAVE_LINUX_MEMFD_H
#include <linux/memfd.h>
#endif
#include "alloc-util.h"
#include "copy.h"
#include "data-fd-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "io-util.h"
#include "memfd-util.h"
#include "missing_mman.h"
#include "missing_syscall.h"
#include "tmpfile-util.h"
/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */
/* When the data is smaller or equal to 64K, try to place the copy in a memfd */
#define DATA_FD_MEMORY_LIMIT (64U * U64_KB)
/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */
/* If memfd didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp/ instead. */
#define DATA_FD_TMP_LIMIT (1U * U64_MB)
int acquire_data_fd_full(const void *data, size_t size, DataFDFlags flags) {
_cleanup_close_ int fd = -EBADF;
ssize_t n;
int r;
assert(data || size == 0);
/* Acquire a read-only file descriptor that when read from returns the specified data. This is much more
* complex than I wish it was. But here's why:
*
* a) First we try to use memfds. They are the best option, as we can seal them nicely to make them
* read-only. Unfortunately they require kernel 3.17, and at the time of writing we still support 3.14.
*
* b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining
* a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged
* clients can only bump their size to a system-wide limit, which might be quite low.
*
* c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from
* earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via
* /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs.
*
* d) Finally, we try creating a regular file in /dev/shm, which we then delete.
*
* It sucks a bit that depending on the situation we return very different objects here, but that's Linux I
* figure. */
if (size == SIZE_MAX)
size = strlen(data);
if (size == 0 && !FLAGS_SET(flags, ACQUIRE_NO_DEV_NULL))
/* As a special case, return /dev/null if we have been called for an empty data block */
return RET_NERRNO(open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY));
if (!FLAGS_SET(flags, ACQUIRE_NO_MEMFD)) {
fd = memfd_new_and_seal("data-fd", data, size);
if (fd < 0 && !ERRNO_IS_NOT_SUPPORTED(fd))
return fd;
if (fd >= 0)
return TAKE_FD(fd);
}
if (!FLAGS_SET(flags, ACQUIRE_NO_PIPE)) {
_cleanup_close_pair_ int pipefds[2] = EBADF_PAIR;
int isz;
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size) {
isz = (int) size;
if (isz < 0 || (size_t) isz != size)
return -E2BIG;
/* Try to bump the pipe size */
(void) fcntl(pipefds[1], F_SETPIPE_SZ, isz);
/* See if that worked */
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
if ((size_t) isz < size)
goto try_dev_shm;
}
n = write(pipefds[1], data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
try_dev_shm:
if (!FLAGS_SET(flags, ACQUIRE_NO_TMPFILE)) {
fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500);
if (fd < 0)
goto try_dev_shm_without_o_tmpfile;
n = write(fd, data, size);
if (n < 0)
return -errno;
if ((size_t) n != size)
return -EIO;
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
return fd_reopen(fd, O_RDONLY|O_CLOEXEC);
}
try_dev_shm_without_o_tmpfile:
if (!FLAGS_SET(flags, ACQUIRE_NO_REGULAR)) {
char pattern[] = "/dev/shm/data-fd-XXXXXX";
fd = mkostemp_safe(pattern);
if (fd < 0)
return fd;
n = write(fd, data, size);
if (n < 0) {
r = -errno;
goto unlink_and_return;
}
if ((size_t) n != size) {
r = -EIO;
goto unlink_and_return;
}
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
r = fd_reopen(fd, O_RDONLY|O_CLOEXEC);
unlink_and_return:
(void) unlink(pattern);
return r;
}
return -EOPNOTSUPP;
}
int copy_data_fd(int fd) {
_cleanup_close_ int copy_fd = -EBADF, tmp_fd = -EBADF;
_cleanup_free_ void *remains = NULL;
size_t remains_size = 0;
const char *td;
struct stat st;
int r;
/* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but
* independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be
* somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported
* uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in
* /var/tmp. */
/* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only
* fashion, but independent of it (i.e. the source fd can be closed and unmounted after this call
* succeeded). Tries to be somewhat smart about where to place the data. In the best case uses a
* memfd(). For larger data will use an unlinked file in /tmp/, and for even larger data one in
* /var/tmp/. */
if (fstat(fd, &st) < 0)
return -errno;
@ -175,129 +37,71 @@ int copy_data_fd(int fd) {
if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode))
return -EBADFD;
/* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note
* that we use the reported regular file size only as a hint, given that there are plenty special files in
* /proc and /sys which report a zero file size but can be read from. */
/* If we have reason to believe the data is bounded in size, then let's use memfds as backing
* fd. Note that we use the reported regular file size only as a hint, given that there are plenty
* special files in /proc/ and /sys/ which report a zero file size but can be read from. */
if (!S_ISREG(st.st_mode) || (uint64_t) st.st_size < DATA_FD_MEMORY_LIMIT) {
/* Try a memfd first */
copy_fd = memfd_new("data-fd");
if (copy_fd >= 0) {
off_t f;
copy_fd = memfd_new_full("data-fd", MFD_ALLOW_SEALING);
if (copy_fd < 0)
return copy_fd;
r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0);
r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, COPY_REFLINK);
if (r < 0)
return r;
off_t f = lseek(copy_fd, 0, SEEK_SET);
if (f < 0)
return -errno;
if (f != 0)
return -EIO;
if (r == 0) {
/* Did it fit into the limit? If so, we are done. */
r = memfd_set_sealed(copy_fd);
if (r < 0)
return r;
f = lseek(copy_fd, 0, SEEK_SET);
if (f != 0)
return -errno;
if (r == 0) {
/* Did it fit into the limit? If so, we are done. */
r = memfd_set_sealed(copy_fd);
if (r < 0)
return r;
return TAKE_FD(copy_fd);
}
/* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */
} else {
_cleanup_close_pair_ int pipefds[2] = EBADF_PAIR;
int isz;
/* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather
* then block indefinitely when we hit the pipe size limit */
if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
return -errno;
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
/* Try to enlarge the pipe size if necessary */
if ((size_t) isz < DATA_FD_MEMORY_LIMIT) {
(void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT);
isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
if (isz < 0)
return -errno;
}
if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
if (r < 0 && r != -EAGAIN)
return r; /* If we get EAGAIN it could be because of the source or because of
* the destination fd, we can't know, as sendfile() and friends won't
* tell us. Hence, treat this as reason to fall back, just to be
* sure. */
if (r == 0) {
/* Everything fit in, yay! */
(void) fd_nonblock(pipefds[0], false);
return TAKE_FD(pipefds[0]);
}
/* Things didn't fit in. But we read data into the pipe, let's remember that, so that
* when writing the new file we incorporate this first. */
copy_fd = TAKE_FD(pipefds[0]);
}
return TAKE_FD(copy_fd);
}
}
/* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */
if ((!S_ISREG(st.st_mode) || (uint64_t) st.st_size < DATA_FD_TMP_LIMIT) &&
(DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) {
off_t f;
if ((!S_ISREG(st.st_mode) || (uint64_t) st.st_size < DATA_FD_TMP_LIMIT)) {
tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC);
if (tmp_fd < 0)
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first and it ended up being too large, then copy this into the
/* If we tried a memfd first and it ended up being too large, then copy this into the
* temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0);
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return r;
assert(r == 0);
}
if (remains_size > 0) {
/* If there were remaining bytes (i.e. read into memory, but not written out yet) from the
* failed copy operation, let's flush them out next. */
r = loop_write(tmp_fd, remains, remains_size);
if (r < 0)
return r;
}
r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK);
r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT, COPY_REFLINK);
if (r < 0)
return r;
if (r == 0)
goto finish; /* Yay, it fit in */
/* It didn't fit in. Let's not forget to use what we already used */
f = lseek(tmp_fd, 0, SEEK_SET);
if (f != 0)
off_t f = lseek(tmp_fd, 0, SEEK_SET);
if (f < 0)
return -errno;
if (f != 0)
return -EIO;
close_and_replace(copy_fd, tmp_fd);
remains = mfree(remains);
remains_size = 0;
}
/* As last fallback use /var/tmp */
/* As last fallback use /var/tmp/ */
r = var_tmp_dir(&td);
if (r < 0)
return r;
@ -307,7 +111,7 @@ int copy_data_fd(int fd) {
return tmp_fd;
if (copy_fd >= 0) {
/* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this
/* If we tried a memfd first, or a file in /tmp/, and it ended up being too large, than copy this
* into the temporary file first. */
r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
@ -316,13 +120,6 @@ int copy_data_fd(int fd) {
assert(r == 0);
}
if (remains_size > 0) {
/* Then, copy in any read but not yet written bytes. */
r = loop_write(tmp_fd, remains, remains_size);
if (r < 0)
return r;
}
/* Copy in the rest */
r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
@ -370,17 +167,11 @@ int memfd_clone_fd(int fd, const char *name, int mode) {
return r;
if (ro) {
_cleanup_close_ int rfd = -EBADF;
r = memfd_set_sealed(mfd);
if (r < 0)
return r;
rfd = fd_reopen(mfd, mode);
if (rfd < 0)
return rfd;
return TAKE_FD(rfd);
return fd_reopen(mfd, mode);
}
off_t f = lseek(mfd, 0, SEEK_SET);

View File

@ -4,18 +4,5 @@
#include <stddef.h>
#include <stdint.h>
typedef enum DataFDFlags {
ACQUIRE_NO_DEV_NULL = 1 << 0,
ACQUIRE_NO_MEMFD = 1 << 1,
ACQUIRE_NO_PIPE = 1 << 2,
ACQUIRE_NO_TMPFILE = 1 << 3,
ACQUIRE_NO_REGULAR = 1 << 4,
} DataFDFlags;
int acquire_data_fd_full(const void *data, size_t size, DataFDFlags flags);
static inline int acquire_data_fd(const void *data) {
return acquire_data_fd_full(data, SIZE_MAX, 0);
}
int copy_data_fd(int fd);
int memfd_clone_fd(int fd, const char *name, int mode);

Some files were not shown because too many files have changed in this diff Show More