mirror of
https://github.com/systemd/systemd.git
synced 2026-06-24 08:47:49 +00:00
tpm2-generator: if requested run things with an swtpm
We want to start the software TPM fallback only if no real hw is evailable and if the user opts-in to this behaviour. Add a generator that drives all this, based on kernel command line configuration.
This commit is contained in:
@@ -782,6 +782,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.tpm2_software_fallback=</varname></term>
|
||||
|
||||
<listitem><para>Controls whether to start a fallback software TPM service in case a hardware TPM is
|
||||
not available, implemented by
|
||||
<citerefentry><refentrytitle>systemd-tpm2-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.factory_reset=</varname></term>
|
||||
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
for it yet. The latter might be useful in environments where a suitable TPM2 driver for the available
|
||||
hardware is not available.</para>
|
||||
|
||||
<para>The <option>systemd.tpm2_software_fallback=</option> kernel command line option (which takes a
|
||||
boolean argument, defaulting to false) may be used to enable an automatic software TPM fallback in case a
|
||||
hardware TPM is not detected and
|
||||
<citerefentry><refentrytitle>swtpm</refentrytitle><manvolnum>8</manvolnum></citerefentry> is
|
||||
available. This pulls in the
|
||||
<citerefentry><refentrytitle>systemd-tpm2-swtpm.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
service.</para>
|
||||
|
||||
<para><command>systemd-tpm2-generator</command> implements
|
||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
@@ -55,6 +63,7 @@
|
||||
<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>
|
||||
<member><citerefentry><refentrytitle>systemd-tpm2-swtpm.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dropin.h"
|
||||
#include "efivars.h"
|
||||
#include "generator.h"
|
||||
#include "initrd-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "special.h"
|
||||
#include "tpm2-util.h"
|
||||
@@ -15,6 +21,7 @@
|
||||
|
||||
static const char *arg_dest = NULL;
|
||||
static int arg_tpm2_wait = -1; /* tri-state: negative → don't know */
|
||||
static bool arg_tpm2_software_fallback = false;
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
@@ -27,12 +34,19 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
log_warning_errno(r, "Failed to parse 'systemd.tpm2_wait=' kernel command line argument, ignoring: %s", value);
|
||||
else
|
||||
arg_tpm2_wait = r;
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.tpm2_software_fallback")) {
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse 'systemd.tpm2_software_fallback=' kernel command line argument, ignoring: %s", value);
|
||||
else
|
||||
arg_tpm2_software_fallback = r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generate_tpm_target_symlink(void) {
|
||||
static int generate_tpm_target_symlink(Tpm2Support support, bool software_fallback_enabled) {
|
||||
int r;
|
||||
|
||||
if (arg_tpm2_wait == 0) {
|
||||
@@ -40,9 +54,7 @@ static int generate_tpm_target_symlink(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_tpm2_wait < 0) {
|
||||
Tpm2Support support = tpm2_support();
|
||||
|
||||
if (arg_tpm2_wait < 0 && !software_fallback_enabled) {
|
||||
if (FLAGS_SET(support, TPM2_SUPPORT_DRIVER)) {
|
||||
log_debug("Not generating tpm2.target synchronization point, as TPM2 device is already present.");
|
||||
return 0;
|
||||
@@ -52,11 +64,6 @@ static int generate_tpm_target_symlink(void) {
|
||||
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);
|
||||
@@ -66,6 +73,93 @@ static int generate_tpm_target_symlink(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generate_swtpm_symlink(Tpm2Support support) {
|
||||
int r;
|
||||
|
||||
if (!arg_tpm2_software_fallback)
|
||||
return 0;
|
||||
|
||||
if (FLAGS_SET(support, TPM2_SUPPORT_DRIVER) || FLAGS_SET(support, TPM2_SUPPORT_FIRMWARE)) {
|
||||
log_debug("Not generating software TPM units, as a TPM2 device is otherwise available.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_efi_boot()) { /* We need the ESP to store the TPM state. */
|
||||
log_warning("TPM software fallback requested but not booted in EFI mode, not pulling in software TPM unit.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = find_executable("swtpm", /* ret_filename= */ NULL);
|
||||
if (r == -ENOENT) {
|
||||
log_warning("TPM software fallback requested but swtpm not available, not pulling in software TPM unit.");
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine if 'swtpm' is available: %m");
|
||||
|
||||
r = generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SYSTEM_DATA_UNIT_DIR "/systemd-tpm2-swtpm.service");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to hook in systemd-tpm2-swtpm.service: %m");
|
||||
|
||||
if (in_initrd())
|
||||
/* Order + pull in the early ESP mount so that swtpm has a place to store its data. */
|
||||
r = write_drop_in(
|
||||
arg_dest,
|
||||
"systemd-tpm2-swtpm.service",
|
||||
50, "esp",
|
||||
"# Automatically generated by systemd-tpm2-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Wants=sysefi.mount\n"
|
||||
"After=sysefi.mount\n");
|
||||
else
|
||||
/* Order (but not pull in) the regular ESP automount so that swtpm has a place to store its
|
||||
* data. Note that it might be mounted to two different places depending on the existence of
|
||||
* XBOOTLDR, hence order after both. */
|
||||
r = write_drop_in(
|
||||
arg_dest,
|
||||
"systemd-tpm2-swtpm.service",
|
||||
50, "esp",
|
||||
"# Automatically generated by systemd-tpm2-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"After=boot.automount efi.automount\n");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to hook ESP mount before systemd-tpm2-swtpm.service: %m");
|
||||
|
||||
return 1; /* Tell caller we now created swtpm units */
|
||||
}
|
||||
|
||||
static int generate_now(void) {
|
||||
int r;
|
||||
|
||||
/* Let's shortcut things before we check for TPM2 support if no one cares anyway */
|
||||
if (arg_tpm2_wait == 0 && !arg_tpm2_software_fallback) {
|
||||
log_debug("Not generating tpm2.target synchronization point or activating software TPM, as turned off via kernel command line.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We are supposed to sync on TPM or do a software fallback, let's first and unconditionally validate this makes sense at
|
||||
* all, i.e. if we have a suitable kernel+userspace. */
|
||||
Tpm2Support support = tpm2_support();
|
||||
if (!FLAGS_SET(support, TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES)) {
|
||||
|
||||
/* Raise log level if things were explicitly configured */
|
||||
log_full((arg_tpm2_wait > 0 ||
|
||||
arg_tpm2_software_fallback) ? LOG_NOTICE : LOG_DEBUG,
|
||||
"Not generating tpm2.target synchronization point or activating software TPM, as userspace support for TPM2 is not complete.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = generate_swtpm_symlink(support);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = generate_tpm_target_symlink(support, /* software_fallback_enabled= */ r > 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
int r;
|
||||
|
||||
@@ -75,7 +169,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
return generate_tpm_target_symlink();
|
||||
return generate_now();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
||||
|
||||
Reference in New Issue
Block a user