Skip to content

Commit d900f21

Browse files
author
Gareth Widlansky
committed
sdboot: add support for autoenroll in bootc install
Signed-off-by: Gareth Widlansky <[email protected]> cleanup Signed-off-by: Gareth Widlansky <[email protected]> don't expect `/usr/lib/bootc/keys` to exist Signed-off-by: Gareth Widlansky <[email protected]> remove comment Signed-off-by: Gareth Widlansky <[email protected]> don't use ambient authority Signed-off-by: Gareth Widlansky <[email protected]> use option rather than an enum Signed-off-by: Gareth Widlansky <[email protected]> use fs.open_dir_optional Signed-off-by: Gareth Widlansky <[email protected]>
1 parent f687add commit d900f21

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@
6161
//! 1. **Primary**: New/upgraded deployment (default boot target)
6262
//! 2. **Secondary**: Currently booted deployment (rollback option)
6363
64-
use std::ffi::OsStr;
6564
use std::fs::create_dir_all;
6665
use std::io::Write;
6766
use std::path::Path;
67+
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
6868

69-
use anyhow::{anyhow, Context, Result};
69+
use anyhow::{anyhow, bail, Context, Result};
7070
use bootc_blockdev::find_parent_devices;
7171
use bootc_kernel_cmdline::utf8::{Cmdline, Parameter};
7272
use bootc_mount::inspect_filesystem_of_dir;
@@ -132,6 +132,8 @@ const SYSTEMD_LOADER_CONF_PATH: &str = "loader/loader.conf";
132132
const INITRD: &str = "initrd";
133133
const VMLINUZ: &str = "vmlinuz";
134134

135+
const BOOTC_AUTOENROLL_PATH: &str = "usr/lib/bootc/keys";
136+
135137
/// We want to be able to control the ordering of UKIs so we put them in a directory that's not the
136138
/// directory specified by the BLS spec. We do this because we want systemd-boot to only look at
137139
/// our config files and not show the actual UKIs in the bootloader menu
@@ -1142,6 +1144,47 @@ pub(crate) fn setup_composefs_uki_boot(
11421144
Ok(())
11431145
}
11441146

1147+
pub struct AutoEnroll {
1148+
pub dir: Dir,
1149+
pub keys: Vec<Utf8PathBuf>,
1150+
}
1151+
1152+
fn get_systemd_boot_autoenroll(fs: &Dir, p: &str) -> Result<Option<AutoEnroll>> {
1153+
let mut entries = vec![];
1154+
1155+
// if the dir doesn't exist, return None
1156+
let keys_dir = match fs.open_dir_optional(p)? {
1157+
Some(d) => d,
1158+
None => return Ok(None),
1159+
};
1160+
1161+
for entry in keys_dir.entries()? {
1162+
let file = entry?;
1163+
1164+
let name = file.file_name();
1165+
if !file.file_type()?.is_file() {
1166+
bail!("/{p}/{name:?} is a not a regular file");
1167+
}
1168+
1169+
if !name.as_bytes().ends_with(b".auth") {
1170+
continue;
1171+
}
1172+
1173+
let path = match Utf8PathBuf::from_os_string(name.clone()) {
1174+
Ok(p) => p,
1175+
Err(_) => bail!("couldn't get pathbuf: /{p}/{name:?}"),
1176+
};
1177+
entries.push(path);
1178+
}
1179+
if entries.len() > 0 {
1180+
return Ok(Some(AutoEnroll {
1181+
dir: keys_dir,
1182+
keys: entries,
1183+
}));
1184+
}
1185+
return Ok(None);
1186+
}
1187+
11451188
#[context("Setting up composefs boot")]
11461189
pub(crate) fn setup_composefs_boot(
11471190
root_setup: &RootSetup,
@@ -1181,6 +1224,7 @@ pub(crate) fn setup_composefs_boot(
11811224
&root_setup.physical_root_path,
11821225
&state.config_opts,
11831226
None,
1227+
get_systemd_boot_autoenroll(&mounted_fs, BOOTC_AUTOENROLL_PATH)?,
11841228
)?;
11851229
}
11861230

crates/lib/src/bootloader.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
use std::fs::create_dir_all;
12
use std::process::Command;
23

34
use anyhow::{anyhow, bail, Context, Result};
45
use bootc_utils::CommandRunExt;
56
use camino::Utf8Path;
67
use cap_std_ext::cap_std::fs::Dir;
8+
use cap_std_ext::dirext::CapStdExtDirExt;
79
use fn_error_context::context;
810

911
use bootc_blockdev::{Partition, PartitionTable};
1012
use bootc_mount as mount;
1113

12-
use crate::bootc_composefs::boot::mount_esp;
14+
use crate::bootc_composefs::boot::{mount_esp, AutoEnroll};
1315
use crate::{discoverable_partition_specification, utils};
1416

1517
/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
@@ -19,6 +21,8 @@ pub(crate) const EFI_DIR: &str = "efi";
1921
#[allow(dead_code)]
2022
const BOOTUPD_UPDATES: &str = "usr/lib/bootupd/updates";
2123

24+
const SYSTEMD_AUTOENROLL: &str = "loader/keys/auto";
25+
2226
#[allow(dead_code)]
2327
pub(crate) fn esp_in(device: &PartitionTable) -> Result<&Partition> {
2428
device
@@ -74,6 +78,7 @@ pub(crate) fn install_systemd_boot(
7478
_rootfs: &Utf8Path,
7579
_configopts: &crate::install::InstallConfigOpts,
7680
_deployment_path: Option<&str>,
81+
autoenroll: Option<AutoEnroll>,
7782
) -> Result<()> {
7883
let esp_part = device
7984
.find_partition_of_type(discoverable_partition_specification::ESP)
@@ -87,7 +92,29 @@ pub(crate) fn install_systemd_boot(
8792
Command::new("bootctl")
8893
.args(["install", "--esp-path", esp_path.as_str()])
8994
.log_debug()
90-
.run_inherited_with_cmd_context()
95+
.run_inherited_with_cmd_context()?;
96+
97+
match autoenroll {
98+
None => return Ok(()),
99+
Some(AutoEnroll { dir, keys }) => {
100+
println!("Autoenrolling keys");
101+
let path = esp_path.join(SYSTEMD_AUTOENROLL);
102+
create_dir_all(&path)?;
103+
104+
let keys_dir = esp_mount
105+
.fd
106+
.open_dir(SYSTEMD_AUTOENROLL)
107+
.with_context(|| format!("Opening {path}"))?;
108+
for filename in keys.iter() {
109+
let p = path.join(filename.clone());
110+
keys_dir
111+
.atomic_write(&filename, dir.read(&filename)?)
112+
.with_context(|| format!("Writing secure boot key: {p}"))?;
113+
println!("Wrote secure boot key: {p}");
114+
}
115+
}
116+
}
117+
Ok(())
91118
}
92119

93120
#[context("Installing bootloader using zipl")]

0 commit comments

Comments
 (0)