1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-22 09:48:03 -08:00

Compare commits

...

49 Commits

Author SHA1 Message Date
Michal Sekletar
bf630fb078
Merge d11e70d92f into 33c15ba8e8 2024-12-22 05:19:25 +00:00
Daan De Meyer
33c15ba8e8 Remove leftover .gitmodules file 2024-12-21 22:43:57 +00:00
Daan De Meyer
5495b11360 mkosi: Fix authselect systemd-homed feature name
The feature name is with-systemd-homed, not with-homed.
2024-12-21 21:03:03 +01:00
Daan De Meyer
7655550a49 systemd-homed: Give access to /dev/btrfs-control
Otherwise, we see "WARNING: failed to open /dev/btrfs-control,
skipping device registration: Operation not permitted" in systemd-homed's
logs when creating a btrfs on luks home.
2024-12-21 19:15:01 +01:00
Daan De Meyer
36dd429680 units: Order systemd-oomd after systemd-sysusers
systemd-sysusers might create the systemd-oom system user that
systemd-oomd runs under so let's order systemd-oomd after
systemd-sysusers.
2024-12-21 19:14:30 +01:00
Yu Watanabe
52a2b04947 hwdb: comment out the entry for Logitech MX Keys for Mac
This effectively reverts the commit f70e5620b6,
as the entry seems to match multiple models.

Fixes #35691.
2024-12-21 12:19:08 +00:00
Lennart Poettering
ccaa76ac48
image-discovery: add per-user scope (#35510) 2024-12-20 22:12:35 +01:00
Lennart Poettering
2232038187
pid1: complete per-user credentials support (#35536)
Fixes: #33887 #33796 #33318
2024-12-20 22:12:08 +01:00
Lennart Poettering
1563404159
analyze: extend CHID support to more types (#35699)
Let's implement the spec more comprehensively.

This is piece by piece work, There's more to do on the EFI side before
all CHID types are supported, but in userspace it should be reasonably
complete now.
2024-12-20 22:11:39 +01:00
Daan De Meyer
2138278d25
Various mkosi improvements (#35684) 2024-12-20 21:24:51 +01:00
Daan De Meyer
34b5a27b0b docs: Simplify hacking documentation
Let's use "mkosi sandbox" in the docs so that users can build systemd
without having to install anything except mkosi. Using mkosi sandbox
will use tools and dependencies from the tools tree which is also used
in CI and thus has a higher chance of working from the first try compared
to whatever tools might be installed on the host system of a new contributor.
2024-12-20 20:09:36 +01:00
Daan De Meyer
ba3f148307 mkosi.clangd: Fail on command errors 2024-12-20 20:09:36 +01:00
Daan De Meyer
b133f57544 mkosi.clangd: Don't pass --host if we're not using flatpak-spawn 2024-12-20 20:09:36 +01:00
Daan De Meyer
8c5b4df543 mkosi: Use build/ as extra search path by default
Building systemd with mkosi generally requires a very recent version
of systemd which might not be installed on the host. Let's configure
mkosi to look for extra executables in the build/ directory by default
so that we prefer systemd executables from the build directory over those
on the host as those on the host are likely to be too old.
2024-12-20 20:09:36 +01:00
Daan De Meyer
1995084a9e mkosi: Use tools tree by default
Let's enable usage of a tools tree by default to simplify the setup
for new contributors and save them from having to install or upgrade
a bunch of extra tools to get mkosi working as expected.
2024-12-20 20:09:35 +01:00
Daan De Meyer
ac1a711d9a mkosi: Enable EPEL for CentOS Stream tools tree
We need packages from EPEL to be able to build CentOS Stream images
with a CentOS Stream tools tree so enable it. This is broken on CentOS
Stream 10 but given using a CentOS Stream tools tree is broken without
EPEL as well, we might as well enable it and just wait until the packages
are added to EPEL 10.
2024-12-20 20:09:35 +01:00
Daan De Meyer
d4dda34854 mkosi: Add libz1 to opensuse tools tree
Without meson fails to configure properly.
2024-12-20 20:09:35 +01:00
Daan De Meyer
7337f4b197 mkosi: Add gdb to tools tree 2024-12-20 20:09:35 +01:00
Daan De Meyer
3ee5cab490 docs: Move fuzzers documentation to test README.md 2024-12-20 20:09:35 +01:00
Daan De Meyer
3add2d73b3 coverage: Run on pull request in a few cases
If we're changing the integration test wrapper or coverage.yml, let's
run the coverage workflow on PRs as well to make sure it doesn't break.
2024-12-20 20:09:35 +01:00
Daan De Meyer
1dd345b00d mkosi: Update to latest 2024-12-20 20:09:35 +01:00
Lennart Poettering
8ca50bde48 analyze-chid: fully support all CHID types
This adds logic to read the missing SMBIOS fields from userspace, too.
With this we should have full CHID coverage now, matching fwupd's output
fully.
2024-12-20 18:13:18 +01:00
Lennart Poettering
0eb51d9913 analyze-chid: split out code that reads smbios into helper 2024-12-20 18:13:18 +01:00
Lennart Poettering
6b99f3ba5a analyze: C escape weird chars in SMBIOS fields
just in case, let's not write garbled crap to the TTY but escape and
potential weird chars before output.
2024-12-20 18:13:18 +01:00
Lennart Poettering
95cd07e772 chid: add missing CHID type definitions
This add he missing CHID types to our tables, but doesn't add all
necessary code to calculate them yet.

This brings us closer to what the CHID spec documents, and what
"fupwdtool hwids" outputs.
2024-12-20 18:13:18 +01:00
Lennart Poettering
0f55038c84 analyze-chid: show friendly smbios field names
Some of the field names between kernel and smbios spec differ. Kinda
confusing. Let's use the smbios field names, to match the CHID spec,
which also uses them, and thus be least confusing, treating kernel
attribute fields as an internal Linux thing only.
2024-12-20 18:13:18 +01:00
Lennart Poettering
37e02b455b analyze: not all smbios fields are always defined, deal with that
As per previous commit, accept that not all SMBIOS fields are alwaysa
available (or set, but empty), hence handle this gracefully and don't
generate relevant CHIDs, as per docs.
2024-12-20 18:13:18 +01:00
Lennart Poettering
a04af8516e chid-fundamental: rework bit checking to use FLAGS_SET() 2024-12-20 18:13:16 +01:00
Lennart Poettering
094e2ace12 chid-fundamental: use right type to iterate through smbios fields 2024-12-20 18:06:34 +01:00
Lennart Poettering
f8988a5e45 chid-fundamental: make namespace GUID static, too 2024-12-20 18:06:34 +01:00
Lennart Poettering
d1bbfaeba5 chid-fundamental: not all SMBIOS fields are available on all systems
And the CHID documentation says that CHIDs that require fields that are
not available on the local system should not be generated. Follow that,
and generate a NULL CHID in that case (which we generally ignore
otherwise).
2024-12-20 18:06:34 +01:00
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
Lennart Poettering
8cbcdc78db update TODO 2024-12-20 17:52:09 +01:00
Lennart Poettering
4103bf9f2f man: document the new per-use credstore paths
(And some other minor tweaks)
2024-12-20 17:52:07 +01:00
Lennart Poettering
026dfd60d4 test: add integration test that makes sure unpriv creds work correctly
This checks both the per-user credstore directory logic, and that
unprivileged, encrypted credentials work.
2024-12-20 17:52:04 +01:00
Lennart Poettering
1af989e8de pid1: add support for decrypting per-user credentials
When I added support for unprivileged credentials I apparently never
hooked them up to service management correctly. Let's fix that.

Fixes: #33796 #33318
2024-12-20 17:52:01 +01:00
Lennart Poettering
8506a9955c execute: introduce a user-scoped credstore
Fixes: #33887
2024-12-20 17:51:58 +01:00
Lennart Poettering
d2cd189324 sd-path: expose credential store in sd-path 2024-12-20 17:51:54 +01:00
Lennart Poettering
b226b7fb6d systemd-path: add the usual ANSI sequences to --help text 2024-12-20 17:51:52 +01:00
Lennart Poettering
060e2512cd systemd-path: guarantee that tool exit status is zero on success
Let's not inherit the error code from an earlier function invocation.
2024-12-20 17:51:50 +01:00
Lennart Poettering
81082f2dc2 systemd-path: order all listed paths by their ID alphabetically
Let's add some system to the madness, given we added user-specific dirs
to the end of the list, but they should really be listed together with
the other user-specific ones.
2024-12-20 17:51:48 +01:00
Lennart Poettering
616586b910 sd-path: don't chop off trailing slash in sd_path apis, when user provided them
This is a minor compat break, but given the slow adoption of the
sd-path.h APIs I think it's one we should take. Basically, the idea is
that if the user provides a suffix path with a trailing slash (thus
encoding in the path that the last element must be a dir), we should
keep it in place, and not suppress it, in order to not willy nilly
reduce the amount of information contained in the path.

Simplifications that do not alter meaning, and do not suppress
information should be fine to apply to a path, but otherwise we really
should be conservative on this.
2024-12-20 17:51:46 +01:00
Lennart Poettering
cf7d0a2d2e pid1: normalize oom error handling a bit 2024-12-20 17:51:42 +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
Michal Sekletar
d11e70d92f core/transaction: generate DOT graph of dependency cycle for easier debugging 2024-11-29 17:27:45 +01:00
Michal Sekletar
66146f21c0 systemctl: display dep-cycle taint flag in unit status 2024-11-29 17:13:40 +01:00
Michal Sekletar
afbde99253 core/transaction: add taint flag signifying presence of dependency cycles 2024-11-29 17:12:28 +01:00
71 changed files with 1054 additions and 382 deletions

View File

@ -7,6 +7,14 @@ on:
# Calculate coverage daily at midnight
- cron: '0 0 * * *'
pull_request:
branches:
- main
- v[0-9]+-stable
paths:
- .github/workflows/coverage.yml
- test/integration-test-wrapper.py
permissions:
contents: read
@ -16,7 +24,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
- uses: systemd/mkosi@ba07d53000b6c560ad0b9f07550aca93c0284e88
# 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
@ -49,7 +57,6 @@ jobs:
Distribution=arch
[Build]
ToolsTree=default
ToolsTreeDistribution=arch
UseSubvolumes=yes
WithTests=no

View File

@ -113,7 +113,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@7d45366395f29fdb2b534a850c09d23d29b78fa9
- uses: systemd/mkosi@ba07d53000b6c560ad0b9f07550aca93c0284e88
# 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
@ -152,7 +152,6 @@ jobs:
[Build]
UseSubvolumes=yes
ToolsTree=default
ToolsTreeDistribution=fedora
ToolsTreeRelease=rawhide

1
.gitignore vendored
View File

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

0
.gitmodules vendored
View File

18
TODO
View File

@ -122,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
@ -391,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.
@ -446,10 +456,6 @@ Features:
* credentials: add a flag to the scoped credentials that if set require PK
reauthentication when unlocking a secret.
* teach systemd --user to properly load credentials off disk, with
/etc/credstore equivalent and similar. Make sure that $CREDENTIALS_DIRECTORY=
actually works too when run with user privs.
* extend the smbios11 logic for passing credentials so that instead of passing
the credential data literally it can also just reference an AF_VSOCK CID/port
to read them from. This way the data doesn't remain in the SMBIOS blob during

View File

@ -7,94 +7,97 @@ SPDX-License-Identifier: LGPL-2.1-or-later
# Hacking on systemd
We welcome all contributions to systemd.
If you notice a bug or a missing feature, please feel invited to fix it, and submit your work as a
We welcome all contributions to systemd. If you notice a bug or a missing
feature, please feel invited to fix it, and submit your work as a
[GitHub Pull Request (PR)](https://github.com/systemd/systemd/pull/new).
Please make sure to follow our [Coding Style](/CODING_STYLE) when submitting patches.
Also have a look at our [Contribution Guidelines](/CONTRIBUTING).
Please make sure to follow our [Coding Style](/CODING_STYLE) when submitting
patches. Also have a look at our [Contribution Guidelines](/CONTRIBUTING).
When adding new functionality, tests should be added.
For shared functionality (in `src/basic/` and `src/shared/`) unit tests should be sufficient.
The general policy is to keep tests in matching files underneath `src/test/`,
e.g. `src/test/test-path-util.c` contains tests for any functions in `src/basic/path-util.c`.
If adding a new source file, consider adding a matching test executable.
For features at a higher level, tests in `src/test/` are very strongly recommended.
If that is not possible, integration tests in `test/` are encouraged.
When adding new functionality, tests should be added. For shared functionality
(in `src/basic/` and `src/shared/`) unit tests should be sufficient. The general
policy is to keep tests in matching files underneath `src/test/`, e.g.
`src/test/test-path-util.c` contains tests for any functions in
`src/basic/path-util.c`. If adding a new source file, consider adding a matching
test executable. For features at a higher level, tests in `src/test/` are very
strongly recommended. If that is not possible, integration tests in `test/` are
encouraged. Please always test your work before submitting a PR.
Please always test your work before submitting a PR.
For many of the components of systemd testing is straightforward as you can simply compile systemd and run the relevant tool from the build directory.
## Hacking on systemd with mkosi
For some components (most importantly, systemd/PID 1 itself) this is not possible, however.
In order to simplify testing for cases like this we provide a set of `mkosi` config files directly in the source tree.
[mkosi](https://mkosi.systemd.io/)
is a tool for building clean OS images from an upstream distribution in combination with a fresh build of the project in the local working directory.
To make use of this, please install `mkosi` from the [GitHub repository](https://github.com/systemd/mkosi#running-mkosi-from-the-repository).
`mkosi` will build an image for the host distro by default.
First, run `mkosi genkey` to generate a key and certificate to be used for secure boot and verity signing.
After that is done, it is sufficient to type `mkosi` in the systemd project directory to generate a disk image you can boot either in `systemd-nspawn` or in a UEFI-capable VM:
[mkosi](https://mkosi.systemd.io/) is our swiss army knife for hacking on
systemd. It makes sure all necessary dependencies are available to build systemd
and allows building and booting an OS image with the latest systemd installed
for testing purposes.
First, install `mkosi` from the
[GitHub repository](https://github.com/systemd/mkosi#running-mkosi-from-the-repository).
Note that it's not possible to use your distribution's packaged version of mkosi
as mkosi has to be installed outside of `/usr` for the following steps to work.
Then, you can build and run systemd executables as follows:
```sh
$ sudo mkosi boot # nspawn still needs sudo for now
$ mkosi -f sandbox meson setup build
$ mkosi -f sandbox ninja -C build
$ mkosi -f sandbox build/systemctl --version
```
or:
To build and boot an OS image with the latest systemd installed:
```sh
$ mkosi qemu
$ mkosi -f genkey # Generate signing keys once.
$ mkosi -f sandbox ninja -C build mkosi # (re-)build the OS image
$ sudo mkosi boot # Boot the image with systemd-nspawn.
$ mkosi qemu # Boot the image with qemu.
```
By default, the tools from your host system are used to build the image.
Sometimes we start using mkosi features that rely on functionality in systemd
tools that's not in an official release yet. In that case, you'll need to build
systemd from source on the host and configure mkosi to use the tools from the
systemd build directory.
To do a local build, most distributions provide very simple and convenient ways
to install most development packages necessary to build systemd:
Putting this all together, here's a series of commands for preparing a patch for
systemd:
```sh
# Fedora
$ sudo dnf builddep systemd
# Debian/Ubuntu
$ sudo apt-get build-dep systemd
# Arch
$ sudo pacman -S devtools
$ pkgctl repo clone --protocol=https systemd
$ git clone https://github.com/systemd/mkosi.git
$ ln -s $PWD/mkosi/bin/mkosi ~/.local/bin/mkosi # Make sure ~/.local/bin is in $PATH.
$ git clone https://github.com/systemd/systemd.git
$ cd systemd
$ makepkg -seoc
$ git checkout -b <BRANCH> # where BRANCH is the name of the branch
$ $EDITOR src/core/main.c # or wherever you'd like to make your changes
$ mkosi -f sandbox meson setup build # Set up meson
$ mkosi -f genkey # Generate signing keys once.
$ mkosi -f sandbox ninja -C build mkosi # (re-)build the test image
$ mkosi qemu # Boot the image in qemu
$ git add -p # interactively put together your patch
$ git commit # commit it
$ git push -u <REMOTE> # where REMOTE is your "fork" on GitHub
```
After installing the development packages, systemd can be built from source as follows:
And after that, head over to your repo on GitHub and click "Compare & pull
request"
```sh
$ meson setup build <options>
$ ninja -C build
$ meson test -C build
```
Happy hacking!
To have `mkosi` use the systemd tools from the `build/` directory, add the
following to `mkosi.local.conf`:
The following sections contain advanced topics on how to speed up development or
streamline debugging. Feel free to read them if you're interested but they're
not required to write basic patches.
## Building the OS image without a tools tree
By default, `mkosi` will first build a tools tree and use it build the image and
provide the environment for `mkosi sandbox`. To disable the tools tree and use
binaries from your host instead, write the following to `mkosi.local.conf`:
```conf
[Host]
ExtraSearchPaths=build/
[Build]
ToolsTree=
```
And if you want `mkosi` to build a tools image and use the tools from there
instead of looking for tools on the host, add the following to
`mkosi.local.conf`:
## Rebuilding systemd without rebuilding the OS image
```conf
[Host]
ToolsTree=default
```
Every time you rerun the `mkosi` command a fresh image is built, incorporating
all current changes you made to the project tree. To build the latest changes
and re-install after booting the image, run one of the following commands in
another terminal on your host (choose the right one depending on the
distribution of the container or virtual machine):
Every time the `mkosi` target is built, a fresh image is built. To build the
latest changes and re-install systemd without rebuilding the image, run one of
the following commands in another terminal on your host after booting the image
(choose the right one depending on the distribution of the container or virtual
machine):
```sh
mkosi -t none && mkosi ssh dnf upgrade --disablerepo="*" --assumeyes "/work/build/*.rpm" # CentOS/Fedora
@ -107,26 +110,6 @@ and optionally restart the daemon(s) you're working on using
`systemctl restart <units>` or `systemctl daemon-reexec` if you're working on
pid1 or `systemctl soft-reboot` to restart everything.
Putting this all together, here's a series of commands for preparing a patch for systemd:
```sh
$ git clone https://github.com/systemd/mkosi.git
$ ln -s $PWD/mkosi/bin/mkosi /usr/local/bin/mkosi
$ git clone https://github.com/systemd/systemd.git
$ cd systemd
$ git checkout -b <BRANCH> # where BRANCH is the name of the branch
$ vim src/core/main.c # or wherever you'd like to make your changes
$ mkosi -f qemu # (re-)build and boot up the test image in qemu
$ mkosi -t none # Build new packages without rebuilding the image
$ git add -p # interactively put together your patch
$ git commit # commit it
$ git push -u <REMOTE> # where REMOTE is your "fork" on GitHub
```
And after that, head over to your repo on GitHub and click "Compare & pull request"
Happy hacking!
## Building distribution packages with mkosi
To build distribution packages for a specific distribution and release without
@ -201,67 +184,6 @@ Those are not useful when compiling for distribution and can be disabled by sett
See [Testing systemd using sanitizers](/TESTING_WITH_SANITIZERS) for more information on how to build with sanitizers enabled in mkosi.
## Fuzzers
systemd includes fuzzers in `src/fuzz/` that use libFuzzer and are automatically run by [OSS-Fuzz](https://github.com/google/oss-fuzz) with sanitizers.
To add a fuzz target, create a new `src/fuzz/fuzz-foo.c` file with a `LLVMFuzzerTestOneInput` function and add it to the list in `src/fuzz/meson.build`.
Whenever possible, a seed corpus and a dictionary should also be added with new fuzz targets.
The dictionary should be named `src/fuzz/fuzz-foo.dict` and the seed corpus should be built and exported as `$OUT/fuzz-foo_seed_corpus.zip` in `tools/oss-fuzz.sh`.
The fuzzers can be built locally if you have libFuzzer installed by running `tools/oss-fuzz.sh`, or by running:
```sh
CC=clang CXX=clang++ \
meson setup build-libfuzz -Dllvm-fuzz=true -Db_sanitize=address,undefined -Db_lundef=false \
-Dc_args='-fno-omit-frame-pointer -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'
ninja -C build-libfuzz fuzzers
```
Each fuzzer then can be then run manually together with a directory containing the initial corpus:
```
export UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
build-libfuzz/fuzz-varlink-idl test/fuzz/fuzz-varlink-idl/
```
Note: the `halt_on_error=1` UBSan option is especially important,
otherwise the fuzzer won't crash when undefined behavior is triggered.
You should also confirm that the fuzzers can be built and run using
[the OSS-Fuzz toolchain](https://google.github.io/oss-fuzz/advanced-topics/reproducing/#building-using-docker):
```sh
path_to_systemd=...
git clone --depth=1 https://github.com/google/oss-fuzz
cd oss-fuzz
for sanitizer in address undefined memory; do
for engine in libfuzzer afl honggfuzz; do
./infra/helper.py build_fuzzers --sanitizer "$sanitizer" --engine "$engine" \
--clean systemd "$path_to_systemd"
./infra/helper.py check_build --sanitizer "$sanitizer" --engine "$engine" \
-e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
done
done
./infra/helper.py build_fuzzers --clean --architecture i386 systemd "$path_to_systemd"
./infra/helper.py check_build --architecture i386 -e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
./infra/helper.py build_fuzzers --clean --sanitizer coverage systemd "$path_to_systemd"
./infra/helper.py coverage --no-corpus-download systemd
```
If you find a bug that impacts the security of systemd,
please follow the guidance in [CONTRIBUTING.md](/CONTRIBUTING) on how to report a security vulnerability.
For more details on building fuzzers and integrating with OSS-Fuzz, visit:
- [Setting up a new project - OSS-Fuzz](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
- [Tutorials - OSS-Fuzz](https://google.github.io/oss-fuzz/reference/useful-links/#tutorials)
## Debugging binaries that need to run as root in vscode
When trying to debug binaries that need to run as root,

View File

@ -1451,10 +1451,15 @@ evdev:input:b0003v046DpC309*
KEYBOARD_KEY_c01b6=images # My Pictures (F11)
KEYBOARD_KEY_c01b7=audio # My Music (F12)
# The wireless receiver b0003v046Dp4092* seems to be used by multiple models.
# See issue #35691. Hence, the entry below cannot be enabled by default. If
# you're using the model below, consider copying the entry to a custom hwdb
# file to enable the setting.
#
# Logitech MX Keys for Mac
evdev:input:b0003v046Dp4092*
KEYBOARD_KEY_70035=102nd # '<' key
KEYBOARD_KEY_70064=grave # '^' key
#evdev:input:b0003v046Dp4092*
# KEYBOARD_KEY_70035=102nd # '<' key
# KEYBOARD_KEY_70064=grave # '^' key
###########################################################
# Maxdata

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

@ -3468,37 +3468,43 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<term><varname>LoadCredentialEncrypted=</varname><replaceable>ID</replaceable><optional>:<replaceable>PATH</replaceable></optional></term>
<listitem><para>Pass a credential to the unit. Credentials are limited-size binary or textual objects
that may be passed to unit processes. They are primarily used for passing cryptographic keys (both
public and private) or certificates, user account information or identity information from host to
services. The data is accessible from the unit's processes via the file system, at a read-only
location that (if possible and permitted) is backed by non-swappable memory. The data is only
accessible to the user associated with the unit, via the
<varname>User=</varname>/<varname>DynamicUser=</varname> settings (as well as the superuser). When
available, the location of credentials is exported as the <varname>$CREDENTIALS_DIRECTORY</varname>
environment variable to the unit's processes.</para>
that may be passed to unit processes. They are primarily intended for passing cryptographic keys
(both public and private) or certificates, user account information or identity information from host
to services, but can be freely used to pass any kind of limited-size information to a service. The
data is accessible from the unit's processes via the file system, at a read-only location that (if
possible and permitted) is backed by non-swappable memory. The data is only accessible to the user
associated with the unit, via the <varname>User=</varname>/<varname>DynamicUser=</varname> settings
(as well as the superuser). When available, the location of credentials is exported as the
<varname>$CREDENTIALS_DIRECTORY</varname> environment variable to the unit's processes.</para>
<para>The <varname>LoadCredential=</varname> setting takes a textual ID to use as name for a
credential plus a file system path, separated by a colon. The ID must be a short ASCII string
suitable as filename in the filesystem, and may be chosen freely by the user. If the specified path
is absolute it is opened as regular file and the credential data is read from it. If the absolute
path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is made
to it (only once at unit start-up) and the credential data read from the connection, providing an
to it (once at process invocation) and the credential data read from the connection, providing an
easy IPC integration point for dynamically transferring credentials from other services.</para>
<para>If the specified path is not absolute and itself qualifies as valid credential identifier it is
attempted to find a credential that the service manager itself received under the specified name —
which may be used to propagate credentials from an invoking environment (e.g. a container manager
that invoked the service manager) into a service. If no matching system credential is found, the
directories <filename>/etc/credstore/</filename>, <filename>/run/credstore/</filename> and
<filename>/usr/lib/credstore/</filename> are searched for files under the credential's name — which
hence are recommended locations for credential data on disk. If
that invoked the service manager) into a service. If no matching passed credential is found, the
system service manager will search the directories <filename>/etc/credstore/</filename>,
<filename>/run/credstore/</filename> and <filename>/usr/lib/credstore/</filename> for files under the
credential's name — which hence are recommended locations for credential data on disk. If
<varname>LoadCredentialEncrypted=</varname> is used <filename>/run/credstore.encrypted/</filename>,
<filename>/etc/credstore.encrypted/</filename>, and
<filename>/usr/lib/credstore.encrypted/</filename> are searched as well.</para>
<filename>/usr/lib/credstore.encrypted/</filename> are searched as well. The per-user service manager
will search <filename>$XDG_CONFIG_HOME/credstore/</filename>,
<filename>$XDG_RUNTIME_DIR/credstore/</filename>, <filename>$HOME/.local/lib/credstore/</filename>
(and the counterparts ending with <filename>…/credstore.encrypted/</filename>) instead. The
<citerefentry><refentrytitle>systemd-path</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
may be used to query the precise credential store search path.</para>
<para>If the file system path is omitted it is chosen identical to the credential name, i.e. this is
a terse way to declare credentials to inherit from the service manager into a service. This option
may be used multiple times, each time defining an additional credential to pass to the unit.</para>
a terse way to declare credentials to inherit from the service manager or credstore directories into
a service. This option may be used multiple times, each time defining an additional credential to
pass to the unit.</para>
<para>Note that if the path is not specified or a valid credential identifier is given, i.e.
in the above two cases, a missing credential is not considered fatal.</para>

View File

@ -1,5 +1,6 @@
#!/bin/bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e
if command -v flatpak-spawn >/dev/null; then
SPAWN=(flatpak-spawn --host)
@ -7,7 +8,7 @@ else
SPAWN=()
fi
MKOSI_CONFIG="$("${SPAWN[@]}" --host mkosi --json summary | jq -r .Images[-1])"
MKOSI_CONFIG="$("${SPAWN[@]}" mkosi --json summary | jq -r .Images[-1])"
DISTRIBUTION="$(jq -r .Distribution <<< "$MKOSI_CONFIG")"
RELEASE="$(jq -r .Release <<< "$MKOSI_CONFIG")"
ARCH="$(jq -r .Architecture <<< "$MKOSI_CONFIG")"

View File

@ -29,6 +29,7 @@ RepartDirectories=mkosi.repart
OutputDirectory=build/mkosi.output
[Build]
ToolsTree=default
BuildDirectory=build/mkosi.builddir
CacheDirectory=build/mkosi.cache
BuildSourcesEphemeral=yes

View File

@ -3,6 +3,7 @@
[Build]
ToolsTreePackages=
gcc
gdb
gperf
lcov
llvm

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
ToolsTreeDistribution=centos
[Build]
ToolsTreeRepositories=epel,epel-next

View File

@ -5,6 +5,7 @@ ToolsTreeDistribution=opensuse
[Build]
ToolsTreePackages=
libz1
gh
mypy
pkgconfig(blkid)

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
PathExists=build/
[Build]
ExtraSearchPaths=build/

View File

@ -24,8 +24,8 @@ if command -v authselect >/dev/null; then
authselect select "$PROFILE"
if authselect list-features "$PROFILE" | grep -q "with-homed"; then
authselect enable-feature with-homed
if authselect list-features "$PROFILE" | grep -q "with-systemd-homed"; then
authselect enable-feature with-systemd-homed
fi
fi

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

@ -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

View File

@ -4,6 +4,7 @@
#include "analyze-chid.h"
#include "chid-fundamental.h"
#include "efi-api.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
@ -30,6 +31,20 @@ static int parse_chid_type(const char *s, size_t *ret) {
return 0;
}
static const char *const chid_smbios_friendly[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = "manufacturer",
[CHID_SMBIOS_FAMILY] = "family",
[CHID_SMBIOS_PRODUCT_NAME] = "product-name",
[CHID_SMBIOS_PRODUCT_SKU] = "product-sku",
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "baseboard-manufacturer",
[CHID_SMBIOS_BASEBOARD_PRODUCT] = "baseboard-product",
[CHID_SMBIOS_BIOS_VENDOR] = "bios-vendor",
[CHID_SMBIOS_BIOS_VERSION] = "bios-version",
[CHID_SMBIOS_BIOS_MAJOR] = "bios-major",
[CHID_SMBIOS_BIOS_MINOR] = "bios-minor",
[CHID_SMBIOS_ENCLOSURE_TYPE] = "enclosure-type",
};
static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = 'M',
[CHID_SMBIOS_FAMILY] = 'F',
@ -37,6 +52,11 @@ static const char chid_smbios_fields_char[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_PRODUCT_SKU] = 'S',
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = 'm',
[CHID_SMBIOS_BASEBOARD_PRODUCT] = 'p',
[CHID_SMBIOS_BIOS_VENDOR] = 'B',
[CHID_SMBIOS_BIOS_VERSION] = 'v',
[CHID_SMBIOS_BIOS_MAJOR] = 'R',
[CHID_SMBIOS_BIOS_MINOR] = 'r',
[CHID_SMBIOS_ENCLOSURE_TYPE] = 'e',
};
static char *chid_smbios_fields_string(uint32_t combination) {
@ -87,7 +107,7 @@ static void smbios_fields_free(char16_t *(*fields)[_CHID_SMBIOS_FIELDS_MAX]) {
free(*i);
}
int verb_chid(int argc, char *argv[], void *userdata) {
static int smbios_fields_acquire(char16_t *fields[static _CHID_SMBIOS_FIELDS_MAX]) {
static const char *const smbios_files[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_MANUFACTURER] = "sys_vendor",
@ -96,8 +116,115 @@ int verb_chid(int argc, char *argv[], void *userdata) {
[CHID_SMBIOS_PRODUCT_SKU] = "product_sku",
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = "board_vendor",
[CHID_SMBIOS_BASEBOARD_PRODUCT] = "board_name",
[CHID_SMBIOS_BIOS_VENDOR] = "bios_vendor",
[CHID_SMBIOS_BIOS_VERSION] = "bios_version",
[CHID_SMBIOS_BIOS_MAJOR] = "bios_release",
[CHID_SMBIOS_BIOS_MINOR] = "bios_release",
[CHID_SMBIOS_ENCLOSURE_TYPE] = "chassis_type",
};
int r;
_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");
for (ChidSmbiosFields f = 0; f < _CHID_SMBIOS_FIELDS_MAX; f++) {
_cleanup_free_ char *buf = NULL;
size_t size;
/* According to the CHID spec we should not generate CHIDs for SMBIOS fields that aren't set
* or are set to an empty string. Hence leave them NULL here. */
if (!smbios_files[f])
continue;
r = read_virtual_file_at(smbios_fd, smbios_files[f], SIZE_MAX, &buf, &size);
if (r == -ENOENT) {
log_debug_errno(r, "SMBIOS field '%s' not set, skipping.", smbios_files[f]);
continue;
}
if (r < 0)
return log_error_errno(r, "Failed to read SMBIOS field '%s': %m", smbios_files[f]);
if (size == 0 || (size == 1 && buf[0] == '\n')) {
log_debug("SMBIOS field '%s' is empty, skipping.", smbios_files[f]);
continue;
}
if (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]);
buf[size-1] = 0;
size--;
switch (f) {
case CHID_SMBIOS_BIOS_MAJOR:
case CHID_SMBIOS_BIOS_MINOR: {
/* The kernel exposes this a string <major>.<minor>, split them apart again. */
char *dot = memchr(buf, '.', size);
if (!dot)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "BIOS release field '%s' contains no dot?", smbios_files[f]);
const char *p;
if (f == CHID_SMBIOS_BIOS_MAJOR) {
*dot = 0;
p = buf;
} else {
assert(f == CHID_SMBIOS_BIOS_MINOR);
p = dot + 1;
}
/* The kernel exports the enclosure in decimal, we need it in hex (zero left-padded) */
uint8_t u;
r = safe_atou8(p, &u);
if (r < 0)
return log_error_errno(r, "Failed to parse BIOS release: %s", p);
buf = mfree(buf);
if (asprintf(&buf, "%02x", u) < 0)
return log_oom();
size = strlen(buf);
break;
}
case CHID_SMBIOS_ENCLOSURE_TYPE: {
/* The kernel exports the enclosure in decimal, we need it in hex (no padding!) */
uint8_t u;
r = safe_atou8(buf, &u);
if (r < 0)
return log_error_errno(r, "Failed to parse enclosure type: %s", buf);
buf = mfree(buf);
if (u == 0)
buf = strdup(""); /* zero is mapped to empty string */
else
(void) asprintf(&buf, "%x", u);
if (!buf)
return log_oom();
size = strlen(buf);
break;
}
default:
break;
}
fields[f] = utf8_to_utf16(buf, size);
if (!fields[f])
return log_oom();
}
return 0;
}
int verb_chid(int argc, char *argv[], void *userdata) {
_cleanup_(table_unrefp) Table *table = NULL;
int r;
@ -111,28 +238,10 @@ int verb_chid(int argc, char *argv[], void *userdata) {
(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();
}
r = smbios_fields_acquire(smbios_fields);
if (r < 0)
return r;
EFI_GUID chids[CHID_TYPES_MAX] = {};
chid_calculate((const char16_t* const*) smbios_fields, chids);
@ -172,9 +281,19 @@ int verb_chid(int argc, char *argv[], void *userdata) {
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();
_cleanup_free_ char *c = NULL;
if (smbios_fields[f]) {
_cleanup_free_ char *u = NULL;
u = utf16_to_utf8(smbios_fields[f], SIZE_MAX);
if (!u)
return log_oom();
c = cescape(u);
if (!c)
return log_oom();
}
if (!strextend(&legend,
ansi_grey(),
@ -188,11 +307,11 @@ int verb_chid(int argc, char *argv[], void *userdata) {
special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
" ",
ansi_normal(),
smbios_files[f],
chid_smbios_friendly[f],
ansi_grey(),
" (",
ansi_highlight(),
c,
c ? ansi_highlight() : ansi_grey(),
strna(c),
ansi_grey(),
")",
ansi_normal()))
@ -200,9 +319,9 @@ int verb_chid(int argc, char *argv[], void *userdata) {
w += separator * 3 +
4 +
utf8_console_width(smbios_files[f]) +
utf8_console_width(chid_smbios_friendly[f]) +
2 +
utf8_console_width(c) +
utf8_console_width(strna(c)) +
1;
if (w > 79) {

View File

@ -127,8 +127,10 @@ static int property_get_tainted(
assert(bus);
assert(reply);
assert(userdata);
_cleanup_free_ char *s = taint_string();
Manager *m = userdata;
_cleanup_free_ char *s = taint_string(m);
if (!s)
return log_oom();

View File

@ -939,6 +939,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
SD_BUS_PROPERTY("ActivationDetails", "a(ss)", bus_property_get_activation_details, offsetof(Unit, activation_details), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("DebugInvocation", "b", bus_property_get_bool, offsetof(Unit, debug_invocation), 0),
SD_BUS_PROPERTY("WasOnDependencyCycle", "b", NULL, offsetof(Unit, was_on_dependency_cycle), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_ARGS("Start",
SD_BUS_ARGS("s", mode),

View File

@ -117,10 +117,9 @@ int exec_context_put_load_credential(ExecContext *c, const char *id, const char
return -ENOMEM;
r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
if (r < 0) {
assert(r != -EEXIST);
assert(r != -EEXIST);
if (r < 0)
return r;
}
TAKE_PTR(lc);
}
@ -167,10 +166,9 @@ int exec_context_put_set_credential(
return -ENOMEM;
r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
if (r < 0) {
assert(r != -EEXIST);
assert(r != -EEXIST);
if (r < 0)
return r;
}
TAKE_PTR(sc);
}
@ -193,19 +191,22 @@ int exec_context_put_import_credential(ExecContext *c, const char *glob, const c
*ic = (ExecImportCredential) {
.glob = strdup(glob),
.rename = rename ? strdup(rename) : NULL,
};
if (!ic->glob || (rename && !ic->rename))
if (!ic->glob)
return -ENOMEM;
if (rename) {
ic->rename = strdup(rename);
if (!ic->rename)
return -ENOMEM;
}
if (ordered_set_contains(c->import_credentials, ic))
return 0;
r = ordered_set_ensure_put(&c->import_credentials, &exec_import_credential_hash_ops, ic);
if (r < 0) {
assert(r != -EEXIST);
assert(r != -EEXIST);
if (r < 0)
return r;
}
TAKE_PTR(ic);
@ -383,30 +384,46 @@ typedef enum CredentialSearchPath {
_CREDENTIAL_SEARCH_PATH_INVALID = -EINVAL,
} CredentialSearchPath;
static char** credential_search_path(const ExecParameters *params, CredentialSearchPath path) {
static int credential_search_path(const ExecParameters *params, CredentialSearchPath path, char ***ret) {
_cleanup_strv_free_ char **l = NULL;
int r;
assert(params);
assert(path >= 0 && path < _CREDENTIAL_SEARCH_PATH_MAX);
assert(ret);
/* Assemble a search path to find credentials in. For non-encrypted credentials, We'll look in
* /etc/credstore/ (and similar directories in /usr/lib/ + /run/). If we're looking for encrypted
* credentials, we'll look in /etc/credstore.encrypted/ (and similar dirs). */
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_ENCRYPTED, CREDENTIAL_SEARCH_PATH_ALL)) {
if (strv_extend(&l, params->received_encrypted_credentials_directory) < 0)
return NULL;
r = strv_extend(&l, params->received_encrypted_credentials_directory);
if (r < 0)
return r;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore.encrypted"), /* filter_duplicates= */ true) < 0)
return NULL;
_cleanup_strv_free_ char **add = NULL;
r = credential_store_path_encrypted(params->runtime_scope, &add);
if (r < 0)
return r;
r = strv_extend_strv_consume(&l, TAKE_PTR(add), /* filter_duplicates= */ false);
if (r < 0)
return r;
}
if (IN_SET(path, CREDENTIAL_SEARCH_PATH_TRUSTED, CREDENTIAL_SEARCH_PATH_ALL)) {
if (strv_extend(&l, params->received_credentials_directory) < 0)
return NULL;
r = strv_extend(&l, params->received_credentials_directory);
if (r < 0)
return r;
if (strv_extend_strv(&l, CONF_PATHS_STRV("credstore"), /* filter_duplicates= */ true) < 0)
return NULL;
_cleanup_strv_free_ char **add = NULL;
r = credential_store_path(params->runtime_scope, &add);
if (r < 0)
return r;
r = strv_extend_strv_consume(&l, TAKE_PTR(add), /* filter_duplicates= */ false);
if (r < 0)
return r;
}
if (DEBUG_LOGGING) {
@ -414,7 +431,8 @@ static char** credential_search_path(const ExecParameters *params, CredentialSea
log_debug("Credential search path is: %s", strempty(t));
}
return TAKE_PTR(l);
*ret = TAKE_PTR(l);
return 0;
}
struct load_cred_args {
@ -445,15 +463,38 @@ static int maybe_decrypt_and_write_credential(
assert(data || size == 0);
if (args->encrypted) {
r = decrypt_credential_and_warn(
id,
now(CLOCK_REALTIME),
/* tpm2_device= */ NULL,
/* tpm2_signature_path= */ NULL,
getuid(),
&IOVEC_MAKE(data, size),
CREDENTIAL_ANY_SCOPE,
&plaintext);
switch (args->params->runtime_scope) {
case RUNTIME_SCOPE_SYSTEM:
/* In system mode talk directly to the TPM */
r = decrypt_credential_and_warn(
id,
now(CLOCK_REALTIME),
/* tpm2_device= */ NULL,
/* tpm2_signature_path= */ NULL,
getuid(),
&IOVEC_MAKE(data, size),
CREDENTIAL_ANY_SCOPE,
&plaintext);
break;
case RUNTIME_SCOPE_USER:
/* In per user mode we'll not have access to the machine secret, nor to the TPM (most
* likely), hence go via the IPC service instead. Do this if we are run in root's
* per-user invocation too, to minimize differences and because isolating this logic
* into a separate process is generally a good thing anyway. */
r = ipc_decrypt_credential(
id,
now(CLOCK_REALTIME),
getuid(),
&IOVEC_MAKE(data, size),
/* flags= */ 0, /* only allow user creds in user scope */
&plaintext);
break;
default:
assert_not_reached();
}
if (r < 0)
return r;
@ -611,9 +652,9 @@ static int load_credential(
* directory we received ourselves. We don't support the AF_UNIX stuff in this mode, since we
* are operating on a credential store, i.e. this is guaranteed to be regular files. */
search_path = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL);
if (!search_path)
return -ENOMEM;
r = credential_search_path(args->params, CREDENTIAL_SEARCH_PATH_ALL, &search_path);
if (r < 0)
return r;
missing_ok = true;
} else
@ -797,9 +838,9 @@ static int acquire_credentials(
ORDERED_SET_FOREACH(ic, context->import_credentials) {
_cleanup_free_ char **search_path = NULL;
search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED);
if (!search_path)
return -ENOMEM;
r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_TRUSTED, &search_path);
if (r < 0)
return r;
args.encrypted = false;
@ -811,9 +852,10 @@ static int acquire_credentials(
return r;
search_path = strv_free(search_path);
search_path = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED);
if (!search_path)
return -ENOMEM;
r = credential_search_path(params, CREDENTIAL_SEARCH_PATH_ENCRYPTED, &search_path);
if (r < 0)
return r;
args.encrypted = true;

View File

@ -3853,7 +3853,7 @@ static void log_taint_string(Manager *m) {
m->taint_logged = true; /* only check for taint once */
_cleanup_free_ char *taint = taint_string();
_cleanup_free_ char *taint = taint_string(m);
if (isempty(taint))
return;
@ -5298,6 +5298,16 @@ int manager_allocate_idle_pipe(Manager *m) {
return 1;
}
bool manager_was_dependency_cycle(const Manager *m) {
const Unit *u;
HASHMAP_FOREACH(u, m->units)
if (u->was_on_dependency_cycle)
return true;
return false;
}
void unit_defaults_init(UnitDefaults *defaults, RuntimeScope scope) {
assert(defaults);
assert(scope >= 0);

View File

@ -679,6 +679,8 @@ OOMPolicy oom_policy_from_string(const char *s) _pure_;
void unit_defaults_init(UnitDefaults *defaults, RuntimeScope scope);
void unit_defaults_done(UnitDefaults *defaults);
bool manager_was_dependency_cycle(const Manager *m);
enum {
/* most important … */
EVENT_PRIORITY_USER_LOOKUP = SD_EVENT_PRIORITY_NORMAL-12,

View File

@ -9,6 +9,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "log.h"
#include "manager.h"
#include "os-util.h"
#include "path-util.h"
#include "strv.h"
@ -31,8 +32,8 @@ static int short_uid_gid_range(UIDRangeUsernsMode mode) {
return !uid_range_covers(p, 0, 65535);
}
char** taint_strv(void) {
const char *stage[12] = {};
char** taint_strv(const Manager *m) {
const char *stage[13] = {};
size_t n = 0;
/* Returns a "taint string", e.g. "local-hwclock:var-run-bad". Only things that are detected at
@ -78,16 +79,18 @@ char** taint_strv(void) {
stage[n++] = "short-uid-range";
if (short_uid_gid_range(GID_RANGE_USERNS_INSIDE) > 0)
stage[n++] = "short-gid-range";
if (manager_was_dependency_cycle(m))
stage[n++] = "dependency-cycle";
assert(n < ELEMENTSOF(stage) - 1); /* One extra for NULL terminator */
return strv_copy((char *const *) stage);
}
char* taint_string(void) {
char* taint_string(const Manager *m) {
_cleanup_strv_free_ char **taints = NULL;
taints = taint_strv();
taints = taint_strv(m);
if (!taints)
return NULL;

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
char** taint_strv(void);
char* taint_string(void);
typedef struct Manager Manager;
char** taint_strv(const Manager *m);
char* taint_string(const Manager *m);

View File

@ -366,8 +366,12 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
/* Have we seen this before? */
if (j->generation == generation) {
Job *k, *delete = NULL;
Job *k, *prev = NULL, *delete = NULL;
_cleanup_free_ char **array = NULL, *unit_ids = NULL;
_cleanup_free_ char *dot = NULL;
if (!strextend(&dot, "digraph {"))
log_oom();
/* If the marker is NULL we have been here already and decided the job was loop-free from
* here. Hence shortcut things and return right-away. */
@ -382,6 +386,18 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
/* For logging below */
if (strv_push_pair(&array, k->unit->id, (char*) job_type_to_string(k->type)) < 0)
log_oom();
/* Add edge to the graph when we already have part of it. */
else if (dot) {
r = strextendf(&dot, "\"%s\" -> \"%s\";", k->unit->id, prev ? prev->unit->id : j->unit->id);
if (r < 0) {
log_oom();
/* Dot output is not essential so let's get rid of it in case we ran into OOM. */
dot = mfree(dot);
}
}
/* Mark every unit along the cycle */
k->unit->was_on_dependency_cycle = true;
if (!delete && hashmap_contains(tr->jobs, k->unit) && !job_matters_to_anchor(k))
/* Ok, we can drop this one, so let's do so. */
@ -390,8 +406,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
/* Check if this in fact was the beginning of the cycle */
if (k == j)
break;
prev = k;
}
if (dot && !strextend(&dot, "}"))
log_oom();
unit_ids = merge_unit_ids(j->manager->unit_log_field, array); /* ignore error */
STRV_FOREACH_PAIR(unit_id, job_type, array)
@ -403,6 +424,12 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
*unit_id, *job_type),
"%s", strna(unit_ids));
if (dot && IN_SET(log_get_target(), LOG_TARGET_AUTO, LOG_TARGET_JOURNAL, LOG_TARGET_JOURNAL_OR_KMSG)) {
log_struct(LOG_WARNING,
LOG_UNIT_MESSAGE(j->unit, "Ordering cycle generated, see TRANSACTION_CYCLE= for details. Note that each arc represents Before= dependency."),
"TRANSACTION_CYCLE=%s", dot);
}
if (delete) {
const char *status;
/* logging for j not k here to provide a consistent narrative */

View File

@ -3834,6 +3834,7 @@ void unit_reset_failed(Unit *u) {
ratelimit_reset(&u->start_ratelimit);
u->start_limit_hit = false;
u->debug_invocation = false;
u->was_on_dependency_cycle = false;
}
Unit *unit_following(Unit *u) {

View File

@ -464,6 +464,9 @@ typedef struct Unit {
/* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
* == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
signed int last_section_private:2;
/* Remember this unit was part of some dependency cycle. */
bool was_on_dependency_cycle;
} Unit;
typedef struct UnitStatusMessageFormats {

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

@ -28,23 +28,36 @@
#include "memory-util-fundamental.h"
#include "sha1-fundamental.h"
static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], uint32_t mask, EFI_GUID *ret_chid) {
static void get_chid(
const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX],
uint32_t mask,
EFI_GUID *ret_chid) {
assert(mask != 0);
assert(ret_chid);
const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */
struct sha1_ctx ctx = {};
sha1_init_ctx(&ctx);
static const EFI_GUID namespace = { UINT32_C(0x12d8ff70), UINT16_C(0x7f4c), UINT16_C(0x7d4c), {} }; /* Swapped to BE */
sha1_process_bytes(&namespace, sizeof(namespace), &ctx);
for (unsigned i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++)
if ((mask >> i) & 1) {
if (i > 0)
sha1_process_bytes(L"&", 2, &ctx);
sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx);
for (ChidSmbiosFields i = 0; i < _CHID_SMBIOS_FIELDS_MAX; i++) {
if (!FLAGS_SET(mask, UINT32_C(1) << i))
continue;
if (!smbios_fields[i]) {
/* If some SMBIOS field is missing, don't generate the CHID, as per spec */
memzero(ret_chid, sizeof(EFI_GUID));
return;
}
if (i > 0)
sha1_process_bytes(L"&", 2, &ctx);
sha1_process_bytes(smbios_fields[i], strlen16(smbios_fields[i]) * sizeof(char16_t), &ctx);
}
uint8_t hash[SHA1_DIGEST_SIZE];
sha1_finish_ctx(&ctx, hash);
@ -62,6 +75,30 @@ static void get_chid(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIE
}
const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[0] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
[1] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
[2] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VENDOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_VERSION) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MAJOR) |
(UINT32_C(1) << CHID_SMBIOS_BIOS_MINOR),
[3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
@ -102,18 +139,26 @@ const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[11] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY),
[12] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_ENCLOSURE_TYPE),
[13] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
[14] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER),
};
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]) {
assert(smbios_fields);
assert(ret_chids);
for (size_t i = 0; i < CHID_TYPES_MAX; i++)
if (chid_smbios_table[i] != 0)
get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]);
else
for (size_t i = 0; i < CHID_TYPES_MAX; i++) {
if (chid_smbios_table[i] == 0) {
memzero(&ret_chids[i], sizeof(EFI_GUID));
continue;
}
get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]);
}
}

View File

@ -20,6 +20,11 @@ typedef enum ChidSmbiosFields {
CHID_SMBIOS_PRODUCT_SKU,
CHID_SMBIOS_BASEBOARD_MANUFACTURER,
CHID_SMBIOS_BASEBOARD_PRODUCT,
CHID_SMBIOS_BIOS_VENDOR,
CHID_SMBIOS_BIOS_VERSION,
CHID_SMBIOS_BIOS_MAJOR,
CHID_SMBIOS_BIOS_MINOR,
CHID_SMBIOS_ENCLOSURE_TYPE,
_CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields;

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

@ -84,3 +84,19 @@ static inline char** generator_binary_paths(RuntimeScope runtime_scope) {
static inline char** env_generator_binary_paths(RuntimeScope runtime_scope) {
return generator_binary_paths_internal(runtime_scope, true);
}
static inline int credential_store_path(RuntimeScope runtime_scope, char ***ret) {
return sd_path_lookup_strv(
runtime_scope == RUNTIME_SCOPE_SYSTEM ?
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE : SD_PATH_USER_SEARCH_CREDENTIAL_STORE,
/* suffix= */ NULL,
ret);
}
static inline int credential_store_path_encrypted(RuntimeScope runtime_scope, char ***ret) {
return sd_path_lookup_strv(
runtime_scope == RUNTIME_SCOPE_SYSTEM ?
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED : SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
/* suffix= */ NULL,
ret);
}

View File

@ -36,7 +36,12 @@ static int from_environment(const char *envname, const char *fallback, const cha
return -ENXIO;
}
static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) {
static int from_home_dir(
const char *envname,
const char *suffix,
char **buffer,
const char **ret) {
_cleanup_free_ char *h = NULL;
int r;
@ -350,6 +355,30 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
case SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR:
*ret = USER_ENV_GENERATOR_DIR;
return 0;
case SD_PATH_SYSTEM_CREDENTIAL_STORE:
*ret = "/etc/credstore";
return 0;
case SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED:
*ret = "/etc/credstore.encrypted";
return 0;
case SD_PATH_USER_CREDENTIAL_STORE:
r = xdg_user_config_dir("credstore", buffer);
if (r < 0)
return r;
*ret = *buffer;
return 0;
case SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED:
r = xdg_user_config_dir("credstore.encrypted", buffer);
if (r < 0)
return r;
*ret = *buffer;
return 0;
}
return -EOPNOTSUPP;
@ -366,12 +395,12 @@ static int get_path_alloc(uint64_t type, const char *suffix, char **ret) {
if (r < 0)
return r;
if (suffix) {
if (!isempty(suffix)) {
char *suffixed = path_join(p, suffix);
if (!suffixed)
return -ENOMEM;
path_simplify(suffixed);
path_simplify_full(suffixed, PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
free_and_replace(buffer, suffixed);
} else if (!buffer) {
@ -601,8 +630,55 @@ static int get_search(uint64_t type, char ***ret) {
case SD_PATH_SYSTEMD_SEARCH_NETWORK:
return strv_from_nulstr(ret, NETWORK_DIRS_NULSTR);
case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE:
case SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED: {
const char *suffix =
type == SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED ? "credstore.encrypted" : "credstore";
_cleanup_strv_free_ char **l = NULL;
FOREACH_STRING(d, CONF_PATHS("")) {
char *j = path_join(d, suffix);
if (!j)
return -ENOMEM;
r = strv_consume(&l, TAKE_PTR(j));
if (r < 0)
return r;
}
*ret = TAKE_PTR(l);
return 0;
}
case SD_PATH_USER_SEARCH_CREDENTIAL_STORE:
case SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED: {
const char *suffix =
type == SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED ? "credstore.encrypted" : "credstore";
static const uint64_t dirs[] = {
SD_PATH_USER_CONFIGURATION,
SD_PATH_USER_RUNTIME,
SD_PATH_USER_LIBRARY_PRIVATE,
};
_cleanup_strv_free_ char **l = NULL;
FOREACH_ELEMENT(d, dirs) {
_cleanup_free_ char *p = NULL;
r = sd_path_lookup(*d, suffix, &p);
if (r == -ENXIO)
continue;
if (r < 0)
return r;
r = strv_consume(&l, TAKE_PTR(p));
if (r < 0)
return r;
}
*ret = TAKE_PTR(l);
return 0;
}}
return -EOPNOTSUPP;
}
@ -637,7 +713,7 @@ _public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***ret)
if (!path_extend(i, suffix))
return -ENOMEM;
path_simplify(*i);
path_simplify_full(*i, PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
}
*ret = TAKE_PTR(l);

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

@ -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

@ -3167,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)

View File

@ -14,6 +14,7 @@
#include "main-func.h"
#include "pager.h"
#include "pretty-print.h"
#include "sort-util.h"
#include "string-util.h"
static const char *arg_suffix = NULL;
@ -101,27 +102,50 @@ static const char* const path_table[_SD_PATH_MAX] = {
[SD_PATH_SYSTEMD_USER_ENVIRONMENT_GENERATOR] = "systemd-user-environment-generator",
[SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR] = "systemd-search-system-environment-generator",
[SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR] = "systemd-search-user-environment-generator",
[SD_PATH_SYSTEM_CREDENTIAL_STORE] = "system-credential-store",
[SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE] = "system-search-credential-store",
[SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED] = "system-credential-store-encrypted",
[SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED] = "system-search-credential-store-encrypted",
[SD_PATH_USER_CREDENTIAL_STORE] = "user-credential-store",
[SD_PATH_USER_SEARCH_CREDENTIAL_STORE] = "user-search-credential-store",
[SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED] = "user-credential-store-encrypted",
[SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED] = "user-search-credential-store-encrypted",
};
static int order_cmp(const size_t *a, const size_t *b) {
assert(*a < ELEMENTSOF(path_table));
assert(*b < ELEMENTSOF(path_table));
return strcmp(path_table[*a], path_table[*b]);
}
static int list_paths(void) {
int r = 0;
int ret = 0, r;
pager_open(arg_pager_flags);
for (size_t i = 0; i < ELEMENTSOF(path_table); i++) {
_cleanup_free_ char *p = NULL;
int q;
size_t order[ELEMENTSOF(path_table)];
q = sd_path_lookup(i, arg_suffix, &p);
if (q < 0) {
log_full_errno(q == -ENXIO ? LOG_DEBUG : LOG_ERR,
q, "Failed to query %s: %m", path_table[i]);
if (q != -ENXIO)
RET_GATHER(r, q);
for (size_t i = 0; i < ELEMENTSOF(order); i++)
order[i] = i;
typesafe_qsort(order, ELEMENTSOF(order), order_cmp);
for (size_t i = 0; i < ELEMENTSOF(order); i++) {
size_t j = order[i];
const char *t = ASSERT_PTR(path_table[j]);
_cleanup_free_ char *p = NULL;
r = sd_path_lookup(j, arg_suffix, &p);
if (r < 0) {
log_full_errno(r == -ENXIO ? LOG_DEBUG : LOG_ERR, r, "Failed to query %s, proceeding: %m", t);
if (r != -ENXIO)
RET_GATHER(ret, r);
continue;
}
printf("%s%s:%s %s\n", ansi_highlight(), path_table[i], ansi_normal(), p);
printf("%s%s:%s %s\n", ansi_highlight(), t, ansi_normal(), p);
}
return r;
@ -154,14 +178,16 @@ static int help(void) {
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] [NAME...]\n\n"
"Show system and user paths.\n\n"
printf("%s [OPTIONS...] [NAME...]\n"
"\n%sShow system and user paths.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --suffix=SUFFIX Suffix to append to paths\n"
" --no-pager Do not pipe output into a pager\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
return 0;
@ -224,10 +250,11 @@ static int run(int argc, char* argv[]) {
if (r <= 0)
return r;
if (argc > optind)
if (argc > optind) {
r = 0;
for (int i = optind; i < argc; i++)
RET_GATHER(r, print_path(argv[i]));
else
} else
r = list_paths();
return r;

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

@ -12,6 +12,8 @@
#include <sys/stat.h>
#include <unistd.h>
#include "sd-path.h"
#include "alloc-util.h"
#include "blockdev-util.h"
#include "btrfs-util.h"
@ -553,12 +555,95 @@ static int image_make(
return -EMEDIUMTYPE;
}
static const char *pick_image_search_path(ImageClass class) {
if (class < 0 || class >= _IMAGE_CLASS_MAX)
return NULL;
static int pick_image_search_path(
RuntimeScope scope,
ImageClass class,
char ***ret) {
/* Use the initrd search path if there is one, otherwise use the common one */
return in_initrd() && image_search_path_initrd[class] ? image_search_path_initrd[class] : image_search_path[class];
int r;
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
assert(class < _IMAGE_CLASS_MAX);
assert(ret);
if (class < 0) {
*ret = NULL;
return 0;
}
if (scope < 0) {
_cleanup_strv_free_ char **a = NULL, **b = NULL;
r = pick_image_search_path(RUNTIME_SCOPE_USER, class, &a);
if (r < 0)
return r;
r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, &b);
if (r < 0)
return r;
r = strv_extend_strv(&a, b, /* filter_duplicates= */ false);
if (r < 0)
return r;
*ret = TAKE_PTR(a);
return 0;
}
switch (scope) {
case RUNTIME_SCOPE_SYSTEM: {
const char *ns;
/* Use the initrd search path if there is one, otherwise use the common one */
ns = in_initrd() && image_search_path_initrd[class] ?
image_search_path_initrd[class] :
image_search_path[class];
if (!ns)
break;
_cleanup_strv_free_ char **search = strv_split_nulstr(ns);
if (!search)
return -ENOMEM;
*ret = TAKE_PTR(search);
return 0;
}
case RUNTIME_SCOPE_USER: {
if (class != IMAGE_MACHINE)
break;
static const uint64_t dirs[] = {
SD_PATH_USER_RUNTIME,
SD_PATH_USER_STATE_PRIVATE,
SD_PATH_USER_LIBRARY_PRIVATE,
};
_cleanup_strv_free_ char **search = NULL;
FOREACH_ELEMENT(d, dirs) {
_cleanup_free_ char *p = NULL;
r = sd_path_lookup(*d, "machines", &p);
if (r == -ENXIO) /* No XDG_RUNTIME_DIR set */
continue;
if (r < 0)
return r;
r = strv_consume(&search, TAKE_PTR(p));
if (r < 0)
return r;
}
*ret = TAKE_PTR(search);
return 0;
}
default:
assert_not_reached();
}
*ret = NULL;
return 0;
}
static char **make_possible_filenames(ImageClass class, const char *image_name) {
@ -592,7 +677,8 @@ static char **make_possible_filenames(ImageClass class, const char *image_name)
return TAKE_PTR(l);
}
int image_find(ImageClass class,
int image_find(RuntimeScope scope,
ImageClass class,
const char *name,
const char *root,
Image **ret) {
@ -602,6 +688,7 @@ int image_find(ImageClass class,
* some root directory.) */
int open_flags = root ? O_NOFOLLOW : 0, r;
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
assert(class >= 0);
assert(class < _IMAGE_CLASS_MAX);
assert(name);
@ -614,11 +701,16 @@ int image_find(ImageClass class,
if (!names)
return -ENOMEM;
NULSTR_FOREACH(path, pick_image_search_path(class)) {
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
if (r < 0)
return r;
STRV_FOREACH(path, search) {
_cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL;
r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT)
continue;
if (r < 0)
@ -722,7 +814,7 @@ int image_find(ImageClass class,
}
}
if (class == IMAGE_MACHINE && streq(name, ".host")) {
if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && streq(name, ".host")) {
r = image_make(class,
".host",
/* dir_fd= */ AT_FDCWD,
@ -771,14 +863,21 @@ int image_from_path(const char *path, Image **ret) {
ret);
}
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) {
int image_find_harder(
RuntimeScope scope,
ImageClass class,
const char *name_or_path,
const char *root,
Image **ret) {
if (image_name_is_valid(name_or_path))
return image_find(class, name_or_path, root, ret);
return image_find(scope, class, name_or_path, root, ret);
return image_from_path(name_or_path, ret);
}
int image_discover(
RuntimeScope scope,
ImageClass class,
const char *root,
Hashmap *h) {
@ -788,15 +887,21 @@ int image_discover(
* some root directory.) */
int open_flags = root ? O_NOFOLLOW : 0, r;
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
assert(class >= 0);
assert(class < _IMAGE_CLASS_MAX);
assert(h);
NULSTR_FOREACH(path, pick_image_search_path(class)) {
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
if (r < 0)
return r;
STRV_FOREACH(path, search) {
_cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL;
r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT)
continue;
if (r < 0)
@ -946,7 +1051,7 @@ int image_discover(
}
}
if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
_cleanup_(image_unrefp) Image *image = NULL;
r = image_make(IMAGE_MACHINE,
@ -1063,7 +1168,7 @@ static int rename_auxiliary_file(const char *path, const char *new_name, const c
return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
}
int image_rename(Image *i, const char *new_name) {
int image_rename(Image *i, const char *new_name, RuntimeScope scope) {
_cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
_cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
_cleanup_strv_free_ char **settings = NULL;
@ -1098,7 +1203,7 @@ int image_rename(Image *i, const char *new_name) {
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL);
if (r >= 0)
return -EEXIST;
if (r != -ENOENT)
@ -1185,7 +1290,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch
return copy_file_atomic(path, rs, 0664, COPY_REFLINK);
}
int image_clone(Image *i, const char *new_name, bool read_only) {
int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope) {
_cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT;
_cleanup_strv_free_ char **settings = NULL;
_cleanup_free_ char *roothash = NULL;
@ -1212,7 +1317,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL);
if (r >= 0)
return -EEXIST;
if (r != -ENOENT)
@ -1646,24 +1751,35 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
}
bool image_in_search_path(
RuntimeScope scope,
ImageClass class,
const char *root,
const char *image) {
int r;
assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL);
assert(class >= 0);
assert(class < _IMAGE_CLASS_MAX);
assert(image);
NULSTR_FOREACH(path, pick_image_search_path(class)) {
_cleanup_strv_free_ char **search = NULL;
r = pick_image_search_path(scope, class, &search);
if (r < 0)
return r;
STRV_FOREACH(path, search) {
const char *p, *q;
size_t k;
if (!empty_or_root(root)) {
q = path_startswith(path, root);
q = path_startswith(*path, root);
if (!q)
continue;
} else
q = path;
q = *path;
p = path_startswith(q, path);
p = path_startswith(q, *path);
if (!p)
continue;

View File

@ -13,6 +13,7 @@
#include "macro.h"
#include "os-util.h"
#include "path-util.h"
#include "runtime-scope.h"
#include "string-util.h"
#include "time-util.h"
@ -60,14 +61,14 @@ Image *image_ref(Image *i);
DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
int image_find(ImageClass class, const char *name, const char *root, Image **ret);
int image_find(RuntimeScope scope, ImageClass class, const char *name, const char *root, Image **ret);
int image_from_path(const char *path, Image **ret);
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret);
int image_discover(ImageClass class, const char *root, Hashmap *map);
int image_find_harder(RuntimeScope scope, ImageClass class, const char *name_or_path, const char *root, Image **ret);
int image_discover(RuntimeScope scope, ImageClass class, const char *root, Hashmap *map);
int image_remove(Image *i);
int image_rename(Image *i, const char *new_name);
int image_clone(Image *i, const char *new_name, bool read_only);
int image_rename(Image *i, const char *new_name, RuntimeScope scope);
int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope);
int image_read_only(Image *i, bool b);
const char* image_type_to_string(ImageType t) _const_;
@ -80,7 +81,7 @@ int image_set_limit(Image *i, uint64_t referenced_max);
int image_read_metadata(Image *i, const ImagePolicy *image_policy);
bool image_in_search_path(ImageClass class, const char *root, const char *image);
bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image);
static inline char **image_extension_release(Image *image, ImageClass class) {
assert(image);

View File

@ -2031,7 +2031,7 @@ static int image_discover_and_read_metadata(
if (!images)
return log_oom();
r = image_discover(image_class, arg_root, images);
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images);
if (r < 0)
return log_error_errno(r, "Failed to discover images: %m");
@ -2278,7 +2278,7 @@ static int verb_list(int argc, char **argv, void *userdata) {
if (!images)
return log_oom();
r = image_discover(arg_image_class, arg_root, images);
r = image_discover(RUNTIME_SCOPE_SYSTEM, arg_image_class, arg_root, images);
if (r < 0)
return log_error_errno(r, "Failed to discover images: %m");
@ -2339,7 +2339,7 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl
if (!images)
return -ENOMEM;
r = image_discover(image_class, arg_root, images);
r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images);
if (r < 0)
return r;

View File

@ -168,6 +168,7 @@ typedef struct UnitStatusInfo {
const char *active_state;
const char *freezer_state;
const char *sub_state;
bool was_on_dependency_cycle;
const char *unit_file_state;
const char *unit_file_preset;
@ -374,12 +375,13 @@ static void print_status_info(
bool show_preset = !isempty(i->unit_file_preset) &&
show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
printf(" Loaded: %s%s%s (%s; %s%s%s%s%s%s%s)\n",
printf(" Loaded: %s%s%s (%s; %s%s%s%s%s%s%s%s%s%s%s)\n",
on, strna(i->load_state), off,
path,
enable_on, i->unit_file_state, enable_off,
show_preset ? "; preset: " : "",
preset_on, show_preset ? i->unit_file_preset : "", preset_off);
preset_on, show_preset ? i->unit_file_preset : "", preset_off,
i->was_on_dependency_cycle ? ", " : "", ansi_highlight_red(), i->was_on_dependency_cycle ? "dependency-cycle" : "", ansi_normal());
} else if (path)
printf(" Loaded: %s%s%s (%s)\n",
@ -2078,6 +2080,7 @@ static int show_one(
{ "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
{ "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
{ "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
{ "WasOnDependencyCycle", "b", NULL, offsetof(UnitStatusInfo, was_on_dependency_cycle) },
{ "Job", "(uo)", bus_map_job_id, offsetof(UnitStatusInfo, job_id) },
{ "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
{ "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },

View File

@ -120,6 +120,16 @@ enum {
SD_PATH_USER_STATE_PRIVATE,
/* credential store */
SD_PATH_SYSTEM_CREDENTIAL_STORE,
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE,
SD_PATH_SYSTEM_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_SYSTEM_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_USER_CREDENTIAL_STORE,
SD_PATH_USER_SEARCH_CREDENTIAL_STORE,
SD_PATH_USER_CREDENTIAL_STORE_ENCRYPTED,
SD_PATH_USER_SEARCH_CREDENTIAL_STORE_ENCRYPTED,
_SD_PATH_MAX
};

View File

@ -46,6 +46,8 @@ typedef struct Manager {
Hashmap *polkit_registry;
sd_event_source *notify_event;
RuntimeScope runtime_scope; /* For now only RUNTIME_SCOPE_SYSTEM */
} Manager;
/* Forward declare so that jobs can call it on exit */
@ -1730,10 +1732,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;
@ -1795,7 +1801,7 @@ static int manager_enumerate_image_class(Manager *m, TargetClass class) {
if (!images)
return -ENOMEM;
r = image_discover((ImageClass) class, NULL, images);
r = image_discover(m->runtime_scope, (ImageClass) class, NULL, images);
if (r < 0)
return r;

View File

@ -11,6 +11,7 @@ const char16_t *const test_fields[_CHID_SMBIOS_FIELDS_MAX] = {
[CHID_SMBIOS_FAMILY] = u"To be filled by O.E.M.",
[CHID_SMBIOS_BASEBOARD_PRODUCT] = u"MPG X670E CARBON WIFI (MS-7D70)",
[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = u"Micro-Star International Co., Ltd.",
[CHID_SMBIOS_ENCLOSURE_TYPE] = u"3",
};
/* Actual output of `fwupdtool hwids`:
@ -51,7 +52,7 @@ Extra Hardware IDs
{7b3d90ce-ed79-5951-a48a-764ea9f11146} <- Manufacturer + BiosVendor
*/
static const EFI_GUID actual_chids[] = {
static const EFI_GUID actual_chids[CHID_TYPES_MAX] = {
{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
@ -64,9 +65,9 @@ static const EFI_GUID actual_chids[] = {
{0xc12c1f4a, 0x332d, 0x5d72, {0xaa, 0x36, 0x7a, 0x3d, 0x41, 0x3b, 0x47, 0x9a}},
{0x28ac9cf2, 0x5bde, 0x59f7, {0xae, 0xbe, 0x4b, 0x3d, 0x00, 0x80, 0x90, 0xfe}},
{0xe821e0e2, 0xe11a, 0x5e94, {0xbf, 0x5d, 0xff, 0xe5, 0x3c, 0x5e, 0x50, 0x48}},
{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{0xbdd76d3e, 0x147f, 0x58a9, {0xa0, 0xb2, 0x42, 0x13, 0x64, 0x54, 0xed, 0x07}},
{0xb2e58e8b, 0xfb10, 0x5cd0, {0x8f, 0xb0, 0x5b, 0xd9, 0x31, 0xf1, 0x87, 0x1a}},
{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{0x50af5797, 0xa2f2, 0x58b1, {0x9a, 0x1a, 0x45, 0x3b, 0xcb, 0xb2, 0xe0, 0x25}},
};
TEST(chid) {

View File

@ -1398,6 +1398,10 @@ static void run_tests(RuntimeScope scope, char **patterns) {
ASSERT_NOT_NULL(unit_paths = strjoin(PRIVATE_UNIT_DIR, ":", user_runtime_unit_dir));
ASSERT_OK(setenv_unit_path(unit_paths));
/* Write credential for test-execute-load-credential to the fake runtime dir, too */
_cleanup_free_ char *j = ASSERT_PTR(path_join(runtime_dir, "credstore/test-execute.load-credential"));
ASSERT_OK(write_string_file(j, "foo", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755));
r = manager_new(scope, MANAGER_TEST_RUN_BASIC, &m);
if (manager_errno_skip_test(r))
return (void) log_tests_skipped_errno(r, "manager_new");

View File

@ -1,10 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "manager.h"
#include "taint.h"
#include "tests.h"
TEST(taint_string) {
_cleanup_free_ char *a = taint_string();
Manager m = {};
_cleanup_free_ char *a = taint_string(&m);
assert_se(a);
log_debug("taint string: '%s'", a);

View File

@ -2236,7 +2236,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)

View File

@ -459,3 +459,72 @@ test unit (be it a static one or a transient one created via systemd-run), with
main mount namespace - in that case use `IGNORE_MISSING_COVERAGE=yes` in the
test definition (i.e. `TEST-*-NAME/test.sh`), which will skip the post-test
check for missing coverage for the respective test.
## Fuzzers
systemd includes fuzzers in `src/fuzz/` that use libFuzzer and are automatically
run by [OSS-Fuzz](https://github.com/google/oss-fuzz) with sanitizers. To add a
fuzz target, create a new `src/fuzz/fuzz-foo.c` file with a
`LLVMFuzzerTestOneInput` function and add it to the list in
`src/fuzz/meson.build`.
Whenever possible, a seed corpus and a dictionary should also be added with new
fuzz targets. The dictionary should be named `src/fuzz/fuzz-foo.dict` and the
seed corpus should be built and exported as `$OUT/fuzz-foo_seed_corpus.zip` in
`tools/oss-fuzz.sh`.
The fuzzers can be built locally if you have libFuzzer installed by running
`tools/oss-fuzz.sh`, or by running:
```sh
CC=clang CXX=clang++ \
meson setup build-libfuzz -Dllvm-fuzz=true -Db_sanitize=address,undefined -Db_lundef=false \
-Dc_args='-fno-omit-frame-pointer -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'
ninja -C build-libfuzz fuzzers
```
Each fuzzer then can be then run manually together with a directory containing
the initial corpus:
```
export UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
build-libfuzz/fuzz-varlink-idl test/fuzz/fuzz-varlink-idl/
```
Note: the `halt_on_error=1` UBSan option is especially important, otherwise the
fuzzer won't crash when undefined behavior is triggered.
You should also confirm that the fuzzers can be built and run using
[the OSS-Fuzz toolchain](https://google.github.io/oss-fuzz/advanced-topics/reproducing/#building-using-docker):
```sh
path_to_systemd=...
git clone --depth=1 https://github.com/google/oss-fuzz
cd oss-fuzz
for sanitizer in address undefined memory; do
for engine in libfuzzer afl honggfuzz; do
./infra/helper.py build_fuzzers --sanitizer "$sanitizer" --engine "$engine" \
--clean systemd "$path_to_systemd"
./infra/helper.py check_build --sanitizer "$sanitizer" --engine "$engine" \
-e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
done
done
./infra/helper.py build_fuzzers --clean --architecture i386 systemd "$path_to_systemd"
./infra/helper.py check_build --architecture i386 -e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
./infra/helper.py build_fuzzers --clean --sanitizer coverage systemd "$path_to_systemd"
./infra/helper.py coverage --no-corpus-download systemd
```
If you find a bug that impacts the security of systemd, please follow the
guidance in [CONTRIBUTING.md](/CONTRIBUTING) on how to report a security
vulnerability.
For more details on building fuzzers and integrating with OSS-Fuzz, visit:
- [Setting up a new project - OSS-Fuzz](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
- [Tutorials - OSS-Fuzz](https://google.github.io/oss-fuzz/reference/useful-links/#tutorials)

View File

@ -1129,7 +1129,7 @@ testcase_unpriv() {
local tmpdir name
tmpdir="$(mktemp -d /var/tmp/TEST-13-NSPAWN.unpriv.XXX)"
name="unpriv-${tmpdir##*.}"
name="unprv-${tmpdir##*.}"
trap 'rm -fr ${tmpdir@Q} || true; rm -f /run/verity.d/test-13-nspawn-${name@Q} || true' RETURN ERR
create_dummy_ddi "$tmpdir" "$name"
chown --recursive testuser: "$tmpdir"
@ -1141,6 +1141,17 @@ testcase_unpriv() {
-- \
systemd-nspawn --pipe --private-network --register=no --keep-unit --image="$tmpdir/$name.raw" echo hello >"$tmpdir/stdout.txt"
echo hello | cmp "$tmpdir/stdout.txt" -
# Make sure per-user search path logic works
systemd-run --pipe --uid=testuser mkdir -p /home/testuser/.local/state/machines
systemd-run --pipe --uid=testuser ln -s "$tmpdir/$name.raw" /home/testuser/.local/state/machines/"x$name.raw"
systemd-run \
--pipe \
--uid=testuser \
--property=Delegate=yes \
-- \
systemd-nspawn --pipe --private-network --register=no --keep-unit --machine="x$name" echo hello >"$tmpdir/stdout.txt"
echo hello | cmp "$tmpdir/stdout.txt" -
}
testcase_fuse() {

View File

@ -615,6 +615,10 @@ grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/
grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
systemd-dissect --discover --system
systemd-dissect --discover --user
systemd-dissect --discover --system --user
LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")"
# Wait until the symlinks we want to test are established

View File

@ -490,7 +490,7 @@ cmp /tmp/vlcredsdata /tmp/vlcredsdata2
rm /tmp/vlcredsdata /tmp/vlcredsdata2
clean_usertest() {
rm -f /tmp/usertest.data /tmp/usertest.data
rm -f /tmp/usertest.data /tmp/usertest.data /tmp/brummbaer.data
}
trap clean_usertest EXIT
@ -520,6 +520,12 @@ XDG_RUNTIME_DIR=/run/user/0 systemd-run --pipe --user --unit=waldi.service -p Lo
# Test mount unit with credential
test_mount_with_credential
# Fully unpriv operation
dd if=/dev/urandom of=/tmp/brummbaer.data bs=4096 count=1
run0 -u testuser --pipe mkdir -p /home/testuser/.config/credstore.encrypted
run0 -u testuser --pipe systemd-creds encrypt --user --name=brummbaer - /home/testuser/.config/credstore.encrypted/brummbaer < /tmp/brummbaer.data
run0 -u testuser --pipe systemd-run --user --pipe -p ImportCredential=brummbaer systemd-creds cat brummbaer | cmp /tmp/brummbaer.data
systemd-analyze log-level info
touch /testok

View File

@ -18,6 +18,7 @@ BusName=org.freedesktop.home1
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER CAP_FSETID CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE CAP_SETPCAP CAP_DAC_READ_SEARCH CAP_SETFCAP
DeviceAllow=/dev/loop-control rw
DeviceAllow=/dev/mapper/control rw
DeviceAllow=/dev/btrfs-control rw
DeviceAllow=block-* rw
DeviceAllow=char-hidraw rw
ExecStart={{LIBEXECDIR}}/systemd-homed

View File

@ -20,7 +20,7 @@ ConditionPathExists=/proc/pressure/cpu
ConditionPathExists=/proc/pressure/io
ConditionPathExists=/proc/pressure/memory
Requires=systemd-oomd.socket
After=systemd-oomd.socket
After=systemd-oomd.socket systemd-sysusers.service
[Service]
AmbientCapabilities=CAP_KILL CAP_DAC_OVERRIDE