fix(shim/hook): call original hook function if the shim verify fails

This commit is contained in:
2025-11-02 01:07:16 -05:00
parent 1a6ed0af99
commit eabb612330

View File

@@ -53,9 +53,10 @@ pub struct SecurityHook;
impl SecurityHook { impl SecurityHook {
/// Shared verifier logic for both hook types. /// Shared verifier logic for both hook types.
fn verify(input: ShimInput) -> Status { #[must_use]
// Verify the input. fn verify(input: ShimInput) -> bool {
match ShimSupport::verify(input) { // Verify the input and convert the result to a status.
let status = match ShimSupport::verify(input) {
Ok(output) => match output { Ok(output) => match output {
// If the verification failed, return the access-denied status. // If the verification failed, return the access-denied status.
ShimVerificationOutput::VerificationFailed(status) => status, ShimVerificationOutput::VerificationFailed(status) => status,
@@ -70,14 +71,22 @@ impl SecurityHook {
warn!("unable to verify image: {}", error); warn!("unable to verify image: {}", error);
Status::ACCESS_DENIED Status::ACCESS_DENIED
} }
};
// If the status is not a success, log the status.
if !status.is_success() {
warn!("shim verification failed: {}", status);
} }
// Return whether the status is a success.
// If it's not a success, the original hook should be called.
status.is_success()
} }
/// File authentication state verifier for the EFI_SECURITY_ARCH protocol. /// File authentication state verifier for the EFI_SECURITY_ARCH protocol.
/// Takes the `path` and determines the verification. /// Takes the `path` and determines the verification.
unsafe extern "efiapi" fn arch_file_authentication_state( unsafe extern "efiapi" fn arch_file_authentication_state(
_this: *const SecurityArchProtocol, this: *const SecurityArchProtocol,
_status: u32, status: u32,
path: *mut FfiDevicePath, path: *mut FfiDevicePath,
) -> Status { ) -> Status {
// Verify the path is not null. // Verify the path is not null.
@@ -88,14 +97,44 @@ impl SecurityHook {
// Construct a shim input from the path. // Construct a shim input from the path.
let input = ShimInput::SecurityHookPath(path); let input = ShimInput::SecurityHookPath(path);
// Verify the input. // Verify the input, if it fails, call the original hook.
Self::verify(input) if !Self::verify(input) {
// Acquire the global hook state to grab the original hook.
let function = match GLOBAL_HOOK_STATE.lock() {
// We have acquired the lock, so we can find the original hook.
Ok(state) => match state.as_ref() {
// The hook state is available, so we can acquire the original hook.
Some(state) => state.original_hook.file_authentication_state,
// The hook state is not available, so we can't call the original hook.
None => {
warn!("global hook state is not available, unable to call original hook");
return Status::LOAD_ERROR;
}
},
Err(error) => {
warn!(
"unable to acquire global hook state lock to call original hook: {}",
error
);
return Status::LOAD_ERROR;
}
};
// Call the original hook function to see what it reports.
// SAFETY: This function is safe to call as it is stored by us and is required
// in the UEFI specification.
unsafe { function(this, status, path) }
} else {
Status::SUCCESS
}
} }
/// File authentication verifier for the EFI_SECURITY_ARCH2 protocol. /// File authentication verifier for the EFI_SECURITY_ARCH2 protocol.
/// Takes the `path` and a file buffer to determine the verification. /// Takes the `path` and a file buffer to determine the verification.
unsafe extern "efiapi" fn arch2_file_authentication( unsafe extern "efiapi" fn arch2_file_authentication(
_this: *const SecurityArch2Protocol, this: *const SecurityArch2Protocol,
path: *mut FfiDevicePath, path: *mut FfiDevicePath,
file_buffer: *mut u8, file_buffer: *mut u8,
file_size: usize, file_size: usize,
@@ -117,8 +156,38 @@ impl SecurityHook {
// Construct a shim input from the path. // Construct a shim input from the path.
let input = ShimInput::SecurityHookBuffer(Some(path), buffer); let input = ShimInput::SecurityHookBuffer(Some(path), buffer);
// Verify the input. // Verify the input, if it fails, call the original hook.
Self::verify(input) if !Self::verify(input) {
// Acquire the global hook state to grab the original hook.
let function = match GLOBAL_HOOK_STATE.lock() {
// We have acquired the lock, so we can find the original hook.
Ok(state) => match state.as_ref() {
// The hook state is available, so we can acquire the original hook.
Some(state) => state.original_hook2.file_authentication,
// The hook state is not available, so we can't call the original hook.
None => {
warn!("global hook state is not available, unable to call original hook");
return Status::LOAD_ERROR;
}
},
Err(error) => {
warn!(
"unable to acquire global hook state lock to call original hook: {}",
error
);
return Status::LOAD_ERROR;
}
};
// Call the original hook function to see what it reports.
// SAFETY: This function is safe to call as it is stored by us and is required
// in the UEFI specification.
unsafe { function(this, path, file_buffer, file_size, boot_policy) }
} else {
Status::SUCCESS
}
} }
/// Install the security hook if needed. /// Install the security hook if needed.