#include "missing_efi.h"
#include "util.h"
+#include "secure-boot.h"
#include "shim.h"
#if defined(__x86_64__) || defined(__i386__)
return shim_lock->shim_verify(data, size) == EFI_SUCCESS;
}
-/* Handle to the original authenticator for security1 protocol */
-static EFI_SECURITY_FILE_AUTHENTICATION_STATE esfas = NULL;
-
-/* Handle to the original authenticator for security2 protocol */
-static EFI_SECURITY2_FILE_AUTHENTICATION es2fa = NULL;
-
-/*
- * Perform shim/MOK and Secure Boot authentication on a binary that's already been
- * loaded into memory. This function does the platform SB authentication first
- * but preserves its return value in case of its failure, so that it can be
- * returned in case of a shim/MOK authentication failure. This is done because
- * the SB failure code seems to vary from one implementation to another, and I
- * don't want to interfere with that at this time.
- */
-static EFIAPI EFI_STATUS security2_policy_authentication(
- const EFI_SECURITY2_ARCH_PROTOCOL *this,
+static EFIAPI EFI_STATUS security2_hook(
+ const SecurityOverride *this,
const EFI_DEVICE_PATH *device_path,
void *file_buffer,
UINTN file_size,
BOOLEAN boot_policy) {
- EFI_STATUS err;
assert(this);
- /* device_path and file_buffer may be NULL */
-
- /* Chain original security policy */
- err = es2fa(this, device_path, file_buffer, file_size, boot_policy);
-
- /* if OK, don't bother with MOK check */
- if (err == EFI_SUCCESS)
- return err;
+ assert(this->hook == security2_hook);
if (shim_validate(file_buffer, file_size))
return EFI_SUCCESS;
- return err;
+ return this->original_security2->FileAuthentication(
+ this->original_security2, device_path, file_buffer, file_size, boot_policy);
}
-/*
- * Perform both shim/MOK and platform Secure Boot authentication. This function loads
- * the file and performs shim/MOK authentication first simply to avoid double loads
- * of Linux kernels, which are much more likely to be shim/MOK-signed than platform-signed,
- * since kernels are big and can take several seconds to load on some computers and
- * filesystems. This also has the effect of returning whatever the platform code is for
- * authentication failure, be it EFI_ACCESS_DENIED, EFI_SECURITY_VIOLATION, or something
- * else. (This seems to vary between implementations.)
- */
-static EFIAPI EFI_STATUS security_policy_authentication(
- const EFI_SECURITY_ARCH_PROTOCOL *this,
+static EFIAPI EFI_STATUS security_hook(
+ const SecurityOverride *this,
uint32_t authentication_status,
- const EFI_DEVICE_PATH *device_path_const) {
+ const EFI_DEVICE_PATH *device_path) {
+
EFI_STATUS err;
- _cleanup_free_ char16_t *dev_path_str = NULL;
- EFI_HANDLE h;
- _cleanup_free_ char *file_buffer = NULL;
- UINTN file_size;
assert(this);
+ assert(this->hook == security_hook);
- if (!device_path_const)
- return EFI_INVALID_PARAMETER;
+ if (!device_path)
+ return this->original_security->FileAuthenticationState(
+ this->original_security, authentication_status, device_path);
- EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) device_path_const;
- err = BS->LocateDevicePath(&FileSystemProtocol, &dp, &h);
+ EFI_HANDLE device_handle;
+ EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) device_path;
+ err = BS->LocateDevicePath(&FileSystemProtocol, &dp, &device_handle);
if (err != EFI_SUCCESS)
return err;
_cleanup_(file_closep) EFI_FILE *root = NULL;
- err = open_volume(h, &root);
+ err = open_volume(device_handle, &root);
if (err != EFI_SUCCESS)
return err;
- err = device_path_to_str(dp, &dev_path_str);
+ _cleanup_free_ char16_t *dp_str = NULL;
+ err = device_path_to_str(dp, &dp_str);
if (err != EFI_SUCCESS)
return err;
- err = file_read(root, dev_path_str, 0, 0, &file_buffer, &file_size);
+ char *file_buffer;
+ size_t file_size;
+ err = file_read(root, dp_str, 0, 0, &file_buffer, &file_size);
if (err != EFI_SUCCESS)
return err;
if (shim_validate(file_buffer, file_size))
return EFI_SUCCESS;
- /* Try using the platform's native policy.... */
- return esfas(this, authentication_status, device_path_const);
+ return this->original_security->FileAuthenticationState(
+ this->original_security, authentication_status, device_path);
}
-EFI_STATUS security_policy_install(void) {
- EFI_SECURITY_ARCH_PROTOCOL *security_protocol;
- EFI_SECURITY2_ARCH_PROTOCOL *security2_protocol = NULL;
- EFI_STATUS err;
+EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image) {
+ assert(device_path);
+ assert(ret_image);
- /* Already Installed */
- if (esfas)
- return EFI_ALREADY_STARTED;
+ bool have_shim = shim_loaded();
- /*
- * Don't bother with status here. The call is allowed
- * to fail, since SECURITY2 was introduced in PI 1.2.1.
- * Use security2_protocol == NULL as indicator.
- */
- BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID, NULL, (void **) &security2_protocol);
+ SecurityOverride security_override = {
+ .hook = security_hook,
+ }, security2_override = {
+ .hook = security2_hook,
+ };
- err = BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID, NULL, (void**) &security_protocol);
- /* This one is mandatory, so there's a serious problem */
- if (err != EFI_SUCCESS)
- return err;
+ if (have_shim)
+ install_security_override(&security_override, &security2_override);
- esfas = security_protocol->FileAuthenticationState;
- security_protocol->FileAuthenticationState = security_policy_authentication;
+ EFI_STATUS ret = BS->LoadImage(
+ /*BootPolicy=*/false, parent, (EFI_DEVICE_PATH *) device_path, NULL, 0, ret_image);
- if (security2_protocol) {
- es2fa = security2_protocol->FileAuthentication;
- security2_protocol->FileAuthentication = security2_policy_authentication;
- }
+ if (have_shim)
+ uninstall_security_override(&security_override, &security2_override);
- return EFI_SUCCESS;
+ return ret;
}