Skip to content

Commit 5a03150

Browse files
composefs-native/uki: Handle UKI addons
If we find UKI addons in the boot entries list, write them to ESP along with the UKI Signed-off-by: Johan-Liebert1 <[email protected]>
1 parent fd703ec commit 5a03150

File tree

2 files changed

+147
-71
lines changed

2 files changed

+147
-71
lines changed

crates/lib/src/cli.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -945,11 +945,11 @@ async fn upgrade_composefs(_opts: UpgradeOpts) -> Result<()> {
945945

946946
let (repo, entries, id, fs) = pull_composefs_repo(&imgref.transport, &imgref.image).await?;
947947

948-
let Some(entry) = entries.into_iter().next() else {
948+
let Some(entry) = entries.iter().next() else {
949949
anyhow::bail!("No boot entries!");
950950
};
951951

952-
let boot_type = BootType::from(&entry);
952+
let boot_type = BootType::from(entry);
953953
let mut boot_digest = None;
954954

955955
match boot_type {
@@ -962,7 +962,7 @@ async fn upgrade_composefs(_opts: UpgradeOpts) -> Result<()> {
962962
)?)
963963
}
964964

965-
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade(&fs), repo, &id, entry)?,
965+
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade(&fs), repo, &id, entries)?,
966966
};
967967

968968
write_composefs_state(
@@ -1130,11 +1130,11 @@ async fn switch_composefs(opts: SwitchOpts) -> Result<()> {
11301130
let (repo, entries, id, fs) =
11311131
pull_composefs_repo(&"docker".into(), &target_imgref.image).await?;
11321132

1133-
let Some(entry) = entries.into_iter().next() else {
1133+
let Some(entry) = entries.iter().next() else {
11341134
anyhow::bail!("No boot entries!");
11351135
};
11361136

1137-
let boot_type = BootType::from(&entry);
1137+
let boot_type = BootType::from(entry);
11381138
let mut boot_digest = None;
11391139

11401140
match boot_type {
@@ -1143,10 +1143,10 @@ async fn switch_composefs(opts: SwitchOpts) -> Result<()> {
11431143
BootSetupType::Upgrade(&fs),
11441144
repo,
11451145
&id,
1146-
entry,
1146+
&entry,
11471147
)?)
11481148
}
1149-
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade(&fs), repo, &id, entry)?,
1149+
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade(&fs), repo, &id, entries)?,
11501150
};
11511151

11521152
write_composefs_state(

crates/lib/src/install.rs

Lines changed: 140 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ use cap_std_ext::cmdext::CapStdExtCommandExt;
4444
use cap_std_ext::prelude::CapStdExtDirExt;
4545
use clap::ValueEnum;
4646
use composefs::fs::read_file;
47-
use composefs::tree::FileSystem;
47+
use composefs::tree::{FileSystem, RegularFile};
48+
use composefs_boot::bootloader::{
49+
PEType, Type2Entry, UsrLibModulesUki, EFI_ADDON_DIR_EXT, EFI_ADDON_FILE_EXT, EFI_EXT,
50+
};
4851
use fn_error_context::context;
4952
use ostree::gio;
5053
use ostree_ext::composefs::{
@@ -1717,7 +1720,7 @@ pub(crate) fn setup_composefs_bls_boot(
17171720
// TODO: Make this generic
17181721
repo: ComposefsRepository<Sha256HashValue>,
17191722
id: &Sha256HashValue,
1720-
entry: ComposefsBootEntry<Sha256HashValue>,
1723+
entry: &ComposefsBootEntry<Sha256HashValue>,
17211724
) -> Result<String> {
17221725
let id_hex = id.to_hex();
17231726

@@ -1931,13 +1934,106 @@ fi
19311934
)
19321935
}
19331936

1937+
fn write_pe_to_esp(
1938+
repo: &ComposefsRepository<Sha256HashValue>,
1939+
file: &RegularFile<Sha256HashValue>,
1940+
file_path: &PathBuf,
1941+
pe_type: PEType,
1942+
uki_id: &String,
1943+
is_insecure_from_opts: bool,
1944+
mounted_efi: &PathBuf,
1945+
) -> Result<Option<String>> {
1946+
let efi_bin = read_file(file, &repo).context("Reading .efi binary")?;
1947+
1948+
let mut boot_label = None;
1949+
1950+
// UKI Extension might not even have a cmdline
1951+
// TODO: UKI Addon might also have a composefs= cmdline???
1952+
if matches!(pe_type, PEType::Uki) {
1953+
let cmdline = uki::get_cmdline(&efi_bin).context("Getting UKI cmdline")?;
1954+
1955+
let (composefs_cmdline, insecure) = get_cmdline_composefs::<Sha256HashValue>(cmdline)?;
1956+
1957+
// If the UKI cmdline does not match what the user has passed as cmdline option
1958+
// NOTE: This will only be checked for new installs and now upgrades/switches
1959+
match is_insecure_from_opts {
1960+
true => {
1961+
if !insecure {
1962+
tracing::warn!(
1963+
"--insecure passed as option but UKI cmdline does not support it"
1964+
);
1965+
}
1966+
}
1967+
1968+
false => {
1969+
if insecure {
1970+
tracing::warn!("UKI cmdline has composefs set as insecure")
1971+
}
1972+
}
1973+
}
1974+
1975+
if composefs_cmdline.to_hex() != *uki_id {
1976+
anyhow::bail!(
1977+
"The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {uki_id:?})"
1978+
);
1979+
}
1980+
1981+
boot_label = Some(uki::get_boot_label(&efi_bin).context("Getting UKI boot label")?);
1982+
}
1983+
1984+
// Write the UKI to ESP
1985+
let efi_linux_path = mounted_efi.join(EFI_LINUX);
1986+
create_dir_all(&efi_linux_path).context("Creating EFI/Linux")?;
1987+
1988+
let final_pe_path = if let Some(parent) = file_path.parent() {
1989+
let renamed_path = if parent.as_str()?.ends_with(EFI_ADDON_DIR_EXT) {
1990+
let dir_name = format!("{}{}", uki_id, EFI_ADDON_DIR_EXT);
1991+
1992+
parent
1993+
.parent()
1994+
.map(|p| p.join(&dir_name))
1995+
.unwrap_or(dir_name.into())
1996+
} else {
1997+
parent.to_path_buf()
1998+
};
1999+
2000+
let full_path = efi_linux_path.join(renamed_path);
2001+
create_dir_all(&full_path)?;
2002+
2003+
full_path
2004+
} else {
2005+
efi_linux_path
2006+
};
2007+
2008+
let pe_dir = cap_std::fs::Dir::open_ambient_dir(&final_pe_path, cap_std::ambient_authority())
2009+
.with_context(|| format!("Opening {final_pe_path:?}"))?;
2010+
2011+
let pe_name = match pe_type {
2012+
PEType::Uki => format!("{}{}", uki_id, EFI_EXT),
2013+
PEType::UkiAddon => format!("{}{}", uki_id, EFI_ADDON_FILE_EXT),
2014+
};
2015+
2016+
pe_dir
2017+
.atomic_write(pe_name, efi_bin)
2018+
.context("Writing UKI")?;
2019+
2020+
rustix::fs::fsync(
2021+
pe_dir
2022+
.reopen_as_ownedfd()
2023+
.context("Reopening as owned fd")?,
2024+
)
2025+
.context("fsync")?;
2026+
2027+
Ok(boot_label)
2028+
}
2029+
19342030
#[context("Setting up UKI boot")]
19352031
pub(crate) fn setup_composefs_uki_boot(
19362032
setup_type: BootSetupType,
19372033
// TODO: Make this generic
19382034
repo: ComposefsRepository<Sha256HashValue>,
19392035
id: &Sha256HashValue,
1940-
entry: ComposefsBootEntry<Sha256HashValue>,
2036+
entries: Vec<ComposefsBootEntry<Sha256HashValue>>,
19412037
) -> Result<()> {
19422038
let (root_path, esp_device, is_insecure_from_opts) = match setup_type {
19432039
BootSetupType::Setup((root_setup, state, ..)) => {
@@ -1957,7 +2053,11 @@ pub(crate) fn setup_composefs_uki_boot(
19572053
(
19582054
root_setup.physical_root_path.clone(),
19592055
esp_part.node.clone(),
1960-
state.composefs_options.as_ref().map(|x| x.insecure),
2056+
state
2057+
.composefs_options
2058+
.as_ref()
2059+
.map(|x| x.insecure)
2060+
.unwrap_or(false),
19612061
)
19622062
}
19632063

@@ -1971,7 +2071,7 @@ pub(crate) fn setup_composefs_uki_boot(
19712071
anyhow::bail!("Could not find parent device for mountpoint /sysroot");
19722072
};
19732073

1974-
(sysroot, get_esp_partition(&parent)?.0, None)
2074+
(sysroot, get_esp_partition(&parent)?.0, false)
19752075
}
19762076
};
19772077

@@ -1983,66 +2083,42 @@ pub(crate) fn setup_composefs_uki_boot(
19832083
.args([&PathBuf::from(&esp_device), &mounted_efi.clone()])
19842084
.run()?;
19852085

1986-
let boot_label = match entry {
1987-
ComposefsBootEntry::Type1(..) => unimplemented!(),
1988-
ComposefsBootEntry::UsrLibModulesUki(..) => unimplemented!(),
1989-
ComposefsBootEntry::UsrLibModulesVmLinuz(..) => unimplemented!(),
1990-
1991-
ComposefsBootEntry::Type2(type2_entry) => {
1992-
let uki = read_file(&type2_entry.file, &repo).context("Reading UKI")?;
1993-
let cmdline = uki::get_cmdline(&uki).context("Getting UKI cmdline")?;
1994-
let (composefs_cmdline, insecure) = get_cmdline_composefs::<Sha256HashValue>(cmdline)?;
1995-
1996-
// If the UKI cmdline does not match what the user has passed as cmdline option
1997-
// NOTE: This will only be checked for new installs and now upgrades/switches
1998-
if let Some(is_insecure_from_opts) = is_insecure_from_opts {
1999-
match is_insecure_from_opts {
2000-
true => {
2001-
if !insecure {
2002-
tracing::warn!(
2003-
"--insecure passed as option but UKI cmdline does not support it"
2004-
)
2005-
}
2006-
}
2086+
let mut boot_label = String::new();
20072087

2008-
false => {
2009-
if insecure {
2010-
tracing::warn!("UKI cmdline has composefs set as insecure")
2011-
}
2012-
}
2013-
}
2088+
for entry in entries {
2089+
match entry {
2090+
ComposefsBootEntry::Type1(..) => tracing::debug!("Skipping Type1 Entry"),
2091+
ComposefsBootEntry::UsrLibModulesVmLinuz(..) => {
2092+
tracing::debug!("Skipping vmlinuz in /usr/lib/modules")
20142093
}
20152094

2016-
let boot_label = uki::get_boot_label(&uki).context("Getting UKI boot label")?;
2017-
2018-
if composefs_cmdline != *id {
2019-
anyhow::bail!(
2020-
"The UKI has the wrong composefs= parameter (is '{composefs_cmdline:?}', should be {id:?})"
2021-
);
2095+
ComposefsBootEntry::UsrLibModulesUki(UsrLibModulesUki {
2096+
file,
2097+
file_path,
2098+
pe_type,
2099+
..
2100+
})
2101+
| ComposefsBootEntry::Type2(Type2Entry {
2102+
file,
2103+
file_path,
2104+
pe_type,
2105+
}) => {
2106+
let ret = write_pe_to_esp(
2107+
&repo,
2108+
&file,
2109+
&file_path,
2110+
pe_type,
2111+
&id.to_hex(),
2112+
is_insecure_from_opts,
2113+
&mounted_efi,
2114+
)?;
2115+
2116+
if let Some(label) = ret {
2117+
boot_label = label;
2118+
}
20222119
}
2023-
2024-
// Write the UKI to ESP
2025-
let efi_linux_path = mounted_efi.join(EFI_LINUX);
2026-
create_dir_all(&efi_linux_path).context("Creating EFI/Linux")?;
2027-
2028-
let efi_linux =
2029-
cap_std::fs::Dir::open_ambient_dir(&efi_linux_path, cap_std::ambient_authority())
2030-
.with_context(|| format!("Opening {efi_linux_path:?}"))?;
2031-
2032-
efi_linux
2033-
.atomic_write(format!("{}.efi", id.to_hex()), uki)
2034-
.context("Writing UKI")?;
2035-
2036-
rustix::fs::fsync(
2037-
efi_linux
2038-
.reopen_as_ownedfd()
2039-
.context("Reopening as owned fd")?,
2040-
)
2041-
.context("fsync")?;
2042-
2043-
boot_label
2044-
}
2045-
};
2120+
};
2121+
}
20462122

20472123
Command::new("umount")
20482124
.arg(&mounted_efi)
@@ -2194,11 +2270,11 @@ fn setup_composefs_boot(root_setup: &RootSetup, state: &State, image_id: &str) -
21942270
let entries = fs.transform_for_boot(&repo)?;
21952271
let id = fs.commit_image(&repo, None)?;
21962272

2197-
let Some(entry) = entries.into_iter().next() else {
2273+
let Some(entry) = entries.iter().next() else {
21982274
anyhow::bail!("No boot entries!");
21992275
};
22002276

2201-
let boot_type = BootType::from(&entry);
2277+
let boot_type = BootType::from(entry);
22022278
let mut boot_digest: Option<String> = None;
22032279

22042280
match boot_type {
@@ -2216,7 +2292,7 @@ fn setup_composefs_boot(root_setup: &RootSetup, state: &State, image_id: &str) -
22162292
BootSetupType::Setup((&root_setup, &state, &fs)),
22172293
repo,
22182294
&id,
2219-
entry,
2295+
entries,
22202296
)?,
22212297
};
22222298

0 commit comments

Comments
 (0)