Support secure boot.

This commit is contained in:
Michael Lipp 2023-06-08 13:43:11 +02:00
parent 0225d02114
commit 46c7e8c527
5 changed files with 59 additions and 46 deletions

View file

@ -36,11 +36,11 @@
# Whether to provide a software TPM (defaults to false)
# "useTpm": false
# How to boot:
# How to boot (see https://github.com/mnlipp/VM-Operator/blob/main/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml):
# * bios
# * uefi
# * secure
# "bootMode": "uefi"
# * uefi[-4m]
# * secure[-4m]
# "firmware": "uefi"
# When terminating, a graceful powerdown is attempted. If it
# doesn't succeed within the given timeout (seconds) SIGTERM

View file

@ -1,12 +1,33 @@
# Candidate paths for code and templates for firmware rom and flash
# Candidate paths for code and templates for firmware rom and vars
"firmware":
"rom":
- "/usr/share/OVMF/OVMF_CODE.fd"
- "/usr/share/edk2/x64/OVMF_CODE.fd"
"flash":
- "/usr/share/edk2/ovmf/OVMF_VARS.fd"
- "/usr/share/edk2/x64/OVMF_CODE.fd"
"bios":
"rom": []
"vars": []
"uefi":
"rom":
- "/usr/share/edk2/ovmf/OVMF_CODE.fd"
- "/usr/share/edk2/x64/OVMF_CODE.fd"
"vars":
- "/usr/share/edk2/ovmf/OVMF_VARS.fd"
- "/usr/share/edk2/x64/OVMF_VARS.fd"
"uefi-4m":
"rom":
- "/usr/share/edk2/ovmf-4m/OVMF_CODE.fd"
- "/usr/share/edk2/x64/OVMF_CODE.4m.fd"
"vars":
- "/usr/share/edk2/ovmf-4m/OVMF_VARS.fd"
- "/usr/share/edk2/x64/OVMF_VARS.4m.fd"
"secure":
"flash":
"rom":
- "/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd"
- "/usr/share/edk2/x64/OVMF_CODE.secboot.fd"
"vars":
- "/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd"
- "/usr/share/edk2/x64/OVMF_VARS.fd"
"secure-4m":
"rom":
- "/usr/share/edk2/ovmf-4m/OVMF_CODE.secboot.fd"
- "/usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd"
"vars":
- "/usr/share/edk2/ovmf-4m/OVMF_CODE.secboot.fd"
- "/usr/share/edk2/x64/OVMF_VARS.4m.fd"

View file

@ -34,9 +34,6 @@ class Configuration implements Dto {
@SuppressWarnings("PMD.FieldNamingConventions")
protected final Logger logger = Logger.getLogger(getClass().getName());
public static final Object BOOT_MODE_UEFI = "uefi";
public static final Object BOOT_MODE_SECURE = "secure";
public String dataDir;
public String runtimeDir;
public String template;
@ -44,7 +41,7 @@ class Configuration implements Dto {
public Path swtpmSocket;
public Path monitorSocket;
public Path firmwareRom;
public Path firmwareFlash;
public Path firmwareVars;
@SuppressWarnings("PMD.ShortVariable")
public Vm vm;
@ -56,7 +53,7 @@ class Configuration implements Dto {
public String name;
public String uuid;
public boolean useTpm;
public String bootMode = "uefi";
public String firmware = "uefi";
public String maximumRam;
public String currentRam;
public String cpuModel = "host";

View file

@ -47,8 +47,6 @@ import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import static org.jdrupes.vmoperator.runner.qemu.Configuration.BOOT_MODE_SECURE;
import static org.jdrupes.vmoperator.runner.qemu.Configuration.BOOT_MODE_UEFI;
import org.jdrupes.vmoperator.runner.qemu.StateController.State;
import org.jdrupes.vmoperator.util.ExtendedObjectWrapper;
import org.jgrapes.core.Channel;
@ -151,7 +149,7 @@ public class Runner extends Component {
private static final String DEFAULT_TEMPLATE
= "Standard-VM-latest.ftl.yaml";
private static final String SAVED_TEMPLATE = "VM.ftl.yaml";
private static final String FW_FLASH = "fw-flash.fd";
private static final String FW_VARS = "fw-vars.fd";
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
private final JsonNode defaults;
@ -255,8 +253,9 @@ public class Runner extends Component {
@SuppressWarnings({ "PMD.CognitiveComplexity",
"PMD.DataflowAnomalyAnalysis" })
private void setFirmwarePaths() throws IOException {
JsonNode firmware = defaults.path("firmware").path(config.vm.firmware);
// Get file for firmware ROM
JsonNode codePaths = defaults.path("firmware").path("rom");
JsonNode codePaths = firmware.path("rom");
for (var p : codePaths) {
var path = Path.of(p.asText());
if (Files.exists(path)) {
@ -264,24 +263,14 @@ public class Runner extends Component {
break;
}
}
// Get file for firmware flash, if necessary
config.firmwareFlash = Path.of(config.dataDir, FW_FLASH);
if (!Files.exists(config.firmwareFlash)) {
JsonNode srcPaths = null;
if (BOOT_MODE_UEFI.equals(config.vm.bootMode)) {
srcPaths = defaults.path("firmware").path("flash");
} else if (BOOT_MODE_SECURE.equals(config.vm.bootMode)) {
srcPaths = defaults.path("firmware")
.path("secure").path("flash");
}
// If UEFI boot, srcPaths != null
if (srcPaths != null) {
for (var p : srcPaths) {
var path = Path.of(p.asText());
if (Files.exists(path)) {
Files.copy(path, config.firmwareFlash);
break;
}
// Get file for firmware vars, if necessary
config.firmwareVars = Path.of(config.dataDir, FW_VARS);
if (!Files.exists(config.firmwareVars)) {
for (var p : firmware.path("vars")) {
var path = Path.of(p.asText());
if (Files.exists(path)) {
Files.copy(path, config.firmwareVars);
break;
}
}
}
@ -304,8 +293,10 @@ public class Runner extends Component {
// Configure data model
var model = new HashMap<String, Object>();
model.put("runtimeDir", config.runtimeDir);
model.put("firmwareRom", config.firmwareRom.toString());
model.put("firmwareFlash", config.firmwareFlash.toString());
model.put("firmwareRom", Optional.ofNullable(config.firmwareRom)
.map(Object::toString).orElse(null));
model.put("firmwareVars", Optional.ofNullable(config.firmwareVars)
.map(Object::toString).orElse(null));
model.put("vm", config.vm);
// Combine template and data and parse result

View file

@ -44,8 +44,8 @@
# For smm=on see https://scumjr.github.io/2016/01/04/playing-with-smm-and-qemu/.
# Configure ROM/EEPROM for UEFI.
- [ "-machine", "pc-q35-7.0,usb=off,vmport=off,dump-guest-core=off\
<#if vm.bootMode == "secure">,smm=on</#if>\
<#if vm.bootMode != "bios">,pflash0=fw-rom-device\
<#if vm.firmware?starts_with("secure")>,smm=on</#if>\
<#if firmwareRom??>,pflash0=fw-rom-device\
,pflash1=fw-eeprom-device</#if>,memory-backend=pc.ram,hpet=off" ]
# * https://bugzilla.redhat.com/show_bug.cgi?id=1170533, may be unnecessary
- [ "-global", "ICH9-LPC.disable_s3=1" ]
@ -54,17 +54,21 @@
# -global driver=cfi.pflash01,property=secure,value=on
# -object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/local/qemu/master-key.aes"}'
# {{- end }}
<#if vm.bootMode != "bios">
<#if firmwareRom??>
# * Provide ROM/EEPROM devices (instead of built-in BIOS)
- [ "-blockdev", "node-name=fw-rom-file,driver=file,cache.direct=on,\
filename=${ firmwareRom },auto-read-only=true,discard=unmap" ]
- [ "-blockdev", "node-name=fw-rom-device,driver=raw,\
read-only=true,file=fw-rom-file" ]
- [ "-blockdev", "node-name=fw-eeprom-file,driver=file,cache.direct=on,\
filename=${ firmwareFlash },auto-read-only=true,discard=unmap" ]
filename=${ firmwareVars },auto-read-only=true,discard=unmap" ]
- [ "-blockdev", "node-name=fw-eeprom-device,driver=raw,\
read-only=false,file=fw-eeprom-file" ]
</#if>
</#if>
# https://wiki.debian.org/SecureBoot/VirtualMachine
<#if vm.firmware?starts_with("secure")>
- [ "-global", "driver=cfi.pflash01,property=secure,value=on" ]
</#if>
# * Provide RAM
- [ "-object", "memory-backend-ram,id=pc.ram,\
size=${ vm.maximumRam!"1G" }" ]