stub: split up into a linux-bootloader crate
We introduce `linux-bootloader` a crate made to build Rust-based Linux-oriented bootloaders. It follows systemd/UAPI group and semantics as much as possible, e.g. BLS/loader capabilities/stub capabilities.
This commit is contained in:
parent
6d6cdf59b9
commit
51d9c1dff8
|
@ -0,0 +1,193 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-bootloader"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"goblin",
|
||||
"log",
|
||||
"sha1_smol",
|
||||
"uefi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1_smol"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucs2"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b63e82686b4bdb0db74f18b2abbd60a0470354fb640aa69e115598d714d0a10"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"log",
|
||||
"ptr_meta",
|
||||
"ucs2",
|
||||
"uefi-macros",
|
||||
"uefi-raw",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-macros"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "023d94ef8e135d068b9a3bd94614ef2610b2b0419ade0a9d8f3501fa9cd08e95"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.27",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uefi-raw"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62642516099c6441a5f41b0da8486d5fc3515a0603b0fdaea67b31600e22082e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ptr_meta",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uguid"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16dfbd255defbd727b3a30e8950695d2e6d045841ee250ff0f1f7ced17917f8d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "linux-bootloader"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
publish = true
|
||||
license = "GPL-3.0-only"
|
||||
keywords = ["osdev", "linux", "bootloader"]
|
||||
categories = ["embedded", "hardware-support", "no-std", "os::linux-apis"]
|
||||
description = "Utilities to build Linux-based bootloaders"
|
||||
repository = "https://github.com/nix-community/lanzaboote/"
|
||||
|
||||
[dependencies]
|
||||
uefi = { version = "0.24.0", default-features = false, features = [ "alloc", "global_allocator" ] }
|
||||
goblin = { version = "0.6.1", default-features = false, features = [ "pe64", "alloc" ]}
|
||||
bitflags = "2.3.3"
|
||||
|
||||
# Even in debug builds, we don't enable the debug logs, because they generate a lot of spam from goblin.
|
||||
log = { version = "0.4.19", default-features = false, features = [ "max_level_info", "release_max_level_warn" ]}
|
||||
|
||||
# SHA1 for TPM TCG interface version 1.
|
||||
sha1_smol = "1.0.0"
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
|
@ -0,0 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "1.68.2"
|
||||
components = [ "rust-src" ]
|
||||
targets = [ "x86_64-unknown-uefi" ]
|
|
@ -46,11 +46,7 @@ fn disk_get_part_uuid(boot_services: &BootServices, disk_handle: Handle) -> Resu
|
|||
pub const BOOT_LOADER_VENDOR_UUID: VariableVendor =
|
||||
VariableVendor(guid!("4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"));
|
||||
|
||||
/// Lanzaboote stub name
|
||||
pub static STUB_INFO_STRING: &str = concat!("lanzastub ", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
bitflags! {
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||
/// Feature flags as described in https://systemd.io/BOOT_LOADER_INTERFACE/
|
||||
|
@ -146,7 +142,7 @@ where
|
|||
}
|
||||
|
||||
/// Exports systemd-stub style EFI variables
|
||||
pub fn export_efi_variables(system_table: &SystemTable<Boot>) -> Result<()> {
|
||||
pub fn export_efi_variables(stub_info_name: &str, system_table: &SystemTable<Boot>) -> Result<()> {
|
||||
let boot_services = system_table.boot_services();
|
||||
let runtime_services = system_table.runtime_services();
|
||||
|
||||
|
@ -243,7 +239,7 @@ pub fn export_efi_variables(system_table: &SystemTable<Boot>) -> Result<()> {
|
|||
cstr16!("StubInfo"),
|
||||
&BOOT_LOADER_VENDOR_UUID,
|
||||
default_attributes,
|
||||
&STUB_INFO_STRING
|
||||
&stub_info_name
|
||||
.encode_utf16()
|
||||
.flat_map(|c| c.to_le_bytes())
|
||||
.collect::<Vec<u8>>(),
|
|
@ -0,0 +1,12 @@
|
|||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod efivars;
|
||||
pub mod linux_loader;
|
||||
pub mod measure;
|
||||
pub mod pe_loader;
|
||||
pub mod pe_section;
|
||||
pub mod tpm;
|
||||
pub mod uefi_helpers;
|
||||
pub mod unified_sections;
|
|
@ -12,10 +12,7 @@ use crate::{
|
|||
|
||||
const TPM_PCR_INDEX_KERNEL_IMAGE: PcrIndex = PcrIndex(11);
|
||||
|
||||
pub unsafe fn measure_image(
|
||||
system_table: &SystemTable<Boot>,
|
||||
image: PeInMemory,
|
||||
) -> uefi::Result<u32> {
|
||||
pub fn measure_image(system_table: &SystemTable<Boot>, image: PeInMemory) -> uefi::Result<u32> {
|
||||
let runtime_services = system_table.runtime_services();
|
||||
let boot_services = system_table.boot_services();
|
||||
|
|
@ -83,10 +83,8 @@ dependencies = [
|
|||
name = "lanzaboote_stub"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"goblin",
|
||||
"linux-bootloader",
|
||||
"log",
|
||||
"sha1_smol",
|
||||
"sha2",
|
||||
"uefi",
|
||||
"uefi-services",
|
||||
|
@ -98,6 +96,17 @@ version = "0.2.147"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "linux-bootloader"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"goblin",
|
||||
"log",
|
||||
"sha1_smol",
|
||||
"uefi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
|
|
|
@ -9,16 +9,12 @@ rust-version = "1.68"
|
|||
[dependencies]
|
||||
uefi = { version = "0.24.0", default-features = false, features = [ "alloc", "global_allocator" ] }
|
||||
uefi-services = { version = "0.21.0", default-features = false, features = [ "panic_handler", "logger" ] }
|
||||
goblin = { version = "0.6.1", default-features = false, features = [ "pe64", "alloc" ]}
|
||||
bitflags = "2.3.3"
|
||||
|
||||
# Even in debug builds, we don't enable the debug logs, because they generate a lot of spam from goblin.
|
||||
log = { version = "0.4.19", default-features = false, features = [ "max_level_info", "release_max_level_warn" ]}
|
||||
|
||||
# Use software implementation because the UEFI target seems to need it.
|
||||
sha2 = { version = "0.10.7", default-features = false, features = ["force-soft"], optional = true }
|
||||
# SHA1 for TPM TCG interface version 1.
|
||||
sha1_smol = "1.0.0"
|
||||
# Our linux-bootloader crate containing most of what we need
|
||||
linux-bootloader = { path = "../linux-bootloader" }
|
||||
|
||||
[features]
|
||||
default = [ "thin" ]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use alloc::vec::Vec;
|
||||
use uefi::{prelude::*, CStr16, CString16, Result};
|
||||
|
||||
use crate::linux_loader::InitrdLoader;
|
||||
use crate::pe_loader::Image;
|
||||
use crate::pe_section::pe_section_as_string;
|
||||
use linux_bootloader::linux_loader::InitrdLoader;
|
||||
use linux_bootloader::pe_loader::Image;
|
||||
use linux_bootloader::pe_section::pe_section_as_string;
|
||||
|
||||
/// Extract a string, stored as UTF-8, from a PE section.
|
||||
pub fn extract_string(pe_data: &[u8], section: &str) -> Result<CString16> {
|
||||
|
|
|
@ -2,8 +2,8 @@ use alloc::vec::Vec;
|
|||
use uefi::{prelude::*, CString16, Result};
|
||||
|
||||
use crate::common::{boot_linux_unchecked, extract_string};
|
||||
use crate::pe_section::pe_section;
|
||||
use crate::uefi_helpers::booted_image_file;
|
||||
use linux_bootloader::pe_section::pe_section;
|
||||
use linux_bootloader::uefi_helpers::booted_image_file;
|
||||
|
||||
/// Extract bytes from a PE section.
|
||||
pub fn extract_bytes(pe_data: &[u8], section: &str) -> Result<Vec<u8>> {
|
||||
|
|
|
@ -5,14 +5,6 @@
|
|||
extern crate alloc;
|
||||
|
||||
mod common;
|
||||
mod efivars;
|
||||
mod linux_loader;
|
||||
mod measure;
|
||||
mod pe_loader;
|
||||
mod pe_section;
|
||||
mod tpm;
|
||||
mod uefi_helpers;
|
||||
mod unified_sections;
|
||||
|
||||
#[cfg(feature = "fat")]
|
||||
mod fat;
|
||||
|
@ -23,13 +15,15 @@ mod thin;
|
|||
#[cfg(all(feature = "fat", feature = "thin"))]
|
||||
compile_error!("A thin and fat stub cannot be produced at the same time, disable either `thin` or `fat` feature");
|
||||
|
||||
use efivars::{export_efi_variables, get_loader_features, EfiLoaderFeatures};
|
||||
use linux_bootloader::efivars::{export_efi_variables, get_loader_features, EfiLoaderFeatures};
|
||||
use linux_bootloader::measure::measure_image;
|
||||
use linux_bootloader::tpm::tpm_available;
|
||||
use linux_bootloader::uefi_helpers::booted_image_file;
|
||||
use log::info;
|
||||
use measure::measure_image;
|
||||
use tpm::tpm_available;
|
||||
use uefi::prelude::*;
|
||||
|
||||
use crate::uefi_helpers::booted_image_file;
|
||||
/// Lanzaboote stub name
|
||||
pub static STUB_NAME: &str = concat!("lanzastub ", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
/// Print the startup logo on boot.
|
||||
fn print_logo() {
|
||||
|
@ -54,7 +48,6 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
|
||||
if tpm_available(system_table.boot_services()) {
|
||||
info!("TPM available, will proceed to measurements.");
|
||||
unsafe {
|
||||
// Iterate over unified sections and measure them
|
||||
// For now, ignore failures during measurements.
|
||||
// TODO: in the future, devise a threat model where this can fail
|
||||
|
@ -66,7 +59,6 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
// TODO: Measure kernel parameters
|
||||
// TODO: Measure sysexts
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(features) = get_loader_features(system_table.runtime_services()) {
|
||||
if !features.contains(EfiLoaderFeatures::RandomSeed) {
|
||||
|
@ -74,7 +66,7 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
info!("Random seed is available, but lanzaboote does not support it yet.");
|
||||
}
|
||||
}
|
||||
export_efi_variables(&system_table).expect("Failed to export stub EFI variables");
|
||||
export_efi_variables(STUB_NAME, &system_table).expect("Failed to export stub EFI variables");
|
||||
|
||||
let status;
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ use sha2::{Digest, Sha256};
|
|||
use uefi::{prelude::*, proto::loaded_image::LoadedImage, CStr16, CString16, Result};
|
||||
|
||||
use crate::common::{boot_linux_unchecked, extract_string};
|
||||
use crate::pe_section::pe_section;
|
||||
use crate::{linux_loader::InitrdLoader, uefi_helpers::booted_image_file};
|
||||
use linux_bootloader::pe_section::pe_section;
|
||||
use linux_bootloader::{linux_loader::InitrdLoader, uefi_helpers::booted_image_file};
|
||||
|
||||
type Hash = sha2::digest::Output<Sha256>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue