From 4866961d2f6dfecdbf47a69f34884892f9b29290 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Fri, 31 Oct 2025 15:49:00 -0400 Subject: [PATCH] feat(secure-boot): add support for SBAT section --- build.rs | 57 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 3 +++ src/sbat.rs | 8 ++++++ src/sbat.template.csv | 2 ++ 4 files changed, 70 insertions(+) create mode 100644 build.rs create mode 100644 src/sbat.rs create mode 100644 src/sbat.template.csv diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..054185f --- /dev/null +++ b/build.rs @@ -0,0 +1,57 @@ +use std::path::PathBuf; +use std::{env, fs}; + +/// The size of the sbat.csv file. +const SBAT_SIZE: usize = 512; + +/// Generate the sbat.csv for the .sbat link section. +/// +/// We intake a sbat.template.tsv and output a sbat.csv which is included by src/sbat.rs +fn generate_sbat_csv() { + // Notify Cargo that if the Sprout version changes, we need to regenerate the sbat.csv. + println!("cargo:rerun-if-env-changed=CARGO_PKG_VERSION"); + + // The version of the sprout crate. + let sprout_version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION not set"); + + // The output directory to place the sbat.csv into. + let output_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set")); + + // The output path to the sbat.csv. + let output_file = output_dir.join("sbat.csv"); + + // The path to the root of the sprout crate. + let sprout_root = + PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set")); + + // The path to the sbat.template.tsv file is in the source directory of the sprout crate. + let template_path = sprout_root.join("src/sbat.template.csv"); + + // Read the sbat.csv template file. + let template = fs::read_to_string(&template_path).expect("unable to read template file"); + + // Replace the version placeholder in the template with the actual version. + let sbat = template.replace("{version}", &sprout_version); + + // Encode the sbat.csv as bytes. + let mut encoded = sbat.as_bytes().to_vec(); + + if encoded.len() > SBAT_SIZE { + panic!("sbat.csv is too large"); + } + + // Pad the sbat.csv to the required size. + while encoded.len() < SBAT_SIZE { + encoded.push(0); + } + + // Write the sbat.csv to the output directory. + fs::write(&output_file, encoded).expect("unable to write sbat.csv"); +} + +/// Build script entry point. +/// Right now, all we need to do is generate the sbat.csv file. +fn main() { + // Generate the sbat.csv file. + generate_sbat_csv(); +} diff --git a/src/main.rs b/src/main.rs index a2b288b..ecd0c81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,9 @@ pub mod integrations; /// phases: Hooks into specific parts of the boot process. pub mod phases; +/// sbat: Secure Boot Attestation section. +pub mod sbat; + /// secure: Secure Boot support. pub mod secure; diff --git a/src/sbat.rs b/src/sbat.rs new file mode 100644 index 0000000..c1a24c7 --- /dev/null +++ b/src/sbat.rs @@ -0,0 +1,8 @@ +/// SBAT must be aligned by 512 bytes. +const SBAT_SIZE: usize = 512; + +/// Define the SBAT attestation by including the sbat.csv file. +/// See this document for more details: https://github.com/rhboot/shim/blob/main/SBAT.md +#[used] +#[unsafe(link_section = ".sbat")] +static SBAT: [u8; SBAT_SIZE] = *include_bytes!(concat!(env!("OUT_DIR"), "/sbat.csv")); diff --git a/src/sbat.template.csv b/src/sbat.template.csv new file mode 100644 index 0000000..1def346 --- /dev/null +++ b/src/sbat.template.csv @@ -0,0 +1,2 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +sprout,1,Edera,sprout,{version},https://sprout.edera.dev \ No newline at end of file