Merge pull request #215 from nix-community/linux-bootloader-crate

stub: split up into a linux-bootloader crate
This commit is contained in:
Ryan Lahfa 2023-09-13 16:43:16 +00:00 committed by GitHub
commit 3dc8778c32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 119 additions and 75 deletions

View File

@ -95,18 +95,20 @@
inherit (pkgs) lib; inherit (pkgs) lib;
uefi-rust-stable = pkgs.rust-bin.fromRustupToolchainFile ./rust/stub/rust-toolchain.toml; uefi-rust-stable = pkgs.rust-bin.fromRustupToolchainFile ./rust/uefi/rust-toolchain.toml;
craneLib = crane.lib.x86_64-linux.overrideToolchain uefi-rust-stable; craneLib = crane.lib.x86_64-linux.overrideToolchain uefi-rust-stable;
# Build attributes for a Rust application. # Build attributes for a Rust application.
buildRustApp = lib.makeOverridable ( buildRustApp = lib.makeOverridable (
{ src { pname
, src
, target ? null , target ? null
, doCheck ? true , doCheck ? true
, extraArgs ? { } , extraArgs ? { }
}: }:
let let
commonArgs = { commonArgs = {
inherit pname;
inherit src; inherit src;
CARGO_BUILD_TARGET = target; CARGO_BUILD_TARGET = target;
inherit doCheck; inherit doCheck;
@ -148,7 +150,8 @@
); );
stubCrane = buildRustApp { stubCrane = buildRustApp {
src = craneLib.cleanCargoSource ./rust/stub; pname = "lanzaboote-stub";
src = craneLib.cleanCargoSource ./rust/uefi;
target = "x86_64-unknown-uefi"; target = "x86_64-unknown-uefi";
doCheck = false; doCheck = false;
}; };
@ -163,6 +166,7 @@
fatStub = fatStubCrane.package; fatStub = fatStubCrane.package;
toolCrane = buildRustApp { toolCrane = buildRustApp {
pname = "lanzaboote-tool";
src = ./rust/tool; src = ./rust/tool;
extraArgs = { extraArgs = {
TEST_SYSTEMD = pkgs.systemd; TEST_SYSTEMD = pkgs.systemd;
@ -254,6 +258,7 @@
pkgs.nixpkgs-fmt pkgs.nixpkgs-fmt
pkgs.statix pkgs.statix
pkgs.cargo-release pkgs.cargo-release
pkgs.cargo-machete
]; ];
inputsFrom = [ inputsFrom = [

View File

@ -10,9 +10,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.3.3" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -83,10 +83,8 @@ dependencies = [
name = "lanzaboote_stub" name = "lanzaboote_stub"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"bitflags", "linux-bootloader",
"goblin",
"log", "log",
"sha1_smol",
"sha2", "sha2",
"uefi", "uefi",
"uefi-services", "uefi-services",
@ -94,15 +92,26 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]]
name = "linux-bootloader"
version = "0.3.0"
dependencies = [
"bitflags",
"goblin",
"log",
"sha1_smol",
"uefi",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.19" version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "plain" name = "plain"
@ -141,9 +150,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.31" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -165,7 +174,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.32",
] ]
[[package]] [[package]]
@ -198,9 +207,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.26" version = "2.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -245,7 +254,7 @@ checksum = "023d94ef8e135d068b9a3bd94614ef2610b2b0419ade0a9d8f3501fa9cd08e95"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.32",
] ]
[[package]] [[package]]
@ -278,9 +287,9 @@ checksum = "16dfbd255defbd727b3a30e8950695d2e6d045841ee250ff0f1f7ced17917f8d"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.11" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "version_check" name = "version_check"

17
rust/uefi/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[workspace]
members = [
"stub",
"linux-bootloader",
]
default-members = [
"stub"
]
[workspace.package]
version = "0.3.0"
[profile.release]
opt-level = "s"
lto = true

View File

@ -0,0 +1,26 @@
[package]
name = "linux-bootloader"
version.workspace = true
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/"
# For UEFI target
rust-version = "1.68"
[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" }

View File

@ -46,11 +46,7 @@ fn disk_get_part_uuid(boot_services: &BootServices, disk_handle: Handle) -> Resu
pub const BOOT_LOADER_VENDOR_UUID: VariableVendor = pub const BOOT_LOADER_VENDOR_UUID: VariableVendor =
VariableVendor(guid!("4a67b082-0a4c-41cf-b6c7-440b29bb8c4f")); VariableVendor(guid!("4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"));
/// Lanzaboote stub name
pub static STUB_INFO_STRING: &str = concat!("lanzastub ", env!("CARGO_PKG_VERSION"));
bitflags! { bitflags! {
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
/// Feature flags as described in https://systemd.io/BOOT_LOADER_INTERFACE/ /// Feature flags as described in https://systemd.io/BOOT_LOADER_INTERFACE/
@ -146,7 +142,7 @@ where
} }
/// Exports systemd-stub style EFI variables /// 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 boot_services = system_table.boot_services();
let runtime_services = system_table.runtime_services(); let runtime_services = system_table.runtime_services();
@ -243,7 +239,7 @@ pub fn export_efi_variables(system_table: &SystemTable<Boot>) -> Result<()> {
cstr16!("StubInfo"), cstr16!("StubInfo"),
&BOOT_LOADER_VENDOR_UUID, &BOOT_LOADER_VENDOR_UUID,
default_attributes, default_attributes,
&STUB_INFO_STRING &stub_info_name
.encode_utf16() .encode_utf16()
.flat_map(|c| c.to_le_bytes()) .flat_map(|c| c.to_le_bytes())
.collect::<Vec<u8>>(), .collect::<Vec<u8>>(),

View File

@ -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;

View File

@ -12,10 +12,7 @@ use crate::{
const TPM_PCR_INDEX_KERNEL_IMAGE: PcrIndex = PcrIndex(11); const TPM_PCR_INDEX_KERNEL_IMAGE: PcrIndex = PcrIndex(11);
pub unsafe fn measure_image( pub fn measure_image(system_table: &SystemTable<Boot>, image: PeInMemory) -> uefi::Result<u32> {
system_table: &SystemTable<Boot>,
image: PeInMemory,
) -> uefi::Result<u32> {
let runtime_services = system_table.runtime_services(); let runtime_services = system_table.runtime_services();
let boot_services = system_table.boot_services(); let boot_services = system_table.boot_services();

View File

@ -1,30 +1,20 @@
[package] [package]
name = "lanzaboote_stub" name = "lanzaboote_stub"
version = "0.3.0" version.workspace = true
edition = "2021" edition = "2021"
publish = false publish = false
# For UEFI target
rust-version = "1.68"
[dependencies] [dependencies]
uefi = { version = "0.24.0", default-features = false, features = [ "alloc", "global_allocator" ] } 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" ] } 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. # 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" ]} 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. # Use software implementation because the UEFI target seems to need it.
sha2 = { version = "0.10.7", default-features = false, features = ["force-soft"], optional = true } sha2 = { version = "0.10.7", default-features = false, features = ["force-soft"], optional = true }
# SHA1 for TPM TCG interface version 1. # Our linux-bootloader crate containing most of what we need
sha1_smol = "1.0.0" linux-bootloader = { path = "../linux-bootloader" }
[features] [features]
default = [ "thin" ] default = [ "thin" ]
thin = ["dep:sha2"] thin = ["dep:sha2"]
fat = [] fat = []
[profile.release]
opt-level = "s"
lto = true

View File

@ -1,9 +1,9 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use uefi::{prelude::*, CStr16, CString16, Result}; use uefi::{prelude::*, CStr16, CString16, Result};
use crate::linux_loader::InitrdLoader; use linux_bootloader::linux_loader::InitrdLoader;
use crate::pe_loader::Image; use linux_bootloader::pe_loader::Image;
use crate::pe_section::pe_section_as_string; use linux_bootloader::pe_section::pe_section_as_string;
/// Extract a string, stored as UTF-8, from a PE section. /// Extract a string, stored as UTF-8, from a PE section.
pub fn extract_string(pe_data: &[u8], section: &str) -> Result<CString16> { pub fn extract_string(pe_data: &[u8], section: &str) -> Result<CString16> {

View File

@ -2,8 +2,8 @@ use alloc::vec::Vec;
use uefi::{prelude::*, CString16, Result}; use uefi::{prelude::*, CString16, Result};
use crate::common::{boot_linux_unchecked, extract_string}; use crate::common::{boot_linux_unchecked, extract_string};
use crate::pe_section::pe_section; use linux_bootloader::pe_section::pe_section;
use crate::uefi_helpers::booted_image_file; use linux_bootloader::uefi_helpers::booted_image_file;
/// Extract bytes from a PE section. /// Extract bytes from a PE section.
pub fn extract_bytes(pe_data: &[u8], section: &str) -> Result<Vec<u8>> { pub fn extract_bytes(pe_data: &[u8], section: &str) -> Result<Vec<u8>> {

View File

@ -5,14 +5,6 @@
extern crate alloc; extern crate alloc;
mod common; 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")] #[cfg(feature = "fat")]
mod fat; mod fat;
@ -23,13 +15,15 @@ mod thin;
#[cfg(all(feature = "fat", feature = "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"); 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 log::info;
use measure::measure_image;
use tpm::tpm_available;
use uefi::prelude::*; 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. /// Print the startup logo on boot.
fn print_logo() { fn print_logo() {
@ -54,7 +48,6 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
if tpm_available(system_table.boot_services()) { if tpm_available(system_table.boot_services()) {
info!("TPM available, will proceed to measurements."); info!("TPM available, will proceed to measurements.");
unsafe {
// Iterate over unified sections and measure them // Iterate over unified sections and measure them
// For now, ignore failures during measurements. // For now, ignore failures during measurements.
// TODO: in the future, devise a threat model where this can fail // 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 kernel parameters
// TODO: Measure sysexts // TODO: Measure sysexts
} }
}
if let Ok(features) = get_loader_features(system_table.runtime_services()) { if let Ok(features) = get_loader_features(system_table.runtime_services()) {
if !features.contains(EfiLoaderFeatures::RandomSeed) { 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."); 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; let status;

View File

@ -4,8 +4,8 @@ use sha2::{Digest, Sha256};
use uefi::{prelude::*, proto::loaded_image::LoadedImage, CStr16, CString16, Result}; use uefi::{prelude::*, proto::loaded_image::LoadedImage, CStr16, CString16, Result};
use crate::common::{boot_linux_unchecked, extract_string}; use crate::common::{boot_linux_unchecked, extract_string};
use crate::pe_section::pe_section; use linux_bootloader::pe_section::pe_section;
use crate::{linux_loader::InitrdLoader, uefi_helpers::booted_image_file}; use linux_bootloader::{linux_loader::InitrdLoader, uefi_helpers::booted_image_file};
type Hash = sha2::digest::Output<Sha256>; type Hash = sha2::digest::Output<Sha256>;