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>
|
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><varname>systemd.factory_reset=</varname></term>
|
<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
|
for it yet. The latter might be useful in environments where a suitable TPM2 driver for the available
|
||||||
hardware is not available.</para>
|
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
|
<para><command>systemd-tpm2-generator</command> implements
|
||||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
@@ -55,6 +63,7 @@
|
|||||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</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>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>systemd-tpm2-swtpm.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
</simplelist></para>
|
</simplelist></para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
+104
-10
@@ -1,8 +1,14 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "dropin.h"
|
||||||
|
#include "efivars.h"
|
||||||
#include "generator.h"
|
#include "generator.h"
|
||||||
|
#include "initrd-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "proc-cmdline.h"
|
#include "proc-cmdline.h"
|
||||||
#include "special.h"
|
#include "special.h"
|
||||||
#include "tpm2-util.h"
|
#include "tpm2-util.h"
|
||||||
@@ -15,6 +21,7 @@
|
|||||||
|
|
||||||
static const char *arg_dest = NULL;
|
static const char *arg_dest = NULL;
|
||||||
static int arg_tpm2_wait = -1; /* tri-state: negative → don't know */
|
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) {
|
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||||
int r;
|
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);
|
log_warning_errno(r, "Failed to parse 'systemd.tpm2_wait=' kernel command line argument, ignoring: %s", value);
|
||||||
else
|
else
|
||||||
arg_tpm2_wait = r;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int generate_tpm_target_symlink(void) {
|
static int generate_tpm_target_symlink(Tpm2Support support, bool software_fallback_enabled) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (arg_tpm2_wait == 0) {
|
if (arg_tpm2_wait == 0) {
|
||||||
@@ -40,9 +54,7 @@ static int generate_tpm_target_symlink(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_tpm2_wait < 0) {
|
if (arg_tpm2_wait < 0 && !software_fallback_enabled) {
|
||||||
Tpm2Support support = tpm2_support();
|
|
||||||
|
|
||||||
if (FLAGS_SET(support, TPM2_SUPPORT_DRIVER)) {
|
if (FLAGS_SET(support, TPM2_SUPPORT_DRIVER)) {
|
||||||
log_debug("Not generating tpm2.target synchronization point, as TPM2 device is already present.");
|
log_debug("Not generating tpm2.target synchronization point, as TPM2 device is already present.");
|
||||||
return 0;
|
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.");
|
log_debug("Not generating tpm2.target synchronization point, as firmware reports no TPM2 present.");
|
||||||
return 0;
|
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);
|
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;
|
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) {
|
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -75,7 +169,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
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);
|
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
||||||
|
|||||||
Reference in New Issue
Block a user