Compare commits

...

71 Commits

Author SHA1 Message Date
Dan Streetman 9ab9b3f1c2
Merge 413f6e0f56 into e5011dd239 2024-11-06 08:39:01 -08:00
Daan De Meyer e5011dd239
Introduce systemd-sbsign to do secure boot signing (#35021)
Currently in mkosi and ukify we use sbsigntools to do secure boot
signing. This has multiple issues:

- sbsigntools is practically unmaintained, sbvarsign is completely
broken with the latest gnu-efi when built without -fshort-wchar and
upstream has completely ignored my bug report about this.
- sbsigntools only supports openssl engines and not the new providers
API.
- sbsigntools doesn't allow us to cache hardware token pins in the
kernel keyring like we do nowadays when we sign stuff ourselves in
systemd-repart or systemd-measure

There are alternative tools like sbctl and pesign but these do not
support caching hardware token pins in the kernel keyring either.

To get around the issues with sbsigntools, let's introduce our own
tool systemd-sbsign to do secure boot signing. This allows us to
take advantage of our own openssl infra so that hardware token pins
are cached in the kernel keyring as expected and we get openssl
provider support as well.
2024-11-06 17:38:10 +01:00
Luca Boccassi 66d044b560 Update NEWS for recent PRs 2024-11-06 15:50:59 +00:00
Michele Dionisio d865abf9eb networkd: add possibility to specify MulticastIGMPVersion 2024-11-06 15:50:27 +00:00
Luca Boccassi f72fe2d73c
Grammar and formatting for DeviceTree docs (#35050) 2024-11-06 15:13:18 +00:00
Daan De Meyer 65fbf3b194 ukify: Add --signing-provider= option 2024-11-06 15:18:46 +01:00
Léane GRASSER b8cb1bc983 po: Translated using Weblate (French)
Currently translated at 100.0% (253 of 253 strings)

Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fr/
Translation: systemd/main
2024-11-06 15:07:28 +01:00
Zbigniew Jędrzejewski-Szmek 78ed1e973c docs/TPM2_PCR_MEASUREMENTS: drop quotes from around section titles
The section headers used quotes as if the strings were some constants. But
AFAICT, those are just normal plain-text titles. Also lowercase them, because
this is almost like a table and it's easier to read without capitalization.
2024-11-06 15:02:24 +01:00
Zbigniew Jędrzejewski-Szmek 265488414c tree-wide: use Device*T*ree spelling
We used both, in fact "Devicetree" was more common. But we have a general rule
that we capitalize all words in names and also we have a DeviceTree=
configuration setting, which we cannot change. If we use two different
spelllings, this will make it harder for people to use the correct one in
config files. So use the "DeviceTree" spelling everywhere.
2024-11-06 15:00:55 +01:00
Luca Boccassi d99fe076b5
introduce report_errno_and_exit() helper (#35028)
This is a follow for https://github.com/systemd/systemd/pull/34853. In
particular, this comment
https://github.com/systemd/systemd/pull/34853#discussion_r1825837705.
2024-11-06 13:51:10 +00:00
Yu Watanabe b66948bbf2 core/manager: silence false-positive warning by coverity
Follow-up for 406f177501.

Closes CID#1564897.
2024-11-06 13:47:33 +00:00
Luca Boccassi 4055529003
machine: introduce io.systemd.Machine.Open method (#34867)
This PR introduces io.systemd.Machine.Open method which combines three
DBus alternatives:
- OpenMachinePTY
- OpenMachineLogin
- OpenMachineShell

The PR contains basic tests.
2024-11-06 13:45:04 +00:00
Zbigniew Jędrzejewski-Szmek d0ab0e5fa5 pid1: stop refusing to boot with cgroup v1
Since v256 we completely fail to boot if v1 is configured. Fedora 41 was just
released with v256.7 and this is probably the first major exposure of users to
this code. It turns out not work very well. Fedora switched to v2 as default in
F31 (2019) and at that time some people added configuration to use v1 either
because of Docker or for other reasons. But it's been long enough ago that
people don't remember this and are now very unhappy when the system refuses to
boot after an upgrade.

Refusing to boot is also unnecessarilly punishing to users. For machines that
are used remotely, this could mean somebody needs to physically access the
machine. For other users, the machine might be the only way to access the net
and help, and people might not know how to set kernel parameters without some
docs. And because this is in systemd, after an upgrade all boot choices are
affected, and it's not possible to e.g. select an older kernel for boot. And
crashing the machine doesn't really serve our goal either: we were giving a
hint how to continue using v1 and nothing else.

If the new override is configured, warn and immediately boot to v1.
If v1 is configured w/o the override, warn and wait 30 s and boot to v2.
Also give a hint how to switch to v2.

https://bugzilla.redhat.com/show_bug.cgi?id=2323323
https://bugzilla.redhat.com/show_bug.cgi?id=2323345
https://bugzilla.redhat.com/show_bug.cgi?id=2322467
https://www.reddit.com/r/Fedora/comments/1gfcyw9/refusing_to_run_under_cgroup_01_sy_specified_on/

The advice is to set systemd.unified_cgroup_hierarchy=1 (instead of removing
systemd.unified_cgroup_hierarchy=0). I think this is easier to convey. Users
who are understand what is going on can just remove the option instead.

The caching is dropped in cg_is_legacy_wanted(). It turns out that the
order in which those functions are called during early setup is very fragile.
If cg_is_legacy_wanted() is called before we have set up the v2 hierarchy,
we incorrectly cache a true answer. The function is called just a handful
of times at most, so we don't really need to cache the response.
2024-11-06 13:43:25 +00:00
Zbigniew Jędrzejewski-Szmek bc11463e8e man/systemd-stub: rework the description of sections
The text added for .dtbauto/.hwids was very hard to grok. This rewords it to be
proper English. No semantic changes are intended.

When updating this, I noticed that the interaction of multi-profile UKIs and
dtb autoselection is very unclear, a FIXME is added.
2024-11-06 14:40:21 +01:00
Daan De Meyer d835c4476b ukify: Add support for systemd-sbsign 2024-11-06 14:01:33 +01:00
Daan De Meyer 8cbd9d8328 sbsign: Add validate-key verb
This verb checks that we can load the specified private key.
2024-11-06 14:01:09 +01:00
Daan De Meyer 5f163921e9 Introduce systemd-sbsign to do secure boot signing
Currently in mkosi and ukify we use sbsigntools to do secure boot
signing. This has multiple issues:

- sbsigntools is practically unmaintained, sbvarsign is completely
broken with the latest gnu-efi when built without -fshort-wchar and
upstream has completely ignored my bug report about this.
- sbsigntools only supports openssl engines and not the new providers
API.
- sbsigntools doesn't allow us to cache hardware token pins in the
kernel keyring like we do nowadays when we sign stuff ourselves in
systemd-repart or systemd-measure

There are alternative tools like sbctl and pesign but these do not
support caching hardware token pins in the kernel keyring either.

To get around the issues with sbsigntools, let's introduce our own
tool systemd-sbsign to do secure boot signing. This allows us to
take advantage of our own openssl infra so that hardware token pins
are cached in the kernel keyring as expected and we get openssl
provider support as well.
2024-11-06 14:00:49 +01:00
Ivan Kruglov 1e2cd07394 machine: tests for io.systemd.Machine.Open 2024-11-06 11:58:51 +01:00
Ivan Kruglov a686bedb88 machine: introduce io.systemd.Machine.Open method 2024-11-06 11:37:51 +01:00
Ivan Kruglov 7779d4944c json: introduce json_dispatch_strv_environment()
I just moved json_dispatch_environment() from src/shared/user-record.c
under name 'json_dispatch_strv_environment()' to shared json code.
2024-11-06 11:37:51 +01:00
Ivan Kruglov b0eca6dee0 machine: machine_default_shell_path() & machine_default_shell_args() helper functions 2024-11-06 11:37:51 +01:00
Ivan Kruglov 41f1f283d7 machine: introduce machine_start_getty() and machine_start_shell() helpers 2024-11-06 11:37:51 +01:00
Ivan Kruglov c0589b0227 use report_errno_and_exit() in src/core/exec-invoke.c 2024-11-06 11:18:38 +01:00
Ivan Kruglov 7022563b5b use report_errno_and_exit() in src/shared/elf-util.c 2024-11-06 11:18:38 +01:00
Ivan Kruglov 3d44b469f3 use report_errno_and_exit() in src/shared/dissect-image.c 2024-11-06 11:18:38 +01:00
Ivan Kruglov 9af164b71c use report_errno_and_exit() in src/shared/mount-util.c 2024-11-06 11:18:38 +01:00
Ivan Kruglov f72a64f352 use report_errno_and_exit() in src/shutdown/umount.c 2024-11-06 11:18:38 +01:00
Ivan Kruglov a567de392d process-util: introduce report_errno_and_exit() as part of src/basic/process-util.{h,c} 2024-11-06 11:18:38 +01:00
Yu Watanabe ea457d59e9 man/varlink: fix typo
Follow-up for 4f5fabe7a3.
2024-11-06 19:06:47 +09:00
Yu Watanabe 9dcf5c226e man/udev: fix typo
Follow-up for df8f9b88bd.
2024-11-06 19:06:40 +09:00
Zbigniew Jędrzejewski-Szmek f755ac99cb man/systemd-measure: add forgotten "="
Both syntaxes work, but let's use one syntax for consistency.

Fixup for 0641ce809a27cc1bc358924c26770f19d1213ec1.
2024-11-06 10:18:16 +01:00
Zbigniew Jędrzejewski-Szmek ad6a4bf09c man/systemd-measure: update to new ukify syntax, non-root operation
It's been a while, but systemd-measure doesn't need root, and
ukify has a more modern syntax.
2024-11-06 10:14:29 +01:00
Yu Watanabe df69f29728
network: reconfigure interface more gracefully (#35035)
split-out of #34989.
2024-11-06 17:57:56 +09:00
Lennart Poettering 682195a00a
UKI: Introduce `.dtbauto` sections (#34855)
Split out from #34158
2024-11-06 09:29:04 +01:00
Andres Beltran f348831d27 namespace-util: make idmapping not supported if syscalls return EPERM 2024-11-06 09:27:33 +01:00
Lennart Poettering 299b6c3c28
Various man page updates (#35032)
Fixes: #34996
Fixes: #15032
Fixes: #32751
Fixes: #33130
Fixes: #34735
Fixes: #34840
Fixes: #34949
2024-11-06 09:26:57 +01:00
Zbigniew Jędrzejewski-Szmek ddcdc6b365
mount-util: introduce path_is_network_fs_harder() and use it in networkd (#35040)
Closes #32426.
2024-11-06 08:39:24 +01:00
Lennart Poettering df8f9b88bd man: convert multiple left-over "See Also" sections to <simplelist>
These were forgotten during the initial conversion, probably because
most of them consisted only of a single entry.

Fix that.
2024-11-05 22:57:51 +01:00
Lennart Poettering 607d297487 man: link up D-Bus API docs from daemon man pages
Let's systematically make sure that we link up the D-Bus interfaces from
the daemon man pages once in prose and once in short form at the bottom
("See Also"), for all daemons.

Also, add reverse links at the bottom of the D-Bus API docs.

Fixes: #34996
2024-11-05 22:57:51 +01:00
Lennart Poettering 2f69ad26ca man: point people from sd-bus man page to busctl 2024-11-05 22:57:51 +01:00
Lennart Poettering 4f5fabe7a3 man: add brief entrypoint man page for sd-varlink
We have this in a similar fashion for the other APIs libsystemd
provides. Add the same for sd-varlink. There isn't too much on it for
now, but at least it's a start.

Also link it up everywhere.
2024-11-05 22:57:51 +01:00
Lennart Poettering ac804bc2f8 man: tone down claims on processes having exited already in ExecStop=
Processes can easily survive the first kill operation we execute, hence
we shouldn't make strong claims about them having exited already. Let's
just say "likely" hence.

Fixes: #15032
2024-11-05 22:57:51 +01:00
Lennart Poettering 5adc433799 man: document that .path units don't care for hidden files
Fixes: #32751
2024-11-05 22:57:51 +01:00
Lennart Poettering b711737096 man: document that PrivateTmp= is unaffected by ProtectSystem=strict
Fixes: #33130
2024-11-05 22:57:51 +01:00
Lennart Poettering 172ac39fc8 man: highlight the privilege issues around the LogControl1 more
Let's emphasize the privilege thing with a <caution> section.

Let's also point out that other D-Bus libraries are less restrictive
than sd-bus by default regarding permission access.

Fixes: #34735
2024-11-05 22:57:34 +01:00
anonymix007 73b1fbc777 man: Document stub behaviour for .hwids and .dtbauto sections 2024-11-06 00:47:04 +03:00
anonymix007 1d79f667f4 stub: Handle .dtbauto sections 2024-11-06 00:47:04 +03:00
anonymix007 4c0b7f4250 measure: Introduce .dtbauto support 2024-11-06 00:47:04 +03:00
anonymix007 630cf4e7da uki: add new .dtbauto PE section type
.dtbauto section contains DT blobs, just like .dtb, the difference is
that multiple .dtbauto sections are allowed to be in a UKI and only one
is selected automatically

Temporarily drop an assert_cc() check in systemd-measure to make it compilable before the next commit
2024-11-06 00:47:04 +03:00
anonymix007 763028a16c measure: introduce support for a .hwids section 2024-11-06 00:47:04 +03:00
anonymix007 c033267912 boot: Add .dtbauto section matching in PE section discovery against HWIDs and FW-provided DT 2024-11-06 00:46:57 +03:00
Lennart Poettering ecbe9ae5a0 man: don't claim SELinuxContext= only worked in the system service manager
Fixes: #34840
2024-11-05 22:42:38 +01:00
Lennart Poettering af080967ba man: document the timeout applied to /usr/lib/systemd/system-shutdown/ drop-in binaries
Fixes: #34949
2024-11-05 22:42:32 +01:00
Yu Watanabe c0323de6ca network: use path_is_network_fs_harder()
Closes #32426.
2024-11-06 04:58:59 +09:00
Yu Watanabe d49d95df0a mount-util: introduce path_is_network_fs_harder()
It also detects e.g. glusterfs or mounts with "_netdev" option.
2024-11-06 04:58:55 +09:00
anonymix007 6bb76ab959 boot: Add HWID calculation from SMBIOS strings and matching against a built-in list 2024-11-05 22:29:58 +03:00
anonymix007 1c3a0a4b1f boot: Add firmware_devicetree_exists() 2024-11-05 22:29:58 +03:00
Diogo Ivo e6cb29fa0f boot: add matching against FW-provided Devicetree blob
Add support for matching the DT contained in a .dtb section of the
UKI image against the FW provided FDT or arbitrary compatible.
2024-11-05 22:29:40 +03:00
Daan De Meyer 0bf70b1984 openssl-util: Set default UI method instead of setting engine method
While for engines we have ENGINE_ctrl() to set the UI method for the
second PIN prompt, for openssl providers we don't have such a feature
which means we get the default openssl UI for the second pin prompt.

Instead, let's set the default UI method which does get used for the
second pin prompt by the pkcs11 provider.
2024-11-05 19:58:45 +01:00
Yu Watanabe 6e0c9b7dac network: introduce LINK_RECONFIGURE_CLEANLY flag
And use it when explicit reconfiguration is requested by Reconfigure() DBus method
or networkd certainly detects that connected network is changed.
Otherwise do not use the flag especially when we come back from sleep mode.
2024-11-06 02:05:00 +09:00
Yu Watanabe 451c2baf30 network: keep dynamic configurations as possible as we can on reconfigure
E.g. when a .network file is updated, but DHCP setting is unchanged, it
is not necessary to drop acquired DHCP lease.
So, let's not stop DHCP client and friends in link_reconfigure_impl(),
but stop them later when we know they are not necessary anymore.

Still DHCP clients and friends are stopped and leases are dropped when
the explicit reconfiguration is requested
2024-11-06 02:05:00 +09:00
Yu Watanabe dd6d53a8dc network: merge link_foreignize_config() and link_drop_foreign_config()
When a reconfiguration of an interface is triggered, previously we
call link_foreignize_config(), which sets all static configurations as
foreign, then later call link_drop_foreign_config(), which drops
unnecessary foreign configurations.

This commit merges these two steps into one, link_drop_unmanaged_config(),
which drops unnecessary static and foreign configurations.

Also, this renames link_drop_managed_configs() to
link_drop_static_config(), as it only drops static configurations.
Note that dynamically aquired configurations are dropped by
link_stop_engines().
2024-11-06 02:05:00 +09:00
Yu Watanabe 2b07a3211b network: several cleanups for link_reconfigure()
Effectively no functional changes, just refactoring and preparation for
later changes.

- convert boolean flag 'force' to LinkReconfigurationFlag enum,
- merge link_reconfigure() and reconfigure_handler_on_bus_method_reload() as
  link_reconfigure_full(),
- Rename ReconfigureData -> LinkReconfigurationData,
- make Reconfigure() DBus message wait for reconfiguration being
  started before sending reply.
2024-11-06 02:05:00 +09:00
Yu Watanabe 5a1ef6dffb network: split out link_enter_unmanaged() from link_reconfigure_impl()
No functional change, just refactoring.
2024-11-06 02:05:00 +09:00
Daan De Meyer cf0238d854 pcrlock: Move pe_hash() and uki_hash() to pe-binary.h
Let's move these to shared so we can reuse pe_hash() in the upcoming
systemd-sbsign.
2024-11-05 14:26:21 +01:00
Daan De Meyer 48c5a4cd67 mkosi: Add ruff and mypy to tools tree packages 2024-11-05 14:26:21 +01:00
anonymix007 26060eb7a0 fundamental: Add HWID calculation 2024-11-05 14:48:43 +03:00
anonymix007 09f16de6d8 boot: Add xnew0
Same as xnew but initialized with zeros
2024-11-05 14:48:33 +03:00
Dan Streetman 413f6e0f56 test/test-variadic: add unit tests for variadic helper macros 2023-05-01 14:14:18 -04:00
Dan Streetman f3ab293474 fundamental/variadic-fundamental: add variadic helper macros
Adds VA_MACRO_HELPER() which allows calling another macro with temporary
variables, unique tokens, and/or existing variables protected from side
effects.

Also adds various other helper macros for dealing with variadic args, such as
VA_GROUP(), VA_IF(), VA_FIRST(), etc.
2023-05-01 14:14:18 -04:00
Dan Streetman b595c40c72 fundamental/macro-fundamental: allow stringifying variadic args, instead of just a single arg 2023-05-01 12:58:34 -04:00
162 changed files with 5050 additions and 1398 deletions

View File

@ -69,6 +69,9 @@ The following exceptions apply:
* the following sources are under **Public Domain** (LicenseRef-alg-sha1-public-domain):
- src/fundamental/sha1-fundamental.c
- src/fundamental/sha1-fundamental.h
* the following files are licensed under **BSD-3-Clause** license:
- src/boot/efi/chid.c
- src/boot/efi/chid.h
* Heebo fonts under docs/fonts/ are licensed under the **SIL Open Font License 1.1**,
* any files under test/ without an explicit license we assume non-copyrightable
(eg: computer-generated fuzzer data)

48
NEWS
View File

@ -51,6 +51,12 @@ CHANGES WITH 257 in spe:
too many systems, because most NVMe devices only know a namespace 1
by default.
* Support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now
considered obsolete and systemd by default will ignore configuration
that enables them. To forcibly reenable cgroup v1 support,
SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 must additionally be set on the
kernel command line.
Announcements of Future Feature Removals:
* The D-Bus method org.freedesktop.systemd1.StartAuxiliaryScope() is
@ -64,11 +70,8 @@ CHANGES WITH 257 in spe:
will be phased out in a future release in 2025, i.e. we expect to bump
the minimum baseline to v5.4 then too.
* Support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now
considered obsolete and systemd by default will refuse to boot under
it. To forcibly reenable cgroup v1 support,
SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 must be set on kernel command
line. The complete removal of cgroup v1 is scheduled for v258.
* The complete removal of support for cgroup v1 ('legacy' and 'hybrid'
hierarchies) is scheduled for v258.
* Support for System V service scripts is deprecated and will be
removed in v258. Please make sure to update your software
@ -183,7 +186,7 @@ CHANGES WITH 257 in spe:
* The systemd.machine_id= kernel command line parameter interpreted by
PID 1 now supports an additional special value: if "firmware" is
specified the machine ID is initialized from the SMBIOS/Devicetree
specified the machine ID is initialized from the SMBIOS/DeviceTree
system UUID. (Previously this was already done in VM environments,
this extends the concept to any system, but only on explicit request
via this option.)
@ -273,10 +276,10 @@ CHANGES WITH 257 in spe:
show up as .device units in systemd.
* The firmware_node/sun sysfs attribute will now be used (if available)
for naming slot-based network interfaces,
i.e. ID_NET_NAME_SLOT. Moreover the interface aliases specified in
Devicetree are now searched for both on the interfaces parent device
(as before) and the device itself (new).
for naming slot-based network interfaces, i.e. ID_NET_NAME_SLOT.
Moreover the interface aliases specified in DeviceTree are now
searched for both on the interface's parent device (as before) and
the device itself (new).
* Various USB hardware wallets have are now recognized by udev via a
.hwdb file, and get the ID_HARDWARE_WALLET= property set, which
@ -381,6 +384,16 @@ CHANGES WITH 257 in spe:
reset one, and so on which only differ in kernel command line, but
nothing else).
* New .dtbauto and .hwids sections are now documented and supported in
systemd-measure, ukify, systemd-stub, and systemd-boot. A single UKI
can contain multiple .dtbauto sections, and the 'compatible' string
therein will be compared with the equivalent field in the DTB
provided by the firmware, if present. If absent, SMBIOS will be used
to calculate hardware IDs and compare them with the content of
.hwids. This allows including multiple DTBs in a single UKI, with
the bootloader automatically selecting the correct one for the
current hardware.
* ukify gained an --extend switch to import an existing UKI to
be extended, and a --measure-base= switch to support measurement
of multi-profile UKIs.
@ -643,6 +656,9 @@ CHANGES WITH 257 in spe:
* systemd-tmpfiles --purge switch now requires specification of at
least one tmpfiles.d/ drop-in file.
* tmpfiles.d gained a new '?' specifier for the 'L' type to create a
symlink only if the source exists, and gracefully skip otherwise.
* The new Linux mseal(), listmount(), statmount() syscalls have been
added to relevant system call groups.
@ -2009,7 +2025,7 @@ CHANGES WITH 255:
respective SBAT sections, so that they can be revoked individually if
needed.
* systemd-boot will no longer load unverified Devicetree blobs when UEFI
* systemd-boot will no longer load unverified DeviceTree blobs when UEFI
SecureBoot is enabled. For more details see:
https://github.com/systemd/systemd/security/advisories/GHSA-6m6p-rjcq-334c
@ -2030,7 +2046,7 @@ CHANGES WITH 255:
command-line addons before measuring them in TPM2 PCR 12, in a single
measurement, instead of measuring them individually.
* systemd-stub will now measure and load Devicetree Blob addons, which
* systemd-stub will now measure and load DeviceTree Blob addons, which
are searched and loaded following the same model as the existing
kernel command-line addons.
@ -2038,7 +2054,7 @@ CHANGES WITH 255:
passed from systemd-boot when running inside Confidential VMs with UEFI
SecureBoot enabled.
* systemd-stub will now load a Devicetree blob even if the firmware did
* systemd-stub will now load a DeviceTree blob even if the firmware did
not load any beforehand (e.g.: for ACPI systems).
* ukify is no longer considered experimental, and now ships in /usr/bin/.
@ -2219,6 +2235,10 @@ CHANGES WITH 255:
specific devices explicitly. NetworkManager will soon implement a
similar logic.
* .network files gained a new MulticastIGMPVersion= setting in the
[Network] section, to control sysctl's
/proc/sys/net/ipv4/conf/INTERFACE/force_igmp_version setting.
systemctl:
* systemctl is-failed now checks the system state if no unit is
@ -4352,7 +4372,7 @@ CHANGES WITH 252 🎃:
* 'udevadm wait' will now listen to kernel uevents too when called with
--initialized=no.
* When naming network devices udev will now consult the Devicetree
* When naming network devices udev will now consult the DeviceTree
"alias" fields for the device.
* systemd-udev will now create infiniband/by-path and

View File

@ -41,7 +41,7 @@ used for new, additional measurements.
## PCR Measurements Made by `systemd-boot` (UEFI)
### PCS 5, `EV_EVENT_TAG`, "loader.conf"
### PCS 5, `EV_EVENT_TAG`, `loader.conf`
The content of `systemd-boot`'s configuration file, `loader/loader.conf`, is
measured as a tagged event.
@ -52,7 +52,7 @@ measured as a tagged event.
**Measured hash** covers the content of `loader.conf` as it is read from the ESP.
### PCR 12, `EV_IPL`, "Kernel Command Line"
### PCR 12, `EV_IPL`, kernel command line
If the kernel command line was specified explicitly (by the user or in a Boot
Loader Specification Type #1 file), the kernel command line passed to the
@ -70,7 +70,7 @@ trailing NUL bytes).
## PCR Measurements Made by `systemd-stub` (UEFI)
### PCR 11, `EV_IPL`, "PE Section Name"
### PCR 11, `EV_IPL`, PE section name
A measurement is made for each PE section of the UKI that is defined by the
[UKI
@ -87,7 +87,7 @@ both types of records appear interleaved in the event log.
**Measured hash** covers the PE section name in ASCII (*including* a trailing NUL byte!).
### PCR 11, `EV_IPL`, "PE Section Data"
### PCR 11, `EV_IPL`, PE section data
Happens once for each UKI-defined PE section of the UKI, in the canonical UKI
PE section order, as per the UKI specification, see above.
@ -96,7 +96,7 @@ PE section order, as per the UKI specification, see above.
**Measured hash** covers the (binary) PE section contents.
### PCR 12, `EV_IPL`, "Kernel Command Line"
### PCR 12, `EV_IPL`, kernel command line
Might happen up to three times, for kernel command lines from:
@ -110,37 +110,37 @@ UTF-16.
**Measured hash** covers the literal kernel command line in UTF-16 (without any
trailing NUL bytes).
### PCR 12, `EV_EVENT_TAG`, "Devicetrees"
### PCR 12, `EV_EVENT_TAG`, DeviceTrees
Devicetree addons are measured individually as a tagged event.
DeviceTree addons are measured individually as a tagged event.
**Event Tag** `0x6c46f751`
**Description** the addon filename.
**Description** is the addon filename.
**Measured hash** covers the content of the Devicetree.
**Measured hash** covers the content of the DeviceTree.
### PCR 12, `EV_EVENT_TAG`, "Initrd addons"
### PCR 12, `EV_EVENT_TAG`, initrd addons
Initrd addons are measured individually as a tagged event.
**Event Tag** `0x49dffe0f`
**Description** the addon filename.
**Description** is the addon filename.
**Measured hash** covers the contents of the initrd.
### PCR 12, `EV_EVENT_TAG`, "Ucode addons"
### PCR 12, `EV_EVENT_TAG`, ucode addons
Ucode addons are measured individually as a tagged event.
**Event Tag** `0xdac08e1a`
**Description** the addon filename.
**Description** is the addon filename.
**Measured hash** covers the contents of the ucode initrd.
### PCR 12, `EV_IPL`, "Per-UKI Credentials initrd"
### PCR 12, `EV_IPL`, per-uki credentials initrd
**Description** in the event log record is the constant string "Credentials
initrd" in UTF-16.
@ -148,7 +148,7 @@ initrd" in UTF-16.
**Measured hash** covers the per-UKI credentials cpio archive (which is generated
on-the-fly by `systemd-stub`).
### PCR 12, `EV_IPL`, "Global Credentials initrd"
### PCR 12, `EV_IPL`, global credentials initrd
**Description** in the event log record is the constant string "Global
credentials initrd" in UTF-16.
@ -156,7 +156,7 @@ credentials initrd" in UTF-16.
**Measured hash** covers the global credentials cpio archive (which is generated
on-the-fly by `systemd-stub`).
### PCR 13, `EV_IPL`, "sysext initrd"
### PCR 13, `EV_IPL`, sysext initrd
**Description** in the event log record is the constant string "System extension
initrd" in UTF-16.
@ -166,7 +166,7 @@ on-the-fly by `systemd-stub`).
## PCR Measurements Made by `systemd-pcrextend` (Userspace)
### PCR 11, "Boot Phases"
### PCR 11, boot phases
The `systemd-pcrphase.service`, `systemd-pcrphase-initrd.service`,
`systemd-pcrphase-sysinit.service` services will measure the boot phase reached
@ -178,7 +178,7 @@ choose to define additional/different phases.)
**Measured hash** covers the phase string (in UTF-8, without trailing NUL
bytes).
### PCR 15, "Machine ID"
### PCR 15, machine ID
The `systemd-pcrmachine.service` service will measure the machine ID (as read
from `/etc/machine-id`) during boot.
@ -187,7 +187,7 @@ from `/etc/machine-id`) during boot.
formatted in hexadecimal lowercase characters (in UTF-8, without trailing NUL
bytes).
### PCR 15, "File System"
### PCR 15, file system
The `systemd-pcrfs-root.service` and `systemd-pcrfs@.service` services will
measure a string identifying a specific file system, typically covering the
@ -200,7 +200,7 @@ without trailing NUL bytes).
## PCR Measurements Made by `systemd-cryptsetup` (Userspace)
### PCR 15, "Volume Key"
### PCR 15, volume key
The `systemd-cryptsetup@.service` service will measure a key derived from the
LUKS volume key of a specific encrypted volume, typically covering the backing

View File

@ -106,17 +106,17 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -145,10 +145,8 @@ PROPERTY_WITH_SPACES=some string</programlisting>
<refsect1>
<title>See Also</title>
<para>
<citerefentry>
<refentrytitle>systemd-hwdb</refentrytitle><manvolnum>8</manvolnum>
</citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd-hwdb</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -35,6 +35,7 @@
#include &lt;systemd/sd-login.h&gt;
#include &lt;systemd/sd-messages.h&gt;
#include &lt;systemd/sd-path.h&gt;
#include &lt;systemd/sd-varlink.h&gt;
</programlisting>
<cmdsynopsis>
@ -61,8 +62,9 @@
<citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
and
<citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for information about different parts of the library interface.</para>
</refsect1>

View File

@ -89,7 +89,9 @@ node /org/freedesktop/LogControl1 {
<citerefentry project="man-pages"><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> call).
</para>
<para>Those two properties are writable, so they may be set by sufficiently privileged users.</para>
<caution><title>Write Access</title><para>The <varname>LogLevel</varname> and
<varname>LogTarget</varname> properties are supposed to be writable. Care should be taken to ensure
that only appropriately privileged clients can modify them.</para></caution>
<para><varname>SyslogIdentifier</varname> is a read-only property that shows the "syslog identifier".
It is a short string that identifies the program that is the source of log messages that is passed to
@ -127,6 +129,11 @@ node /org/freedesktop/LogControl1 {
<para>This creates a simple server on the bus. It implements the LogControl1 interface by providing
the required properties and allowing to set the writable ones. It logs at the configured log level using
<citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
<para>Note that when porting this example to other D-Bus libraries it might be necessary to add manual
client privilege checks, as they typically do not default to the restrictive defaults of sd-bus, where
unprivileged access to properties is controlled via the <constant>SD_BUS_VTABLE_UNPRIVILEGED</constant>
flag that is opt-in rather than opt-out.</para>
</example>
</refsect1>

View File

@ -427,8 +427,6 @@ node /org/freedesktop/hostname1 {
name.</para>
</refsect1>
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
<refsect1>
<title>Examples</title>
@ -442,12 +440,7 @@ node /org/freedesktop/hostname1 {
</example>
</refsect1>
<refsect1>
<title>See Also</title>
<para>David Zeuthen's original Fedora
<ulink url="https://fedoraproject.org/wiki/Features/BetterHostname">Feature page about xdg-hostname</ulink></para>
</refsect1>
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
<refsect1>
<title>History</title>
@ -462,4 +455,16 @@ node /org/freedesktop/hostname1 {
<varname>VSockCID</varname> were added in version 256.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member>David Zeuthen's original Fedora
<ulink url="https://fedoraproject.org/wiki/Features/BetterHostname">Feature page about xdg-hostname</ulink></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -453,6 +453,7 @@ node /org/freedesktop/import1/transfer/_1 {
</refsect1>
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
<refsect1>
<title>History</title>
<refsect2>
@ -469,4 +470,13 @@ node /org/freedesktop/import1/transfer/_1 {
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -185,4 +185,14 @@ $ gdbus introspect --system \
<para>These D-Bus interfaces follow <ulink url="https://0pointer.de/blog/projects/versioning-dbus.html">
the usual interface versioning guidelines</ulink>.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -1648,4 +1648,13 @@ node /org/freedesktop/login1/session/1 {
<para><function>SetClass()</function> was added in version 256.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>loginctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -719,4 +719,13 @@ $ gdbus introspect --system \
and <varname>SSHPrivateKeyPath</varname> were added in version 256.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -602,4 +602,13 @@ $ gdbus introspect --system \
<para><varname>NamespaceNSID</varname> was added in version 256.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -103,4 +103,14 @@ node /org/freedesktop/oom1 {
<para><function>Killed()</function> was added in version 252.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-oomd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>oomctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -591,4 +591,13 @@ node /org/freedesktop/portable1 {
<para><function>ReattachWithExtensions()</function> was added in version 254.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-portabled.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>portablectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -935,4 +935,13 @@ $ gdbus introspect --system \
</refsect1>
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>resolvectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -12489,4 +12489,13 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \
<para><varname>DeferReactivation</varname> was added in version 257.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -582,4 +582,13 @@ node /org/freedesktop/sysupdate1/job/_1 {
<varname>Progress</varname> were added in version 257.</para>
</refsect2>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-sysupdated.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>updatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -194,7 +194,11 @@ $ gdbus introspect --system \
<refsect1>
<title>See Also</title>
<para><ulink url="https://lists.freedesktop.org/archives/systemd-devel/2011-May/002526.html">More information on how the system clock and RTC interact</ulink></para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-timedate.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>timedatectl.service</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><ulink url="https://lists.freedesktop.org/archives/systemd-devel/2011-May/002526.html">More information on how the system clock and RTC interact</ulink></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -153,4 +153,11 @@ $ gdbus introspect --system \
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-timesync.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -91,9 +91,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd-pstore.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -155,6 +155,7 @@ manpages = [
['sd-journal', '3', [], ''],
['sd-json', '3', [], ''],
['sd-login', '3', [], 'HAVE_PAM'],
['sd-varlink', '3', [], ''],
['sd_booted', '3', [], ''],
['sd_bus_add_match',
'3',

View File

@ -179,6 +179,9 @@
<member><citerefentry><refentrytitle>sd_bus_track_new</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
</simplelist>
for more information about the functions available.</para>
<para>The <citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
makes the functionality implemented by sd-bus available from the command line.</para>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
@ -189,9 +192,10 @@
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -84,7 +84,8 @@
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>,
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-varlink</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

64
man/sd-varlink.xml Normal file
View File

@ -0,0 +1,64 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="sd-varlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd-varlink</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd-varlink</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd-varlink</refname>
<refpurpose>APIs for Varlink IPC</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-varlink.h&gt;</funcsynopsisinfo>
</funcsynopsis>
<cmdsynopsis>
<command>pkg-config --cflags --libs libsystemd</command>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>sd-varlink.h</filename> is part of
<citerefentry><refentrytitle>libsystemd</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
provides APIs for implementing Varlink IPC clients and services. See <ulink url="https://varlink.org/"/>
for more information about Varlink IPC.</para>
<para>Varlink IPC uses <ulink url="https://json.org/">JSON</ulink> as marshalling format. The sd-varlink
API relies on the
<citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry> API for JSON
serialization, deserialization and manipulation.</para>
<para>The <citerefentry><refentrytitle>varlinkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool
makes the functionality implemented by sd-varlink available from the command line.</para>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-json</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>varlinkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -250,9 +250,10 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-device</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -77,9 +77,10 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -226,10 +226,11 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd-path</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-path</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-path</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -75,9 +75,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -71,9 +71,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -83,9 +83,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -79,9 +79,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -76,6 +76,7 @@
<member><citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -83,8 +83,9 @@
<refsect1>
<title>See Also</title>
<para><citerefentry>
<refentrytitle>hwdb</refentrytitle><manvolnum>7</manvolnum>
</citerefentry></para>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
<citerefentry><refentrytitle>hwdb</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -50,6 +50,7 @@
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.import1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -41,9 +41,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -55,6 +55,7 @@
<member><citerefentry><refentrytitle>vconsole.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.locale1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -104,6 +104,7 @@
<member><citerefentry><refentrytitle>logind.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.login1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -135,6 +135,7 @@
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>nss-mymachines</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.machine1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -77,7 +77,7 @@
<option>--osrel=</option>, <option>--cmdline=</option>, <option>--initrd=</option>,
<option>--ucode=</option>, <option>--splash=</option>, <option>--dtb=</option>,
<option>--uname=</option>, <option>--sbat=</option>, <option>--pcrpkey=</option>,
<option>--profile=</option>, see below. Only <option>--linux=</option> is mandatory. (Alternatively,
<option>--profile=</option>, <option>--dtbauto=</option>, <option>--hwids=</option>, see below. Only <option>--linux=</option> is mandatory. (Alternatively,
specify <option>--current</option> to use the current values of PCR register 11 instead.)</para>
<xi:include href="version-info.xml" xpointer="v252"/>
@ -125,6 +125,8 @@
<term><option>--sbat=<replaceable>PATH</replaceable></option></term>
<term><option>--pcrpkey=<replaceable>PATH</replaceable></option></term>
<term><option>--profile=<replaceable>PATH</replaceable></option></term>
<term><option>--dtbauto=<replaceable>PATH</replaceable></option></term>
<term><option>--hwids=<replaceable>PATH</replaceable></option></term>
<listitem><para>When used with the <command>calculate</command> or <command>sign</command> verb,
configures the files to read the unified kernel image components from. Each option corresponds with
@ -134,7 +136,7 @@
<xi:include href="version-info.xml" xpointer="v252"/>
<para id="v257">With the exception of <option>--profile=</option>, which has been added in version
<para id="v257">With the exception of <option>--profile=</option>, <option>--dtbauto=</option> and <option>--hwids=</option>, which have been added in version
257.</para></listitem>
</varlistentry>
@ -264,13 +266,15 @@
<example>
<title>Generate a unified kernel image, and calculate the expected TPM PCR 11 value</title>
<programlisting>$ ukify --output=vmlinux.efi \
<programlisting>$ ukify build \
--linux=vmlinux \
--initrd=initrd.cpio \
--os-release=@os-release.txt \
--cmdline=@cmdline.txt \
--splash=splash.bmp \
--devicetree=devicetree.dtb \
--measure \
vmlinux initrd.cpio
--output=vmlinux.efi
11:sha1=d775a7b4482450ac77e03ee19bda90bd792d6ec7
11:sha256=bc6170f9ce28eb051ab465cd62be8cf63985276766cf9faf527ffefb66f45651
11:sha384=1cf67dff4757e61e5...7f49ad720be02fd07263e1f93061243aec599d1ee4b4
@ -289,7 +293,7 @@
<programlisting>$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out tpm2-pcr-private-key.pem
..+.+++++++++......+.........+......+.......+....+.....+.+...+..........
$ openssl rsa -pubout -in tpm2-pcr-private-key.pem -out tpm2-pcr-public-key.pem
# systemd-measure sign \
$ systemd-measure sign \
--linux=vmlinux \
--osrel=os-release.txt \
--cmdline=cmdline.txt \
@ -301,7 +305,9 @@ $ openssl rsa -pubout -in tpm2-pcr-private-key.pem -out tpm2-pcr-public-key.pem
--bank=sha256 \
--private-key=tpm2-pcr-private-key.pem \
--public-key=tpm2-pcr-public-key.pem >tpm2-pcr-signature.json
# ukify --output=vmlinuz.efi \
$ ukify build \
--linux=vmlinux \
--initrd=initrd.cpio \
--os-release=@os-release.txt \
--cmdline=@cmdline.txt \
--splash=splash.bmp \
@ -309,7 +315,7 @@ $ openssl rsa -pubout -in tpm2-pcr-private-key.pem -out tpm2-pcr-public-key.pem
--pcr-private-key=tpm2-pcr-private-key.pem \
--pcr-public-key=tpm2-pcr-public-key.pem \
--pcr-banks=sha1,sha256 \
vmlinux initrd.cpio</programlisting>
--output=vmlinuz.efi</programlisting>
<para>Later on, enroll the signed PCR policy on a LUKS volume:</para>
@ -345,7 +351,9 @@ $ openssl rsa -pubout -in tpm2-pcr-private-key.pem -out tpm2-pcr-public-key.pem
$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out tpm2-pcr-private-key-initrd.pem
..+.......++........+........+......+........+....+.....+.+..+..........
$ openssl rsa -pubout -in tpm2-pcr-private-key-initrd.pem -out tpm2-pcr-public-key-initrd.pem
# ukify --output vmlinux-1.2.3.efi \
$ ukify build \
--linux=vmlinux-1.2.3 \
--initrd=initrd.cpio \
--os-release=@os-release.txt \
--cmdline=@cmdline.txt \
--splash=splash.bmp \
@ -357,8 +365,8 @@ $ openssl rsa -pubout -in tpm2-pcr-private-key-initrd.pem -out tpm2-pcr-public-k
--pcr-private-key=tpm2-pcr-private-key-initrd.pem \
--pcr-public-key=tpm2-pcr-public-key-initrd.pem \
--phases=enter-initrd \
vmlinux-1.2.3 initrd.cpio \
--uname=1.2.3
--uname=1.2.3 \
--output=vmlinux-1.2.3.efi
+ /usr/lib/systemd/systemd-measure sign --linux=vmlinux-1.2.3 \
--osrel=os-release.txt --cmdline=cmdline.txt --dtb=devicetree.dtb \
--splash=splash.bmp --initrd=initrd.cpio --bank=sha1 --bank=sha256 \

View File

@ -62,9 +62,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nsresourced.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-nsresourced.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -63,6 +63,12 @@
<para><command>systemd-networkd</command> may be introspected and controlled at runtime using
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para>
<para>See
<citerefentry><refentrytitle>org.freedesktop.network1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of the D-Bus API.</para>
</refsect1>
<refsect1><title>Configuration Files</title>
@ -91,6 +97,7 @@
<member><citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-networkd-wait-online.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-network-generator.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.network1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -69,13 +69,13 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-mountfsd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>user_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-mountfsd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>user_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -57,6 +57,12 @@
<para>See <citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more information about the configuration of this service.</para>
<para>See
<citerefentry><refentrytitle>org.freedesktop.oom1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of the D-Bus API.</para>
</refsect1>
<refsect1>
@ -129,6 +135,7 @@
<member><citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>oomd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>oomctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.oom1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -37,6 +37,12 @@
<para>See the <ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> page
for details about the concepts this service implements.</para>
<para>See
<citerefentry><refentrytitle>org.freedesktop.portable1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>org.freedesktop.LogControl1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of the D-Bus API.</para>
</refsect1>
<refsect1>

View File

@ -44,7 +44,7 @@
<filename>kexec.target</filename> to execute the respective actions.</para>
<para>When these services are run, they ensure that PID 1 is replaced by the
<filename>/usr/lib/systemd/systemd-shutdown</filename> tool which is then responsible for the actual
<filename>/usr/lib/systemd/systemd-shutdown</filename> binary which is then responsible for the actual
shutdown. Before shutting down, this binary will try to unmount all remaining file systems (or at least
remount them read-only), disable all remaining swap devices, detach all remaining storage devices and
kill all remaining processes.</para>
@ -58,12 +58,12 @@
<filename>/usr/lib/systemd/system-shutdown/</filename> and pass one arguments to them: either
<literal>poweroff</literal>, <literal>halt</literal>, <literal>reboot</literal>, or
<literal>kexec</literal>, depending on the chosen action. All executables in this directory are executed
in parallel, and execution of the action is not continued before all executables finished. Note that
these executables are run <emphasis>after</emphasis> all services have been shut down, and after most
mounts have been unmounted (the root file system as well as <filename>/run/</filename> and various API
file systems are still around though). This means any programs dropped into this directory must be
prepared to run in such a limited execution environment and not rely on external services or hierarchies
such as <filename>/var/</filename> to be around (or writable).</para>
in parallel, and execution of the action is not continued before all executables finished. (A safety
timeout of 90s is applied however.) Note that these executables are run <emphasis>after</emphasis> all
services have been shut down, and after most mounts have been unmounted (the root file system as well as
<filename>/run/</filename> and various API file systems are still around though). This means any programs
dropped into this directory must be prepared to run in such a limited execution environment and not rely
on external services or hierarchies such as <filename>/var/</filename> to be around (or writable).</para>
<para>Note that <filename>systemd-poweroff.service</filename> (and the related units) should never be
executed directly. Instead, trigger system shutdown with a command such as <literal>systemctl

View File

@ -107,8 +107,8 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>pstore.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -516,6 +516,7 @@ search foobar.com barbar.com
<member><citerefentry project='man-pages'><refentrytitle>hosts</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.resolve1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -60,9 +60,9 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

111
man/systemd-sbsign.xml Normal file
View File

@ -0,0 +1,111 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-sbsign"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-sbsign</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-sbsign</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-sbsign</refname>
<refpurpose>Sign PE binaries for EFI Secure Boot</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>systemd-sbsign</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="req">COMMAND</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-sbsign</command> can be used to sign PE binaries for EFI Secure Boot.</para>
</refsect1>
<refsect1>
<title>Commands</title>
<variablelist>
<varlistentry>
<term><option>sign</option></term>
<listitem><para>Signs the given PE binary for EFI Secure Boot. Takes a path to a PE binary as its
argument. If the PE binary already has a certificate table, the new signature will be added to it.
Otherwise a new certificate table will be created. The signed PE binary will be written to the path
specified with <option>--output=</option>.</para>
<xi:include href="version-info.xml" xpointer="v257"/>
</listitem>
</varlistentry>
<varlistentry>
<term><option>validate-key</option></term>
<listitem><para>Checks that we can load the private key specified with
<option>--private-key=</option>. </para>
<para>As a side effect, if the private key is loaded from a PIN-protected hardware token, this
command can be used to cache the PIN in the kernel keyring. The
<varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TIMEOUT_SEC</varname> and
<varname>$SYSTEMD_ASK_PASSWORD_KEYRING_TYPE</varname> environment variables can be used to control
how long and in which kernel keyring the PIN is cached.</para>
<xi:include href="version-info.xml" xpointer="v257"/>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--output=<replaceable>PATH</replaceable></option></term>
<listitem><para>Specifies the path where to write the signed PE binary.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--private-key=<replaceable>PATH/URI</replaceable></option></term>
<term><option>--private-key-source=<replaceable>TYPE</replaceable>[:<replaceable>NAME<replaceable>]</option></term>
<term><option>--certificate=<replaceable>PATH</replaceable></option></term>
<listitem><para>Set the Secure Boot private key and certificate for use with the
<command>sign</command>. The <option>--certificate=</option> option takes a path to a PEM encoded
X.509 certificate. The <option>--private-key=</option> option can take a path or a URI that will be
passed to the OpenSSL engine or provider, as specified by <option>--private-key-source=</option> as a
<literal>type:name</literal> tuple, such as <literal>engine:pkcs11</literal>. The specified OpenSSL
signing engine or provider will be used to sign the PE binary.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="help"/>
<xi:include href="standard-options.xml" xpointer="version"/>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -59,44 +59,66 @@
<!-- Let's keep this in the canonical order we also measure the sections by, i.e. as in
src/fundamental/uki.h's UnifiedSection enum -->
<listitem><para>A <literal>.linux</literal> section with the ELF Linux kernel
image. (Required)</para></listitem>
<listitem><para>A <literal>.linux</literal> section with the ELF Linux kernel image.
This section is required.</para></listitem>
<listitem><para>An <literal>.osrel</literal> section with OS release information, i.e. the contents of
the <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> file
of the OS the kernel belongs to.</para></listitem>
<listitem><para>An optional <literal>.osrel</literal> section with OS release information, i.e. the
contents of the
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> file of
the OS the kernel belongs to.</para></listitem>
<listitem><para>A <literal>.cmdline</literal> section with the kernel command line to pass to the
invoked kernel.</para></listitem>
<listitem><para>An optional <literal>.cmdline</literal> section with the kernel command line to pass to
the invoked kernel.</para></listitem>
<listitem><para>An <literal>.initrd</literal> section with the initrd.</para></listitem>
<listitem><para>An optional <literal>.initrd</literal> section with the initrd.</para></listitem>
<listitem><para>A <literal>.ucode</literal> section with an initrd containing microcode, to be handed
to the kernel before any other initrd. This initrd must not be compressed.</para></listitem>
<listitem><para>An optional <literal>.ucode</literal> section with an initrd containing microcode, to
be handed to the kernel before any other initrd. This initrd must not be compressed.</para></listitem>
<listitem><para>A <literal>.splash</literal> section with an image (in the Windows
<listitem><para>An optional <literal>.splash</literal> section with an image (in the Windows
<filename>.BMP</filename> format) to show on screen before invoking the kernel.</para></listitem>
<listitem><para>A <literal>.dtb</literal> section with a compiled binary DeviceTree.</para></listitem>
<listitem><para>An optional <literal>.dtb</literal> section with a compiled binary DeviceTree.
</para></listitem>
<listitem><para>A <literal>.uname</literal> section with the kernel version information, i.e. the
output of <command>uname -r</command> for the kernel included in the <literal>.linux</literal>
<listitem><para>Zero or more <literal>.dtbauto</literal> sections. <filename>systemd-stub</filename>
will always use the first matching one. The match is performed by taking the first DeviceTree's
<varname>compatible</varname> string supplied by the firmware in configuration tables and comparing it
with the first <varname>compatible</varname> string from each of the <literal>.dtbauto</literal>
sections. If the firmware does not provide a DeviceTree, the match is done using the
<varname>.hwids</varname> section instead. After selecting a <literal>.hwids</literal> section (see the
description below), the <varname>compatible</varname> string from that section will be used to perform
the same matching procedure. If a match is found, that <literal>.dtbauto</literal> section will be
loaded and will override <varname>.dtb</varname> if present.</para></listitem>
<listitem><para>Zero or more <literal>.hwids</literal> sections with hardware IDs of the machines to
match DeviceTrees. <filename>systemd-stub</filename> will use the SMBIOS data to calculate hardware IDs
of the machine (as per <ulink
url="https://learn.microsoft.com/en-us/windows-hardware/drivers/install/specifying-hardware-ids-for-a-computer">specification</ulink>),
and then it will try to find any of them in each of the <literal>.hwids</literal> sections. The first
matching section will be used.</para></listitem>
<listitem><para>An optional <literal>.uname</literal> section with the kernel version information, i.e.
the output of <command>uname -r</command> for the kernel included in the <literal>.linux</literal>
section.</para></listitem>
<listitem><para>An <literal>.sbat</literal> section with
<ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">SBAT</ulink> revocation
metadata.</para></listitem>
<listitem><para>An optional <literal>.sbat</literal> section with
<ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">SBAT</ulink> revocation metadata.
</para></listitem>
<listitem><para>A <literal>.pcrsig</literal> section with a set of cryptographic signatures for the
expected TPM2 PCR values after the kernel has been booted, in JSON format. This is useful for
<listitem><para>An optional <literal>.pcrsig</literal> section with a set of cryptographic signatures
for the expected TPM2 PCR values after the kernel has been booted, in JSON format. This is useful for
implementing TPM2 policies that bind disk encryption and similar to kernels that are signed by a
specific key.</para></listitem>
<listitem><para>A <literal>.pcrpkey</literal> section with a public key in the PEM format matching the
signature data in the <literal>.pcrsig</literal> section.</para></listitem>
<listitem><para>An optional <literal>.pcrpkey</literal> section with a public key in the PEM format
matching the signature data in the <literal>.pcrsig</literal> section.</para></listitem>
</itemizedlist>
<para>In a basic UKI, the sections listed above appear at most once. In a multi-profile UKI,
<!-- FIXME: how does .dtauto/.hwids matching interact with profiles? -->
<para>In a basic UKI, the sections listed above appear at most once, with the exception of
<literal>.dtbauto</literal> and <literal>.hwids</literal> sections. In a multi-profile UKI,
multiple sets of these sections are present in a single file and form "profiles",
one of which can be selected at boot. For this, the PE section <literal>.profile</literal> is
defined to be used as the separator between sets of sections. The
@ -192,7 +214,7 @@
<listitem><para>Similarly, files
<filename><replaceable>foo</replaceable>.efi.extra.d/*.addon.efi</filename> are loaded and verified as
PE binaries and specific sections are loaded from them. Addons are used to pass additional kernel
command line parameters (<literal>.cmdline</literal> section), or Devicetree blobs
command line parameters (<literal>.cmdline</literal> section), or DeviceTree blobs
(<literal>.dtb</literal> section), additional initrds (<literal>.initrd</literal> section),
and microcode updates (<literal>.ucode</literal> section). Addons allow those resources to be passed
regardless of the kernel version being booted, for example allowing platform vendors to ship

View File

@ -45,11 +45,12 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-sysupdate</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<citerefentry><refentrytitle>updatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-sysupdate</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>updatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.sysupdate1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -99,6 +99,7 @@ systemd-timesyncd.service
<member><citerefentry><refentrytitle>localtime</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>hwclock</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-timesyncd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.timedate1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>

View File

@ -75,8 +75,8 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -893,8 +893,6 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<refsect1>
<title>Mandatory Access Control</title>
<xi:include href="system-only.xml" xpointer="plural"/>
<variablelist class='unit-directives'>
<varlistentry>
@ -921,6 +919,8 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
prefixed by <literal>-</literal>, all errors will be ignored. This setting has no effect if AppArmor
is not enabled. This setting does not affect commands prefixed with <literal>+</literal>.</para>
<xi:include href="system-only.xml" xpointer="singular"/>
<xi:include href="version-info.xml" xpointer="v210"/>
</listitem>
</varlistentry>
@ -939,6 +939,8 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
value may be specified to unset previous assignments. This does not affect commands prefixed with
<literal>+</literal>.</para>
<xi:include href="system-only.xml" xpointer="singular"/>
<xi:include href="version-info.xml" xpointer="v218"/></listitem>
</varlistentry>
@ -1431,6 +1433,10 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
set. This setting cannot ensure protection in all cases. In general it has the same limitations as
<varname>ReadOnlyPaths=</varname>, see below. Defaults to off.</para>
<para>Note that if <varname>ProtectSystem=</varname> is set to <literal>strict</literal> and
<varname>PrivateTmp=</varname> is enabled, then <filename>/tmp/</filename> and
<filename>/var/tmp/</filename> will be writable.</para>
<xi:include href="version-info.xml" xpointer="v214"/></listitem>
</varlistentry>

View File

@ -123,7 +123,7 @@
<row>
<entry><replaceable>prefix</replaceable><constant>d</constant><replaceable>number</replaceable></entry>
<entry>Devicetree alias index</entry>
<entry>DeviceTree alias index</entry>
</row>
</tbody>

View File

@ -1004,6 +1004,27 @@ DuplicateAddressDetection=none</programlisting></para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>MulticastIGMPVersion=</varname></term>
<listitem>
<para>Configures IPv4 Multicast IGMP Version to be used, and controls the value of
<filename>/proc/sys/net/ipv4/conf/<replaceable>INTERFACE</replaceable>/force_igmp_version</filename>.
Takes one of <literal>no</literal>,
<literal>v1</literal>, <literal>v2</literal>, or <literal>v3</literal>.
When <literal>no</literal>, no enforcement of an IGMP version will be applied, IGMPv1/v2 fallback are allowed, will back to
IGMPv3 mode again if all IGMPv1/v2 Querier Present timer expire.
When <literal>v1</literal>, use of IGMP version 1 will be enforced, and IGMPv1 report will be replied even if IGMPv2/v3
queries are received.
When <literal>v2</literal>, use of IGMP version 2 will be enforced, and IGMPv2 report will be replied if an IGMPv2/v3 query
is received, but fallback to IGMPv1 if an IGMPv1 query is received.
When <literal>v3</literal>, use of IGMP version 3 will be enforced, and the same reaction will be done as <literal>no</literal>.
Defaults to unset, and the sysctl value will be unchanged.
</para>
<xi:include href="version-info.xml" xpointer="v257"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>IPv4AcceptLocal=</varname></term>
<listitem>

View File

@ -153,11 +153,14 @@
not apply to <varname>PathChanged=</varname> and
<varname>PathModified=</varname>.</para>
<para>If the path itself or any of the containing directories
are not accessible, <command>systemd</command> will watch for
permission changes and notice that conditions are satisfied
when permissions allow that. </para></listitem>
<para>If the path itself or any of the containing directories are not accessible,
<command>systemd</command> will watch for permission changes and notice that conditions are satisfied
when permissions allow that. </para>
<para>Note that files whose name starts with a dot (i.e. hidden files) are generally ignored when
monitoring these paths.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Unit=</varname></term>

View File

@ -551,11 +551,11 @@
<varname>ExecStop=</varname> commands specified with this setting are invoked when a service failed to start
up correctly and is shut down again.</para>
<para>It is recommended to use this setting for clean-up operations that shall be executed even when the
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
the service failed starting up half-way and left incompletely initialized data around. As the service's
processes have been terminated already when the commands specified with this setting are executed they should
not attempt to communicate with them.</para>
<para>It is recommended to use this setting for clean-up operations that shall be executed even when
the service failed to start up correctly. Commands configured with this setting need to be able to
operate even if the service failed starting up half-way and left incompletely initialized data
around. As the service's processes have likely exited already when the commands specified with this
setting are executed they should not attempt to communicate with them.</para>
<para>Note that all commands that are configured with this setting are invoked with the result code of the
service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,

View File

@ -224,9 +224,10 @@ KeyThree=value 3\
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -1590,6 +1590,7 @@
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
</simplelist></para>
<para>For more information about the concepts and

View File

@ -82,9 +82,10 @@
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
</para>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -100,10 +100,12 @@
the n-th boot phase path set will be signed by the n-th key. This can be used to build different trust
policies for different phases of the boot. In the config file, <varname>PCRPrivateKey=</varname>,
<varname>PCRPublicKey=</varname>, and <varname>Phases=</varname> are grouped into separate sections,
describing separate boot phases. If <varname>SigningEngine=</varname>/<option>--signing-engine=</option>
is specified, then the private keys arguments will be passed verbatim to OpenSSL as URIs, and the public
key arguments will be loaded as X.509 certificates, so that signing can be performed with an OpenSSL
engine.</para>
describing separate boot phases. If one of
<varname>SigningEngine=</varname>/<option>--signing-engine=</option> or
<varname>SigningProvider=</varname>/<option>--signing-provider=</option> is specified, then the private
key arguments will be passed verbatim to OpenSSL as URIs, and the public key arguments will be loaded
as X.509 certificates, so that signing can be performed with an OpenSSL engine or provider
respectively.</para>
<para>If a SecureBoot signing key is provided via the
<varname>SecureBootPrivateKey=</varname>/<option>--secureboot-private-key=</option> option, the resulting
@ -440,9 +442,9 @@
<term><varname>SecureBootSigningTool=<replaceable>SIGNER</replaceable></varname></term>
<term><option>--signtool=<replaceable>SIGNER</replaceable></option></term>
<listitem><para>Whether to use <literal>sbsign</literal> or <literal>pesign</literal>.
Depending on this choice, different parameters are required in order to sign an image.
Defaults to <literal>sbsign</literal>.</para>
<listitem><para>Whether to use <literal>sbsign</literal>, <literal>pesign</literal>, or
<literal>systemd-sbsign</literal>. Depending on this choice, different parameters are required in
order to sign an image. Defaults to <literal>sbsign</literal>.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
@ -452,8 +454,9 @@
<term><option>--secureboot-private-key=<replaceable>SB_KEY</replaceable></option></term>
<listitem><para>A path to a private key to use for signing of the resulting binary. If the
<varname>SigningEngine=</varname>/<option>--signing-engine=</option> option is used, this may also be
an engine-specific designation. This option is required by
<varname>SigningEngine=</varname>/<option>--signing-engine=</option> or
<varname>SigningProvider=</varname>/<option>--signing-provider=</option> option is used, this may
also be an engine or provider specific designation. This option is required by
<varname>SecureBootSigningTool=sbsign</varname>/<option>--signtool=sbsign</option>. </para>
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
@ -464,8 +467,9 @@
<term><option>--secureboot-certificate=<replaceable>SB_CERT</replaceable></option></term>
<listitem><para>A path to a certificate to use for signing of the resulting binary. If the
<varname>SigningEngine=</varname>/<option>--signing-engine=</option> option is used, this may also
be an engine-specific designation. This option is required by
<varname>SigningEngine=</varname>/<option>--signing-engine=</option> or
<varname>SigningProvider=</varname>/<option>--signing-provider=</option> option is used, this may
also be an engine or provider specific designation. This option is required by
<varname>SecureBootSigningTool=sbsign</varname>/<option>--signtool=sbsign</option>. </para>
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
@ -506,14 +510,23 @@
<term><varname>SigningEngine=<replaceable>ENGINE</replaceable></varname></term>
<term><option>--signing-engine=<replaceable>ENGINE</replaceable></option></term>
<listitem><para>An "engine" for signing of the resulting binary. This option is currently passed
verbatim to the <option>--engine=</option> option of
<citerefentry project='archlinux'><refentrytitle>sbsign</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
<listitem><para>An OpenSSL engine to be used for signing the resulting binary and PCR measurements.
</para>
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>SigningProvider=<replaceable>PROVIDER</replaceable></varname></term>
<term><option>--signing-provider=<replaceable>PROVIDER</replaceable></option></term>
<listitem><para>An OpenSSL provider to be used for signing the resulting binary and PCR
measurements. This option can only be used when using <command>systemd-sbsign</command> as the
signing tool.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>SignKernel=<replaceable>BOOL</replaceable></varname></term>
<term><option>--sign-kernel</option></term>

View File

@ -2,7 +2,9 @@
[Build]
ToolsTreePackages=
meson
gcc
gperf
meson
mypy
pkgconf
ruff

View File

@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-23 15:33+0200\n"
"PO-Revision-Date: 2024-09-06 09:38+0000\n"
"PO-Revision-Date: 2024-11-06 12:46+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n"
@ -21,7 +21,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.7.2\n"
"X-Generator: Weblate 5.8.2\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
@ -815,27 +815,27 @@ msgstr ""
#: src/login/org.freedesktop.login1.policy:374
msgid "Indicate to the boot loader to boot to the boot loader menu"
msgstr "Indiquer au boot loader d'afficher le menu de sélection"
msgstr "Indiquer au bootloader de démarrer sur le menu de sélection"
#: src/login/org.freedesktop.login1.policy:375
msgid ""
"Authentication is required to indicate to the boot loader to boot to the "
"boot loader menu."
msgstr ""
"Une authentification est requise pour indiquer au boot loader d'afficher le "
"menu de sélection."
"Une authentification est requise pour indiquer au bootloader de démarrer sur "
"le menu de sélection."
#: src/login/org.freedesktop.login1.policy:385
msgid "Indicate to the boot loader to boot a specific entry"
msgstr "Indiquer au boot loader de démarrer une entrée spécifique"
msgstr "Indiquer au bootloader de démarrer une entrée spécifique"
#: src/login/org.freedesktop.login1.policy:386
msgid ""
"Authentication is required to indicate to the boot loader to boot into a "
"specific boot loader entry."
msgstr ""
"Une authentification est requise pour indiquer au boot loader de démarrer "
"une entrée spécifique."
"Une authentification est requise pour indiquer au bootloader de démarrer une "
"entrée spécifique."
#: src/login/org.freedesktop.login1.policy:396
msgid "Set a wall message"

View File

@ -527,19 +527,19 @@ int is_idmapping_supported(const char *path) {
return r;
userns_fd = userns_acquire(uid_map, gid_map);
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd))
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd) || ERRNO_IS_NEG_PRIVILEGE(userns_fd))
return false;
if (userns_fd < 0)
return log_debug_errno(userns_fd, "ID-mapping supported namespace acquire failed for '%s' : %m", path);
dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd) || dir_fd == -EINVAL)
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd))
return false;
if (dir_fd < 0)
return log_debug_errno(dir_fd, "ID-mapping supported open failed for '%s' : %m", path);
mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || mount_fd == -EINVAL)
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || ERRNO_IS_NEG_PRIVILEGE(mount_fd) || mount_fd == -EINVAL)
return false;
if (mount_fd < 0)
return log_debug_errno(mount_fd, "ID-mapping supported open_tree failed for '%s' : %m", path);
@ -549,7 +549,7 @@ int is_idmapping_supported(const char *path) {
.attr_set = MOUNT_ATTR_IDMAP | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RDONLY | MOUNT_ATTR_NODEV,
.userns_fd = userns_fd,
}, sizeof(struct mount_attr)));
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || r == -EINVAL || r == -EPERM)
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
return false;
if (r < 0)
return log_debug_errno(r, "ID-mapping supported setattr failed for '%s' : %m", path);

View File

@ -35,6 +35,7 @@
#include "fileio.h"
#include "fs-util.h"
#include "hostname-util.h"
#include "io-util.h"
#include "locale-util.h"
#include "log.h"
#include "macro.h"
@ -2238,3 +2239,18 @@ static const char* const sched_policy_table[] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
_noreturn_ void report_errno_and_exit(int errno_fd, int error) {
int r;
if (error >= 0)
_exit(EXIT_SUCCESS);
assert(errno_fd >= 0);
r = loop_write(errno_fd, &error, sizeof(error));
if (r < 0)
log_debug_errno(r, "Failed to write errno to errno_fd=%d: %m", errno_fd);
_exit(EXIT_FAILURE);
}

View File

@ -273,3 +273,5 @@ int posix_spawn_wrapper(
int proc_dir_open(DIR **ret);
int proc_dir_read(DIR *d, pid_t *ret);
int proc_dir_read_pidref(DIR *d, PidRef *ret);
_noreturn_ void report_errno_and_exit(int errno_fd, int error);

135
src/boot/authenticode.h Normal file
View File

@ -0,0 +1,135 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <openssl/asn1t.h>
#include "macro.h"
#define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
#define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15"
typedef struct {
ASN1_OBJECT *type;
ASN1_TYPE *value;
} SpcAttributeTypeAndOptionalValue;
DECLARE_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue);
ASN1_SEQUENCE(SpcAttributeTypeAndOptionalValue) = {
ASN1_SIMPLE(SpcAttributeTypeAndOptionalValue, type, ASN1_OBJECT),
ASN1_OPT(SpcAttributeTypeAndOptionalValue, value, ASN1_ANY)
} ASN1_SEQUENCE_END(SpcAttributeTypeAndOptionalValue);
IMPLEMENT_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue);
typedef struct {
ASN1_OBJECT *algorithm;
ASN1_TYPE *parameters;
} AlgorithmIdentifier;
DECLARE_ASN1_FUNCTIONS(AlgorithmIdentifier);
ASN1_SEQUENCE(AlgorithmIdentifier) = {
ASN1_SIMPLE(AlgorithmIdentifier, algorithm, ASN1_OBJECT),
ASN1_OPT(AlgorithmIdentifier, parameters, ASN1_ANY)
} ASN1_SEQUENCE_END(AlgorithmIdentifier)
IMPLEMENT_ASN1_FUNCTIONS(AlgorithmIdentifier);
typedef struct {
AlgorithmIdentifier *digestAlgorithm;
ASN1_OCTET_STRING *digest;
} DigestInfo;
DECLARE_ASN1_FUNCTIONS(DigestInfo);
ASN1_SEQUENCE(DigestInfo) = {
ASN1_SIMPLE(DigestInfo, digestAlgorithm, AlgorithmIdentifier),
ASN1_SIMPLE(DigestInfo, digest, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(DigestInfo);
IMPLEMENT_ASN1_FUNCTIONS(DigestInfo);
typedef struct {
SpcAttributeTypeAndOptionalValue *data;
DigestInfo *messageDigest;
} SpcIndirectDataContent;
DECLARE_ASN1_FUNCTIONS(SpcIndirectDataContent);
ASN1_SEQUENCE(SpcIndirectDataContent) = {
ASN1_SIMPLE(SpcIndirectDataContent, data, SpcAttributeTypeAndOptionalValue),
ASN1_SIMPLE(SpcIndirectDataContent, messageDigest, DigestInfo)
} ASN1_SEQUENCE_END(SpcIndirectDataContent);
IMPLEMENT_ASN1_FUNCTIONS(SpcIndirectDataContent);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SpcIndirectDataContent*, SpcIndirectDataContent_free, NULL);
typedef struct {
int type;
union {
ASN1_BMPSTRING *unicode;
ASN1_IA5STRING *ascii;
} value;
} SpcString;
DECLARE_ASN1_FUNCTIONS(SpcString);
ASN1_CHOICE(SpcString) = {
ASN1_IMP_OPT(SpcString, value.unicode, ASN1_BMPSTRING, 0),
ASN1_IMP_OPT(SpcString, value.ascii, ASN1_IA5STRING, 1)
} ASN1_CHOICE_END(SpcString);
IMPLEMENT_ASN1_FUNCTIONS(SpcString);
typedef struct {
ASN1_OCTET_STRING *classId;
ASN1_OCTET_STRING *serializedData;
} SpcSerializedObject;
DECLARE_ASN1_FUNCTIONS(SpcSerializedObject);
ASN1_SEQUENCE(SpcSerializedObject) = {
ASN1_SIMPLE(SpcSerializedObject, classId, ASN1_OCTET_STRING),
ASN1_SIMPLE(SpcSerializedObject, serializedData, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(SpcSerializedObject);
IMPLEMENT_ASN1_FUNCTIONS(SpcSerializedObject);
typedef struct {
int type;
union {
ASN1_IA5STRING *url;
SpcSerializedObject *moniker;
SpcString *file;
} value;
} SpcLink;
DECLARE_ASN1_FUNCTIONS(SpcLink);
ASN1_CHOICE(SpcLink) = {
ASN1_IMP_OPT(SpcLink, value.url, ASN1_IA5STRING, 0),
ASN1_IMP_OPT(SpcLink, value.moniker, SpcSerializedObject, 1),
ASN1_EXP_OPT(SpcLink, value.file, SpcString, 2)
} ASN1_CHOICE_END(SpcLink);
IMPLEMENT_ASN1_FUNCTIONS(SpcLink);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SpcLink*, SpcLink_free, NULL);
typedef struct {
ASN1_BIT_STRING *flags;
SpcLink *file;
} SpcPeImageData;
DECLARE_ASN1_FUNCTIONS(SpcPeImageData);
ASN1_SEQUENCE(SpcPeImageData) = {
ASN1_SIMPLE(SpcPeImageData, flags, ASN1_BIT_STRING),
ASN1_EXP_OPT(SpcPeImageData, file, SpcLink, 0)
} ASN1_SEQUENCE_END(SpcPeImageData)
IMPLEMENT_ASN1_FUNCTIONS(SpcPeImageData);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SpcPeImageData*, SpcPeImageData_free, NULL);

View File

@ -54,7 +54,7 @@ libraries (such as OpenSSL or gnu-efi) are linked, embedded, or used.
## Additional Resources
BLS Type #1 entries allow the user to load two types of additional resources that can affect the system
before `ExitBootServices()` has been called — kernel command line arguments and Devicetree blobs — that are
before `ExitBootServices()` has been called — kernel command line arguments and DeviceTree blobs — that are
not validated before use, as they do not carry signatures. For this reason, when SecureBoot is enabled,
loading these resources is automatically disabled. There is no override for this security mechanism, neither
at build time nor at runtime. Note that initrds are also not verified in BLS Type #1 configurations, for
@ -62,7 +62,7 @@ compatibility with how SecureBoot has been traditionally handled on Linux-based
only load them after `ExitBootServices()` has been called.
Another mechanism is supported by `systemd-boot` and `systemd-stub` to add additional payloads to the boot
process: "addons". Addons are PE signed binaries that can carry kernel command line arguments or Devicetree
process: "addons". Addons are PE signed binaries that can carry kernel command line arguments or DeviceTree
blobs (more payload types might be added in the future).
In contrast to the user-specified additions in the Type #1 case
described above, these addons are loaded through the UEFI image loading protocol, and thus are subject to

129
src/boot/efi/chid.c Normal file
View File

@ -0,0 +1,129 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Based on Nikita Travkin's dtbloader implementation.
* Copyright (c) 2024 Nikita Travkin <nikita@trvn.ru>
*
* https://github.com/TravMurav/dtbloader/blob/main/src/chid.c
*/
/*
* Based on Linaro dtbloader implementation.
* Copyright (c) 2019, Linaro. All rights reserved.
*
* https://github.com/aarch64-laptops/edk2/blob/dtbloader-app/EmbeddedPkg/Application/ConfigTableLoader/CHID.c
*/
#include "chid.h"
#include "chid-fundamental.h"
#include "efi.h"
#include "sha1-fundamental.h"
#include "smbios.h"
#include "util.h"
/**
* smbios_to_hashable_string() - Convert ascii smbios string to stripped char16_t.
*/
static char16_t *smbios_to_hashable_string(const char *str) {
if (!str)
/* User of this function is expected to free the result. */
return xnew0(char16_t, 1);
/*
* We need to strip leading and trailing spaces, leading zeroes.
* See fwupd/libfwupdplugin/fu-hwids-smbios.c
*/
while (*str == ' ')
str++;
while (*str == '0')
str++;
size_t len = strlen8(str);
while (len > 0 && str[len - 1] == ' ')
len--;
return xstrn8_to_16(str, len);
}
/* This has to be in a struct due to _cleanup_ in populate_board_chids */
typedef struct SmbiosInfo {
const char16_t *smbios_fields[_CHID_SMBIOS_FIELDS_MAX];
} SmbiosInfo;
static void smbios_info_populate(SmbiosInfo *ret_info) {
static RawSmbiosInfo raw = {};
static bool raw_info_populated = false;
if (!raw_info_populated) {
smbios_raw_info_populate(&raw);
raw_info_populated = true;
}
ret_info->smbios_fields[CHID_SMBIOS_MANUFACTURER] = smbios_to_hashable_string(raw.manufacturer);
ret_info->smbios_fields[CHID_SMBIOS_PRODUCT_NAME] = smbios_to_hashable_string(raw.product_name);
ret_info->smbios_fields[CHID_SMBIOS_PRODUCT_SKU] = smbios_to_hashable_string(raw.product_sku);
ret_info->smbios_fields[CHID_SMBIOS_FAMILY] = smbios_to_hashable_string(raw.family);
ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_PRODUCT] = smbios_to_hashable_string(raw.baseboard_product);
ret_info->smbios_fields[CHID_SMBIOS_BASEBOARD_MANUFACTURER] = smbios_to_hashable_string(raw.baseboard_manufacturer);
}
static void smbios_info_done(SmbiosInfo *info) {
FOREACH_ELEMENT(i, info->smbios_fields)
free(i);
}
static EFI_STATUS populate_board_chids(EFI_GUID ret_chids[static CHID_TYPES_MAX]) {
_cleanup_(smbios_info_done) SmbiosInfo info = {};
if (!ret_chids)
return EFI_INVALID_PARAMETER;
smbios_info_populate(&info);
chid_calculate(info.smbios_fields, ret_chids);
return EFI_SUCCESS;
}
EFI_STATUS chid_match(const void *hwid_buffer, size_t hwid_length, const Device **ret_device) {
EFI_STATUS status;
if ((uintptr_t) hwid_buffer % alignof(Device) != 0)
return EFI_INVALID_PARAMETER;
const Device *devices = ASSERT_PTR(hwid_buffer);
EFI_GUID chids[CHID_TYPES_MAX] = {};
static const size_t priority[] = { 3, 6, 8, 10, 4, 5, 7, 9, 11 }; /* From most to least specific. */
status = populate_board_chids(chids);
if (EFI_STATUS_IS_ERROR(status))
return log_error_status(status, "Failed to populate board CHIDs: %m");
size_t n_devices = 0;
/* Count devices and check validity */
for (; (n_devices + 1) * sizeof(*devices) < hwid_length;) {
if (devices[n_devices].struct_size == 0)
break;
if (devices[n_devices].struct_size != sizeof(*devices))
return EFI_UNSUPPORTED;
n_devices++;
}
if (n_devices == 0)
return EFI_NOT_FOUND;
FOREACH_ELEMENT(i, priority)
FOREACH_ARRAY(dev, devices, n_devices) {
/* Can't take a pointer to a packed struct member, so copy to a local variable */
EFI_GUID chid = dev->chid;
if (efi_guid_equal(&chids[*i], &chid)) {
*ret_device = dev;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}

23
src/boot/efi/chid.h Normal file
View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#pragma once
#include "efi.h"
#include "chid-fundamental.h"
typedef struct Device {
uint32_t struct_size; /* = sizeof(struct Device), or 0 for EOL */
uint32_t name_offset; /* nul-terminated string or 0 if not present */
uint32_t compatible_offset; /* nul-terminated string or 0 if not present */
EFI_GUID chid;
} _packed_ Device;
static inline const char* device_get_name(const void *base, const Device *device) {
return device->name_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->name_offset);
}
static inline const char* device_get_compatible(const void *base, const Device *device) {
return device->compatible_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->compatible_offset);
}
EFI_STATUS chid_match(const void *chids_buffer, size_t chids_length, const Device **ret_device);

View File

@ -106,6 +106,129 @@ EFI_STATUS devicetree_install(struct devicetree_state *state, EFI_FILE *root_dir
MAKE_GUID_PTR(EFI_DTB_TABLE), PHYSICAL_ADDRESS_TO_POINTER(state->addr));
}
static const char* devicetree_get_compatible(const void *dtb) {
if ((uintptr_t) dtb % alignof(FdtHeader) != 0)
return NULL;
const FdtHeader *dt_header = ASSERT_PTR(dtb);
if (be32toh(dt_header->magic) != UINT32_C(0xd00dfeed))
return NULL;
uint32_t dt_size = be32toh(dt_header->total_size);
uint32_t struct_off = be32toh(dt_header->off_dt_struct);
uint32_t struct_size = be32toh(dt_header->size_dt_struct);
uint32_t strings_off = be32toh(dt_header->off_dt_strings);
uint32_t strings_size = be32toh(dt_header->size_dt_strings);
uint32_t end;
if (PTR_TO_SIZE(dtb) > SIZE_MAX - dt_size)
return NULL;
if (!ADD_SAFE(&end, strings_off, strings_size) || end > dt_size)
return NULL;
const char *strings_block = (const char *) ((const uint8_t *) dt_header + strings_off);
if (struct_off % sizeof(uint32_t) != 0)
return NULL;
if (struct_size % sizeof(uint32_t) != 0 ||
!ADD_SAFE(&end, struct_off, struct_size) ||
end > strings_off)
return NULL;
const uint32_t *cursor = (const uint32_t *) ((const uint8_t *) dt_header + struct_off);
size_t size_words = struct_size / sizeof(uint32_t);
size_t len, name_off, len_words, s;
for (size_t i = 0; i < end; i++) {
switch (be32toh(cursor[i])) {
case FDT_BEGIN_NODE:
if (i >= size_words || cursor[++i] != 0)
return NULL;
break;
case FDT_NOP:
break;
case FDT_PROP:
/* At least 3 words should present: len, name_off, c (nul-terminated string always has non-zero length) */
if (i + 3 >= size_words || cursor[++i] != 0)
return NULL;
len = be32toh(cursor[++i]);
name_off = be32toh(cursor[++i]);
len_words = DIV_ROUND_UP(len, sizeof(uint32_t));
if (ADD_SAFE(&s, name_off, STRLEN("compatible")) &&
s < strings_size && streq8(strings_block + name_off, "compatible")) {
const char *c = (const char *) &cursor[++i];
if (len == 0 || i + len_words > size_words || c[len - 1] != '\0')
c = NULL;
return c;
}
i += len_words;
break;
default:
return NULL;
}
}
return NULL;
}
bool firmware_devicetree_exists(void) {
return !!find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE));
}
/* This function checks if the firmware provided DeviceTree
* and a UKI provided DeviceTree contain the same first entry
* on their respective "compatible" fields (which usually defines
* the actual device model). More specifically, given the FW/UKI
* "compatible" property pair:
*
* compatible = "string1", "string2";
* compatible = "string1", "string3";
*
* the function reports a match, while for
*
* compatible = "string1", "string3";
* compatible = "string2", "string1";
*
* it reports a mismatch.
*
* Other entries might refer to SoC and therefore can't be used for matching
*/
EFI_STATUS devicetree_match(const void *uki_dtb, size_t uki_dtb_length) {
const void *fw_dtb = find_configuration_table(MAKE_GUID_PTR(EFI_DTB_TABLE));
if (!fw_dtb)
return EFI_UNSUPPORTED;
const char *fw_compat = devicetree_get_compatible(fw_dtb);
if (!fw_compat)
return EFI_UNSUPPORTED;
return devicetree_match_by_compatible(uki_dtb, uki_dtb_length, fw_compat);
}
EFI_STATUS devicetree_match_by_compatible(const void *uki_dtb, size_t uki_dtb_length, const char *compat) {
if ((uintptr_t) uki_dtb % alignof(FdtHeader) != 0)
return EFI_INVALID_PARAMETER;
const FdtHeader *dt_header = ASSERT_PTR(uki_dtb);
if (uki_dtb_length < sizeof(FdtHeader) ||
uki_dtb_length < be32toh(dt_header->total_size))
return EFI_INVALID_PARAMETER;
if (!compat)
return EFI_INVALID_PARAMETER;
const char *dt_compat = devicetree_get_compatible(uki_dtb);
if (!dt_compat)
return EFI_INVALID_PARAMETER;
/* Only matches the first compatible string from each DT */
return streq8(dt_compat, compat) ? EFI_SUCCESS : EFI_NOT_FOUND;
}
EFI_STATUS devicetree_install_from_memory(
struct devicetree_state *state, const void *dtb_buffer, size_t dtb_length) {

View File

@ -9,6 +9,30 @@ struct devicetree_state {
void *orig;
};
enum {
FDT_BEGIN_NODE = 1,
FDT_END_NODE = 2,
FDT_PROP = 3,
FDT_NOP = 4,
FDT_END = 9,
};
typedef struct FdtHeader {
uint32_t magic;
uint32_t total_size;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsv_map;
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
} FdtHeader;
bool firmware_devicetree_exists(void);
EFI_STATUS devicetree_match(const void *uki_dtb, size_t uki_dtb_length);
EFI_STATUS devicetree_match_by_compatible(const void *uki_dtb, size_t uki_dtb_length, const char *compat);
EFI_STATUS devicetree_install(struct devicetree_state *state, EFI_FILE *root_dir, char16_t *name);
EFI_STATUS devicetree_install_from_memory(
struct devicetree_state *state, const void *dtb_buffer, size_t dtb_length);

View File

@ -254,6 +254,7 @@ endif
############################################################
libefi_sources = files(
'chid.c',
'console.c',
'device-path-util.c',
'devicetree.c',

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "chid.h"
#include "devicetree.h"
#include "pe.h"
#include "util.h"
@ -162,11 +164,46 @@ static bool pe_section_name_equal(const char *a, const char *b) {
return true;
}
static void pe_locate_sections(
static bool pe_use_this_dtb(
const void *dtb,
size_t dtb_size,
const void *base,
const Device *device,
size_t section_nb) {
assert(dtb);
EFI_STATUS err;
err = devicetree_match(dtb, dtb_size);
if (err == EFI_SUCCESS)
return true;
if (err != EFI_UNSUPPORTED)
return false;
/* There's nothing to match against if firmware does not provide DTB and there is no .hwids section */
if (!device || !base)
return false;
const char *compatible = device_get_compatible(base, device);
if (!compatible)
return false;
err = devicetree_match_by_compatible(dtb, dtb_size, compatible);
if (err == EFI_SUCCESS)
return true;
if (err == EFI_INVALID_PARAMETER)
log_error_status(err, "Found bad DT blob in PE section %zu", section_nb);
return false;
}
static void pe_locate_sections_internal(
const PeSectionHeader section_table[],
size_t n_section_table,
const char *const section_names[],
size_t validate_base,
const void *device_table,
const Device *device,
PeSectionVector sections[]) {
assert(section_table || n_section_table == 0);
@ -206,6 +243,20 @@ static void pe_locate_sections(
continue;
}
/* Special handling for .dtbauto sections compared to plain .dtb */
if (pe_section_name_equal(section_names[i], ".dtbauto")) {
/* .dtbauto sections require validate_base for matching */
if (!validate_base)
break;
if (!pe_use_this_dtb(
(const uint8_t *) SIZE_TO_PTR(validate_base) + j->VirtualAddress,
j->VirtualSize,
device_table,
device,
i))
continue;
}
/* At this time, the sizes and offsets have been validated. Store them away */
sections[i] = (PeSectionVector) {
.memory_size = j->VirtualSize,
@ -224,6 +275,73 @@ static void pe_locate_sections(
}
}
static bool looking_for_dbauto(const char *const section_names[]) {
assert(section_names);
for (size_t i = 0; section_names[i]; i++)
if (pe_section_name_equal(section_names[i], ".dtbauto"))
return true;
return false;
}
static void pe_locate_sections(
const PeSectionHeader section_table[],
size_t n_section_table,
const char *const section_names[],
size_t validate_base,
PeSectionVector sections[]) {
if (!looking_for_dbauto(section_names))
return pe_locate_sections_internal(
section_table,
n_section_table,
section_names,
validate_base,
/* device_base */ NULL,
/* device */ NULL,
sections);
/* It doesn't make sense not to provide validate_base here */
assert(validate_base != 0);
const void *hwids = NULL;
const Device *device = NULL;
if (!firmware_devicetree_exists()) {
/* Find HWIDs table and search for the current device */
PeSectionVector hwids_section = {};
pe_locate_sections_internal(
section_table,
n_section_table,
(const char *const[]) { ".hwids", NULL },
validate_base,
/* device_table */ NULL,
/* device */ NULL,
&hwids_section);
if (hwids_section.memory_offset != 0) {
hwids = (const uint8_t *) SIZE_TO_PTR(validate_base) + hwids_section.memory_offset;
EFI_STATUS err = chid_match(hwids, hwids_section.memory_size, &device);
if (err != EFI_SUCCESS) {
log_error_status(err, "HWID matching failed, no DT blob will be selected: %m");
hwids = NULL;
}
} else
log_info("HWIDs section is missing, no DT blob will be selected");
}
return pe_locate_sections_internal(
section_table,
n_section_table,
section_names,
validate_base,
hwids,
device,
sections);
}
static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) {
/* The kernel may provide alternative PE entry points for different PE architectures. This allows
* booting a 64-bit kernel on 32-bit EFI that is otherwise running on a 64-bit CPU. The locations of any

View File

@ -614,12 +614,13 @@ static EFI_STATUS load_addons(
if (err != EFI_SUCCESS ||
(!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_CMDLINE) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTBAUTO) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_INITRD) &&
!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_UCODE))) {
if (err == EFI_SUCCESS)
err = EFI_NOT_FOUND;
log_error_status(err,
"Unable to locate embedded .cmdline/.dtb/.initrd/.ucode sections in %ls, ignoring: %m",
"Unable to locate embedded .cmdline/.dtb/.dtbauto/.initrd/.ucode sections in %ls, ignoring: %m",
items[i]);
continue;
}
@ -647,7 +648,21 @@ static EFI_STATUS load_addons(
*cmdline = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
}
if (devicetree_addons && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB)) {
// FIXME: do we want to do something else here?
// This should behave exactly as .dtb/.dtbauto in the main UKI
if (devicetree_addons && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTBAUTO)) {
*devicetree_addons = xrealloc(*devicetree_addons,
*n_devicetree_addons * sizeof(NamedAddon),
(*n_devicetree_addons + 1) * sizeof(NamedAddon));
(*devicetree_addons)[(*n_devicetree_addons)++] = (NamedAddon) {
.blob = {
.iov_base = xmemdup((const uint8_t*) loaded_addon->ImageBase + sections[UNIFIED_SECTION_DTBAUTO].memory_offset, sections[UNIFIED_SECTION_DTBAUTO].memory_size),
.iov_len = sections[UNIFIED_SECTION_DTBAUTO].memory_size,
},
.filename = xstrdup16(items[i]),
};
} else if (devicetree_addons && PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB)) {
*devicetree_addons = xrealloc(*devicetree_addons,
*n_devicetree_addons * sizeof(NamedAddon),
(*n_devicetree_addons + 1) * sizeof(NamedAddon));
@ -968,13 +983,20 @@ static void install_embedded_devicetree(
assert(sections);
assert(dt_state);
if (!PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB))
UnifiedSection section = _UNIFIED_SECTION_MAX;
/* Use automatically selected DT if available, otherwise go for "normal" one */
if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTBAUTO))
section = UNIFIED_SECTION_DTBAUTO;
else if (PE_SECTION_VECTOR_IS_SET(sections + UNIFIED_SECTION_DTB))
section = UNIFIED_SECTION_DTB;
else
return;
err = devicetree_install_from_memory(
dt_state,
(const uint8_t*) loaded_image->ImageBase + sections[UNIFIED_SECTION_DTB].memory_offset,
sections[UNIFIED_SECTION_DTB].memory_size);
(const uint8_t*) loaded_image->ImageBase + sections[section].memory_offset,
sections[section].memory_size);
if (err != EFI_SUCCESS)
log_error_status(err, "Error loading embedded devicetree, ignoring: %m");
}

View File

@ -69,6 +69,7 @@ static inline void* xmemdup(const void *p, size_t l) {
}
#define xnew(type, n) ((type *) xmalloc_multiply((n), sizeof(type)))
#define xnew0(type, n) ((type *) xcalloc_multiply((n), sizeof(type)))
bool free_and_xstrdup16(char16_t **p, const char16_t *s);

View File

@ -98,11 +98,12 @@ static int help(int argc, char *argv[], void *userdata) {
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to Devicetree file %7$s .dtb\n"
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"
" --profile=PATH Path to profile file %7$s .profile\n"
" --hwids=PATH Path to HWIDs file %7$s .hwids\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@ -146,8 +147,10 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SBAT,
_ARG_PCRSIG, /* the .pcrsig section is not input for signing, hence not actually an argument here */
ARG_PCRPKEY,
ARG_PROFILE,
ARG_HWIDS,
_ARG_SECTION_LAST,
ARG_PROFILE = _ARG_SECTION_LAST,
ARG_DTBAUTO = _ARG_SECTION_LAST,
ARG_BANK,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
@ -170,10 +173,12 @@ static int parse_argv(int argc, char *argv[]) {
{ "ucode", required_argument, NULL, ARG_UCODE },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "dtbauto", required_argument, NULL, ARG_DTBAUTO },
{ "uname", required_argument, NULL, ARG_UNAME },
{ "sbat", required_argument, NULL, ARG_SBAT },
{ "pcrpkey", required_argument, NULL, ARG_PCRPKEY },
{ "profile", required_argument, NULL, ARG_PROFILE },
{ "hwids", required_argument, NULL, ARG_HWIDS },
{ "current", no_argument, NULL, 'c' },
{ "bank", required_argument, NULL, ARG_BANK },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
@ -834,7 +839,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
/* When signing we only support JSON output */
arg_json_format_flags &= ~SD_JSON_FORMAT_OFF;
/* This must be done before openssl_load_key_from_token() otherwise it will get stuck */
/* This must be done before openssl_load_private_key() otherwise it will get stuck */
if (arg_certificate) {
r = openssl_load_x509_certificate(arg_certificate, &certificate);
if (r < 0)

View File

@ -62,6 +62,14 @@ executables += [
'sources' : files('measure.c'),
'dependencies' : libopenssl,
},
libexec_template + {
'name' : 'systemd-sbsign',
'conditions' : [
'HAVE_OPENSSL',
],
'sources' : files('sbsign.c'),
'dependencies' : libopenssl,
},
libexec_template + {
'name' : 'systemd-boot-check-no-failures',
'sources' : files('boot-check-no-failures.c'),

523
src/boot/sbsign.c Normal file
View File

@ -0,0 +1,523 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "ansi-color.h"
#include "authenticode.h"
#include "build.h"
#include "copy.h"
#include "efi-fundamental.h"
#include "fd-util.h"
#include "log.h"
#include "main-func.h"
#include "openssl-util.h"
#include "parse-argument.h"
#include "pe-binary.h"
#include "pretty-print.h"
#include "stat-util.h"
#include "tmpfile-util.h"
#include "verbs.h"
static PagerFlags arg_pager_flags = 0;
static char *arg_output = NULL;
static char *arg_certificate = NULL;
static char *arg_private_key = NULL;
static KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
static char *arg_private_key_source = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_output, freep);
STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-sbsign", "1", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sSign binaries for EFI Secure Boot%6$s\n"
"\n%3$sCommands:%4$s\n"
" sign EXEFILE Sign the given binary for EFI Secure Boot\n"
" validate-key Load and validate the given private key\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"
" --no-pager Do not pipe output into a pager\n"
" --output Where to write the signed PE binary\n"
" --certificate=PATH PEM certificate to use when signing with a URI\n"
" --private-key=KEY Private key (PEM) to sign with\n"
" --private-key-source=file|provider:PROVIDER|engine:ENGINE\n"
" Specify how to use KEY for --private-key=. Allows\n"
" an OpenSSL engine/provider to be used for signing\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal());
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_OUTPUT,
ARG_CERTIFICATE,
ARG_PRIVATE_KEY,
ARG_PRIVATE_KEY_SOURCE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "version", no_argument, NULL, ARG_VERSION },
{ "output", required_argument, NULL, ARG_OUTPUT },
{ "certificate", required_argument, NULL, ARG_CERTIFICATE },
{ "private-key", required_argument, NULL, ARG_PRIVATE_KEY },
{ "private-key-source", required_argument, NULL, ARG_PRIVATE_KEY_SOURCE },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hjc", options, NULL)) >= 0)
switch (c) {
case 'h':
help(0, NULL, NULL);
return 0;
case ARG_VERSION:
return version();
case ARG_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_OUTPUT:
r = parse_path_argument(optarg, /*suppress_root=*/ false, &arg_output);
if (r < 0)
return r;
break;
case ARG_CERTIFICATE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_certificate);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY:
r = free_and_strdup_warn(&arg_private_key, optarg);
if (r < 0)
return r;
break;
case ARG_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
optarg,
&arg_private_key_source,
&arg_private_key_source_type);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_private_key_source && !arg_certificate)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "When using --private-key-source=, --certificate= must be specified.");
return 1;
}
static int verb_sign(int argc, char *argv[], void *userdata) {
_cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
_cleanup_(X509_freep) X509 *certificate = NULL;
int r;
if (argc < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No input file specified");
if (!arg_certificate)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No certificate specified, use --certificate=");
if (!arg_private_key)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No private key specified, use --private-key=.");
if (!arg_output)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No output specified, use --output=");
r = openssl_load_x509_certificate(arg_certificate, &certificate);
if (r < 0)
return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
}
r = openssl_load_private_key(
arg_private_key_source_type,
arg_private_key_source,
arg_private_key,
&(AskPasswordRequest) {
.id = "sbsign-private-key-pin",
.keyring = arg_private_key,
.credential = "sbsign.private-key-pin",
},
&private_key,
&ui);
if (r < 0)
return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
p7 = PKCS7_sign(certificate, private_key, /*certs=*/ NULL, /*data=*/ NULL, PKCS7_BINARY|PKCS7_PARTIAL);
if (!p7)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to allocate pkcs7 signing context: %s",
ERR_error_string(ERR_get_error(), NULL));
STACK_OF(PKCS7_SIGNER_INFO) *si_stack = PKCS7_get_signer_info(p7);
if (!si_stack)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get pkcs7 signer info stack: %s",
ERR_error_string(ERR_get_error(), NULL));
PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(si_stack, 0);
if (!si)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get pkcs7 signer info: %s",
ERR_error_string(ERR_get_error(), NULL));
int idcnid = OBJ_create(SPC_INDIRECT_DATA_OBJID, "spcIndirectDataContext", "Indirect Data Context");
if (PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(idcnid)) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to add signed attribute to pkcs7 signer info: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_close_ int srcfd = open(argv[1], O_RDONLY|O_CLOEXEC);
if (srcfd < 0)
return log_error_errno(errno, "Failed to open %s: %m", argv[1]);
struct stat st;
if (fstat(srcfd, &st) < 0)
return log_debug_errno(errno, "Failed to stat %s: %m", argv[1]);
r = stat_verify_regular(&st);
if (r < 0)
return log_debug_errno(r, "%s is not a regular file: %m", argv[1]);
_cleanup_(unlink_and_freep) char *tmp = NULL;
_cleanup_close_ int dstfd = open_tmpfile_linkable(arg_output, O_RDWR|O_CLOEXEC, &tmp);
if (dstfd < 0)
return log_error_errno(r, "Failed to open temporary file: %m");
r = copy_bytes(srcfd, dstfd, UINT64_MAX, COPY_REFLINK);
if (r < 0)
return log_error_errno(r, "Failed to copy %s to %s: %m", argv[1], tmp);
_cleanup_free_ void *hash = NULL;
size_t hashsz;
r = pe_hash(dstfd, EVP_sha256(), &hash, &hashsz);
if (r < 0)
return log_error_errno(r, "Failed to hash PE binary %s: %m", argv[0]);
/* <<<Obsolete>>> in unicode bytes. */
static const uint8_t obsolete[] = {
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f,
0x00, 0x62, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c,
0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x3e,
0x00, 0x3e, 0x00, 0x3e
};
_cleanup_(SpcLink_freep) SpcLink *link = SpcLink_new();
if (!link)
return log_oom();
link->type = 2;
link->value.file = SpcString_new();
if (!link->value.file)
return log_oom();
link->value.file->type = 0;
link->value.file->value.unicode = ASN1_BMPSTRING_new();
if (!link->value.file->value.unicode)
return log_oom();
if (ASN1_STRING_set(link->value.file->value.unicode, obsolete, sizeof(obsolete)) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ASN1 string: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_(SpcPeImageData_freep) SpcPeImageData *peid = SpcPeImageData_new();
if (!peid)
return log_oom();
if (ASN1_BIT_STRING_set_bit(peid->flags, 0, 1) == 0)
return log_oom();
peid->file = TAKE_PTR(link);
_cleanup_free_ uint8_t *peidraw = NULL;
int peidrawsz = i2d_SpcPeImageData(peid, &peidraw);
if (peidrawsz < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert SpcPeImageData to BER: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_(SpcIndirectDataContent_freep) SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
idc->data->value = ASN1_TYPE_new();
if (!idc->data->value)
return log_oom();
idc->data->value->type = V_ASN1_SEQUENCE;
idc->data->value->value.sequence = ASN1_STRING_new();
if (!idc->data->value->value.sequence)
return log_oom();
idc->data->type = OBJ_txt2obj(SPC_PE_IMAGE_DATA_OBJID, /*no_name=*/ 1);
if (!idc->data->type)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get SpcPeImageData object: %s",
ERR_error_string(ERR_get_error(), NULL));
idc->data->value->value.sequence->data = TAKE_PTR(peidraw);
idc->data->value->value.sequence->length = peidrawsz;
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(NID_sha256);
if (!idc->messageDigest->digestAlgorithm->algorithm)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get SHA256 object: %s",
ERR_error_string(ERR_get_error(), NULL));
idc->messageDigest->digestAlgorithm->parameters = ASN1_TYPE_new();
if (!idc->messageDigest->digestAlgorithm->parameters)
return log_oom();
idc->messageDigest->digestAlgorithm->parameters->type = V_ASN1_NULL;
if (ASN1_OCTET_STRING_set(idc->messageDigest->digest, hash, hashsz) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set digest: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_free_ uint8_t *idcraw = NULL;
int idcrawsz = i2d_SpcIndirectDataContent(idc, &idcraw);
if (idcrawsz < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert SpcIndirectDataContent to BER: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_(BIO_free_allp) BIO *bio = PKCS7_dataInit(p7, NULL);
if (!bio)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to create PKCS7 data bio: %s",
ERR_error_string(ERR_get_error(), NULL));
int tag, class;
long psz;
const uint8_t *p = idcraw;
/* This function weirdly enough reports errors by setting the 0x80 bit in its return value. */
if (ASN1_get_object(&p, &psz, &tag, &class, idcrawsz) & 0x80)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse ASN.1 object: %s",
ERR_error_string(ERR_get_error(), NULL));
if (BIO_write(bio, p, psz) < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write to PKCS7 data bio: %s",
ERR_error_string(ERR_get_error(), NULL));
if (PKCS7_final(p7, bio, PKCS7_BINARY) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to sign data: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_(PKCS7_freep) PKCS7 *p7c = PKCS7_new();
if (!p7c)
return log_oom();
p7c->type = OBJ_nid2obj(idcnid);
if (!p7c->type)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get SpcIndirectDataContent object: %s",
ERR_error_string(ERR_get_error(), NULL));
p7c->d.other = ASN1_TYPE_new();
if (!p7c->d.other)
return log_oom();
p7c->d.other->type = V_ASN1_SEQUENCE;
p7c->d.other->value.sequence = ASN1_STRING_new();
if (!p7c->d.other->value.sequence)
return log_oom();
if (ASN1_STRING_set(p7c->d.other->value.sequence, idcraw, idcrawsz) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ASN1 string: %s",
ERR_error_string(ERR_get_error(), NULL));
if (PKCS7_set_content(p7, p7c) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 data: %s",
ERR_error_string(ERR_get_error(), NULL));
TAKE_PTR(p7c);
_cleanup_free_ uint8_t *sig = NULL;
int sigsz = i2d_PKCS7(p7, &sig);
if (sigsz < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
ERR_error_string(ERR_get_error(), NULL));
_cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
_cleanup_free_ PeHeader *pe_header = NULL;
r = pe_load_headers(srcfd, &dos_header, &pe_header);
if (r < 0)
return log_error_errno(r, "Failed to load headers from PE file: %m");
const IMAGE_DATA_DIRECTORY *certificate_table;
certificate_table = pe_header_get_data_directory(pe_header, IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE);
if (!certificate_table)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks certificate table.");
off_t end = st.st_size;
ssize_t n;
if (st.st_size % 8 != 0) {
if (certificate_table->VirtualAddress != 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Certificate table is not aligned to 8 bytes");
n = pwrite(dstfd, (const uint8_t[8]) {}, 8 - (st.st_size % 8), st.st_size);
if (n < 0)
return log_error_errno(errno, "Failed to write zero padding: %m");
if (n != 8 - (st.st_size % 8))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing zero padding.");
end += n;
}
uint32_t certsz = offsetof(WIN_CERTIFICATE, bCertificate) + sigsz;
n = pwrite(dstfd,
&(WIN_CERTIFICATE) {
.wRevision = htole16(0x200),
.wCertificateType = htole16(0x0002), /* PKCS7 signedData */
.dwLength = htole32(ROUND_UP(certsz, 8)),
},
sizeof(WIN_CERTIFICATE),
end);
if (n < 0)
return log_error_errno(errno, "Failed to write certificate header: %m");
if (n != sizeof(WIN_CERTIFICATE))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing certificate header.");
end += n;
n = pwrite(dstfd, sig, sigsz, end);
if (n < 0)
return log_error_errno(errno, "Failed to write signature: %m");
if (n != sigsz)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing signature.");
end += n;
if (certsz % 8 != 0) {
n = pwrite(dstfd, (const uint8_t[8]) {}, 8 - (certsz % 8), end);
if (n < 0)
return log_error_errno(errno, "Failed to write zero padding: %m");
if ((size_t) n != 8 - (certsz % 8))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing zero padding.");
}
n = pwrite(dstfd,
&(IMAGE_DATA_DIRECTORY) {
.VirtualAddress = certificate_table->VirtualAddress ?: htole32(ROUND_UP(st.st_size, 8)),
.Size = htole32(le32toh(certificate_table->Size) + ROUND_UP(certsz, 8)),
},
sizeof(IMAGE_DATA_DIRECTORY),
le32toh(dos_header->e_lfanew) + PE_HEADER_OPTIONAL_FIELD_OFFSET(pe_header, DataDirectory[IMAGE_DATA_DIRECTORY_INDEX_CERTIFICATION_TABLE]));
if (n < 0)
return log_error_errno(errno, "Failed to update PE certificate table: %m");
if ((size_t) n != sizeof(IMAGE_DATA_DIRECTORY))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while updating PE certificate table.");
uint32_t checksum;
r = pe_checksum(dstfd, &checksum);
if (r < 0)
return log_error_errno(r, "Failed to calculate PE file checksum: %m");
n = pwrite(dstfd,
&(le32_t) { htole32(checksum) },
sizeof(le32_t),
le32toh(dos_header->e_lfanew) + offsetof(PeHeader, optional.CheckSum));
if (n < 0)
return log_error_errno(errno, "Failed to update PE checksum: %m");
if ((size_t) n != sizeof(le32_t))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while updating PE checksum.");
r = link_tmpfile(dstfd, tmp, arg_output, LINK_TMPFILE_REPLACE|LINK_TMPFILE_SYNC);
if (r < 0)
return log_error_errno(r, "Failed to link temporary file to %s: %m", arg_output);
log_info("Wrote signed PE binary to %s", arg_output);
return 0;
}
static int verb_validate_key(int argc, char *argv[], void *userdata) {
_cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
int r;
if (!arg_private_key)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No private key specified, use --private-key=.");
if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
if (r < 0)
return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
}
r = openssl_load_private_key(
arg_private_key_source_type,
arg_private_key_source,
arg_private_key,
&(AskPasswordRequest) {
.id = "sbsign-private-key-pin",
.keyring = arg_private_key,
.credential = "sbsign.private-key-pin",
},
&private_key,
&ui);
if (r < 0)
return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
puts("OK");
return 0;
}
static int run(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "sign", 2, 2, 0, verb_sign },
{ "validate-key", VERB_ANY, 1, 0, verb_validate_key },
{}
};
int r;
log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
return dispatch_verb(argc, argv, verbs, NULL);
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -2165,10 +2165,8 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
errno_pipe[0] = safe_close(errno_pipe[0]);
/* Wait until the parent unshared the user namespace */
if (read(unshare_ready_fd, &c, sizeof(c)) < 0) {
r = -errno;
goto child_fail;
}
if (read(unshare_ready_fd, &c, sizeof(c)) < 0)
report_errno_and_exit(errno_pipe[1], -errno);
/* Disable the setgroups() system call in the child user namespace, for good. */
a = procfs_file_alloca(ppid, "setgroups");
@ -2176,14 +2174,14 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
if (fd < 0) {
if (errno != ENOENT) {
r = log_debug_errno(errno, "Failed to open %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
/* If the file is missing the kernel is too old, let's continue anyway. */
} else {
if (write(fd, "deny\n", 5) < 0) {
r = log_debug_errno(errno, "Failed to write \"deny\" to %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
fd = safe_close(fd);
@ -2194,12 +2192,14 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
fd = open(a, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
r = log_debug_errno(errno, "Failed to open %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
if (write(fd, gid_map, strlen(gid_map)) < 0) {
r = log_debug_errno(errno, "Failed to write GID map to %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
fd = safe_close(fd);
/* The write the UID map */
@ -2207,18 +2207,15 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
fd = open(a, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
r = log_debug_errno(errno, "Failed to open %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
if (write(fd, uid_map, strlen(uid_map)) < 0) {
r = log_debug_errno(errno, "Failed to write UID map to %s: %m", a);
goto child_fail;
report_errno_and_exit(errno_pipe[1], r);
}
_exit(EXIT_SUCCESS);
child_fail:
(void) write(errno_pipe[1], &r, sizeof(r));
_exit(EXIT_FAILURE);
}
errno_pipe[1] = safe_close(errno_pipe[1]);

View File

@ -3170,21 +3170,11 @@ int main(int argc, char *argv[]) {
}
if (!skip_setup) {
/* Before we actually start deleting cgroup v1 code, make it harder to boot
* in cgroupv1 mode first. See also #30852. */
r = mount_cgroup_legacy_controllers(loaded_policy);
if (r < 0) {
if (r == -ERFKILL)
error_message = "Refusing to run under cgroup v1, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 not specified on kernel command line";
else
error_message = "Failed to mount cgroup v1 hierarchy";
error_message = "Failed to mount cgroup v1 hierarchy";
goto finish;
}
if (r > 0) {
log_full(LOG_CRIT, "Legacy cgroup v1 support selected. This is no longer supported. Will proceed anyway after 30s.");
(void) usleep_safe(30 * USEC_PER_SEC);
}
}
/* The efivarfs is now mounted, let's lock down the system token. */

View File

@ -5067,7 +5067,7 @@ static int manager_dispatch_pidref_transport_fd(sd_event_source *source, int fd,
_cleanup_close_ int child_pidfd = -EBADF, parent_pidfd = -EBADF;
struct ucred *ucred = NULL;
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int)) * 2) control;
pid_t child_pid;
pid_t child_pid = 0; /* silence false-positive warning by coverity */
struct msghdr msghdr = {
.msg_iov = &IOVEC_MAKE(&child_pid, sizeof(child_pid)),
.msg_iovlen = 1,

View File

@ -0,0 +1,120 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Based on Nikita Travkin's dtbloader implementation.
* Copyright (c) 2024 Nikita Travkin <nikita@trvn.ru>
*
* https://github.com/TravMurav/dtbloader/blob/main/src/chid.c
*/
/*
* Based on Linaro dtbloader implementation.
* Copyright (c) 2019, Linaro. All rights reserved.
*
* https://github.com/aarch64-laptops/edk2/blob/dtbloader-app/EmbeddedPkg/Application/ConfigTableLoader/CHID.c
*/
#if SD_BOOT
# include "efi-string.h"
# include "util.h"
#else
# include <byteswap.h>
# include <string.h>
# include <uchar.h>
# include <utf8.h>
#define strsize16(str) ((char16_strlen(str) + 1) * sizeof(char16_t))
#endif
#include "chid-fundamental.h"
#include "macro-fundamental.h"
#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) {
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);
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], strsize16(smbios_fields[i]), &ctx);
}
uint8_t hash[SHA1_DIGEST_SIZE];
sha1_finish_ctx(&ctx, hash);
assert_cc(sizeof(hash) >= sizeof(*ret_chid));
memcpy(ret_chid, hash, sizeof(*ret_chid));
/* Convert the resulting CHID back to little-endian: */
ret_chid->Data1 = bswap_32(ret_chid->Data1);
ret_chid->Data2 = bswap_16(ret_chid->Data2);
ret_chid->Data3 = bswap_16(ret_chid->Data3);
/* set specific bits according to RFC4122 Section 4.1.3 */
ret_chid->Data3 = (ret_chid->Data3 & 0x0fff) | (5 << 12);
ret_chid->Data4[0] = (ret_chid->Data4[0] & UINT8_C(0x3f)) | UINT8_C(0x80);
}
static const uint32_t chid_smbios_table[CHID_TYPES_MAX] = {
[3] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
[4] = (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),
[5] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME),
[6] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
[7] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_SKU),
[8] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
[9] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_PRODUCT_NAME),
[10] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
[11] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_FAMILY),
[13] = (UINT32_C(1) << CHID_SMBIOS_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_MANUFACTURER) |
(UINT32_C(1) << CHID_SMBIOS_BASEBOARD_PRODUCT),
};
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_SMBIOS_FIELDS_MAX; i++)
if (chid_smbios_table[i] != 0)
get_chid(smbios_fields, chid_smbios_table[i], &ret_chids[i]);
else
memzero(&ret_chids[i], sizeof(EFI_GUID));
}

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#pragma once
#include "efi-fundamental.h"
#include "string-util-fundamental.h"
#define CHID_TYPES_MAX 15
typedef enum ChidSmbiosFields {
CHID_SMBIOS_MANUFACTURER,
CHID_SMBIOS_FAMILY,
CHID_SMBIOS_PRODUCT_NAME,
CHID_SMBIOS_PRODUCT_SKU,
CHID_SMBIOS_BASEBOARD_MANUFACTURER,
CHID_SMBIOS_BASEBOARD_PRODUCT,
_CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields;
/* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]);

View File

@ -90,8 +90,8 @@
# define _fallthrough_
#endif
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
#define XSTRINGIFY(...) #__VA_ARGS__
#define STRINGIFY(...) XSTRINGIFY(__VA_ARGS__)
#ifndef __COVERITY__
# define VOID_0 ((void)0)

View File

@ -4,6 +4,7 @@ fundamental_include = include_directories('.')
fundamental_sources = files(
'bootspec-fundamental.c',
'chid-fundamental.c',
'efivars-fundamental.c',
'iovec-util-fundamental.h',
'sha1-fundamental.c',

View File

@ -47,7 +47,7 @@ enum {
/* The tag used for EV_EVENT_TAG event log records covering the boot loader config */
#define LOADER_CONF_EVENT_TAG_ID UINT32_C(0xf5bc582a)
/* The tag used for EV_EVENT_TAG event log records covering Devicetree blobs */
/* The tag used for EV_EVENT_TAG event log records covering DeviceTree blobs */
#define DEVICETREE_ADDON_EVENT_TAG_ID UINT32_C(0x6c46f751)
/* The tag used for EV_EVENT_TAG event log records covering initrd addons */

View File

@ -21,5 +21,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
[UNIFIED_SECTION_PCRSIG] = ".pcrsig",
[UNIFIED_SECTION_PCRPKEY] = ".pcrpkey",
[UNIFIED_SECTION_PROFILE] = ".profile",
[UNIFIED_SECTION_DTBAUTO] = ".dtbauto",
[UNIFIED_SECTION_HWIDS] = ".hwids",
NULL,
};

View File

@ -18,6 +18,8 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_PCRSIG,
UNIFIED_SECTION_PCRPKEY,
UNIFIED_SECTION_PROFILE,
UNIFIED_SECTION_DTBAUTO,
UNIFIED_SECTION_HWIDS,
_UNIFIED_SECTION_MAX,
} UnifiedSection;

View File

@ -0,0 +1,555 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* This contains macros that all help simplify the use of macros with variadic args. Also provided is a macro
* 'helper' that helps provide some commonly used things, such as a unique variable name or temporary
* variable.
*
* Since the C preprocessor does not allow recursive macros, none of these macros may be used to call
* themselves, even indirectly (except by using a "trick"; e.g. see __VA_WRAP_RECURSE() below). If you get a
* compiler error complaining about "implicit declaration of function" for any of the macros here, it is most
* likely due to an attempt to use the macro recursively.
*
* Some macros operate based on if there are 'any variadic args' or 'no variadic args'; this distinction is
* based on the use of __VA_OPT__(). The description 'any variadic args' means __VA_OPT__() evaluates to its
* content, and 'no variadic args' means __VA_OPT__() evaluates to nothing. Note that whitespace is not a
* preprocessor token, so a single whitespace-only arg is the same as no args. For example these calls all
* evaluate to 2:
* VA_IF_ELSE(1,2)
* VA_IF_ELSE(1,2,)
* VA_IF_ELSE(1,2, )
* #define NONE
* VA_IF_ELSE(1,2,NONE)
* VA_IF_ELSE(1,2, NONE)
* However, this call evaluates to 1:
* VA_IF_ELSE(1,2,,)
*/
/* Wraps variadic args in a single group. This can be passed to macros that will then expand the group into
* all its variadic args. */
#define VA_GROUP(...) __VA_ARGS__
/* Evaluates to 'x' if any variadic args, otherwise 'y'. */
#define VA_IF_ELSE(x, y, ...) _VA_IF_ELSE_MACRO(__VA_ARGS__)(_VA_IF_ELSE_GROUP(x), _VA_IF_ELSE_GROUP(y))
#define _VA_IF_ELSE_GROUP(...) __VA_ARGS__
#define _VA_IF_ELSE_MACRO(...) __VA_IF_ELSE_MACRO(__VA_OPT__(1))
#define __VA_IF_ELSE_MACRO(o) _VA_IF_ELSE ## o
#define _VA_IF_ELSE1(x, y) x
#define _VA_IF_ELSE(x, y) y
/* Evaluates to nothing if no variadic args, otherwise 'x'. */
#define VA_IF(x, ...) VA_IF_ELSE(_VA_IF_GROUP(x), /*false*/, __VA_ARGS__)
#define _VA_IF_GROUP(...) __VA_ARGS__
/* Same as VA_IF() but negates the condition. */
#define VA_IF_NOT(x, ...) VA_IF_ELSE(/*true*/, _VA_IF_NOT_GROUP(x), __VA_ARGS__)
#define _VA_IF_NOT_GROUP(...) __VA_ARGS__
/* Evaluates to token 1 if no variadic args, otherwise nothing. */
#define VA_NOT(...) VA_IF_NOT(1, __VA_ARGS__)
/* Evaluates to the first variadic arg, otherwise nothing. */
#define VA_FIRST(...) VA_IF(_VA_FIRST(__VA_ARGS__), __VA_ARGS__)
#define _VA_FIRST(x, ...) x
/* Evaluates to the rest of the variadic args, after the first, otherwise nothing. */
#define VA_REST(...) VA_IF(_VA_REST(__VA_ARGS__), __VA_ARGS__)
#define _VA_REST(x, ...) __VA_ARGS__
/* Evaluates to token , if any variadic args, otherwise nothing. */
#define VA_COMMA(...) __VA_OPT__(,)
/* Evaluates to token 1 if both args are non-empty (ignoring whitespace), otherwise evaluates to nothing. */
#define VA_AND(x, y) VA_NOT(VA_NOT(x) VA_NOT(y))
/* Evaluates to token 1 if either arg is non-empty (ignoring whitespace), otherwise evaluates to nothing. */
#define VA_OR(x, y) VA_IF(1, x y)
/* Evaluates to nothing. */
#define VA_NOOP(...)
/* Similar to VA_GROUP(), but encloses the variadic args in (), so they are not expanded when passed to other
* macros. Unlike VA_GROUP(), this requires the final macro that actually uses the group contents to ungroup it
* using VA_UNPGROUP(), or to handle the () directly. */
#define VA_PGROUP(...) (__VA_ARGS__)
/* Converts a group of args protected with () into a normal VA_GROUP(). 'x' must be a pgroup, i.e. (...). */
#define VA_UNPGROUP(x) VA_GROUP x
/* Similar to VA_FIRST(), but x is a pgroup. Evaluates to the first arg if present, otherwise nothing. */
#define VA_PGROUP_FIRST(x) VA_FIRST(VA_UNPGROUP(x))
/* Similar to VA_REST(), but x is a pgroup. Evaluates to a pgroup of the args after the first. If there are
* no more args after the first, evaluates to an empty pgroup. */
#define VA_PGROUP_REST(x) VA_PGROUP(VA_REST(VA_UNPGROUP(x)))
/* Evaluates to token 1 if pgroup is empty, otherwise nothing. */
#define VA_PGROUP_EMPTY(x) VA_IF_NOT(1, VA_UNPGROUP(x))
/* Similar to VA_PGROUP_EMPTY() but negates the condition. */
#define VA_PGROUP_NOT_EMPTY(x) VA_NOT(VA_PGROUP_EMPTY(x))
/* Evaluates to 'macro' called with the expanded variadic args. */
#define VA_MACRO(macro, ...) macro(__VA_ARGS__)
/* Evaluates to x(__VA_ARGS__) if t is non-empty, otherwise y(__VA_ARGS__). */
#define VA_MACRO_IF_ELSE(x, y, t, ...) VA_IF_ELSE(x, y, t)(__VA_ARGS__)
/* Evaluates to m(__VA_ARGS__) if t is non-empty, otherwise nothing. */
#define VA_MACRO_IF(m, t, ...) VA_MACRO_IF_ELSE(m, VA_NOOP, t, __VA_ARGS__)
/* Evaluates to m(__VA_ARGS__) if t is empty, otherwise nothing. */
#define VA_MACRO_IF_NOT(m, t, ...) VA_MACRO_IF_ELSE(VA_NOOP, m, t, __VA_ARGS__)
/* Same as VA_MACRO() but takes a pgroup, which is unpgrouped before passing to the macro. */
#define VA_MACRO_PGROUP(macro, pgroup) VA_MACRO(macro, VA_UNPGROUP(pgroup))
/* Expands to 'macro' for each variadic arg, which will be called with:
* 1) the provided 'context'
* 2) a hex iteration number (starting at 0x0001)
* 3) the variadic arg
* 4...) the rest of the variadic args
*
* Each expansion of 'macro', except for the last, will be followed by 'separator' called with the same
* parameters as 'macro'.
*
* If there are no variadic args, this evaluates to 'zero' called with the single arg 'context'.
*
* If there are too many variadic args, this evaluates to 'toomany' called with the single arg 'context'.
*
* The 'macro', 'separator', 'zero', and 'toomany' parameters must be callable macros. The VA_WRAP_*() macros
* below may be used. The 'context' parameter may be anything and is not directly called (except by the
* VA_WRAP_*_CONTEXT() below). */
#define VA_WRAP(macro, separator, context, zero, toomany, ...) \
__VA_WRAP_RECURSE(macro, separator, context, zero, toomany, __VA_ARGS__)
/* These can be used for the VA_WRAP() 'macro' parameter. */
#define VA_WRAP_MACRO_CONTEXT(c, i, v, ...) c
#define VA_WRAP_MACRO_INDEX(c, i, v, ...) i
#define VA_WRAP_MACRO_LAST(c, i, v, ...) VA_IF_NOT(v, __VA_ARGS__)
#define VA_WRAP_MACRO_LAST_INDEX(c, i, v, ...) VA_IF_NOT(i, __VA_ARGS__)
#define VA_WRAP_MACRO_NONE(c, i, v, ...)
#define VA_WRAP_MACRO_VALUE(c, i, v, ...) v
/* These can be used for the VA_WRAP() 'separator' parameter. */
#define VA_WRAP_SEPARATOR_AND(c, i, v, ...) &&
#define VA_WRAP_SEPARATOR_COMMA(c, i, v, ...) ,
#define VA_WRAP_SEPARATOR_COMMA_IF_PREV(c, i, v, ...) VA_COMMA(v)
#define VA_WRAP_SEPARATOR_CONTEXT(c, i, v, ...) c
#define VA_WRAP_SEPARATOR_INDEX(c, i, v, ...) i
#define VA_WRAP_SEPARATOR_NONE(c, i, v, ...)
#define VA_WRAP_SEPARATOR_SEMICOLON(c, i, v, ...) ;
/* This can be used for the VA_WRAP() 'context' parameter. It is strictly to help with code readability, and
* is not required. */
#define VA_WRAP_CONTEXT_NONE
/* These can be used for the VA_WRAP() 'zero' parameter. */
#define VA_WRAP_ZERO_0(c) 0
#define VA_WRAP_ZERO_0x0000(c) 0x0000
#define VA_WRAP_ZERO_CONTEXT(c) c
#define VA_WRAP_ZERO_ERROR(c) _Pragma("GCC error \"Zero variadic args.\"")
#define VA_WRAP_ZERO_FALSE(c) false
#define VA_WRAP_ZERO_NONE(c)
#define VA_WRAP_ZERO_TRUE(c) true
#define VA_WRAP_ZERO_VOID_0(c) VOID_0
/* These can be used for the VA_WRAP() 'toomany' parameter. */
#define VA_WRAP_TOOMANY_CONTEXT(c) c
#define VA_WRAP_TOOMANY_ERROR(c) _Pragma("GCC error \"Too many variadic args.\"")
#define VA_WRAP_TOOMANY_FALSE(c) false
#define VA_WRAP_TOOMANY_NONE(c)
#define VA_WRAP_TOOMANY_TRUE(c) true
/* Simple version of VA_WRAP(); each variadic arg is wrapped by the provided macro, separated by commas. No
* context is used. Zero args evaluates to nothing. Toomany args results in error. */
#define VA_MACRO_FOREACH(macro, ...) \
VA_WRAP(macro, \
VA_WRAP_SEPARATOR_COMMA, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
/* Expands to list of variadic args, with any "empty" (whitespace only) args removed. This processes the list
* twice, to remove a trailing comma if needed. */
#define VA_FILTER(...) \
VA_MACRO(VA_WRAP, \
VA_WRAP_MACRO_VALUE, \
VA_WRAP_SEPARATOR_COMMA_IF_PREV, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
VA_WRAP(VA_WRAP_MACRO_VALUE, \
VA_WRAP_SEPARATOR_COMMA_IF_PREV, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__))
/* Evaluates to the number of variadic args. */
#define VA_NARGS(...) \
VA_WRAP(VA_WRAP_MACRO_LAST_INDEX, \
VA_WRAP_SEPARATOR_NONE, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_0x0000, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
/* Evaluates to the last variadic arg. If there are no variadic args, evaluates to nothing. */
#define VA_LAST(...) \
VA_WRAP(VA_WRAP_MACRO_LAST, \
VA_WRAP_SEPARATOR_NONE, \
VA_WRAP_CONTEXT_NONE, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_DECLARATIONS(macro, name, ...) \
VA_WRAP(macro, \
VA_WRAP_SEPARATOR_SEMICOLON, \
name, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_DECLARATION_TOKEN(x, y) __VA_DECLARATION_TOKEN(x, y)
#define __VA_DECLARATION_TOKEN(x, y) x ## _ ## y
/* Evaluates to a variable declaration for each variadic arg. Each variadic arg must be a type. Each variable
* name is the concatenation of 'name', '_', and the variadic arg index (as a hex number). */
#define VA_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_DECLARATION, name, __VA_ARGS__)
#define _VA_DECLARATION(c, i, v, ...) \
v _VA_DECLARATION_TOKEN(c, i)
/* Same as VA_DECLARATIONS(), but the variadic args must be variables (or constants). Each declaration
* uses __auto_type and is initialized to its corresponding variadic arg. */
#define VA_INITIALIZED_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_INITIALIZED_DECLARATION, name, __VA_ARGS__)
#define _VA_INITIALIZED_DECLARATION(c, i, v, ...) \
_VA_DECLARATION(c, i, __auto_type, __VA_ARGS__) = (v)
/* Same as VA_INITIALIZED_DECLARATIONS(), but the temp variable is declared with const. */
#define VA_CONST_INITIALIZED_DECLARATIONS(name, ...) \
_VA_DECLARATIONS(_VA_CONST_INITIALIZED_DECLARATION, name, __VA_ARGS__)
#define _VA_CONST_INITIALIZED_DECLARATION(c, i, v, ...) \
const _VA_INITIALIZED_DECLARATION(c, i, v, __VA_ARGS__)
/* Evaluates to a comma-separated list of tokens by concatenating 'name' and a literal '_' with each variadic
* arg index. This will produce the same tokens as the variable names generated by VA_DECLARATIONS(). Note
* this does not actually evaluate any of the variadic args. */
#define VA_TOKENS(name, ...) \
VA_WRAP(_VA_TOKEN, \
VA_WRAP_SEPARATOR_COMMA, \
name, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_TOKEN(c, i, v, ...) _VA_DECLARATION_TOKEN(c, i)
/* Evaluates to a comma-separated list of unique tokens using UNIQ_T() for each variadic arg. This is similar
* to VA_TOKENS() but uses UNIQ_T() to generate the tokens. */
#define VA_UNIQ(...) \
VA_WRAP(_VA_UNIQ, \
VA_WRAP_SEPARATOR_COMMA, \
UNIQ, \
VA_WRAP_ZERO_NONE, \
VA_WRAP_TOOMANY_ERROR, \
__VA_ARGS__)
#define _VA_UNIQ(c, i, v, ...) UNIQ_T(v, c)
/* This is similar to VA_FILTER(), but we can't use VA_FILTER() because macros can't be used recursively, and
* this is called from inside a VA_WRAP() (which VA_FILTER() relies on). */
#define __VMH_GROUPS(g1, g2, g3, g4, g5) \
g1 VA_IF(VA_COMMA(g1), g2 g3 g4 g5) \
g2 VA_IF(VA_COMMA(g2), g3 g4 g5) \
g3 VA_IF(VA_COMMA(g3), g4 g5) \
g4 VA_IF(VA_COMMA(g4), g5) \
g5
#define __VMH_TOKEN(x, u) __va_macro_helper ## x ## u
#define __VMH_STATEMENT_EXPRESSION(macro, u, uniq, var, varinit, varconst, direct) \
({ \
VA_DECLARATIONS( __VMH_TOKEN(_var_, u), var); \
VA_INITIALIZED_DECLARATIONS( __VMH_TOKEN(_varinit_, u), varinit); \
VA_CONST_INITIALIZED_DECLARATIONS(__VMH_TOKEN(_varconst_, u), varconst); \
VA_MACRO(macro, \
__VMH_GROUPS(VA_UNIQ(uniq), \
VA_TOKENS(__VMH_TOKEN(_var_, u), var), \
VA_TOKENS(__VMH_TOKEN(_varinit_, u), varinit), \
VA_TOKENS(__VMH_TOKEN(_varconst_, u), varconst), \
VA_GROUP(direct))); \
})
#define __VMH_EXPRESSION(macro, u, uniq, var, varinit, varconst, direct) \
VA_MACRO(macro, \
__VMH_GROUPS(VA_UNIQ(uniq), VA_GROUP(direct),,,))
/* Calls 'macro' with a set of args based on the provided arg groups, in the order shown. Multiple args may
* be provided to each group by using VA_GROUP().
*
* Each arg in the 'uniq' group provides a unique token, named based on the arg token, to the macro in
* place of the arg. This is equivalent to UNIQ_T() for each arg.
*
* Each arg in the 'var' group provides a temporary variable of the specified type to the macro in place of
* the arg. All args in this group must be types.
*
* The 'varinit' group is similar to the 'var' group, but each arg must be a variable or constant, and each
* temporary variable is initialized to the value of the provided arg. The macro may use these args without
* any concern for side effects.
*
* The 'varconst' group is similar to the 'varinit' group, but the temporary variables are also marked as
* const. The macro should not modify args in this group.
*
* Each arg in the 'direct' group is provided directly to the macro. */
#define VA_MACRO_HELPER(macro, uniq, var, varinit, varconst, direct) \
VA_IF_ELSE(__VMH_STATEMENT_EXPRESSION, \
__VMH_EXPRESSION, \
var varinit varconst)(macro, \
UNIQ, \
VA_GROUP(uniq), \
VA_GROUP(var), \
VA_GROUP(varinit), \
VA_GROUP(varconst), \
VA_GROUP(direct))
/* Same as VA_MACRO_HELPER() but only with 'uniq' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_UNIQ(macro, uniq, ...) \
VA_MACRO_HELPER(macro, \
VA_GROUP(uniq), \
/* var= */, \
/* varinit= */, \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'var' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VAR(macro, var, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
VA_GROUP(var), \
/* varinit= */, \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'varinit' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VARINIT(macro, varinit, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
/* var= */, \
VA_GROUP(varinit), \
/* varconst= */, \
VA_GROUP(__VA_ARGS__))
/* Same as VA_MACRO_HELPER() but only with 'varconst' group; all variadic args are put in 'direct' group. */
#define VA_MACRO_VARCONST(macro, varconst, ...) \
VA_MACRO_HELPER(macro, \
/* uniq= */, \
/* var= */, \
/* varinit= */, \
VA_GROUP(varconst), \
VA_GROUP(__VA_ARGS__))
/* Macros below are complex, internal-use-only macros and should not be used directly. They are used by the
* macros above. */
/* Integer increment at the preprocessor stage; each macro evaluates to the next integer. Overflow is not
* handled; f wraps to 0. */
#define __VAI0 1
#define __VAI1 2
#define __VAI2 3
#define __VAI3 4
#define __VAI4 5
#define __VAI5 6
#define __VAI6 7
#define __VAI7 8
#define __VAI8 9
#define __VAI9 a
#define __VAIa b
#define __VAIb c
#define __VAIc d
#define __VAId e
#define __VAIe f
#define __VAIf 0
/* Integer increment carryover; all macros evaluate to 0 except f, which evaluates to 1. */
#define __VAC0 0
#define __VAC1 0
#define __VAC2 0
#define __VAC3 0
#define __VAC4 0
#define __VAC5 0
#define __VAC6 0
#define __VAC7 0
#define __VAC8 0
#define __VAC9 0
#define __VACa 0
#define __VACb 0
#define __VACc 0
#define __VACd 0
#define __VACe 0
#define __VACf 1
/* Increment x based on carryover c. Requires x to be single hex digit (0-f) and carryover to be 0-1.
* Evaluates to 0 if x == f and c == 1, otherwise x+1 if c == 1, otherwise x. */
#define ___VAI(x, c) ____VAI(x, c)
#define ____VAI(x, c) ____VAI ## c(x)
#define ____VAI0(x) x
#define ____VAI1(x) __VAI ## x
/* Carryover of x based on carryover c. Requires x to be single hex digit (0-f) and carryover to be
* 0-1. Evaluates to 1 if x is f and c is 1, otherwise 0. */
#define ___VAC(x, c) ____VAC(x, c)
#define ____VAC(x, c) ____VAC ## c(x)
#define ____VAC0(x) 0
#define ____VAC1(x) __VAC ## x
/* Carryover of multiple digits. Each calculates the carryover of its digit, with 1 being the least
* significant digit, and 4 being the most significant digit. */
#define ___VAC1(x1) ___VAC(x1, 1)
#define ___VAC2(x2, x1) ___VAC(x2, ___VAC1(x1))
#define ___VAC3(x3, x2, x1) ___VAC(x3, ___VAC2(x2, x1))
#define ___VAC4(x4, x3, x2, x1) ___VAC(x4, ___VAC3(x3, x2, x1))
/* Increment with carryover across all digits. Each evaluate to their digit incremented if there is carryover
* from previous digits. */
#define ___VAI1(x1) ___VAI(x1, 1)
#define ___VAI2(x2, x1) ___VAI(x2, ___VAC1(x1))
#define ___VAI3(x3, x2, x1) ___VAI(x3, ___VAC2(x2, x1))
#define ___VAI4(x4, x3, x2, x1) ___VAI(x4, ___VAC3(x3, x2, x1))
/* Detect overflow. If all digits are f, this causes preprocessor error, otherwise this evaluates to
* nothing. */
#define ___VAIO(x4, x3, x2, x1) ____VAIO(___VAC4(x4, x3, x2, x1))
#define ____VAIO(c) _____VAIO(c)
#define _____VAIO(c) ______VAIO ## c()
#define ______VAIO0()
#define ______VAIO1() _Pragma("GCC error \"VA increment overflow\"")
/* Increment a 4-digit hex number. Requires pgroup to be a 4-digit hex number pgroup, e.g. (0,1,2,3)
* represents 0x0123. Evaluates to a 4-digit hex number pgroup that has been incremented by 1. On overflow, a
* preprocessor error is generated. */
#define __VAINC4(pgroup) ___VAINC4 pgroup
#define ___VAINC4(x4, x3, x2, x1) \
___VAIO(x4, x3, x2, x1) \
(___VAI4(x4, x3, x2, x1), \
___VAI3(x3, x2, x1), \
___VAI2(x2, x1), \
___VAI1(x1))
/* Convert a 4-digit hex number pgroup to a standard hex number. Requires pgroup to be a 4-digit hex number
* pgroup. Evaluates to a standard hex number for the pgroup, e.g. (a,b,c,d) evalutes to 0xabcd. */
#define __VANUM4(pgroup) ___VANUM4 pgroup
#define ___VANUM4(x4, x3, x2, x1) 0x ## x4 ## x3 ## x2 ## x1
/* Nested repeated evaluations. This is what controls when the 'toomany' VA_WRAP() parameter is evaluated. */
#define __VA_EVAL_0x0002(...) __VA_ARGS__
#define __VA_EVAL_0x0004(...) __VA_EVAL_0x0002(__VA_EVAL_0x0002(__VA_ARGS__))
#define __VA_EVAL_0x0008(...) __VA_EVAL_0x0004(__VA_EVAL_0x0004(__VA_ARGS__))
#define __VA_EVAL_0x0010(...) __VA_EVAL_0x0008(__VA_EVAL_0x0008(__VA_ARGS__))
#define __VA_EVAL_0x0020(...) __VA_EVAL_0x0010(__VA_EVAL_0x0010(__VA_ARGS__))
#define __VA_EVAL_0x0040(...) __VA_EVAL_0x0020(__VA_EVAL_0x0020(__VA_ARGS__))
#define __VA_EVAL_0x0080(...) __VA_EVAL_0x0040(__VA_EVAL_0x0040(__VA_ARGS__))
#define __VA_EVAL_0x0100(...) __VA_EVAL_0x0080(__VA_EVAL_0x0080(__VA_ARGS__))
#define __VA_EVAL_0x0200(...) __VA_EVAL_0x0100(__VA_EVAL_0x0100(__VA_ARGS__))
/* This should match the list of macros above. */
#define __VA_EVAL_STEPS (0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200)
/* Determine which __VA_EVAL_0x* macro to use for the given variadic args. This is a quick evaluation for the
* preprocessor and avoids unnecessary reevaluations for complex macro expansions. Evaluates to the smallest
* (least evaluations) __VA_EVAL_0x* macro token that can handle the number of provided variadic args. */
#define __VA_EVAL_MACRO(...) __VA_EVAL_MACRO_CHECK_EACH(__VA_EVAL_STEPS, __VA_ARGS__)
/* Re-evaluates for each step. If __VA_EVAL_STEPS is increased this may need to be increased. */
#define __VA_EVAL_MACRO_CHECK_EACH(steps, ...) __VA_EVAL_MACRO_EVAL16(__VA_EVAL_MACRO_CHECK(steps, __VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL02(...) __VA_ARGS__
#define __VA_EVAL_MACRO_EVAL04(...) __VA_EVAL_MACRO_EVAL02(__VA_EVAL_MACRO_EVAL02(__VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL08(...) __VA_EVAL_MACRO_EVAL04(__VA_EVAL_MACRO_EVAL04(__VA_ARGS__))
#define __VA_EVAL_MACRO_EVAL16(...) __VA_EVAL_MACRO_EVAL08(__VA_EVAL_MACRO_EVAL08(__VA_ARGS__))
/* Evaluates to the first __VA_EVAL_0x* macro name that can handle all the variadic args. If there are too
* many variadic args for the largest macro to handle, evaluates to nothing. Note this uses the same
* preprocessor recursion "trick" as __VA_WRAP_RECURSE() below. */
#define __VA_EVAL_MACRO_CHECK(steps, ...) \
___VA_EVAL_MACRO_CHECK \
VA_PGROUP(__VA_EVAL_MACRO_MORE(VA_PGROUP_FIRST(steps), __VA_ARGS__))(steps, __VA_ARGS__)
/* 'x' is the evaluation of __VA_EVAL_MACRO_MORE(); if it is empty, this evaluates to __VA_EVAL_MACRO_OK,
* otherwise the tested __VA_EVAL_0x* macro cannot handle all the variadic args, and this evaluates to
* __VA_EVAL_MACRO_NEXT. */
#define ___VA_EVAL_MACRO_CHECK(x) VA_IF_ELSE(__VA_EVAL_MACRO_NEXT, __VA_EVAL_MACRO_OK, x)
/* Move on to testing the next step (i.e. next 0x* value). */
#define __VA_EVAL_MACRO_NEXT(steps, ...) ___VA_EVAL_MACRO_NEXT(VA_PGROUP_REST(steps), __VA_ARGS__)
/* Test the next step value. If there are no more steps, evaluate to nothing. */
#define ___VA_EVAL_MACRO_NEXT(steps, ...) \
VA_MACRO_IF(__VA_EVAL_MACRO_CHECK, VA_PGROUP_NOT_EMPTY(steps), steps, __VA_ARGS__)
/* The first value of 'steps' is acceptable, so evaluate to the corresponding __VA_EVAL_* macro name. */
#define __VA_EVAL_MACRO_OK(steps, ...) ___VA_EVAL_MACRO_OK(VA_PGROUP_FIRST(steps))
#define ___VA_EVAL_MACRO_OK(n) ____VA_EVAL_MACRO_OK(n)
#define ____VA_EVAL_MACRO_OK(n) __VA_EVAL_ ## n
/* Bug in Centos Stream 8 gcc preprocessor doesn't correctly handle __VA_OPT__(); work around it. Once Centos
* Stream 8 is no longer supported, this can be dropped. */
#define __CENTOS_STREAM_8_NONE
#define __CENTOS_STREAM_8_BUG_CHECK() ___CENTOS_STREAM_8_BUG_CHECK(__CENTOS_STREAM_8_NONE)
#define ___CENTOS_STREAM_8_BUG_CHECK(...) __VA_OPT__(1)
#define __VA_EVAL_MACRO_MORE_IF_ONCE(...) __VA_OPT__(1)
#define __VA_EVAL_MACRO_MORE_IF_TWICE(...) __VA_EVAL_MACRO_MORE_IF_ONCE(__VA_ARGS__)
#define __VA_EVAL_MACRO_MORE_IF_MACRO() \
VA_IF_ELSE(__VA_EVAL_MACRO_MORE_IF_TWICE, \
__VA_EVAL_MACRO_MORE_IF_ONCE, \
__CENTOS_STREAM_8_BUG_CHECK())
#define __VA_EVAL_MACRO_MORE_IF() __VA_EVAL_MACRO_MORE_IF_MACRO()
/* Test if the __VA_EVAL_0x* macro for hex number 'n' can handle all the variadic args. Evaluates to 1 if
* there are remaining (unhandled) variadic args after all evaluations, otherwise nothing. */
#define __VA_EVAL_MACRO_MORE(n, ...) \
__VA_EVAL_MACRO_MORE_IF()(__VA_EVAL_MACRO_MORE_N(n)(__VA_OPT__(___VA_EVAL_MACRO_MORE(__VA_ARGS__))))
#define __VA_EVAL_MACRO_MORE_N(n) __VA_EVAL_ ## n
#define ___VA_EVAL_MACRO_MORE(v, ...) __VA_OPT__(___VA_EVAL_MACRO_MORE_NEXT VA_PGROUP()(__VA_ARGS__))
#define ___VA_EVAL_MACRO_MORE_NEXT() ___VA_EVAL_MACRO_MORE
/* Recursive macro evaluation. This is intended for use by VA_WRAP() above. This performs the actions
* described by VA_WRAP() for each variadic arg.
*
* This "trick" inspired by:
* https://www.scs.stanford.edu/~dm/blog/va-opt.html
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
*
* This determines the number of re-evaluations required for the provided number of variadic args, then calls
* the appropriate __VA_EVAL_0x*() macro with ___VA_WRAP_RECURSE(), providing the initial index of 0x0001. */
#define __VA_WRAP_RECURSE(macro, separator, context, zero, toomany, ...) \
VA_IF_ELSE(__VA_WRAP_RECURSE_NONZERO, \
__VA_WRAP_RECURSE_ZERO, \
__VA_ARGS__)(macro, separator, context, zero, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_ZERO(macro, separator, context, zero, toomany, ...) zero(context)
#define __VA_WRAP_RECURSE_NONZERO(macro, separator, context, zero, toomany, ...) \
__VA_WRAP_RECURSE_CHECK_TOOMANY(__VA_EVAL_MACRO(__VA_ARGS__), \
macro, separator, context, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_CHECK_TOOMANY(evalmacro, macro, separator, context, toomany, ...) \
VA_IF_ELSE(__VA_WRAP_RECURSE_EVAL, \
__VA_WRAP_RECURSE_TOOMANY, \
evalmacro)(evalmacro, macro, separator, context, toomany, __VA_ARGS__)
#define __VA_WRAP_RECURSE_TOOMANY(evalmacro, macro, separator, context, toomany, ...) toomany(context)
#define __VA_WRAP_RECURSE_EVAL(evalmacro, macro, separator, context, toomany, ...) \
evalmacro(___VA_WRAP_RECURSE(macro, \
separator, \
context, \
(0,0,0,1), \
__VA_ARGS__))
/* This is the "trick" macro, which evaluates to the current variadic arg 'value' wrapped by 'macro', and
* then (if there are remaining variadic args) followed by 'separator' followed by the "trick"; which is
* ___VA_WRAP_NEXT token and VA_PGROUP(). On the next re-evaluation, this (indirectly) evaluates recursively
* to ___VA_WRAP_RECURSE(). */
#define ___VA_WRAP_RECURSE(macro, separator, context, index, value, ...) \
___VA_WRAP_RECURSE_CALL(macro, \
VA_IF_ELSE(separator, VA_NOOP, __VA_ARGS__), \
VA_GROUP(context, __VANUM4(index), value, __VA_ARGS__)) \
__VA_OPT__(___VA_WRAP_NEXT VA_PGROUP()(macro, separator, context, __VAINC4(index), __VA_ARGS__))
#define ___VA_WRAP_RECURSE_CALL(macro, separator, args) macro(args)separator(args)
#define ___VA_WRAP_NEXT() ___VA_WRAP_RECURSE

View File

@ -502,7 +502,7 @@ try_devicetree:
return NULL;
}
/* Note that the Devicetree specification uses the very same vocabulary
/* Note that the DeviceTree specification uses the very same vocabulary
* of chassis types as we do, hence we do not need to translate these types:
*
* https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */

View File

@ -2,6 +2,7 @@
#include "alloc-util.h"
#include "devnum-util.h"
#include "env-util.h"
#include "fd-util.h"
#include "glyph-util.h"
#include "in-addr-util.h"
@ -369,6 +370,40 @@ int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dis
return 0;
}
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
_cleanup_strv_free_ char **n = NULL;
char ***l = userdata;
int r;
if (sd_json_variant_is_null(variant)) {
*l = strv_free(*l);
return 0;
}
if (!sd_json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
for (size_t i = 0; i < sd_json_variant_elements(variant); i++) {
sd_json_variant *e;
const char *a;
e = sd_json_variant_by_index(variant, i);
if (!sd_json_variant_is_string(e))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
assert_se(a = sd_json_variant_string(e));
if (!env_assignment_is_valid(a))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of environment variables.", strna(name));
r = strv_env_replace_strdup(&n, a);
if (r < 0)
return json_log_oom(variant, flags);
}
return strv_free_and_replace(*l, n);
}
static int json_variant_new_stat(sd_json_variant **ret, const struct stat *st) {
char mode[STRLEN("0755")+1];

View File

@ -116,6 +116,7 @@ int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispa
int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_ifindex(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);

View File

@ -294,59 +294,11 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_send(NULL, reply, NULL);
}
static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
int r;
assert(m);
assert(ret);
switch (m->class) {
case MACHINE_HOST:
*ret = NULL;
break;
case MACHINE_CONTAINER: {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
char *address;
r = sd_bus_new(&bus);
if (r < 0)
return r;
if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader.pid) < 0)
return -ENOMEM;
bus->address = address;
bus->bus_client = true;
bus->trusted = false;
bus->runtime_scope = RUNTIME_SCOPE_SYSTEM;
r = sd_bus_start(bus);
if (r == -ENOENT)
return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
if (r < 0)
return r;
*ret = TAKE_PTR(bus);
break;
}
default:
return -EOPNOTSUPP;
}
return 0;
}
int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *pty_name = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
_cleanup_close_ int master = -EBADF;
sd_bus *container_bus = NULL;
Machine *m = ASSERT_PTR(userdata);
const char *p, *getty;
int r;
assert(message);
@ -372,18 +324,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
if (master < 0)
return master;
p = path_startswith(pty_name, "/dev/pts/");
assert(p);
r = container_bus_new(m, error, &allocated_bus);
if (r < 0)
return r;
container_bus = allocated_bus ?: m->manager->bus;
getty = strjoina("container-getty@", p, ".service");
r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, NULL, "ss", getty, "replace");
r = machine_start_getty(m, pty_name, error);
if (r < 0)
return r;
@ -399,15 +340,13 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
}
int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *pty_name = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
sd_bus *container_bus = NULL;
_cleanup_close_ int master = -EBADF, slave = -EBADF;
_cleanup_close_ int master = -EBADF;
_cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
_cleanup_free_ char *command_line = NULL;
Machine *m = ASSERT_PTR(userdata);
const char *unit, *user, *path, *description, *utmp_id;
const char *user, *path;
int r;
assert(message);
@ -420,25 +359,10 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
if (isempty(path)) {
path = "/bin/sh";
args = new0(char*, 3 + 1);
path = machine_default_shell_path();
args = machine_default_shell_args(user);
if (!args)
return -ENOMEM;
args[0] = strdup("sh");
if (!args[0])
return -ENOMEM;
args[1] = strdup("-c");
if (!args[1])
return -ENOMEM;
r = asprintf(&args[2],
"shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
"exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
user);
if (r < 0) {
args[2] = NULL;
return -ENOMEM;
}
} else {
if (!path_is_absolute(path))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
@ -484,153 +408,10 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (master < 0)
return master;
/* First try to get an fd for the PTY peer via the new racefree ioctl(), directly. Otherwise go via
* joining the namespace, because it goes by path */
slave = pty_open_peer_racefree(master, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (ERRNO_IS_NEG_NOT_SUPPORTED(slave))
slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (slave < 0)
return slave;
utmp_id = path_startswith(pty_name, "/dev/");
assert(utmp_id);
r = container_bus_new(m, error, &allocated_bus);
r = machine_start_shell(m, master, pty_name, user, path, args, env, error);
if (r < 0)
return r;
container_bus = allocated_bus ?: m->manager->bus;
r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return r;
/* Name and mode */
const char *p = ASSERT_PTR(path_startswith(pty_name, "/dev/pts/"));
unit = strjoina("container-shell@", p, ".service");
r = sd_bus_message_append(tm, "ss", unit, "fail");
if (r < 0)
return r;
/* Properties */
r = sd_bus_message_open_container(tm, 'a', "(sv)");
if (r < 0)
return r;
description = strjoina("Shell for User ", user);
r = sd_bus_message_append(tm,
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"Description", "s", description,
"StandardInputFileDescriptor", "h", slave,
"StandardOutputFileDescriptor", "h", slave,
"StandardErrorFileDescriptor", "h", slave,
"SendSIGHUP", "b", true,
"IgnoreSIGPIPE", "b", false,
"KillMode", "s", "mixed",
"TTYPath", "s", pty_name,
"TTYReset", "b", true,
"UtmpIdentifier", "s", utmp_id,
"UtmpMode", "s", "user",
"PAMName", "s", "login",
"WorkingDirectory", "s", "-~");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "(sv)", "User", "s", user);
if (r < 0)
return r;
if (!strv_isempty(env)) {
r = sd_bus_message_open_container(tm, 'r', "sv");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", "Environment");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'v', "as");
if (r < 0)
return r;
r = sd_bus_message_append_strv(tm, env);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
}
/* Exec container */
r = sd_bus_message_open_container(tm, 'r', "sv");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", "ExecStart");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'a', "(sasb)");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'r', "sasb");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", path);
if (r < 0)
return r;
r = sd_bus_message_append_strv(tm, args);
if (r < 0)
return r;
r = sd_bus_message_append(tm, "b", true);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
/* Auxiliary units */
r = sd_bus_message_append(tm, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(container_bus, tm, 0, error, NULL);
if (r < 0)
return r;
slave = safe_close(slave);
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;

View File

@ -7,6 +7,7 @@
#include "sd-varlink.h"
#include "bus-polkit.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "json-util.h"
#include "machine-varlink.h"
@ -16,7 +17,9 @@
#include "process-util.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
#include "user-util.h"
#include "varlink-util.h"
static JSON_DISPATCH_ENUM_DEFINE(dispatch_machine_class, MachineClass, machine_class_from_string);
@ -375,3 +378,195 @@ int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met
return sd_varlink_reply(link, NULL);
}
typedef enum MachineOpenMode {
MACHINE_OPEN_MODE_TTY,
MACHINE_OPEN_MODE_LOGIN,
MACHINE_OPEN_MODE_SHELL,
_MACHINE_OPEN_MODE_MAX,
_MACHINE_OPEN_MODE_INVALID = -EINVAL,
} MachineOpenMode;
static const char* const machine_open_mode_table[_MACHINE_OPEN_MODE_MAX] = {
[MACHINE_OPEN_MODE_TTY] = "tty",
[MACHINE_OPEN_MODE_LOGIN] = "login",
[MACHINE_OPEN_MODE_SHELL] = "shell",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(machine_open_mode, MachineOpenMode);
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_machine_open_mode, MachineOpenMode, machine_open_mode_from_string);
typedef struct MachineOpenParameters {
const char *name, *user;
PidRef pidref;
MachineOpenMode mode;
char *path, **args, **env;
} MachineOpenParameters;
static void machine_open_paramaters_done(MachineOpenParameters *p) {
assert(p);
pidref_done(&p->pidref);
free(p->path);
strv_free(p->args);
strv_free(p->env);
}
inline static const char* machine_open_polkit_action(MachineOpenMode mode, MachineClass class) {
switch (mode) {
case MACHINE_OPEN_MODE_TTY:
return class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty";
case MACHINE_OPEN_MODE_LOGIN:
return class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login";
case MACHINE_OPEN_MODE_SHELL:
return class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell";
default:
assert_not_reached();
}
}
inline static char** machine_open_polkit_details(MachineOpenMode mode, const char *machine_name, const char *user, const char *path, const char *command_line) {
assert(machine_name);
switch (mode) {
case MACHINE_OPEN_MODE_TTY:
return strv_new("machine", machine_name);
case MACHINE_OPEN_MODE_LOGIN:
return strv_new("machine", machine_name, "verb", "login");
case MACHINE_OPEN_MODE_SHELL:
assert(user);
assert(path);
assert(command_line);
return strv_new(
"machine", machine_name,
"verb", "shell",
"user", user,
"program", path,
"command_line", command_line);
default:
assert_not_reached();
}
}
int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineOpenParameters),
{ "mode", SD_JSON_VARIANT_STRING, json_dispatch_machine_open_mode, offsetof(MachineOpenParameters, mode), SD_JSON_MANDATORY },
{ "user", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(MachineOpenParameters, user), SD_JSON_RELAX },
{ "path", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(MachineOpenParameters, path), 0 },
{ "args", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(MachineOpenParameters, args), 0 },
{ "environment", SD_JSON_VARIANT_ARRAY, json_dispatch_strv_environment, offsetof(MachineOpenParameters, env), 0 },
VARLINK_DISPATCH_POLKIT_FIELD,
{}
};
Manager *manager = ASSERT_PTR(userdata);
_cleanup_close_ int ptmx_fd = -EBADF;
_cleanup_(machine_open_paramaters_done) MachineOpenParameters p = {
.pidref = PIDREF_NULL,
.mode = _MACHINE_OPEN_MODE_INVALID,
};
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_free_ char *ptmx_name = NULL, *command_line = NULL;
_cleanup_strv_free_ char **polkit_details = NULL, **args = NULL;
const char *user = NULL, *path = NULL; /* gcc complains about uninitialized variables */
Machine *machine;
int r, ptmx_fd_idx;
assert(link);
assert(parameters);
r = sd_varlink_set_allow_fd_passing_output(link, true);
if (r < 0)
return log_error_errno(r, "Failed to enable varlink fd passing for write: %m");
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
if (r != 0)
return r;
if (p.mode == MACHINE_OPEN_MODE_SHELL) {
/* json_dispatch_const_user_group_name() does valid_user_group_name(p.user) */
/* json_dispatch_path() does path_is_absolute(p.path) */
/* json_dispatch_strv_environment() does validation of p.env */
user = p.user ?: "root";
path = p.path ?: machine_default_shell_path();
args = !p.path ? machine_default_shell_args(user) : strv_isempty(p.args) ? strv_new(path) : TAKE_PTR(p.args);
if (!args)
return -ENOMEM;
command_line = strv_join(args, " ");
if (!command_line)
return -ENOMEM;
}
r = lookup_machine_by_name_or_pidref(link, manager, p.name, &p.pidref, &machine);
if (r == -ESRCH)
return sd_varlink_error(link, "io.systemd.Machine.NoSuchMachine", NULL);
if (r < 0)
return r;
polkit_details = machine_open_polkit_details(p.mode, machine->name, user, path, command_line);
r = varlink_verify_polkit_async(
link,
manager->bus,
machine_open_polkit_action(p.mode, machine->class),
(const char**) polkit_details,
&manager->polkit_registry);
if (r <= 0)
return r;
ptmx_fd = machine_openpt(machine, O_RDWR|O_NOCTTY|O_CLOEXEC, &ptmx_name);
if (ERRNO_IS_NEG_NOT_SUPPORTED(ptmx_fd))
return sd_varlink_error(link, "io.systemd.Machine.NotSupported", NULL);
if (ptmx_fd < 0)
return log_debug_errno(ptmx_fd, "Failed to open pseudo terminal: %m");
switch (p.mode) {
case MACHINE_OPEN_MODE_TTY:
/* noop */
break;
case MACHINE_OPEN_MODE_LOGIN:
r = machine_start_getty(machine, ptmx_name, /* error = */ NULL);
if (r == -ENOENT)
return sd_varlink_error(link, "io.systemd.Machine.NoIPC", NULL);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
return sd_varlink_error(link, "io.systemd.Machine.NotSupported", NULL);
if (r < 0)
return log_debug_errno(r, "Failed to start getty for machine '%s': %m", machine->name);
break;
case MACHINE_OPEN_MODE_SHELL: {
assert(user && path && args); /* to avoid gcc complaining about possible uninitialized variables */
r = machine_start_shell(machine, ptmx_fd, ptmx_name, user, path, args, p.env, /* error = */ NULL);
if (r == -ENOENT)
return sd_varlink_error(link, "io.systemd.Machine.NoIPC", NULL);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
return sd_varlink_error(link, "io.systemd.Machine.NotSupported", NULL);
if (r < 0)
return log_debug_errno(r, "Failed to start shell for machine '%s': %m", machine->name);
break;
}
default:
assert_not_reached();
}
ptmx_fd_idx = sd_varlink_push_fd(link, ptmx_fd);
/* no need to handle -EPERM because we do sd_varlink_set_allow_fd_passing_output() above */
if (ptmx_fd_idx < 0)
return log_debug_errno(ptmx_fd_idx, "Failed to push file descriptor over varlink: %m");
TAKE_FD(ptmx_fd);
r = sd_json_buildo(
&v,
SD_JSON_BUILD_PAIR_INTEGER("ptyFileDescriptor", ptmx_fd_idx),
JSON_BUILD_PAIR_STRING_NON_EMPTY("ptyPath", ptmx_name));
if (r < 0)
return r;
return sd_varlink_reply(link, v);
}

View File

@ -24,3 +24,4 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink
int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);

View File

@ -8,6 +8,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-locator.h"
#include "bus-unit-util.h"
#include "bus-util.h"
@ -702,6 +703,276 @@ int machine_open_terminal(Machine *m, const char *path, int mode) {
}
}
static int machine_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
int r;
assert(m);
assert(ret);
switch (m->class) {
case MACHINE_HOST:
*ret = NULL;
return 0;
case MACHINE_CONTAINER: {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
char *address;
r = sd_bus_new(&bus);
if (r < 0)
return log_debug_errno(r, "Failed to allocate new DBus: %m");
if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader.pid) < 0)
return -ENOMEM;
bus->address = address;
bus->bus_client = true;
bus->trusted = false;
bus->runtime_scope = RUNTIME_SCOPE_SYSTEM;
r = sd_bus_start(bus);
if (r == -ENOENT)
return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
if (r < 0)
return r;
*ret = TAKE_PTR(bus);
return 0;
}
default:
return -EOPNOTSUPP;
}
}
int machine_start_getty(Machine *m, const char *ptmx_name, sd_bus_error *error) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
sd_bus *container_bus = NULL;
const char *p, *getty;
int r;
assert(m);
assert(ptmx_name);
p = path_startswith(ptmx_name, "/dev/pts/");
if (!p)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Path of pseudo TTY has unexpected prefix");
r = machine_bus_new(m, error, &allocated_bus);
if (r < 0)
return log_debug_errno(r, "Failed to create DBus to machine: %m");
container_bus = allocated_bus ?: m->manager->bus;
getty = strjoina("container-getty@", p, ".service");
r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, /* reply = */ NULL, "ss", getty, "replace");
if (r < 0)
return log_debug_errno(r, "Failed to StartUnit '%s' in container '%s': %m", getty, m->name);
return 0;
}
int machine_start_shell(
Machine *m,
int ptmx_fd,
const char *ptmx_name,
const char *user,
const char *path,
char **args,
char **env,
sd_bus_error *error) {
_cleanup_close_ int pty_fd = -EBADF;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *tm = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
const char *p, *utmp_id, *unit, *description;
sd_bus *container_bus = NULL;
int r;
assert(m);
assert(ptmx_fd >= 0);
assert(ptmx_name);
if (isempty(user) || isempty(path) || strv_isempty(args))
return -EINVAL;
p = path_startswith(ptmx_name, "/dev/pts/");
utmp_id = path_startswith(ptmx_name, "/dev/");
if (!p || !utmp_id)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Path of pseudo TTY has unexpected prefix");
/* First try to get an fd for the PTY peer via the new racefree ioctl(), directly. Otherwise go via
* joining the namespace, because it goes by path */
pty_fd = pty_open_peer_racefree(ptmx_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (ERRNO_IS_NEG_NOT_SUPPORTED(pty_fd))
pty_fd = machine_open_terminal(m, ptmx_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (pty_fd < 0)
return log_debug_errno(pty_fd, "Failed to open terminal: %m");
r = machine_bus_new(m, error, &allocated_bus);
if (r < 0)
return log_debug_errno(r, "Failed to create DBus to machine: %m");
container_bus = allocated_bus ?: m->manager->bus;
r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
if (r < 0)
return r;
/* Name and mode */
unit = strjoina("container-shell@", p, ".service");
r = sd_bus_message_append(tm, "ss", unit, "fail");
if (r < 0)
return r;
/* Properties */
r = sd_bus_message_open_container(tm, 'a', "(sv)");
if (r < 0)
return r;
description = strjoina("Shell for User ", user);
r = sd_bus_message_append(tm,
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"Description", "s", description,
"StandardInputFileDescriptor", "h", pty_fd,
"StandardOutputFileDescriptor", "h", pty_fd,
"StandardErrorFileDescriptor", "h", pty_fd,
"SendSIGHUP", "b", true,
"IgnoreSIGPIPE", "b", false,
"KillMode", "s", "mixed",
"TTYPath", "s", ptmx_name,
"TTYReset", "b", true,
"UtmpIdentifier", "s", utmp_id,
"UtmpMode", "s", "user",
"PAMName", "s", "login",
"WorkingDirectory", "s", "-~");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "(sv)", "User", "s", user);
if (r < 0)
return r;
if (!strv_isempty(env)) {
r = sd_bus_message_open_container(tm, 'r', "sv");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", "Environment");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'v', "as");
if (r < 0)
return r;
r = sd_bus_message_append_strv(tm, env);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
}
/* Exec container */
r = sd_bus_message_open_container(tm, 'r', "sv");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", "ExecStart");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'a', "(sasb)");
if (r < 0)
return r;
r = sd_bus_message_open_container(tm, 'r', "sasb");
if (r < 0)
return r;
r = sd_bus_message_append(tm, "s", path);
if (r < 0)
return r;
r = sd_bus_message_append_strv(tm, args);
if (r < 0)
return r;
r = sd_bus_message_append(tm, "b", true);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
r = sd_bus_message_close_container(tm);
if (r < 0)
return r;
/* Auxiliary units */
r = sd_bus_message_append(tm, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(container_bus, tm, 0, error, NULL);
if (r < 0)
return r;
return 0;
}
char** machine_default_shell_args(const char *user) {
_cleanup_strv_free_ char **args = NULL;
int r;
assert(user);
args = new0(char*, 3 + 1);
if (!args)
return NULL;
args[0] = strdup("sh");
if (!args[0])
return NULL;
args[1] = strdup("-c");
if (!args[1])
return NULL;
r = asprintf(&args[2],
"shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
"exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
user);
if (r < 0) {
args[2] = NULL;
return NULL;
}
return TAKE_PTR(args);
}
void machine_release_unit(Machine *m) {
assert(m);

View File

@ -102,6 +102,10 @@ KillWhom kill_whom_from_string(const char *s) _pure_;
int machine_openpt(Machine *m, int flags, char **ret_slave);
int machine_open_terminal(Machine *m, const char *path, int mode);
int machine_start_getty(Machine *m, const char *ptmx_name, sd_bus_error *error);
int machine_start_shell(Machine *m, int ptmx_fd, const char *ptmx_name, const char *user, const char *path, char **args, char **env, sd_bus_error *error);
#define machine_default_shell_path() ("/bin/sh")
char** machine_default_shell_args(const char *user);
int machine_get_uid_shift(Machine *m, uid_t *ret);

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