stub: Allow loading unsigned kernel images
This commit is contained in:
+55
-2
@@ -14,17 +14,50 @@
|
||||
#include "initrd.h"
|
||||
#include "linux.h"
|
||||
#include "pe.h"
|
||||
#include "secure-boot.h"
|
||||
#include "util.h"
|
||||
|
||||
#define STUB_PAYLOAD_GUID \
|
||||
{ 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } }
|
||||
|
||||
static EFIAPI EFI_STATUS security_hook(
|
||||
const SecurityOverride *this, uint32_t authentication_status, const EFI_DEVICE_PATH *file) {
|
||||
|
||||
assert(this);
|
||||
assert(this->hook == security_hook);
|
||||
|
||||
if (file == this->payload_device_path)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
return this->original_security->FileAuthenticationState(
|
||||
this->original_security, authentication_status, file);
|
||||
}
|
||||
|
||||
static EFIAPI EFI_STATUS security2_hook(
|
||||
const SecurityOverride *this,
|
||||
const EFI_DEVICE_PATH *device_path,
|
||||
void *file_buffer,
|
||||
size_t file_size,
|
||||
BOOLEAN boot_policy) {
|
||||
|
||||
assert(this);
|
||||
assert(this->hook == security2_hook);
|
||||
|
||||
if (file_buffer == this->payload && file_size == this->payload_len &&
|
||||
device_path == this->payload_device_path)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
return this->original_security2->FileAuthentication(
|
||||
this->original_security2, device_path, file_buffer, file_size, boot_policy);
|
||||
}
|
||||
|
||||
EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HANDLE *ret_image) {
|
||||
assert(parent);
|
||||
assert(source);
|
||||
assert(ret_image);
|
||||
|
||||
/* We could pass a NULL device path, but it's nicer to provide something. */
|
||||
/* We could pass a NULL device path, but it's nicer to provide something and it allows us to identify
|
||||
* the loaded image from within the security hooks. */
|
||||
struct {
|
||||
VENDOR_DEVICE_PATH payload;
|
||||
EFI_DEVICE_PATH end;
|
||||
@@ -44,13 +77,33 @@ EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HAN
|
||||
},
|
||||
};
|
||||
|
||||
return BS->LoadImage(
|
||||
/* We want to support unsigned kernel images as payload, which is safe to do under secure boot
|
||||
* because it is embedded in this stub loader (and since it is already running it must be trusted). */
|
||||
SecurityOverride security_override = {
|
||||
.hook = security_hook,
|
||||
.payload = source,
|
||||
.payload_len = len,
|
||||
.payload_device_path = &payload_device_path.payload.Header,
|
||||
}, security2_override = {
|
||||
.hook = security2_hook,
|
||||
.payload = source,
|
||||
.payload_len = len,
|
||||
.payload_device_path = &payload_device_path.payload.Header,
|
||||
};
|
||||
|
||||
install_security_override(&security_override, &security2_override);
|
||||
|
||||
EFI_STATUS ret = BS->LoadImage(
|
||||
/*BootPolicy=*/false,
|
||||
parent,
|
||||
&payload_device_path.payload.Header,
|
||||
(void *) source,
|
||||
len,
|
||||
ret_image);
|
||||
|
||||
uninstall_security_override(&security_override, &security2_override);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EFI_STATUS linux_exec(
|
||||
|
||||
@@ -126,3 +126,70 @@ out_deallocate:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static EFI_STATUS install_security_override_one(EFI_GUID guid, SecurityOverride *override) {
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(override);
|
||||
|
||||
_cleanup_free_ EFI_HANDLE *handles = NULL;
|
||||
size_t n_handles = 0;
|
||||
|
||||
err = BS->LocateHandleBuffer(ByProtocol, &guid, NULL, &n_handles, &handles);
|
||||
if (err != EFI_SUCCESS)
|
||||
/* No security arch protocol around? */
|
||||
return err;
|
||||
|
||||
/* There should only ever be one security arch protocol instance, but let's be paranoid here. */
|
||||
assert(n_handles == 1);
|
||||
|
||||
void *security = NULL;
|
||||
err = BS->LocateProtocol(&guid, NULL, &security);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Error getting security arch protocol: %r", err);
|
||||
|
||||
err = BS->ReinstallProtocolInterface(handles[0], &guid, security, override);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Error overriding security arch protocol: %r", err);
|
||||
|
||||
override->original = security;
|
||||
override->original_handle = handles[0];
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* This replaces the platform provided security arch protocols (defined in the UEFI Platform Initialization
|
||||
* Specification) with the provided override instances. If not running in secure boot or the protocols are
|
||||
* not available nothing happens. The override instances are provided with the neccessary info to undo this
|
||||
* in uninstall_security_override(). */
|
||||
void install_security_override(SecurityOverride *override, SecurityOverride *override2) {
|
||||
assert(override);
|
||||
assert(override2);
|
||||
|
||||
if (!secure_boot_enabled())
|
||||
return;
|
||||
|
||||
(void) install_security_override_one((EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID, override);
|
||||
(void) install_security_override_one((EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID, override2);
|
||||
}
|
||||
|
||||
void uninstall_security_override(SecurityOverride *override, SecurityOverride *override2) {
|
||||
assert(override);
|
||||
assert(override2);
|
||||
|
||||
/* We use assert_se here to guarantee the system is not in a weird state in the unlikely case of an
|
||||
* error restoring the original protocols. */
|
||||
|
||||
if (override->original_handle)
|
||||
assert_se(BS->ReinstallProtocolInterface(
|
||||
override->original_handle,
|
||||
&(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID,
|
||||
override,
|
||||
override->original) == EFI_SUCCESS);
|
||||
|
||||
if (override2->original_handle)
|
||||
assert_se(BS->ReinstallProtocolInterface(
|
||||
override2->original_handle,
|
||||
&(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID,
|
||||
override2,
|
||||
override2->original) == EFI_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
#include "efivars-fundamental.h"
|
||||
#include "missing_efi.h"
|
||||
|
||||
typedef enum {
|
||||
ENROLL_OFF, /* no Secure Boot key enrollment whatsoever, even manual entries are not generated */
|
||||
@@ -14,3 +16,24 @@ bool secure_boot_enabled(void);
|
||||
SecureBootMode secure_boot_mode(void);
|
||||
|
||||
EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path);
|
||||
|
||||
typedef struct {
|
||||
void *hook;
|
||||
|
||||
/* End of EFI_SECURITY_ARCH(2)_PROTOCOL. The rest is our own protocol instance data. */
|
||||
|
||||
EFI_HANDLE original_handle;
|
||||
union {
|
||||
void *original;
|
||||
EFI_SECURITY_ARCH_PROTOCOL *original_security;
|
||||
EFI_SECURITY2_ARCH_PROTOCOL *original_security2;
|
||||
};
|
||||
|
||||
/* Used by the stub to identify the embedded image. */
|
||||
const void *payload;
|
||||
size_t payload_len;
|
||||
const EFI_DEVICE_PATH *payload_device_path;
|
||||
} SecurityOverride;
|
||||
|
||||
void install_security_override(SecurityOverride *override, SecurityOverride *override2);
|
||||
void uninstall_security_override(SecurityOverride *override, SecurityOverride *override2);
|
||||
|
||||
Reference in New Issue
Block a user