use core::ffi::c_void;
use log::warn;
use uefi::{
Status, boot,
proto::device_path::{DevicePath, FfiDevicePath},
};
use crate::{
boot::secure_boot::{SECURITY_OVERRIDE, security_override::SecurityOverrideInner},
system::protos::{Security2Arch, Security2ArchProtocol, SecurityArch, SecurityArchProtocol},
};
impl SecurityOverrideInner {
pub(super) fn install_security1_hook(&mut self) {
if let Ok(handle) = boot::get_handle_for_protocol::<SecurityArch>()
&& let Ok(mut security) = boot::open_protocol_exclusive::<SecurityArch>(handle)
{
security.get_inner_mut().auth_state = auth_state_hook;
self.original_hook = Some(security.get_inner().auth_state);
self.security = Some(handle);
}
}
pub(super) fn install_security2_hook(&mut self) {
if let Ok(handle) = boot::get_handle_for_protocol::<Security2Arch>()
&& let Ok(mut security) = boot::open_protocol_exclusive::<Security2Arch>(handle)
{
security.get_inner_mut().authentication = authentication_hook;
self.original_hook2 = Some(security.get_inner().authentication);
self.security2 = Some(handle);
}
}
pub(super) fn uninstall_security1_hook(&self) {
if let Some(original_hook) = self.original_hook
&& let Some(handle) = self.security
&& let Ok(mut security) = boot::open_protocol_exclusive::<SecurityArch>(handle)
{
security.get_inner_mut().auth_state = original_hook;
}
}
pub(super) fn uninstall_security2_hook(&self) {
if let Some(original_hook2) = self.original_hook2
&& let Some(handle) = self.security2
&& let Ok(mut security) = boot::open_protocol_exclusive::<Security2Arch>(handle)
{
security.get_inner_mut().authentication = original_hook2;
}
}
}
unsafe extern "efiapi" fn auth_state_hook(
this: *const SecurityArchProtocol,
auth_status: u32,
file: *const FfiDevicePath,
) -> Status {
let security_override = &SECURITY_OVERRIDE;
match security_override
.get()
.call_validator(ffi_ptr_to_device_path(file), None)
{
Err(e) => {
warn!("{e}");
unsafe {
security_override
.get()
.call_original_hook(this, auth_status, file)
}
}
_ => Status::SUCCESS, }
}
unsafe extern "efiapi" fn authentication_hook(
this: *const Security2ArchProtocol,
device_path: *const FfiDevicePath,
file_buffer: *mut c_void,
file_size: usize,
boot_policy: u8,
) -> Status {
let security_override = &SECURITY_OVERRIDE;
let slice = unsafe { mut_ptr_to_u8_slice(file_buffer, file_size) };
match security_override
.get()
.call_validator(ffi_ptr_to_device_path(device_path), slice)
{
Err(e) => {
warn!("{e}");
unsafe {
security_override.get().call_original_hook2(
this,
device_path,
file_buffer,
file_size,
boot_policy,
)
}
}
_ => Status::SUCCESS, }
}
unsafe fn mut_ptr_to_u8_slice<'a>(ptr: *mut c_void, size: usize) -> Option<&'a mut [u8]> {
(!ptr.is_null() && ptr.is_aligned())
.then(|| unsafe { core::slice::from_raw_parts_mut(ptr.cast::<u8>(), size) })
}
fn ffi_ptr_to_device_path<'a>(ptr: *const FfiDevicePath) -> Option<&'a DevicePath> {
(!ptr.is_null() && ptr.is_aligned()).then(|| unsafe { DevicePath::from_ffi_ptr(ptr) })
}