blob: 5da298c10a686a6dafc18fda1480e70ba7e64cbf [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Port to systemd-boot
* Copyright © 2017 Max Resch <resch.max@gmail.com>
*
* Security Policy Handling
* Copyright © 2012 <James.Bottomley@HansenPartnership.com>
* https://github.com/mjg59/efitools
*/
#include <efi.h>
#include <efilib.h>
#include "missing_efi.h"
#include "util.h"
#include "secure-boot.h"
#include "shim.h"
#if defined(__x86_64__) || defined(__i386__)
#define __sysv_abi__ __attribute__((sysv_abi))
#else
#define __sysv_abi__
#endif
struct ShimLock {
EFI_STATUS __sysv_abi__ (*shim_verify) (const void *buffer, uint32_t size);
/* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface
* see shim.c/shim.h and PeHeader.h in the github shim repo */
EFI_STATUS __sysv_abi__ (*generate_hash) (void *data, uint32_t datasize, void *context, uint8_t *sha256hash, uint8_t *sha1hash);
EFI_STATUS __sysv_abi__ (*read_header) (void *data, uint32_t datasize, void *context);
};
#define SHIM_LOCK_GUID \
{ 0x605dab50, 0xe046, 0x4300, { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } }
bool shim_loaded(void) {
struct ShimLock *shim_lock;
return BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock) == EFI_SUCCESS;
}
static bool shim_validate(
const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) {
EFI_STATUS err;
_cleanup_free_ char *file_buffer_owned = NULL;
if (!file_buffer) {
if (!device_path)
return false;
EFI_HANDLE device_handle;
EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path;
err = BS->LocateDevicePath(
MAKE_GUID_PTR(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), &file_dp, &device_handle);
if (err != EFI_SUCCESS)
return false;
_cleanup_(file_closep) EFI_FILE *root = NULL;
err = open_volume(device_handle, &root);
if (err != EFI_SUCCESS)
return false;
_cleanup_free_ char16_t *dp_str = NULL;
err = device_path_to_str(file_dp, &dp_str);
if (err != EFI_SUCCESS)
return false;
err = file_read(root, dp_str, 0, 0, &file_buffer_owned, &file_size);
if (err != EFI_SUCCESS)
return false;
file_buffer = file_buffer_owned;
}
struct ShimLock *shim_lock;
err = BS->LocateProtocol(MAKE_GUID_PTR(SHIM_LOCK), NULL, (void **) &shim_lock);
if (err != EFI_SUCCESS)
return false;
return shim_lock->shim_verify(file_buffer, file_size) == EFI_SUCCESS;
}
EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image) {
assert(device_path);
assert(ret_image);
bool have_shim = shim_loaded();
if (have_shim)
install_security_override(shim_validate, NULL);
EFI_STATUS ret = BS->LoadImage(
/*BootPolicy=*/false, parent, (EFI_DEVICE_PATH *) device_path, NULL, 0, ret_image);
if (have_shim)
uninstall_security_override();
return ret;
}