keyring-setup: add systemd-keyring-setup (#44114)

Lennart asked in #44114 to split the preparatory stuff out so it can
be merged in smaller PRs. So this is a stack of five, each based on
the one before it and each showing only its own commits:

1. #44323, the C helpers (merged)
2. #44324, support for programs written in Rust (merged)
3. #44420, bindings.h lists only the headers Rust code uses (merged)
4. #44325, the systemd_shared wrappers systemd-keyring-setup needs
(merged)
5. #44114, systemd-keyring-setup itself

This one is 5.

This adds systemd-keyring-setup which enrolls X.509 certificates from
the VOA hierarchy into the kernel's .dm-verity, .fs-verity and .bpf
keyrings at boot and seals them afterwards. It's the first program in
systemd written in Rust. The C prototype in #43549 was never merged, so
nothing is ported here.

The kernel has various keyrings that early userspace may choose to set
up. Right now it has the .fs-verity and .dm-verity keyrings and in the
next kernel it will also have a .bpf keyring.

All three keyrings accept X.509 certificates in DER form. The .dm-verity
and .bpf keyrings are inactive and restricted by default unless the
respective kernel command line options are passed that leave them
unrestricted. Both keyrings are ignored until they are restricted. IOW,
restricting them causes the kernel to use them for signature
verification. The .fs-verity keyring is always active and is taken into
account as soon as it contains a key.

The UAPI group published the File Hierarchy for the Verification of OS
Artifacts (VOA) specification (cf. [1]). systemd-keyring-setup reads the
certificates for each keyring from the kernel-keyring role with the
keyring as the context and the trust anchors from the
trust-anchor-kernel-keyring counterpart:

```
<load-path>/<os>/kernel-keyring/<context>/x509/<name>-certificate.pem
<load-path>/<os>/trust-anchor-kernel-keyring/<context>/x509/<name>-certificate.pem
```

The load paths in descending priority are /etc/voa, /run/voa,
/usr/local/share/voa and /usr/share/voa. `<os>` is the exact identifier
`ID[:VERSION_ID[:VARIANT_ID[:IMAGE_ID[:IMAGE_VERSION]]]]` and the bare
`ID`. `<context>` is dm-verity, fs-verity or bpf.

Examples for a vendor shipping verifiers on Debian:

```
/usr/share/voa/debian/kernel-keyring/dm-verity/x509/vendor-certificate.pem
/usr/share/voa/debian/kernel-keyring/fs-verity/x509/vendor-certificate.pem
/usr/share/voa/debian/kernel-keyring/bpf/x509/vendor-certificate.pem
```

A CA certificate as a trust anchor and an admin override in /etc for a
specific release:

```
/usr/share/voa/debian/trust-anchor-kernel-keyring/dm-verity/x509/vendor-ca-certificate.pem
/etc/voa/debian:13/kernel-keyring/dm-verity/x509/corp-certificate.pem
```

Masking works as everywhere in VOA via a /dev/null symlink under the
same file name in any load path:

```
/etc/voa/debian/kernel-keyring/dm-verity/x509/vendor-certificate.pem -> /dev/null
```

The lookup is anchored at a pinned root directory and drops verifiers
that somebody else could have tampered with. That's what CHASE_MAX_MODE
and the CONF_FILES_CHASE_* flags are for. The VOA lookup, the keyring
helpers and the X.509 helpers are all C in libsystemd-shared and the
Rust program calls into them.

After enrolling, the keyring is restricted to certificates signed by an
enrolled key and SetAttr is dropped from its permission mask. So neither
the restriction nor the mask can be changed anymore. Any keyring that's
still open is sealed at the end of a run, even when it's empty. The
binary may run in the initrd and on the host. A second run detects the
sealed keyring, skips certificates that are enrolled already and enrolls
the ones signed by an enrolled key. The service isn't enabled by
default.

Certificates can also be shipped as `keyring-setup.<keyring>.<name>`
system credentials (SMBIOS, ESP credential drop-ins, --set-credential
for the boot loader). This lets users avoid having to ship keys as part
of the initrd. We don't enroll them directly but follow the VOA spec
instead. They are placed into /run/voa first so masking, merging and
deduplication apply to them like to any other file:

```
/run/voa/debian/kernel-keyring/dm-verity/x509/corp-certificate.pem
```

A keyring-setup.os credential overrides the OS identifiers derived from
os-release. This is useful for generic initrds whose identity differs
from the host's.

The specification requires the extended key usage of a verifier to be
aligned with its purpose. The kernel has no concept of this. So
systemd-keyring-setup checks it.

TEST-98-KEYRING-SETUP boots with and without
dm_verity.keyring_unsealed=1 and the kernel verifies the signed test
image against the keyring that systemd-keyring-setup provisioned.
TEST-90 copes with a .dm-verity keyring that was sealed at boot.

[1]:
https://uapi-group.org/specifications/specs/file_hierarchy_for_the_verification_of_os_artifacts/

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Christian Brauner authored and GitHub committed 2026-10-27 10:27:21 +01:00
commit db8557d8a5
27 files changed
+2273 -11

No files matched your search

+26
View File
@@ -209,6 +209,32 @@ CHANGES WITH 263 in spe:
"# [Experimental]" comment line in the interface description, which
sd_varlink_idl_parse() turns back into the flag.
Changes in systemd-keyring-setup:
* A new service systemd-keyring-setup.service has been added that
enrolls X.509 certificates into the kernel's .dm-verity, .fs-verity
and .bpf keyrings early during boot, and seals the keyrings
afterwards. The certificates are read from the File Hierarchy for
the Verification of OS Artifacts (VOA), i.e. from /etc/voa/,
/run/voa/, /usr/local/share/voa/ and /usr/share/voa/, or may be
passed in as keyring-setup.* system credentials. This allows the
kernel to verify signed dm-verity volumes, fs-verity files and BPF
programs with certificates provided by the OS vendor or the local
administrator, without rebuilding the kernel or enrolling keys into
the firmware. Note that the kernel seals the .dm-verity and .bpf
keyrings while they are still empty, unless
dm_verity.keyring_unsealed=1 or bpf.keyring_unsealed=1 is specified
on the kernel command line, respectively. The service is enabled
statically whenever it is built, and is considered experimental for
now. See
systemd-keyring-setup.service(8) and
https://uapi-group.org/specifications/specs/file_hierarchy_for_the_verification_of_os_artifacts/
for details.
systemd-keyring-setup is the first systemd component written in
Rust, and is hence only built if Rust support is enabled with the
new -Drust= build option.
CHANGES WITH 262:
Announcements of Future Feature Removals and Incompatible Changes:
+5
View File
@@ -87,6 +87,7 @@ REQUIREMENTS:
PIDFD_INFO_COREDUMP by ioctl(PIDFD_GET_INFO)
≥ 6.17 for coredump socket pattern ('@@' prefix)
≥ 6.19 for PIDFD_INFO_SUPPORTED_MASK and PIDFD_INFO_COREDUMP_SIGNAL
≥ 7.0 for the .dm-verity keyring provisioned by systemd-keyring-setup
≥ 7.1 for PIDFD_INFO_COREDUMP_CODE
✅ systemd utilizes several new kernel APIs, but will fall back gracefully
@@ -182,6 +183,10 @@ REQUIREMENTS:
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING
CONFIG_IMA_ARCH_POLICY
CONFIG_INTEGRITY_MACHINE_KEYRING
Required to verify signed Verity images and fs-verity files with
certificates enrolled by systemd-keyring-setup:
CONFIG_KEYS
CONFIG_FS_VERITY_BUILTIN_SIGNATURES
Required for reading credentials from SMBIOS:
CONFIG_DMI
+4
View File
@@ -1143,6 +1143,10 @@ manpages = [
'systemd-journald@.service',
'systemd-journald@.socket'],
''],
['systemd-keyring-setup.service',
'8',
['systemd-keyring-setup'],
'HAVE_OPENSSL HAVE_RUST'],
['systemd-keyutil', '1', [], ''],
['systemd-localed.service', '8', ['systemd-localed'], 'ENABLE_LOCALED'],
['systemd-logind.service',
+300
View File
@@ -0,0 +1,300 @@
<?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-keyring-setup.service" conditional='HAVE_OPENSSL HAVE_RUST'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-keyring-setup.service</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-keyring-setup.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-keyring-setup.service</refname>
<refname>systemd-keyring-setup</refname>
<refpurpose>Enroll certificates into kernel keyrings</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-keyring-setup.service</filename></para>
<cmdsynopsis>
<command>/usr/lib/systemd/systemd-keyring-setup</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">KEYRING</arg>
</cmdsynopsis>
</refsynopsisdiv>
<xi:include href="experimental.xml" xpointer="component" />
<refsect1>
<title>Description</title>
<para><filename>systemd-keyring-setup.service</filename> is an early boot service that enrolls X.509
certificates into the kernel keyrings used to verify signatures on dm-verity volumes, fs-verity files and
BPF programs, and then seals these keyrings. The certificates are read from the <ulink
url="https://uapi-group.org/specifications/specs/file_hierarchy_for_the_verification_of_os_artifacts/">File
Hierarchy for the Verification of OS Artifacts</ulink> (VOA). This allows the kernel to verify signatures
with keys provided by the OS vendor or the local administrator, without rebuilding the kernel and without
enrolling the keys into the firmware.</para>
<para>The following keyrings are provisioned, each from a VOA <emphasis>context</emphasis> of the
<literal>kernel-keyring</literal> purpose:</para>
<table>
<title>Keyrings and VOA contexts</title>
<tgroup cols="3">
<colspec colname="keyring"/>
<colspec colname="context"/>
<colspec colname="use"/>
<thead>
<row>
<entry>Keyring</entry>
<entry>VOA context</entry>
<entry>Used to verify</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>.dm-verity</literal></entry>
<entry><literal>dm-verity</literal></entry>
<entry>Signatures of the root hashes of dm-verity volumes, such as those of Discoverable Disk Images set up by <citerefentry><refentrytitle>systemd-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry> or the <varname>RootImage=</varname> setting of services</entry>
</row>
<row>
<entry><literal>.fs-verity</literal></entry>
<entry><literal>fs-verity</literal></entry>
<entry>Built-in signatures of fs-verity protected files</entry>
</row>
<row>
<entry><literal>.bpf</literal></entry>
<entry><literal>bpf</literal></entry>
<entry>Signatures of BPF programs</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The kernel only uses the <literal>.dm-verity</literal> and <literal>.bpf</literal> keyrings once they
have been sealed, and seals them itself while they are still empty, unless
<varname>dm_verity.keyring_unsealed=1</varname> or <varname>bpf.keyring_unsealed=1</varname> is specified on
the kernel command line, respectively. Hence, these options are required to provision the two keyrings, see
below. The <literal>.fs-verity</literal> keyring is not sealed by the kernel, and is used as soon as it
contains a key.</para>
<para>For each keyring that is not sealed yet, the service enrolls the certificates it finds and then seals
the keyring: it installs a restriction so that only certificates signed by a key in the keyring can be added
afterwards, and removes the permission to change this restriction or the permissions of the keyring. The
keyring is sealed even if no certificates were found, or if some of them could not be enrolled. Keys that
were already in the keyring before the service ran are sealed in as well, and a warning is logged about
them.</para>
<para>Note that kexec will unseal and empty the keyrings.</para>
<para>The service runs both in the initrd and on the host. Usually, the keyrings are provisioned in the
initrd, since the root file system might itself be a dm-verity volume that is verified with one of the
enrolled keys. When the service runs again on the host, the keyrings have been sealed already. In this case,
only certificates signed by a key that was enrolled earlier can be added, and all other certificates are
rejected. Certificates that have been enrolled already are skipped.</para>
</refsect1>
<refsect1>
<title>Certificate Directories and Precedence</title>
<para>Certificates are read from the VOA load paths <filename>/etc/voa/</filename>,
<filename>/run/voa/</filename>, <filename>/usr/local/share/voa/</filename> and
<filename>/usr/share/voa/</filename>, in order of decreasing priority. For each keyring, artifact verifiers
are read from
<filename><replaceable>OS</replaceable>/kernel-keyring/<replaceable>CONTEXT</replaceable>/x509/<replaceable>NAME</replaceable>-certificate.pem</filename>,
and trust anchors from
<filename><replaceable>OS</replaceable>/trust-anchor-kernel-keyring/<replaceable>CONTEXT</replaceable>/x509/<replaceable>NAME</replaceable>-certificate.pem</filename>
below each load path. Both are enrolled into the same keyring, and only differ in how their usage is
checked, see below. <replaceable>NAME</replaceable> may consist of lowercase letters, digits,
<literal>.</literal>, <literal>_</literal> and <literal>-</literal>, other files are ignored. Each file must
contain a single PEM-encoded certificate. A file that contains more than one certificate is ignored as a
whole. CA certificates should be placed in separate files among the trust anchors instead.</para>
<para>Certificates are looked up for two OS identifiers derived from
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>: the exact
identifier, and the value of <varname>ID=</varname> alone. The exact identifier consists of the values of
<varname>ID=</varname>, <varname>VERSION_ID=</varname>, <varname>VARIANT_ID=</varname>,
<varname>IMAGE_ID=</varname> and <varname>IMAGE_VERSION=</varname>, separated by <literal>:</literal>. A
field that is not set is left empty, and unset fields at the end are omitted. For example,
<literal>ID=debian</literal> and <literal>VERSION_ID=13</literal> result in the identifiers
<literal>debian:13</literal> and <literal>debian</literal>. If <varname>ID=</varname> is not set,
<literal>linux</literal> is used. If one of the other fields contains characters that are not permitted by
the VOA specification, only the value of <varname>ID=</varname> is used. If <varname>ID=</varname> itself
contains such characters, no certificates are looked up. The <varname>keyring-setup.os</varname> credential
may be used to specify the identifiers explicitly, see below.</para>
<para>Note that the VOA specification requires different semantics than the usual logic for configuration
files, where a file in a directory with higher priority replaces a file with the same name in a directory
with lower priority. Instead, X.509 certificates are merged: all files in all load paths are used. A
certificate that is found in more than one place is only enrolled once. If two different certificates have
the same subject and key identifier, only one of them can be added to a keyring. In this case, certificates
found for the exact OS identifier take precedence over the ones found for the value of <varname>ID=</varname>
alone, and among those, the certificate from the load path with the highest priority is enrolled.</para>
<para>A certificate may be masked by placing a symlink to <filename>/dev/null</filename> with the same file
name in any of the load paths, usually in <filename>/etc/voa/</filename> or <filename>/run/voa/</filename>.
As required by the VOA specification, a masked certificate is ignored in all load paths, including the
ones with a higher priority than the one containing the symlink. Masking is meant as a substitute for
revocation: if a certificate is considered compromised, a single symlink ensures that none of its copies is
enrolled. Other symlinks are followed as long as they point to a location within the VOA hierarchy, and
symlinks to certificate files only if the target has the same file name.</para>
<para>To make sure that certificates cannot be placed by unprivileged users, files that are executable or
world-writable, and directories that are world-writable, are ignored. Once a directory owned by an
unprivileged user has been entered, the lookup does not continue into files or directories owned by anyone
else.</para>
<para>As required by the VOA specification, the usage of each certificate is checked against its purpose.
An artifact verifier is ignored if it has an extended key usage extension that permits neither code signing
nor any extended key usage, or a key usage extension that does not permit digital signatures. A trust anchor
that is not a CA certificate is enrolled nonetheless, since self-signed certificates that act as their own
trust anchor are common, but a message is logged about it. Certificates with invalid extensions are
ignored.</para>
</refsect1>
<refsect1>
<title>Credentials</title>
<para><command>systemd-keyring-setup</command> supports the service credentials logic as implemented by
<varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>keyring-setup.dm-verity.<replaceable>NAME</replaceable></varname></term>
<term><varname>keyring-setup.fs-verity.<replaceable>NAME</replaceable></varname></term>
<term><varname>keyring-setup.bpf.<replaceable>NAME</replaceable></varname></term>
<listitem><para>A PEM-encoded X.509 certificate to enroll into the <literal>.dm-verity</literal>,
<literal>.fs-verity</literal> or <literal>.bpf</literal> keyring, respectively.
<replaceable>NAME</replaceable> may consist of lowercase letters, digits, <literal>.</literal>,
<literal>_</literal> and <literal>-</literal>. As suggested by the VOA specification for certificates
obtained from elsewhere, the certificate is not enrolled directly, but is first written to
<filename>/run/voa/<replaceable>OS</replaceable>/kernel-keyring/<replaceable>CONTEXT</replaceable>/x509/<replaceable>NAME</replaceable>-certificate.pem</filename>,
using the first OS identifier. Hence, masking and merging apply to it like to any other file in the
hierarchy. Only the certificate itself is written there, so that a private key included in the
credential is not made readable to other users. A credential that does not contain exactly one
certificate is ignored.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>keyring-setup.os</varname></term>
<listitem><para>A whitespace-separated list of up to 64 OS identifiers to use instead of the ones
derived from <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
This is useful for generic initrds, whose <filename>os-release</filename> does not match the one of the
host. If the list is empty, too long or contains an invalid identifier, the credential is ignored and
the identifiers derived from <filename>os-release</filename> are used.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
</variablelist>
<para>See
<citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details about system credentials.</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>If one or more <replaceable>KEYRING</replaceable> names, such as <literal>.dm-verity</literal>, are
specified, only those keyrings are processed. Otherwise, all keyrings listed above are processed.</para>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--dry-run</option></term>
<listitem><para>Show which certificates would be enrolled into which keyring, and the current state
of the keyrings, without changing anything.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="json"/>
<xi:include href="standard-options.xml" xpointer="help"/>
<xi:include href="standard-options.xml" xpointer="version"/>
</variablelist>
<para><option>--json=</option> is only supported together with <option>--dry-run</option>.</para>
</refsect1>
<refsect1>
<title>Exit status</title>
<para>On success, 0 is returned. This includes the cases where a keyring does not exist, or has been
provisioned by an earlier run already. If a certificate or a credential could not be used, for example
because it is malformed, or because it is not signed by a key in a keyring that has been sealed already, 65
(<constant>EX_DATAERR</constant>) is returned. <filename>systemd-keyring-setup.service</filename> treats this
exit status as success. On other failures, a different non-zero exit status is returned.</para>
</refsect1>
<refsect1>
<title>Kernel Command Line</title>
<variablelist class='kernel-commandline-options'>
<varlistentry>
<term><varname>dm_verity.keyring_unsealed=</varname></term>
<term><varname>bpf.keyring_unsealed=</varname></term>
<listitem><para>These options are interpreted by the kernel. If set to <literal>1</literal>, the kernel
leaves the <literal>.dm-verity</literal> or <literal>.bpf</literal> keyring unsealed during boot, so
that it can be provisioned by <filename>systemd-keyring-setup.service</filename>. Otherwise, the kernel
seals the keyring while it is still empty, and no certificates can be enrolled into it.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Security Considerations</title>
<para>The enrolled certificates can only be trusted as much as the files they were read from. The intended
deployment is to provision the keyrings from the initrd of a signed Unified Kernel Image, see
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>Until a keyring is sealed, any sufficiently privileged process may add arbitrary keys to it. After it
has been sealed, privileged processes may still remove keys from it, and add certificates that are signed
by a key in the keyring, but they cannot add other keys, or change the restriction or the permissions of
the keyring. The keyrings stay sealed until the next reboot. A soft reboot, see
<citerefentry><refentrytitle>systemd-soft-reboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
does not reset them.</para>
<para>If dm-verity is built as a kernel module, unloading and reloading the module discards the
<literal>.dm-verity</literal> keyring, including its seal, and creates a new, empty one. If
<varname>dm_verity.keyring_unsealed=1</varname> is set, the new keyring may then be provisioned with
arbitrary keys again. <command>systemd-keyring-setup</command> logs a warning if a keyring belongs to a
loadable kernel module. For high-security setups, dm-verity should be built into the kernel.</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-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-dissect</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry project='man-pages'><refentrytitle>keyctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>
+29
View File
@@ -119,6 +119,35 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>keyring-setup.dm-verity.<replaceable>NAME</replaceable></varname></term>
<term><varname>keyring-setup.fs-verity.<replaceable>NAME</replaceable></varname></term>
<term><varname>keyring-setup.bpf.<replaceable>NAME</replaceable></varname></term>
<listitem>
<para>A PEM-encoded X.509 certificate to enroll into the <literal>.dm-verity</literal>,
<literal>.fs-verity</literal> or <literal>.bpf</literal> kernel keyring, respectively (e.g.
<varname>keyring-setup.dm-verity.vendor</varname>). Read by
<citerefentry><refentrytitle>systemd-keyring-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
which writes the certificate to <filename>/run/voa/</filename> before enrolling it, see there for
details. <replaceable>NAME</replaceable> may consist of lowercase letters, digits, <literal>.</literal>,
<literal>_</literal> and <literal>-</literal>.</para>
<xi:include href="version-info.xml" xpointer="v263"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>keyring-setup.os</varname></term>
<listitem>
<para>A whitespace-separated list of OS identifiers (e.g. <literal>debian:13 debian</literal>) under
which certificates are looked up in the VOA hierarchy, instead of the ones derived from
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Read by
<citerefentry><refentrytitle>systemd-keyring-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<xi:include href="version-info.xml" xpointer="v263"/>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>login.issue</varname></term>
<listitem>
+1
View File
@@ -2419,6 +2419,7 @@ subdir('src/integritysetup')
subdir('src/journal')
subdir('src/journal-remote')
subdir('src/kernel-install')
subdir('src/keyring-setup')
subdir('src/keyutil')
subdir('src/locale')
subdir('src/login')
+11
View File
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBnDCCAUOgAwIBAgIURIGL6fLWIcO+/Ako2/UTNpYX3LUwCgYIKoZIzj0EAwIw
GzEZMBcGA1UEAwwQa2V5cmluZy1zZXR1cC1jYTAgFw0yNjA5MDExOTI0MzZaGA8y
MTI2MDgwODE5MjQzNlowGzEZMBcGA1UEAwwQa2V5cmluZy1zZXR1cC1jYTBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABIE9RbLZ1pLUETv15tD8Pu8M7VujIPsLyfbI
gnnnMt8DuCWBcYpskR7UaXz3KGw8mrHSCXYHcjNr1VH1jKX1u9ijYzBhMB0GA1Ud
DgQWBBSJJP2p6+SQKwQUKcskhuxFrHPYIDAfBgNVHSMEGDAWgBSJJP2p6+SQKwQU
KcskhuxFrHPYIDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAKBggq
hkjOPQQDAgNHADBEAiBbfas+St1VlhTqYskeDmT3ysCEP/Mbnmq9ailCP+7C1wIg
dU2k8OMygpbLZBJaBWHvkKTXHrvGjYHslqtu7hO4W0A=
-----END CERTIFICATE-----
+5
View File
@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3BJkI9JHC9ZZF2dO
C3y3uBEpZrLp6pPnYniJ1KoJx4ehRANCAASBPUWy2daS1BE79ebQ/D7vDO1boyD7
C8n2yIJ55zLfA7glgXGKbJEe1Gl89yhsPJqx0gl2B3Iza9VR9Yyl9bvY
-----END PRIVATE KEY-----
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
"""Mint the extension-less test certificates embedded in TEST-98-KEYRING-SETUP.unsealed.sh.
The subtests for the serial-number fallback of certificate_description_suffix() need certificates without
a subjectKeyIdentifier extension. OpenSSL's x509 tool adds one to every certificate it signs, no
matter what, so they cannot be produced with it. python-cryptography only adds what is asked for.
The issuing CA pair next to this script was created with
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-subj /CN=keyring-setup-ca -days 36500 \
-keyout keyring-setup-test-ca.key -out keyring-setup-test-ca.crt
and is installed into the trust-anchor hierarchy of the test images by mkosi.finalize. After
rotating the pair, rerun this script and paste the output over the embedded blobs.
"""
import pathlib
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.oid import NameOID
here = pathlib.Path(__file__).parent
ca_cert = x509.load_pem_x509_certificate((here / 'keyring-setup-test-ca.crt').read_bytes())
ca_key = serialization.load_pem_private_key((here / 'keyring-setup-test-ca.key').read_bytes(), password=None)
for cn, serial in (('noskid', 0x8112131415161718), ('noskid2', 0x11121314)):
key = ec.generate_private_key(ec.SECP256R1())
cert = (
x509.CertificateBuilder()
.subject_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)]))
.issuer_name(ca_cert.subject)
.public_key(key.public_key())
.serial_number(serial)
.not_valid_before(ca_cert.not_valid_before_utc)
.not_valid_after(ca_cert.not_valid_after_utc)
.sign(ca_key, hashes.SHA256())
)
print(f'# {cn}, serial {serial:#x}')
print(cert.public_bytes(serialization.Encoding.PEM).decode(), end='')
+11
View File
@@ -16,3 +16,14 @@ fi
# Used to sign artifacts verified by kernel platform keyring
cp "$SRCDIR/mkosi/mkosi.crt" "$SRCDIR/mkosi/mkosi.key" "$BUILDROOT/usr/share/"
# The same certificate in the VOA hierarchy, for systemd-keyring-setup to enroll into the .dm-verity and
# .fs-verity keyrings
# shellcheck source=/dev/null
id=$(. "$BUILDROOT/usr/lib/os-release" && echo "$ID")
for context in dm-verity fs-verity; do
install -D -m 0644 "$SRCDIR/mkosi/mkosi.crt" "$BUILDROOT/usr/share/voa/$id/kernel-keyring/$context/x509/mkosi-certificate.pem"
done
# A CA certificate among the trust anchors, so that those get enrolled as well
install -D -m 0644 "$SRCDIR/mkosi/keyring-setup-test-ca.crt" \
"$BUILDROOT/usr/share/voa/$id/trust-anchor-kernel-keyring/dm-verity/x509/ca-certificate.pem"
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -e
# The certificate mkosi installs for userspace verification, mirrored into the VOA hierarchy so that
# systemd-keyring-setup enrolls it into the .dm-verity and .fs-verity keyrings while the initrd still can.
if [ -f "$BUILDROOT/usr/lib/verity.d/mkosi.crt" ]; then
# shellcheck source=/dev/null
id=$(. "$BUILDROOT/usr/lib/os-release" && echo "$ID")
for context in dm-verity fs-verity; do
install -D -m 0644 "$BUILDROOT/usr/lib/verity.d/mkosi.crt" "$BUILDROOT/usr/share/voa/$id/kernel-keyring/$context/x509/mkosi-certificate.pem"
done
install -D -m 0644 "$SRCDIR/mkosi/keyring-setup-test-ca.crt" \
"$BUILDROOT/usr/share/voa/$id/trust-anchor-kernel-keyring/dm-verity/x509/ca-certificate.pem"
fi
+1
View File
@@ -37,4 +37,5 @@ disable systemd-boot-check-no-failures.service
disable systemd-journal-gatewayd.*
disable systemd-journal-remote.*
disable systemd-journal-upload.*
disable systemd-keyring-setup.service
disable systemd-time-wait-sync.service
+5
View File
@@ -44,3 +44,8 @@ typedef int32_t key_serial_t;
#else
static_assert(KEY_OTH_ALL == 0x0000003f, "");
#endif
/* TODO: drop once the headers we require carry it */
#ifndef KEY_SPEC_BPF_KEYRING
# define KEY_SPEC_BPF_KEYRING -9 /* - key ID for the .bpf keyring */
#endif
File diff suppressed because it is too large. Load diff
+14
View File
@@ -0,0 +1,14 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
if not have_rust
subdir_done()
endif
executables += [
rust_executable_template + {
'name' : 'systemd-keyring-setup',
'sources' : files('keyring-setup.rs'),
'install_dir' : libexecdir,
'conditions' : ['HAVE_OPENSSL'],
},
]
+1
View File
@@ -73,6 +73,7 @@
#include "process-util.h"
#include "recurse-dir.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "tests.h"
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBkzCCATmgAwIBAgIUB1iKsODqTZ1IYTA+/glv7DzSkPgwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTa2V5cmluZy1zZXR1cC1leHRyYTAgFw0yNjA4MjgxMjM2MDVa
GA8yMTI2MDgwNDEyMzYwNVowHjEcMBoGA1UEAwwTa2V5cmluZy1zZXR1cC1leHRy
YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOOeWwYTrf2uIUeUBTSvorTIYhwI
zfn12j9HHwaQ8fTC+ZezLp6LIQoTZRk6dPyzZ9mYOcNVdvMdWq+c2oEUq32jUzBR
MB0GA1UdDgQWBBSY71cv1pViqLGu0C8Kn4+Uyg0KQDAfBgNVHSMEGDAWgBSY71cv
1pViqLGu0C8Kn4+Uyg0KQDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA
MEUCIQCNDKa0r7Omk8sUfVCtxhd1KADE0jluRr0N81//h/5a5AIgCCJRcwS72mkS
nVEUTbIWQfDVNIJ52tSPbu/GlgENhb4=
-----END CERTIFICATE-----
@@ -0,0 +1,36 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# Without dm_verity.keyring_unsealed=1 the kernel seals .dm-verity empty and the
# service must leave it alone. .fs-verity is provisioned and sealed by the service.
# Both variants boot through an initrd, where the service runs first.
integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'vm' : true,
'firmware' : 'linux',
'configuration' : integration_test_template['configuration'] + {
'env' : {'TEST_MATCH_SUBTEST' : '[.](sealed|fs-verity)[.]sh$'},
},
},
]
# With the flag the service provisions .dm-verity from the VOA hierarchy at
# boot, and the kernel verifies the signed test image against it.
integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()) + '-unsealed',
'vm' : true,
'firmware' : 'linux',
'credentials' : integration_test_template['credentials'] + [
files('keyring-setup.dm-verity.extra'),
],
'cmdline' : integration_test_template['cmdline'] + [
'dm_verity.keyring_unsealed=1',
'dm_verity.require_signatures=1',
],
'configuration' : integration_test_template['configuration'] + {
'command' : '/usr/lib/systemd/tests/testdata/units/' + fs.name(meson.current_source_dir()) + '.sh',
'env' : {'TEST_MATCH_SUBTEST' : 'unsealed'},
},
},
]
+1
View File
@@ -115,6 +115,7 @@ foreach dirname : [
'TEST-95-DBUS-RECONNECT',
'TEST-96-PTYBROKER',
'TEST-97-VMSPAWN-MEMORY',
'TEST-98-KEYRING-SETUP',
]
subdir(dirname)
endforeach
@@ -57,20 +57,50 @@ if [[ "$val" != "Y" && "$val" != "1" ]]; then
exit 77
fi
# Provision the .dm-verity keyring. Empty description lets the kernel derive
# one from the X.509 subject so machine_supports_verity_keyring finds the CN.
keyid=$(openssl x509 -in /usr/share/mkosi.crt -outform DER |
keyctl padd asymmetric '' %:.dm-verity 2>/dev/null) || keyid=""
if [[ -z "$keyid" ]]; then
echo ".dm-verity keyring not provisionable (kernel < v7.0?), skipping"
if ! grep -E ' keyring +\.dm-verity: ' /proc/keys >/dev/null; then
echo ".dm-verity keyring not available (kernel < v7.0?), skipping"
exit 77
fi
if ! keyctl restrict_keyring %:.dm-verity; then
keyctl unlink "$keyid" %:.dm-verity 2>/dev/null || true
echo "ERROR: keyctl restrict_keyring failed" >&2
# systemd-keyring-setup.service provisions the keyring at boot and seals it
# (permission mask 08070000), after which only certificates signed by an
# enrolled key can be added and the certificate must already be in place.
# Provision by hand only otherwise.
if grep -E '^[0-9a-f]+ [^ ]+ +[0-9]+ +[^ ]+ +08070000 +[0-9]+ +[0-9]+ +keyring +\.dm-verity: [0-9]+$' /proc/keys >/dev/null; then
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=stranger -days 1 \
-keyout /dev/null -out /tmp/stranger.pem
openssl x509 -in /tmp/stranger.pem -outform DER -out /tmp/stranger.der
if keyctl padd asymmetric '' %:.dm-verity </tmp/stranger.der 2>/dev/null; then
echo "ERROR: sealed .dm-verity keyring accepted a stranger" >&2
exit 1
fi
echo ".dm-verity keyring already provisioned and sealed at boot"
elif grep -E ' +08070000 +[0-9]+ +[0-9]+ +keyring +\.dm-verity: empty$' /proc/keys >/dev/null; then
echo "ERROR: .dm-verity keyring sealed empty, systemd-keyring-setup enrolled nothing" >&2
exit 1
else
# With the keyring left open by the kernel and systemd-keyring-setup enabled,
# getting here means the service did not provision it
if systemctl -q is-enabled systemd-keyring-setup.service 2>/dev/null &&
[[ "$(cat /sys/module/dm_verity/parameters/keyring_unsealed 2>/dev/null)" == "Y" ]]; then
echo "ERROR: .dm-verity keyring left open, systemd-keyring-setup did not provision it" >&2
exit 1
fi
# Empty description lets the kernel derive one from the X.509 subject so
# machine_supports_verity_keyring finds the CN.
openssl x509 -in /usr/share/mkosi.crt -outform DER -out /tmp/mkosi.der
keyid=$(keyctl padd asymmetric '' %:.dm-verity </tmp/mkosi.der 2>/dev/null) || keyid=""
if [[ -z "$keyid" ]]; then
echo ".dm-verity keyring sealed by the kernel at boot (no dm_verity.keyring_unsealed=1), skipping"
exit 77
fi
if ! keyctl restrict_keyring %:.dm-verity; then
keyctl unlink "$keyid" %:.dm-verity 2>/dev/null || true
echo "ERROR: keyctl restrict_keyring failed" >&2
exit 1
fi
echo "Provisioned .dm-verity keyring with mkosi.crt"
fi
echo "Provisioned .dm-verity keyring with mkosi.crt"
at_exit() {
set +e
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Note that unlike the .dm-verity and .bpf keyrings the kernel never seals
# .fs-verity. Only systemd-keyring-setup does. It enrolled the certificate from
# the VOA hierarchy at boot and sealed the keyring like the others, so only
# certificates chaining to it can be added later, also via a credential.
set -eux
set -o pipefail
KEYRING_SETUP=/usr/lib/systemd/systemd-keyring-setup
if [[ ! -x "$KEYRING_SETUP" ]]; then
echo "systemd-keyring-setup is not built (no Rust support), skipping"
exit 77
fi
# Everything up to the keyring gate below needs no kernel keyring support
[[ "$(systemctl show -P ActiveState systemd-keyring-setup.service)" == "active" ]]
[[ "$(systemctl show -P Result systemd-keyring-setup.service)" == "success" ]]
[[ "$(systemctl show -P ExecMainStatus systemd-keyring-setup.service)" == "0" ]]
# Rejected credential names are ignored and do not fail the run
systemd-run --pipe --wait \
--property LoadCredential=keyring-setup.fs-verityX.foo:/usr/share/mkosi.crt \
--property LoadCredential=keyring-setup.fs-verity.Bad:/usr/share/mkosi.crt \
--property LoadCredential=keyring-setup.bogus.foo:/usr/share/mkosi.crt \
"$KEYRING_SETUP" .fs-verity 2>&1 | tee /tmp/keyring-setup-creds.log
grep -F "Ignoring unrecognized credential 'keyring-setup.fs-verityX.foo'" /tmp/keyring-setup-creds.log >/dev/null
grep -F "Ignoring unrecognized credential 'keyring-setup.bogus.foo'" /tmp/keyring-setup-creds.log >/dev/null
grep -F "Ignoring credential 'keyring-setup.fs-verity.Bad'" /tmp/keyring-setup-creds.log >/dev/null
(! find /run/voa \( -name 'foo-certificate.pem' -o -name 'Bad-certificate.pem' \) | grep . >/dev/null)
# keyring-setup.os overrides where credentials are placed, an invalid identifier is bad input
systemd-run --pipe --wait \
--property SetCredential=keyring-setup.os:testos \
--property LoadCredential=keyring-setup.fs-verity.osname:/usr/share/mkosi.crt \
"$KEYRING_SETUP" .fs-verity
ls /run/voa/testos/kernel-keyring/fs-verity/x509/osname-certificate.pem
rc=0
systemd-run --pipe --wait --property SetCredential=keyring-setup.os:INVALID "$KEYRING_SETUP" .fs-verity || rc=$?
[[ "$rc" -eq 65 ]]
# Only the certificate of a credential is placed, a private key that came along stays out of the
# world-readable hierarchy. A credential without a certificate is bad input.
cat /usr/share/mkosi.key /usr/share/mkosi.crt >/tmp/withkey.pem
systemd-run --pipe --wait \
--property SetCredential=keyring-setup.os:testos \
--property LoadCredential=keyring-setup.fs-verity.withkey:/tmp/withkey.pem \
"$KEYRING_SETUP" .fs-verity
(! grep -F "PRIVATE KEY" /run/voa/testos/kernel-keyring/fs-verity/x509/withkey-certificate.pem >/dev/null)
cmp <(openssl x509 -in /run/voa/testos/kernel-keyring/fs-verity/x509/withkey-certificate.pem -outform DER) \
<(openssl x509 -in /usr/share/mkosi.crt -outform DER)
rm -f /tmp/withkey.pem
rc=0
systemd-run --pipe --wait \
--property SetCredential=keyring-setup.os:testos \
--property LoadCredential=keyring-setup.fs-verity.nocert:/usr/share/mkosi.key \
"$KEYRING_SETUP" .fs-verity || rc=$?
[[ "$rc" -eq 65 ]]
[[ ! -e /run/voa/testos/kernel-keyring/fs-verity/x509/nocert-certificate.pem ]]
# Multiple identifiers feed the lookup, not only the placement of credentials. A distinct
# certificate, the byte-identical dedup would hide a copy of an already collected one.
mkdir -p /usr/share/voa/zweitos/kernel-keyring/fs-verity/x509
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=zwei -days 1 \
-keyout /dev/null -out /usr/share/voa/zweitos/kernel-keyring/fs-verity/x509/zwei-certificate.pem
systemd-run --pipe --wait \
--property SetCredential="keyring-setup.os:zweitos testos" \
"$KEYRING_SETUP" --dry-run --no-pager --json=short .fs-verity | tee /tmp/keyring-setup-multi.json
jq -e '.[0].certificates | any(contains("/zweitos/")) and any(contains("/testos/"))' /tmp/keyring-setup-multi.json
rm -rf /usr/share/voa/zweitos
# An empty identifier list and one longer than 64 entries are bad input
rc=0
systemd-run --pipe --wait --property SetCredential=keyring-setup.os: \
"$KEYRING_SETUP" .fs-verity 2>&1 | tee /tmp/keyring-setup-os-empty.log || rc=$?
[[ "$rc" -eq 65 ]]
grep -F "Credential keyring-setup.os is empty, ignoring." /tmp/keyring-setup-os-empty.log >/dev/null
rc=0
systemd-run --pipe --wait --property SetCredential="keyring-setup.os:$(seq -f 'os%.0f' 65 | tr '\n' ' ')" \
"$KEYRING_SETUP" .fs-verity 2>&1 | tee /tmp/keyring-setup-os-many.log || rc=$?
[[ "$rc" -eq 65 ]]
grep -F "lists more than 64 OS identifiers, ignoring it." /tmp/keyring-setup-os-many.log >/dev/null
# An os-release ID= outside of the VOA charset disables the lookup, reported once, the run still fails
printf 'ID=Debian\n' >/tmp/bad-os-release
rc=0
systemd-run --pipe --wait --property BindReadOnlyPaths=/tmp/bad-os-release:/etc/os-release \
"$KEYRING_SETUP" .fs-verity 2>&1 | tee /tmp/keyring-setup-badid.log || rc=$?
[[ "$rc" -eq 1 ]]
grep -F "Failed to determine the OS identifier from os-release, enrolling nothing" /tmp/keyring-setup-badid.log >/dev/null
(! grep -F "Failed to enumerate certificates" /tmp/keyring-setup-badid.log >/dev/null)
if ! grep -E ' keyring +\.fs-verity: ' /proc/keys >/dev/null; then
echo ".fs-verity keyring not available (CONFIG_FS_VERITY_BUILTIN_SIGNATURES?), skipping"
exit 77
fi
# Sealed, holding the mkosi certificate
grep -E '^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +08070000 +0 +0 +keyring +\.fs-verity: 1$' /proc/keys
CN="$(openssl x509 -noout -subject -in /usr/share/mkosi.crt | sed 's/^.*CN *= *//')"
grep -E "^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +39010000 +0 +0 +asymmetri .*$CN" /proc/keys
. /etc/os-release
# Not -u: messages of the initrd run carry no _SYSTEMD_UNIT=, see the unsealed subtest
journalctl --merge -o cat -t systemd-keyring-setup |
grep -F "Enrolled '/usr/share/voa/$ID/kernel-keyring/fs-verity/x509/mkosi-certificate.pem' into keyring .fs-verity" >/dev/null
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=stranger -days 1 \
-keyout /dev/null -out /tmp/stranger.pem
openssl x509 -in /tmp/stranger.pem -outform DER -out /tmp/stranger.der
(! keyctl padd asymmetric '' %:.fs-verity </tmp/stranger.der)
keyctl list %:.fs-verity | grep -F "$CN"
# A certificate handed over later is placed into the hierarchy, and one that is
# enrolled already is not enrolled twice
systemd-run --pipe --wait \
--property LoadCredential=keyring-setup.fs-verity.late:/usr/share/mkosi.crt \
"$KEYRING_SETUP" .fs-verity 2>&1 | tee /tmp/keyring-setup-late.log
(! grep -F "Enrolled '" /tmp/keyring-setup-late.log >/dev/null)
ls /run/voa/*/kernel-keyring/fs-verity/x509/late-certificate.pem
grep -E ' +08070000 +0 +0 +keyring +\.fs-verity: 1$' /proc/keys
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Booted without dm_verity.keyring_unsealed=1: the kernel sealed .dm-verity
# empty, systemd-keyring-setup finds the certificates but can enroll nothing,
# and must leave the keyring alone.
set -eux
set -o pipefail
KEYRING_SETUP=/usr/lib/systemd/systemd-keyring-setup
if [[ ! -x "$KEYRING_SETUP" ]]; then
echo "systemd-keyring-setup is not built (no Rust support), skipping"
exit 77
fi
# Everything up to the keyring gate below needs no kernel keyring support
[[ "$(systemctl show -P ActiveState systemd-keyring-setup.service)" == "active" ]]
[[ "$(systemctl show -P Result systemd-keyring-setup.service)" == "success" ]]
[[ "$(systemctl show -P ExecMainStatus systemd-keyring-setup.service)" == "0" ]]
# An unknown keyring, a name without its leading dot, and --json= without --dry-run are rejected
(! "$KEYRING_SETUP" --dry-run .bogus)
(! "$KEYRING_SETUP" --dry-run dm-verity)
(! "$KEYRING_SETUP" --json=short .dm-verity)
# The usage check keeps a certificate that cannot sign code out and reports it as bad input, while
# one permitting any usage and a CA certificate placed among the trust anchors are accepted
. /etc/os-release
mkdir -p "/etc/voa/$ID/kernel-keyring/dm-verity/x509" "/etc/voa/$ID/trust-anchor-kernel-keyring/dm-verity/x509"
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=tls -days 1 \
-addext extendedKeyUsage=serverAuth \
-keyout /dev/null -out "/etc/voa/$ID/kernel-keyring/dm-verity/x509/tls-certificate.pem"
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=anyeku -days 1 \
-addext extendedKeyUsage=critical,anyExtendedKeyUsage \
-keyout /dev/null -out "/etc/voa/$ID/kernel-keyring/dm-verity/x509/anyeku-certificate.pem"
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=ca -days 1 \
-addext basicConstraints=critical,CA:TRUE -addext keyUsage=critical,keyCertSign \
-keyout /dev/null -out "/etc/voa/$ID/trust-anchor-kernel-keyring/dm-verity/x509/ca-certificate.pem"
:>"/etc/voa/$ID/kernel-keyring/dm-verity/x509/empty-certificate.pem"
truncate -s 2M "/etc/voa/$ID/kernel-keyring/dm-verity/x509/large-certificate.pem"
rc=0
"$KEYRING_SETUP" --dry-run --no-pager --json=short .dm-verity >/tmp/keyring-setup.json || rc=$?
[[ "$rc" -eq 65 ]]
jq -e '.[0].certificates | any(endswith("/mkosi-certificate.pem")) and any(endswith("/anyeku-certificate.pem"))
and any(endswith("/trust-anchor-kernel-keyring/dm-verity/x509/ca-certificate.pem"))
and (any(endswith("/tls-certificate.pem")) | not)
and (any(endswith("/empty-certificate.pem")) | not)
and (any(endswith("/large-certificate.pem")) | not)' /tmp/keyring-setup.json
# The .bpf spec looks up the bpf role
mkdir -p "/etc/voa/$ID/kernel-keyring/bpf/x509"
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=bpfrole -days 1 \
-keyout /dev/null -out "/etc/voa/$ID/kernel-keyring/bpf/x509/bpfrole-certificate.pem"
"$KEYRING_SETUP" --dry-run --no-pager --json=short .bpf >/tmp/keyring-setup-bpf.json
jq -e '.[0].certificates | any(endswith("/kernel-keyring/bpf/x509/bpfrole-certificate.pem"))' /tmp/keyring-setup-bpf.json
# .fs-verity has no keyring_unsealed parameter, its kernel_unsealed state is null
"$KEYRING_SETUP" --dry-run --no-pager --json=short .fs-verity | jq -e '.[0].kernel_unsealed == null'
rm -rf "/etc/voa/$ID" /tmp/keyring-setup.json /tmp/keyring-setup-bpf.json
if ! grep -E ' keyring +\.dm-verity: ' /proc/keys >/dev/null; then
if ! modprobe dm_verity 2>/dev/null || ! grep -E ' keyring +\.dm-verity: ' /proc/keys >/dev/null; then
echo ".dm-verity keyring not available (kernel < v7.0?), skipping"
exit 77
fi
# The service loads dm_verity itself, the keyring must have existed when it ran
echo "ERROR: dm_verity was not loaded when systemd-keyring-setup.service ran" >&2
exit 1
fi
[[ "$(cat /sys/module/dm_verity/parameters/keyring_unsealed)" == "N" ]]
# The initial permission mask is untouched and the keyring stays empty
grep -E '^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +082f0000 +0 +0 +keyring +\.dm-verity: empty$' /proc/keys
# The certificates were found, mkosi.crt among them
"$KEYRING_SETUP" --dry-run --no-pager --json=short .dm-verity |
jq -e '.[0] | .exists == true and .kernel_unsealed == false and .sealed == false and (.certificates | any(endswith("/mkosi-certificate.pem")))'
# Running again changes nothing
"$KEYRING_SETUP" .dm-verity
grep -E ' +082f0000 +0 +0 +keyring +\.dm-verity: empty$' /proc/keys
# Without a key in the .dm-verity keyring the kernel cannot verify the signed
# test image, so with systemd's userspace fallback masked the activation must
# fail, and succeed once the fallback is available again.
mkdir -p /etc/verity.d
ln -sf /dev/null /etc/verity.d/mkosi.crt
(! systemd-run --pipe --wait \
--property RootImage=/usr/share/minimal_0.raw \
--property RootImagePolicy=root=signed \
bash --version >/dev/null)
rm -f /etc/verity.d/mkosi.crt
systemd-run --pipe --wait \
--property RootImage=/usr/share/minimal_0.raw \
--property RootImagePolicy=root=signed \
bash --version >/dev/null
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests_and_exit
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Booted with dm_verity.keyring_unsealed=1: systemd-keyring-setup enrolled the
# certificates from the VOA hierarchy at boot, sealed the keyring, and the
# kernel verifies the signed test image against it.
set -eux
set -o pipefail
KEYRING_SETUP=/usr/lib/systemd/systemd-keyring-setup
if [[ ! -x "$KEYRING_SETUP" ]]; then
echo "systemd-keyring-setup is not built (no Rust support), skipping"
exit 77
fi
if ! grep -E ' keyring +\.dm-verity: ' /proc/keys >/dev/null; then
echo ".dm-verity keyring not available (kernel < v7.0?), skipping"
exit 77
fi
[[ "$(systemctl show -P ActiveState systemd-keyring-setup.service)" == "active" ]]
[[ "$(systemctl show -P Result systemd-keyring-setup.service)" == "success" ]]
[[ "$(systemctl show -P ExecMainStatus systemd-keyring-setup.service)" == "0" ]]
[[ "$(cat /sys/module/dm_verity/parameters/keyring_unsealed)" == "Y" ]]
# Sealed, holding the mkosi certificate under its kernel-derived description, the one handed
# over as a credential and the trust anchor
grep -E '^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +08070000 +0 +0 +keyring +\.dm-verity: 3$' /proc/keys
CN="$(openssl x509 -noout -subject -in /usr/share/mkosi.crt | sed 's/^.*CN *= *//')"
grep -E "^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +39010000 +0 +0 +asymmetri .*$CN" /proc/keys
grep -E '^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +39010000 +0 +0 +asymmetri .*keyring-setup-extra' /proc/keys
grep -E '^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +39010000 +0 +0 +asymmetri .*keyring-setup-ca' /proc/keys
# /proc/keys does not say which keyring a key is linked into, check that they are members of .dm-verity
keyctl list %:.dm-verity | grep -F "$CN"
keyctl list %:.dm-verity | grep -F keyring-setup-extra
keyctl list %:.dm-verity | grep -F keyring-setup-ca
"$KEYRING_SETUP" --dry-run --no-pager --json=short .dm-verity | jq -e '.[0].kernel_unsealed == true'
# The service enrolled them from the VOA hierarchy in the initrd, before the switch to the host
. /etc/os-release
# Not -u: the initrd run has exited by the time journald reads its messages, so they carry no _SYSTEMD_UNIT=
journalctl --merge -o json -t systemd-keyring-setup >/tmp/keyring-setup.journal.json
enrolled="$(jq -rn --arg m "Enrolled '/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem' into keyring .dm-verity" \
'first(inputs | select(.MESSAGE | startswith($m)) | .__MONOTONIC_TIMESTAMP)' /tmp/keyring-setup.journal.json)"
journalctl --merge -o json _PID=1 >/tmp/pid1.journal.json
switched="$(jq -rn 'first(inputs | select(.MESSAGE | startswith("Switching root")) | .__MONOTONIC_TIMESTAMP)' /tmp/pid1.journal.json)"
rm -f /tmp/keyring-setup.journal.json /tmp/pid1.journal.json
[[ -n "$enrolled" && -n "$switched" && "$enrolled" -lt "$switched" ]]
journalctl --merge -o cat -t systemd-keyring-setup |
grep -E "^Enrolled '/run/voa/[^/]+/kernel-keyring/dm-verity/x509/extra-certificate.pem' into keyring .dm-verity" >/dev/null
journalctl --merge -o cat -t systemd-keyring-setup |
grep -F "Enrolled '/usr/share/voa/$ID/trust-anchor-kernel-keyring/dm-verity/x509/ca-certificate.pem' into keyring .dm-verity" >/dev/null
# From now on, only certificates signed by an enrolled key can be added, and neither the mask nor the
# restriction can be changed, not even by root
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=stranger -days 1 \
-keyout /dev/null -out /tmp/stranger.pem
openssl x509 -in /tmp/stranger.pem -outform DER -out /tmp/stranger.der
(! keyctl padd asymmetric '' %:.dm-verity </tmp/stranger.der)
(! keyctl restrict_keyring %:.dm-verity)
(! keyctl invalidate %:.dm-verity)
(! keyctl setperm %:.dm-verity 0x3f3f0000)
keyctl list %:.dm-verity
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=chained \
-keyout /dev/null -out /tmp/chained.csr
openssl x509 -req -in /tmp/chained.csr -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial 1 -days 1 -extfile <(echo authorityKeyIdentifier=keyid,issuer) -out /tmp/chained.pem
openssl x509 -in /tmp/chained.pem -outform DER | keyctl padd asymmetric '' %:.dm-verity
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 4$' /proc/keys
# A later stage finds the keyring provisioned and exits successfully without enrolling anything twice
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-again.log
(! grep -F "Enrolled '" /tmp/keyring-setup-again.log >/dev/null)
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 4$' /proc/keys
# A certificate configured after the fact is refused and reported as bad input unless it is signed
# by an enrolled key
mkdir -p "/etc/voa/$ID/kernel-keyring/dm-verity/x509"
cp /tmp/stranger.pem "/etc/voa/$ID/kernel-keyring/dm-verity/x509/late-certificate.pem"
rc=0
"$KEYRING_SETUP" .dm-verity || rc=$?
[[ "$rc" -eq 65 ]]
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 4$' /proc/keys
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=late \
-keyout /dev/null -out /tmp/late.csr
openssl x509 -req -in /tmp/late.csr -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial 2 -days 1 -extfile <(echo authorityKeyIdentifier=keyid,issuer) \
-out "/etc/voa/$ID/kernel-keyring/dm-verity/x509/late-certificate.pem"
"$KEYRING_SETUP" .dm-verity
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 5$' /proc/keys
grep -E "^[0-9a-f]+ [A-Za-z-]{7} +[0-9]+ +perm +39010000 +0 +0 +asymmetri +late: [0-9a-f]+: " /proc/keys
# On a colliding subject and key identifier the copy from the highest-priority load path wins
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=dup \
-keyout /tmp/dup.key -out /tmp/dup.csr
openssl x509 -req -in /tmp/dup.csr -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial 3 -days 1 \
-extfile <(printf 'authorityKeyIdentifier=keyid,issuer\nsubjectKeyIdentifier=hash\n') \
-out "/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem"
openssl x509 -req -in /tmp/dup.csr -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial 4 -days 2 \
-extfile <(printf 'authorityKeyIdentifier=keyid,issuer\nsubjectKeyIdentifier=hash\n') \
-out "/etc/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem"
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-dup.log
grep -F "Enrolled '/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem'" /tmp/keyring-setup-dup.log >/dev/null
grep -F "Enrolled '/etc/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem'" /tmp/keyring-setup-dup.log >/dev/null
grep -F "'/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem' was superseded by a certificate of higher priority" /tmp/keyring-setup-dup.log >/dev/null
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 6$' /proc/keys
rm -f "/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/dup-certificate.pem"
# The same certificate in two load paths is enrolled once, neither copy supersedes the other
cp "/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem" \
"/etc/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem"
SYSTEMD_LOG_LEVEL=debug "$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-samecert.log
grep -F "'/usr/share/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem' is identical to '/etc/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem', skipping." /tmp/keyring-setup-samecert.log >/dev/null
(! grep -F "Enrolled '" /tmp/keyring-setup-samecert.log >/dev/null)
(! grep -F "was superseded" /tmp/keyring-setup-samecert.log >/dev/null)
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 6$' /proc/keys
rm -f "/etc/voa/$ID/kernel-keyring/dm-verity/x509/mkosi-certificate.pem"
# Without a subject key identifier the serial number, DER padding included, identifies the key:
# CN=noskid, serial 0x8112131415161718, no extensions, signed by the committed keyring-setup-test-ca key,
# minted by mkosi/keyring-setup-test-ca.py
cat >"/etc/voa/$ID/kernel-keyring/dm-verity/x509/noskid-certificate.pem" <<'CERT'
-----BEGIN CERTIFICATE-----
MIIBIjCByaADAgECAgkAgRITFBUWFxgwCgYIKoZIzj0EAwIwGzEZMBcGA1UEAwwQ
a2V5cmluZy1zZXR1cC1jYTAgFw0yNjA5MDExOTI0MzZaGA8yMTI2MDgwODE5MjQz
NlowETEPMA0GA1UEAwwGbm9za2lkMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
FRpKLUgmHK8vFB9/N5ZRV54Bwk8uOxU8tt1R1A3OMwgn/ct32PBBNj5HbiS/Wta2
qs6KODUBlPVfCEXktGHMYzAKBggqhkjOPQQDAgNIADBFAiEAsd92t7WgIFHe+cp/
1gjd7OXQw+wkW+Y33iixvkGLA/QCIBLVHP7dhYYkqkxZSkrcUQF805lE893LDnuF
MQVSUlGj
-----END CERTIFICATE-----
CERT
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-noskid.log
grep -F "Enrolled '/etc/voa/$ID/kernel-keyring/dm-verity/x509/noskid-certificate.pem' into keyring .dm-verity as noskid: 008112131415161718" /tmp/keyring-setup-noskid.log >/dev/null
keyctl list %:.dm-verity | grep -F 'noskid: 008112131415161718'
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 7$' /proc/keys
# And the second run recognizes it by that identifier and enrolls nothing
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-noskid2.log
(! grep -F "Enrolled '/etc/voa/$ID/kernel-keyring/dm-verity/x509/noskid-certificate.pem'" /tmp/keyring-setup-noskid2.log >/dev/null)
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 7$' /proc/keys
# A serial without the top bit set gets no zero pad: CN=noskid2, serial 0x11121314, same CA and script
cat >"/etc/voa/$ID/kernel-keyring/dm-verity/x509/noskid2-certificate.pem" <<'CERT'
-----BEGIN CERTIFICATE-----
MIIBHjCBxaADAgECAgQREhMUMAoGCCqGSM49BAMCMBsxGTAXBgNVBAMMEGtleXJp
bmctc2V0dXAtY2EwIBcNMjYwOTAxMTkyNDM2WhgPMjEyNjA4MDgxOTI0MzZaMBIx
EDAOBgNVBAMMB25vc2tpZDIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQZeGsy
lGeEJ5rQtap+PKYtjPtqc3j84NM++obHFcfMjt+jhTRUUtoZxP7cYvODHLZiJqne
y5VXUwcozNcN7E3EMAoGCCqGSM49BAMCA0gAMEUCIQCjnDs9G6zA1fNGMhIRSnHV
f0WXbXciDE8wxo/p7owp7wIgGMLuK/KOyRkgKZLNZx9HG38xmgZYb73tcGFeqg2X
ihY=
-----END CERTIFICATE-----
CERT
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-noskid3.log
grep -F "Enrolled '/etc/voa/$ID/kernel-keyring/dm-verity/x509/noskid2-certificate.pem' into keyring .dm-verity as noskid2: 11121314" /tmp/keyring-setup-noskid3.log >/dev/null
keyctl list %:.dm-verity | grep -F 'noskid2: 11121314'
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 8$' /proc/keys
# Key material writable by others is refused, once the mode is sane it is enrolled
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj /CN=loose \
-keyout /dev/null -out /tmp/loose.csr
openssl x509 -req -in /tmp/loose.csr -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial 5 -days 1 -extfile <(echo authorityKeyIdentifier=keyid,issuer) \
-out "/etc/voa/$ID/kernel-keyring/dm-verity/x509/loose-certificate.pem"
chmod 0666 "/etc/voa/$ID/kernel-keyring/dm-verity/x509/loose-certificate.pem"
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-loose.log
grep -F "Failed to chase '/etc/voa/$ID/kernel-keyring/dm-verity/x509/loose-certificate.pem': Link has been severed" /tmp/keyring-setup-loose.log >/dev/null
(! keyctl list %:.dm-verity | grep -F 'loose' >/dev/null)
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 8$' /proc/keys
chmod 0644 "/etc/voa/$ID/kernel-keyring/dm-verity/x509/loose-certificate.pem"
"$KEYRING_SETUP" .dm-verity
keyctl list %:.dm-verity | grep -F 'loose'
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 9$' /proc/keys
# A file holding more than one certificate is refused as a whole, intermediates cannot be smuggled in
for cn in chainfirst chainsecond; do
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -subj "/CN=$cn" \
-keyout /dev/null -out "/tmp/$cn.csr"
openssl x509 -req -in "/tmp/$cn.csr" -CA /usr/share/mkosi.crt -CAkey /usr/share/mkosi.key \
-set_serial "0x$(printf '%s' "$cn" | sha256sum | cut -c1-8)" -days 1 \
-extfile <(echo authorityKeyIdentifier=keyid,issuer) -out "/tmp/$cn.pem"
done
cat /tmp/chainfirst.pem /tmp/chainsecond.pem >"/etc/voa/$ID/kernel-keyring/dm-verity/x509/chain-certificate.pem"
rc=0
"$KEYRING_SETUP" .dm-verity 2>&1 | tee /tmp/keyring-setup-chain.log || rc=$?
[[ "$rc" -eq 65 ]]
grep -F "'/etc/voa/$ID/kernel-keyring/dm-verity/x509/chain-certificate.pem' contains more than one certificate, ignoring." /tmp/keyring-setup-chain.log >/dev/null
(! keyctl list %:.dm-verity | grep -F 'chainfirst' >/dev/null)
(! keyctl list %:.dm-verity | grep -F 'chainsecond' >/dev/null)
grep -E ' +08070000 +0 +0 +keyring +\.dm-verity: 9$' /proc/keys
rm -rf "/etc/voa/$ID"
# Check that the kernel verifies the image against the .dm-verity keyring: with the certificate masked
# for systemd's userspace fallback and a signed image required, activation only succeeds if the
# kernel accepted the signature.
mkdir -p /etc/verity.d
ln -sf /dev/null /etc/verity.d/mkosi.crt
systemd-run --pipe --wait \
--property RootImage=/usr/share/minimal_0.raw \
--property RootImagePolicy=root=signed \
bash --version >/dev/null
rm -f /etc/verity.d/mkosi.crt
+4 -1
View File
@@ -306,7 +306,10 @@ kernel_supports_lsm() {
machine_supports_verity_keyring() {
# Requires kernel built with certain kconfigs, as listed in README:
# https://oracle.github.io/kconfigs/?config=UTS_RELEASE&config=DM_VERITY_VERIFY_ROOTHASH_SIG&config=DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING&config=DM_VERITY_VERIFY_ROOTHASH_SIG_PLATFORM_KEYRING&config=IMA_ARCH_POLICY&config=INTEGRITY_MACHINE_KEYRING
if grep -q "$(openssl x509 -noout -subject -in /usr/share/mkosi.crt | sed 's/^.*CN=//')" /proc/keys && \
# Only the keyrings dm-verity consults count, .fs-verity holds the same certificate without implying
# verity signature support
if { keyctl list %:.dm-verity; keyctl list %:.platform; keyctl list %:.machine; keyctl list %:.secondary_trusted_keys; :; } 2>/dev/null |
grep -F "$(openssl x509 -noout -subject -in /usr/share/mkosi.crt | sed 's/^.*CN=//')" >/dev/null && \
( . /etc/os-release; [ "$ID" != "centos" ] || systemd-analyze compare-versions "$VERSION_ID" ge 10 ) && \
( . /etc/os-release; [ "$ID" != "debian" ] || [ -z "${VERSION_ID:-}" ] || systemd-analyze compare-versions "$VERSION_ID" ge 13 ) && \
( . /etc/os-release; [ "$ID" != "ubuntu" ] || systemd-analyze compare-versions "$VERSION_ID" ge 24.04 ) && \
+5
View File
@@ -546,6 +546,11 @@ units = [
{ 'file' : 'systemd-journald@.service.in' },
{ 'file' : 'systemd-journald@.socket' },
{ 'file' : 'systemd-kexec.service' },
{
'file' : 'systemd-keyring-setup.service.in',
'conditions' : ['HAVE_OPENSSL', 'HAVE_RUST'],
'symlinks' : ['sysinit.target.wants/'],
},
{
'file' : 'systemd-localed.service.in',
'conditions' : ['ENABLE_LOCALED'],
+55
View File
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Enroll Certificates into Kernel Keyrings
Documentation=man:systemd-keyring-setup.service(8)
DefaultDependencies=no
Conflicts=shutdown.target initrd-switch-root.target
Before=sysinit.target shutdown.target initrd-switch-root.target
# Verity devices are set up after veritysetup-pre.target, everything mounting images after local-fs-pre.target
Before=local-fs-pre.target veritysetup-pre.target
Wants=local-fs-pre.target veritysetup-pre.target
Before=systemd-sysext-initrd.service systemd-confext-initrd.service systemd-mountfsd.service
# A privileged container sharing the initial user namespace could otherwise provision the host's keyrings
ConditionVirtualization=!container
[Service]
Type=oneshot
RemainAfterExit=yes
SuccessExitStatus=DATAERR
ImportCredential=keyring-setup.*
ExecStart={{LIBEXECDIR}}/systemd-keyring-setup
# Loading dm_verity is the only privileged operation, the keyrings belong to root anyway
CapabilityBoundingSet=CAP_SYS_MODULE
IPAddressDeny=any
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelTunables=yes
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
# The ephemeral load path credentials are placed into, kept for the consumers of the hierarchy
RuntimeDirectory=voa
RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service @module