mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 19:00:18 +00:00
feat(safety): bail if secure boot is enabled early
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
use crate::platform::timer::PlatformTimer;
|
||||
use crate::utils::device_path_subpath;
|
||||
use crate::utils::variables::{VariableClass, VariableController};
|
||||
use anyhow::{Context, Result};
|
||||
use uefi::proto::device_path::DevicePath;
|
||||
use uefi::{CString16, Guid, guid};
|
||||
use uefi_raw::table::runtime::{VariableAttributes, VariableVendor};
|
||||
use uefi::{Guid, guid};
|
||||
use uefi_raw::table::runtime::VariableVendor;
|
||||
|
||||
/// The name of the bootloader to tell the system.
|
||||
const LOADER_NAME: &str = "Sprout";
|
||||
@@ -13,7 +14,9 @@ pub struct BootloaderInterface;
|
||||
|
||||
impl BootloaderInterface {
|
||||
/// Bootloader Interface GUID from https://systemd.io/BOOT_LOADER_INTERFACE
|
||||
const VENDOR: VariableVendor = VariableVendor(guid!("4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"));
|
||||
const VENDOR: VariableController = VariableController::new(VariableVendor(guid!(
|
||||
"4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"
|
||||
)));
|
||||
|
||||
/// Tell the system that Sprout was initialized at the current time.
|
||||
pub fn mark_init(timer: &PlatformTimer) -> Result<()> {
|
||||
@@ -35,23 +38,39 @@ impl BootloaderInterface {
|
||||
fn mark_time(key: &str, timer: &PlatformTimer) -> Result<()> {
|
||||
// Measure the elapsed time since the hardware timer was started.
|
||||
let elapsed = timer.elapsed_since_lifetime();
|
||||
Self::set_cstr16(key, &elapsed.as_micros().to_string())
|
||||
Self::VENDOR.set_cstr16(
|
||||
key,
|
||||
&elapsed.as_micros().to_string(),
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system what loader is being used.
|
||||
pub fn set_loader_info() -> Result<()> {
|
||||
Self::set_cstr16("LoaderInfo", LOADER_NAME)
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderInfo",
|
||||
LOADER_NAME,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system the relative path to the partition root of the current bootloader.
|
||||
pub fn set_loader_path(path: &DevicePath) -> Result<()> {
|
||||
let subpath = device_path_subpath(path).context("unable to get loader path subpath")?;
|
||||
Self::set_cstr16("LoaderImageIdentifier", &subpath)
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderImageIdentifier",
|
||||
&subpath,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system what the partition GUID of the ESP Sprout was booted from is.
|
||||
pub fn set_partition_guid(guid: &Guid) -> Result<()> {
|
||||
Self::set_cstr16("LoaderDevicePartUUID", &guid.to_string())
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderDevicePartUUID",
|
||||
&guid.to_string(),
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system what boot entries are available.
|
||||
@@ -69,17 +88,29 @@ impl BootloaderInterface {
|
||||
// Write the bytes (including the null terminator) into the data buffer.
|
||||
data.extend_from_slice(&encoded);
|
||||
}
|
||||
Self::set("LoaderEntries", &data)
|
||||
Self::VENDOR.set(
|
||||
"LoaderEntries",
|
||||
&data,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system what the default boot entry is.
|
||||
pub fn set_default_entry(entry: String) -> Result<()> {
|
||||
Self::set_cstr16("LoaderEntryDefault", &entry)
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderEntryDefault",
|
||||
&entry,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system what the selected boot entry is.
|
||||
pub fn set_selected_entry(entry: String) -> Result<()> {
|
||||
Self::set_cstr16("LoaderEntrySelected", &entry)
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderEntrySelected",
|
||||
&entry,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
|
||||
/// Tell the system about the UEFI firmware we are running on.
|
||||
@@ -91,35 +122,18 @@ impl BootloaderInterface {
|
||||
uefi::system::firmware_revision() >> 16,
|
||||
uefi::system::firmware_revision() & 0xFFFFF,
|
||||
);
|
||||
Self::set_cstr16("LoaderFirmwareInfo", &firmware_info)?;
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderFirmwareInfo",
|
||||
&firmware_info,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)?;
|
||||
|
||||
// Format the firmware revision into something human-readable.
|
||||
let firmware_type = format!("UEFI {:02}", uefi::system::firmware_revision());
|
||||
Self::set_cstr16("LoaderFirmwareType", &firmware_type)
|
||||
}
|
||||
|
||||
/// The [VariableAttributes] for bootloader interface variables.
|
||||
fn attributes() -> VariableAttributes {
|
||||
VariableAttributes::BOOTSERVICE_ACCESS | VariableAttributes::RUNTIME_ACCESS
|
||||
}
|
||||
|
||||
/// Set a bootloader interface variable specified by `key` to `value`.
|
||||
fn set(key: &str, value: &[u8]) -> Result<()> {
|
||||
let name =
|
||||
CString16::try_from(key).context("unable to convert variable name to CString16")?;
|
||||
uefi::runtime::set_variable(&name, &Self::VENDOR, Self::attributes(), value)
|
||||
.with_context(|| format!("unable to set efi variable {}", key))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set a bootloader interface variable specified by `key` to `value`, converting the value to
|
||||
/// a [CString16].
|
||||
fn set_cstr16(key: &str, value: &str) -> Result<()> {
|
||||
// Encode the value as a CString16 little endian.
|
||||
let encoded = value
|
||||
.encode_utf16()
|
||||
.flat_map(|c| c.to_le_bytes())
|
||||
.collect::<Vec<u8>>();
|
||||
Self::set(key, &encoded)
|
||||
Self::VENDOR.set_cstr16(
|
||||
"LoaderFirmwareType",
|
||||
&firmware_type,
|
||||
VariableClass::BootAndRuntimeTemporary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user