use core::cell::Cell;
use core::ptr::NonNull;
use thiserror::Error;
use uefi::{cstr16, proto::device_path::DevicePath, runtime::VariableVendor};
use crate::{
BootResult, boot::secure_boot::security_override::SecurityOverrideInner,
system::variable::get_variable,
};
pub mod security_hooks;
pub mod security_override;
pub mod shim;
#[derive(Error, Debug)]
pub enum SecureBootError {
#[error("DevicePath and file buffer were both None")]
NoDevicePathOrFile,
#[error("Validator was not installed")]
NoValidator,
}
pub(super) type Validator = fn(
ctx: Option<NonNull<u8>>,
device_path: Option<&DevicePath>,
file_buffer: Option<&mut [u8]>,
file_size: usize,
) -> BootResult<()>;
static SECURITY_OVERRIDE: SecurityOverride = SecurityOverride {
inner: Cell::new(None),
};
struct SecurityOverride {
inner: Cell<Option<SecurityOverrideInner>>,
}
impl SecurityOverride {
const fn get(&self) -> SecurityOverrideInner {
self.inner
.get()
.expect("The static Cell should always be initialized at the start of the program")
}
}
unsafe impl Sync for SecurityOverride {}
pub(super) struct SecurityOverrideGuard;
impl SecurityOverrideGuard {
pub(super) fn new(validator: Validator, validator_ctx: Option<NonNull<u8>>) -> Self {
install_security_override(validator, validator_ctx);
Self
}
}
impl Drop for SecurityOverrideGuard {
fn drop(&mut self) {
uninstall_security_override();
}
}
#[must_use = "Has no effect if the result is unused"]
fn secure_boot_enabled() -> bool {
matches!(
get_variable::<bool>(cstr16!("SecureBoot"), Some(VariableVendor::GLOBAL_VARIABLE)),
Ok(true)
)
}
fn install_security_override(validator: Validator, validator_ctx: Option<NonNull<u8>>) {
let security_override = &SECURITY_OVERRIDE;
security_override
.inner
.set(Some(SecurityOverrideInner::new(validator, validator_ctx)));
}
fn uninstall_security_override() {
let security_override = &SECURITY_OVERRIDE;
security_override.get().uninstall_validator();
security_override.inner.take();
}