tool: write systemd-boot loader.conf

To minimize the number of arguments passed to `lzbt`, the loader config
is assembled outside `lzbt` and passed as a single argument.

Instead of reimplementing `consoleMode` under the `lanzaboote`
namespace, `config.loader.systemd-boot.consoleMode` is reused as is.
This commit is contained in:
nikstur 2023-01-27 00:37:05 +01:00
parent 57b56e104c
commit ce3b2c27b5
7 changed files with 62 additions and 1 deletions

View File

@ -7,6 +7,12 @@ let
}; };
configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit; configurationLimit = if cfg.configurationLimit == null then 0 else cfg.configurationLimit;
timeout = if config.boot.loader.timeout == null then 0 else config.boot.loader.timeout;
systemdBootLoaderConfig = pkgs.writeText "loader.conf" ''
timeout ${toString timeout}
console-mode ${config.boot.loader.systemd-boot.consoleMode}
'';
in in
{ {
options.boot.lanzaboote = { options.boot.lanzaboote = {
@ -60,6 +66,7 @@ in
${cfg.package}/bin/lzbt install \ ${cfg.package}/bin/lzbt install \
--systemd ${pkgs.systemd} \ --systemd ${pkgs.systemd} \
--systemd-boot-loader-config ${systemdBootLoaderConfig} \
--public-key ${cfg.publicKeyFile} \ --public-key ${cfg.publicKeyFile} \
--private-key ${cfg.privateKeyFile} \ --private-key ${cfg.privateKeyFile} \
--configuration-limit ${toString configurationLimit} \ --configuration-limit ${toString configurationLimit} \

View File

@ -154,4 +154,21 @@ in
machine.succeed("efibootmgr") machine.succeed("efibootmgr")
''; '';
}; };
systemd-boot-loader-config = mkSecureBootTest {
name = "lanzaboote-systemd-boot-loader-config";
machine = {
boot.loader.timeout = 0;
boot.loader.systemd-boot.consoleMode = "auto";
};
testScript = ''
machine.start()
actual_loader_config = machine.succeed("cat /boot/loader/loader.conf")
expected_loader_config = "timeout 0\nconsole-mode auto\n"
assert actual_loader_config == expected_loader_config, \
f"Actual: '{actual_loader_config}' is not equal to expected: '{expected_loader_config}'"
'';
};
} }

View File

@ -23,6 +23,10 @@ struct InstallCommand {
#[arg(long)] #[arg(long)]
systemd: PathBuf, systemd: PathBuf,
/// Systemd-boot loader config
#[arg(long)]
systemd_boot_loader_config: PathBuf,
/// sbsign Public Key /// sbsign Public Key
#[arg(long)] #[arg(long)]
public_key: PathBuf, public_key: PathBuf,
@ -65,6 +69,7 @@ fn install(args: InstallCommand) -> Result<()> {
install::Installer::new( install::Installer::new(
PathBuf::from(lanzaboote_stub), PathBuf::from(lanzaboote_stub),
args.systemd, args.systemd,
args.systemd_boot_loader_config,
key_pair, key_pair,
args.configuration_limit, args.configuration_limit,
args.esp, args.esp,

View File

@ -15,6 +15,8 @@ pub struct EspPaths {
pub efi_fallback: PathBuf, pub efi_fallback: PathBuf,
pub systemd: PathBuf, pub systemd: PathBuf,
pub systemd_boot: PathBuf, pub systemd_boot: PathBuf,
pub loader: PathBuf,
pub systemd_boot_loader_config: PathBuf,
} }
impl EspPaths { impl EspPaths {
@ -25,6 +27,8 @@ impl EspPaths {
let efi_linux = efi.join("Linux"); let efi_linux = efi.join("Linux");
let efi_systemd = efi.join("systemd"); let efi_systemd = efi.join("systemd");
let efi_efi_fallback_dir = efi.join("BOOT"); let efi_efi_fallback_dir = efi.join("BOOT");
let loader = esp.join("loader");
let systemd_boot_loader_config = loader.join("loader.conf");
Self { Self {
esp: esp.to_path_buf(), esp: esp.to_path_buf(),
@ -35,11 +39,13 @@ impl EspPaths {
efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"), efi_fallback: efi_efi_fallback_dir.join("BOOTX64.EFI"),
systemd: efi_systemd.clone(), systemd: efi_systemd.clone(),
systemd_boot: efi_systemd.join("systemd-bootx64.efi"), systemd_boot: efi_systemd.join("systemd-bootx64.efi"),
loader,
systemd_boot_loader_config,
} }
} }
/// Return the used file paths to store as garbage collection roots. /// Return the used file paths to store as garbage collection roots.
pub fn to_iter(&self) -> IntoIter<&PathBuf, 8> { pub fn to_iter(&self) -> IntoIter<&PathBuf, 10> {
[ [
&self.esp, &self.esp,
&self.efi, &self.efi,
@ -49,6 +55,8 @@ impl EspPaths {
&self.efi_fallback, &self.efi_fallback,
&self.systemd, &self.systemd,
&self.systemd_boot, &self.systemd_boot,
&self.loader,
&self.systemd_boot_loader_config,
] ]
.into_iter() .into_iter()
} }

View File

@ -19,6 +19,7 @@ pub struct Installer {
gc_roots: Roots, gc_roots: Roots,
lanzaboote_stub: PathBuf, lanzaboote_stub: PathBuf,
systemd: PathBuf, systemd: PathBuf,
systemd_boot_loader_config: PathBuf,
key_pair: KeyPair, key_pair: KeyPair,
configuration_limit: usize, configuration_limit: usize,
esp_paths: EspPaths, esp_paths: EspPaths,
@ -29,6 +30,7 @@ impl Installer {
pub fn new( pub fn new(
lanzaboote_stub: PathBuf, lanzaboote_stub: PathBuf,
systemd: PathBuf, systemd: PathBuf,
systemd_boot_loader_config: PathBuf,
key_pair: KeyPair, key_pair: KeyPair,
configuration_limit: usize, configuration_limit: usize,
esp: PathBuf, esp: PathBuf,
@ -42,6 +44,7 @@ impl Installer {
gc_roots, gc_roots,
lanzaboote_stub, lanzaboote_stub,
systemd, systemd,
systemd_boot_loader_config,
key_pair, key_pair,
configuration_limit, configuration_limit,
esp_paths, esp_paths,
@ -221,6 +224,18 @@ impl Installer {
.with_context(|| format!("Failed to install systemd-boot binary to: {to:?}"))?; .with_context(|| format!("Failed to install systemd-boot binary to: {to:?}"))?;
} }
} }
install(
&self.systemd_boot_loader_config,
&self.esp_paths.systemd_boot_loader_config,
)
.with_context(|| {
format!(
"Failed to install systemd-boot loader.conf to {:?}",
&self.esp_paths.systemd_boot_loader_config
)
})?;
Ok(()) Ok(())
} }
} }

View File

@ -107,12 +107,18 @@ pub fn lanzaboote_install(
let test_systemd = systemd_location_from_env()?; let test_systemd = systemd_location_from_env()?;
let test_systemd_stub = format!("{test_systemd}/lib/systemd/boot/efi/linuxx64.efi.stub"); let test_systemd_stub = format!("{test_systemd}/lib/systemd/boot/efi/linuxx64.efi.stub");
let test_loader_config_path = tempfile::NamedTempFile::new()?;
let test_loader_config = r"timeout 0\nconsole-mode 1\n";
fs::write(test_loader_config_path.path(), test_loader_config)?;
let mut cmd = Command::cargo_bin("lzbt")?; let mut cmd = Command::cargo_bin("lzbt")?;
let output = cmd let output = cmd
.env("LANZABOOTE_STUB", test_systemd_stub) .env("LANZABOOTE_STUB", test_systemd_stub)
.arg("install") .arg("install")
.arg("--systemd") .arg("--systemd")
.arg(test_systemd) .arg(test_systemd)
.arg("--systemd-boot-loader-config")
.arg(test_loader_config_path.path())
.arg("--public-key") .arg("--public-key")
.arg("tests/fixtures/uefi-keys/db.pem") .arg("tests/fixtures/uefi-keys/db.pem")
.arg("--private-key") .arg("--private-key")

View File

@ -61,9 +61,11 @@ fn keep_unrelated_files_on_esp() -> Result<()> {
let output0 = common::lanzaboote_install(0, esp_mountpoint.path(), generation_links.clone())?; let output0 = common::lanzaboote_install(0, esp_mountpoint.path(), generation_links.clone())?;
assert!(output0.status.success()); assert!(output0.status.success());
let unrelated_loader_config = esp_mountpoint.path().join("loader/loader.conf");
let unrelated_uki = esp_mountpoint.path().join("EFI/Linux/ubuntu.efi"); let unrelated_uki = esp_mountpoint.path().join("EFI/Linux/ubuntu.efi");
let unrelated_os = esp_mountpoint.path().join("EFI/windows"); let unrelated_os = esp_mountpoint.path().join("EFI/windows");
let unrelated_firmware = esp_mountpoint.path().join("dell"); let unrelated_firmware = esp_mountpoint.path().join("dell");
fs::File::create(&unrelated_loader_config)?;
fs::File::create(&unrelated_uki)?; fs::File::create(&unrelated_uki)?;
fs::create_dir(&unrelated_os)?; fs::create_dir(&unrelated_os)?;
fs::create_dir(&unrelated_firmware)?; fs::create_dir(&unrelated_firmware)?;
@ -72,6 +74,7 @@ fn keep_unrelated_files_on_esp() -> Result<()> {
let output1 = common::lanzaboote_install(2, esp_mountpoint.path(), generation_links)?; let output1 = common::lanzaboote_install(2, esp_mountpoint.path(), generation_links)?;
assert!(output1.status.success()); assert!(output1.status.success());
assert!(unrelated_loader_config.exists());
assert!(unrelated_uki.exists()); assert!(unrelated_uki.exists());
assert!(unrelated_os.exists()); assert!(unrelated_os.exists());
assert!(unrelated_firmware.exists()); assert!(unrelated_firmware.exists());