vmspawn: allow opt-in Secure Boot firmware for coco
CoCo firmware is stateless, so Secure Boot keys cannot be enrolled at runtime: it only enforces Secure Boot with keys baked in at build time, refusing unsigned images from the first boot. The default exclusion of the enrolled-keys firmware feature hence keeps unsigned images bootable, but it also makes firmware discovery fail on distros that only ship SNP/TDX firmware with pre-enrolled keys (e.g. Fedora's TDVF). Drop the rejection of --secure-boot=yes with --coco= and instead treat it as an opt-in to such firmware, by lifting the enrolled-keys exclusion. While at it, reject --efi-nvram-template= and an explicit --efi-nvram-state= path with --coco=, which were silently ignored, as stateless firmware has no NVRAM to instantiate or persist. Signed-off-by: Paul Meyer <katexochen0@gmail.com>
This commit is contained in:
+15
-4
@@ -269,7 +269,8 @@
|
||||
<listitem><para>Takes an absolute path, or a relative path beginning with
|
||||
<filename>./</filename>. Specifies the path to an EFI NVRAM template file to copy and use as the
|
||||
initial EFI variable NVRAM state. If not specified, the default NVRAM template from the firmware
|
||||
definition is copied and used.</para>
|
||||
definition is copied and used. Cannot be used together with <option>--coco=</option>, as
|
||||
confidential computing firmware is stateless.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
@@ -283,7 +284,8 @@
|
||||
automatically derived from the VM image path or directory path, with the
|
||||
<literal>.efinvramstate</literal> suffix appended. If set to the special string
|
||||
<literal>off</literal> the EFI variable NVRAM state is only maintained transiently and flushed out
|
||||
when the VM shuts down. Defaults to <literal>auto</literal>.</para>
|
||||
when the VM shuts down. Defaults to <literal>auto</literal>. An explicit path cannot be used
|
||||
together with <option>--coco=</option>, as confidential computing firmware is stateless.</para>
|
||||
|
||||
<para>If <option>--ephemeral</option> is specified, <literal>auto</literal> behaves like
|
||||
<literal>off</literal>.</para>
|
||||
@@ -300,6 +302,13 @@
|
||||
<option>--firmware-features=~secure-boot</option>. Setting this to <literal>auto</literal>
|
||||
removes <literal>secure-boot</literal> from both the included and excluded feature lists.</para>
|
||||
|
||||
<para>With <option>--coco=</option>, setting this to <literal>yes</literal> additionally
|
||||
requires the <literal>enrolled-keys</literal> firmware feature, overriding its default
|
||||
exclusion: confidential computing firmware is stateless, so keys cannot be enrolled at runtime
|
||||
and Secure Boot is only operative with keys baked into the image at build time, which in turn
|
||||
makes the firmware refuse to boot unsigned images from the very first boot. The default
|
||||
exclusion of <literal>enrolled-keys</literal> hence keeps unsigned images bootable.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -353,7 +362,8 @@
|
||||
SNP-capable hardware and firmware. A suitable SNP-built OVMF firmware is picked automatically
|
||||
from the installed QEMU firmware descriptors, by requiring the <literal>amd-sev-snp</literal>
|
||||
firmware feature; use <option>--firmware=</option> with a path to a firmware descriptor file to
|
||||
select a specific one. Secure Boot is unavailable. Direct kernel boot via
|
||||
select a specific one. Secure Boot is effectively off by default (see
|
||||
<option>--secure-boot=</option>). Direct kernel boot via
|
||||
<option>--linux=</option> is required so that the kernel, initrd and command line are hashed
|
||||
into the launch measurement (<literal>kernel-hashes=on</literal>); booting the kernel off the
|
||||
disk image via the firmware would leave it outside the measurement. Credentials passed via
|
||||
@@ -376,7 +386,8 @@
|
||||
<option>--firmware=</option> with a path to a firmware descriptor file to select a specific
|
||||
one. The CPU model is fixed to <literal>host</literal>. Firmware is measured into MRTD when the
|
||||
TD is built. Secure Boot cannot be enrolled at runtime (there is no writable NVRAM); its state
|
||||
is fixed by the selected TDVF image and is part of the measured firmware.
|
||||
is fixed by the selected TDVF image and is part of the measured firmware (see
|
||||
<option>--secure-boot=</option>).
|
||||
When booting a UKI, the whole UKI PE is measured into RTMR 1, and the loaded sections are
|
||||
measured individually by <command>systemd-stub</command> into RTMR 2. For direct linux boot,
|
||||
firmware measures the kernel PE into RTMR 1, and the Linux EFI stub measures initrd and
|
||||
|
||||
+23
-9
@@ -2574,6 +2574,14 @@ static int discover_ovmf_config(OvmfConfig **ret, sd_json_variant **ret_firmware
|
||||
r = set_put_strdup(&arg_firmware_features_include, coco_feature);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
/* CoCo firmware is stateless, so Secure Boot keys cannot be enrolled at runtime
|
||||
* but must have baked-in, enrolled keys, which we avoid in other cases. */
|
||||
if (set_contains(arg_firmware_features_include, "secure-boot")) {
|
||||
r = set_put_strdup(&arg_firmware_features_include, "enrolled-keys");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
FindOvmfConfigFlags flags =
|
||||
@@ -2584,7 +2592,8 @@ static int discover_ovmf_config(OvmfConfig **ret, sd_json_variant **ret_firmware
|
||||
if (r == -ENOENT && coco_feature)
|
||||
return log_error_errno(r, "No suitable firmware descriptor found for --coco=%s "
|
||||
"(requires stateless firmware in raw format with the '%s' firmware feature). "
|
||||
"Install a suitable firmware or select a firmware descriptor with --firmware=.",
|
||||
"Install a suitable firmware, select a firmware descriptor with --firmware=, or "
|
||||
"opt in with --secure-boot=yes if the installed firmware enforces Secure Boot.",
|
||||
confidential_computing_to_string(arg_confidential_computing), coco_feature);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find OVMF config: %m");
|
||||
@@ -4244,6 +4253,19 @@ static int verify_arguments(void) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--grow-image is not supported for qcow2 images, use 'qemu-img resize FILE SIZE'.");
|
||||
|
||||
if (arg_confidential_computing != COCO_NO) {
|
||||
/* Confidential computing firmware is stateless, there is no NVRAM to instantiate from a
|
||||
* template or to persist. */
|
||||
if (arg_efi_nvram_template)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--efi-nvram-template= cannot be used with --coco=, "
|
||||
"confidential computing firmware is stateless.");
|
||||
if (arg_efi_nvram_state_mode == STATE_PATH)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"An explicit --efi-nvram-state= path cannot be used with --coco=, "
|
||||
"confidential computing firmware is stateless. Use 'off' or 'auto'.");
|
||||
}
|
||||
|
||||
if (arg_confidential_computing == COCO_AMD_SEV_SNP) {
|
||||
if (native_architecture() != ARCHITECTURE_X86_64)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
@@ -4255,9 +4277,6 @@ static int verify_arguments(void) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--coco=sev-snp can't be used with %s firmware",
|
||||
firmware_to_string(arg_firmware_type));
|
||||
if (set_contains(arg_firmware_features_include, "secure-boot"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--coco=sev-snp cannot be combined with --secure-boot=yes.");
|
||||
if (arg_tpm > 0)
|
||||
log_warning("TPM can't be trusted by the confidential computing guest");
|
||||
/* kernel-hashes=on only covers what QEMU itself loads via -kernel/-initrd/-append.
|
||||
@@ -4281,11 +4300,6 @@ static int verify_arguments(void) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--coco=tdx can't be used with %s firmware",
|
||||
firmware_to_string(arg_firmware_type));
|
||||
/* Secure Boot state is baked into the supplied TDVF image and can't be enrolled at
|
||||
* runtime (no writable NVRAM), so --secure-boot=yes would silently have no effect. */
|
||||
if (set_contains(arg_firmware_features_include, "secure-boot"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--coco=tdx cannot be combined with --secure-boot=yes.");
|
||||
if (arg_tpm > 0)
|
||||
log_warning("TPM can't be trusted by the confidential computing guest");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user