mirror of
https://github.com/systemd/systemd.git
synced 2024-11-26 19:53:45 +08:00
units: add a tpm2.target synchronization point and small generator that pulls in
Distributions apparently only compile a subset of TPM2 drivers into the kernel. For those not compiled it but provided as kmod we need a synchronization point: we must wait before the first TPM2 interaction until the driver is available and accessible. This adds a tpm2.target unit as such a synchronization point. It's ordered after /dev/tpmrm0, and is pulled in by a generator whenever we detect that the kernel reported a TPM2 to exist but we have no device for it yet. This should solve the issue, but might create problems: if there are TPM devices supported by firmware that we don't have Linux drivers for we'll hang for a bit. Hence let's add a kernel cmdline switch to disable (or alternatively force) this logic. Fixes: #30164
This commit is contained in:
parent
6018a27cb7
commit
4e1f0037b8
@ -1100,6 +1100,7 @@ manpages = [
|
||||
'systemd-tmpfiles-setup-dev.service',
|
||||
'systemd-tmpfiles-setup.service'],
|
||||
''],
|
||||
['systemd-tpm2-generator', '8', [], ''],
|
||||
['systemd-tpm2-setup.service',
|
||||
'8',
|
||||
['systemd-tpm2-setup', 'systemd-tpm2-setup-early.service'],
|
||||
|
60
man/systemd-tpm2-generator.xml
Normal file
60
man/systemd-tpm2-generator.xml
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||
<!ENTITY % entities SYSTEM "custom-entities.ent" >
|
||||
%entities;
|
||||
]>
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-tpm2-generator">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-tpm2-generator</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-tpm2-generator</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-tpm2-generator</refname>
|
||||
<refpurpose>Generator for inserting TPM2 synchronization point in the boot process</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/usr/lib/systemd/system-generators/systemd-tpm2-generator</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-tpm2-generator</filename> is a generator that adds a <varname>Wants=</varname>
|
||||
dependency from <filename>sysinit.target</filename> to <filename>tpm2.target</filename> when it detects
|
||||
that the firmware discovered a TPM2 device but the OS kernel so far did
|
||||
not. <filename>tpm2.target</filename> is supposed to act as synchronization point for all services that
|
||||
require TPM2 device access. See
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
|
||||
<para>The <option>systemd.tpm2_wait=</option> kernel command line option may be used to override
|
||||
behaviour of the generator. It accepts a boolean value: if true then <filename>tpm2.target</filename>
|
||||
will be added as synchronization point even if the firmware has not detected a TPM2 device. If false, the
|
||||
target will not be inserted even if firmware reported a device but the OS kernel doesn't expose a device
|
||||
for it yet. The latter might be useful in environments where a suitable TPM2 driver for the available
|
||||
hardware is not available.</para>
|
||||
|
||||
<para><filename>systemd-tpm2-generator</filename> implements
|
||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</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.special</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -92,6 +92,7 @@
|
||||
<filename>time-set.target</filename>,
|
||||
<filename>time-sync.target</filename>,
|
||||
<filename>timers.target</filename>,
|
||||
<filename>tpm2.target</filename>,
|
||||
<filename>umount.target</filename>,
|
||||
<filename>usb-gadget.target</filename>,
|
||||
<!-- slices --><filename>-.slice</filename>,
|
||||
@ -948,6 +949,24 @@
|
||||
<xi:include href="version-info.xml" xpointer="v242"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>tpm2.target</filename></term>
|
||||
<listitem>
|
||||
<para>This target is started automatically if a TPM2 device is discovered, either by the OS or by
|
||||
the firmware. It acts as synchronization point for services that require TPM2 device access. The
|
||||
target unit is enqueued by
|
||||
<citerefentry><refentrytitle>systemd-tpm2-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
if it detects that the firmware has discovered a TPM2 device but the OS kernel has not activated
|
||||
a driver for it yet. It is also pulled in whenever
|
||||
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
discovers a TPM2 device. The target unit is ordered after the <filename>/dev/tpmrm0</filename>
|
||||
device node, so that it only becomes active once the TPM2 device is actually accessible. Early
|
||||
boot programs that intend to access the TPM2 device should hence order themselves after this
|
||||
target unit, but not pull it in.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
|
@ -85,4 +85,7 @@ SUBSYSTEM=="misc", KERNEL=="rfkill", TAG+="systemd", ENV{SYSTEMD_WANTS}+="system
|
||||
SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
|
||||
SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"
|
||||
|
||||
# Pull in tpm2.target whenever /dev/tpmrm* shows up
|
||||
SUBSYSTEM=="tpmrm", KERNEL=="tpmrm[0-9]*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="tpm2.target"
|
||||
|
||||
LABEL="systemd_end"
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */
|
||||
#define SPECIAL_TIME_SET_TARGET "time-set.target"
|
||||
#define SPECIAL_BASIC_TARGET "basic.target"
|
||||
#define SPECIAL_TPM2_TARGET "tpm2.target"
|
||||
|
||||
/* LSB compatibility */
|
||||
#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */
|
||||
|
@ -13,4 +13,10 @@ executables += [
|
||||
libopenssl,
|
||||
],
|
||||
},
|
||||
|
||||
generator_template + {
|
||||
'name' : 'systemd-tpm2-generator',
|
||||
'sources' : files('tpm2-generator.c'),
|
||||
},
|
||||
|
||||
]
|
||||
|
80
src/tpm2-setup/tpm2-generator.c
Normal file
80
src/tpm2-setup/tpm2-generator.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "generator.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "special.h"
|
||||
#include "tpm2-util.h"
|
||||
#include "parse-util.h"
|
||||
|
||||
/* A small generator that enqueues tpm2.target as synchronization point if the TPM2 device hasn't shown up
|
||||
* yet, but the firmware reports it to exist. This is supposed to deal with systems where the TPM2 driver
|
||||
* support is built as kmod and must be loaded before it's ready to be used. The tpm2.target is only enqueued
|
||||
* if firmware says there is a TPM2 device, our userspace support for TPM2 is fully available but the TPM2
|
||||
* device hasn't shown up in /dev/ yet. */
|
||||
|
||||
static const char *arg_dest = NULL;
|
||||
static int arg_tpm2_wait = -1; /* tri-state: negative → don't know */
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
if (proc_cmdline_key_streq(key, "systemd.tpm2-wait")) {
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse 'systemd.tpm2-wait' kernel command line argument, ignoring: %s", value);
|
||||
else
|
||||
arg_tpm2_wait = r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generate_tpm_target_symlink(void) {
|
||||
int r;
|
||||
|
||||
if (arg_tpm2_wait == 0) {
|
||||
log_debug("Not generating tpm2.target synchronization point, as this was explicitly turned off via kernel command line.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_tpm2_wait < 0) {
|
||||
Tpm2Support support = tpm2_support();
|
||||
|
||||
if (FLAGS_SET(support, TPM2_SUPPORT_DRIVER)) {
|
||||
log_debug("Not generating tpm2.target synchronization point, as TPM2 device is already present.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(support, TPM2_SUPPORT_FIRMWARE)) {
|
||||
log_debug("Not generating tpm2.target synchronization point, as firmware reports no TPM2 present.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(support, TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES)) {
|
||||
log_debug("Not generating tpm2.target synchronization point, as userspace support for TPM2 is not complete.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SYSTEM_DATA_UNIT_DIR "/" SPECIAL_TPM2_TARGET);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to hook in tpm2.target: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
int r;
|
||||
|
||||
assert_se(arg_dest = dest);
|
||||
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
return generate_tpm_target_symlink();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
@ -700,6 +700,7 @@ units = [
|
||||
'file' : 'tmp.mount',
|
||||
'symlinks' : ['local-fs.target.wants/'],
|
||||
},
|
||||
{ 'file' : 'tpm2.target' },
|
||||
{ 'file' : 'umount.target' },
|
||||
{ 'file' : 'usb-gadget.target' },
|
||||
{ 'file' : 'user-runtime-dir@.service.in' },
|
||||
|
@ -11,6 +11,7 @@
|
||||
Description=TPM2 PCR Extension (Varlink)
|
||||
Documentation=man:systemd-pcrextend(8)
|
||||
DefaultDependencies=no
|
||||
After=tpm2.target
|
||||
Before=sockets.target
|
||||
ConditionSecurity=measured-uki
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
Description=TPM2 PCR Extension (Varlink)
|
||||
Documentation=man:systemd-pcrphase.service(8)
|
||||
DefaultDependencies=no
|
||||
After=tpm2.target
|
||||
Conflicts=shutdown.target initrd-switch-root.target
|
||||
Before=shutdown.target initrd-switch-root.target
|
||||
|
||||
|
@ -12,7 +12,7 @@ Description=TPM2 PCR Root File System Measurement
|
||||
Documentation=man:systemd-pcrfs-root.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=systemd-pcrmachine.service
|
||||
After=tpm2.target systemd-pcrmachine.service
|
||||
Before=shutdown.target
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -13,7 +13,7 @@ Documentation=man:systemd-pcrfs@.service(8)
|
||||
DefaultDependencies=no
|
||||
BindsTo=%i.mount
|
||||
Conflicts=shutdown.target
|
||||
After=%i.mount systemd-pcrfs-root.service
|
||||
After=%i.mount tpm2.target systemd-pcrfs-root.service
|
||||
Before=shutdown.target
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -12,6 +12,7 @@ Description=TPM2 PCR Machine ID Measurement
|
||||
Documentation=man:systemd-pcrmachine.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=tpm2.target
|
||||
Before=sysinit.target shutdown.target
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -12,6 +12,7 @@ Description=TPM2 PCR Barrier (initrd)
|
||||
Documentation=man:systemd-pcrphase-initrd.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target initrd-switch-root.target
|
||||
After=tpm2.target
|
||||
Before=sysinit.target cryptsetup-pre.target cryptsetup.target shutdown.target initrd-switch-root.target systemd-sysext.service
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -12,7 +12,7 @@ Description=TPM2 PCR Barrier (Initialization)
|
||||
Documentation=man:systemd-pcrphase-sysinit.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=sysinit.target
|
||||
After=sysinit.target tpm2.target
|
||||
Before=basic.target shutdown.target
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -10,7 +10,7 @@
|
||||
[Unit]
|
||||
Description=TPM2 PCR Barrier (User)
|
||||
Documentation=man:systemd-pcrphase.service(8)
|
||||
After=remote-fs.target remote-cryptsetup.target
|
||||
After=remote-fs.target remote-cryptsetup.target tpm2.target
|
||||
Before=systemd-user-sessions.service
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
ConditionSecurity=measured-uki
|
||||
|
@ -15,6 +15,7 @@ Conflicts=shutdown.target
|
||||
Before=sysinit.target shutdown.target
|
||||
ConditionSecurity=measured-uki
|
||||
ConditionPathExists=!/run/systemd/tpm2-srk-public-key.pem
|
||||
After=tpm2.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
@ -17,6 +17,7 @@ Before=sysinit.target shutdown.target
|
||||
RequiresMountsFor=/var/lib/systemd/tpm2-srk-public-key.pem
|
||||
ConditionSecurity=measured-uki
|
||||
ConditionPathExists=!/etc/initrd-release
|
||||
After=tpm2.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
16
units/tpm2.target
Normal file
16
units/tpm2.target
Normal file
@ -0,0 +1,16 @@
|
||||
# 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=Trusted Platform Module
|
||||
Documentation=man:systemd.special(7)
|
||||
|
||||
# Make this a synchronization point on the first TPM device found
|
||||
After=dev-tpmrm0.device
|
||||
Wants=dev-tpmrm0.device
|
Loading…
Reference in New Issue
Block a user