From: Jan Kiszka <
jan.k...@siemens.com>
Make sure we always roll back resource allocations and protocol
registrations on errors so that nothing is leaked and nothing could
break when running a different UEFI binary after the stub has failed.
Requires to let replace_fdt return an error rather than terminating
the stub.
kernel-stub/fdt.c | 17 ++++++++++------
kernel-stub/kernel-stub.h | 3 ++-
kernel-stub/main.c | 41 ++++++++++++++++++++++++++-------------
3 files changed, 40 insertions(+), 21 deletions(-)
diff --git a/kernel-stub/fdt.c b/kernel-stub/fdt.c
index 513aa76..b64cd7d 100644
--- a/kernel-stub/fdt.c
+++ b/kernel-stub/fdt.c
@@ -152,7 +152,7 @@ BOOLEAN match_fdt(const VOID *fdt, const CHAR8 *compatible)
return strcmpa(compatible, alt_compatible) == 0;
}
-VOID replace_fdt(const VOID *fdt)
+EFI_STATUS replace_fdt(const VOID *fdt)
{
const FDT_HEADER *header = fdt;
EFI_DT_FIXUP_PROTOCOL *protocol;
@@ -162,7 +162,8 @@ VOID replace_fdt(const VOID *fdt)
status = LibLocateProtocol(&EfiDtFixupProtocol, (VOID **)&protocol);
if (EFI_ERROR(status)) {
- error_exit(L"Did not find device tree fixup protocol", status);
+ error(L"Did not find device tree fixup protocol", status);
+ return status;
}
/* Find out which size we need */
@@ -170,13 +171,15 @@ VOID replace_fdt(const VOID *fdt)
status = protocol->Fixup(protocol, (VOID *)fdt, &size,
EFI_DT_APPLY_FIXUPS);
if (status != EFI_BUFFER_TOO_SMALL) {
- error_exit(L"Device tree fixup: unexpected error", status);
+ error(L"Device tree fixup: unexpected error", status);
+ return status;
}
fdt_buffer = AllocatePool(size);
if (!fdt_buffer) {
- error_exit(L"Error allocating device tree buffer",
- EFI_OUT_OF_RESOURCES);
+ status = EFI_OUT_OF_RESOURCES;
+ error(L"Error allocating device tree buffer", status);
+ return status;
}
CopyMem(fdt_buffer, fdt, BE32_TO_HOST(header->TotalSize));
@@ -185,6 +188,8 @@ VOID replace_fdt(const VOID *fdt)
EFI_DT_INSTALL_TABLE);
if (EFI_ERROR(status)) {
FreePool(fdt_buffer);
- error_exit(L"Device tree fixup failed", status);
+ error(L"Device tree fixup failed", status);
}
+
+ return status;
}
diff --git a/kernel-stub/kernel-stub.h b/kernel-stub/kernel-stub.h
index 4944355..c0bd542 100644
--- a/kernel-stub/kernel-stub.h
+++ b/kernel-stub/kernel-stub.h
@@ -14,11 +14,12 @@
#include <efi.h>
+VOID error(CHAR16 *message, EFI_STATUS status);
VOID __attribute__((noreturn)) error_exit(CHAR16 *message, EFI_STATUS status);
const VOID *get_fdt_compatible(VOID);
BOOLEAN match_fdt(const VOID *fdt, const CHAR8 *compatible);
-VOID replace_fdt(const VOID *fdt);
+EFI_STATUS replace_fdt(const VOID *fdt);
VOID install_initrd_loader(VOID *initrd, UINTN initrd_size);
VOID uninstall_initrd_loader(VOID);
diff --git a/kernel-stub/main.c b/kernel-stub/main.c
index 95a9593..3858b24 100644
--- a/kernel-stub/main.c
+++ b/kernel-stub/main.c
@@ -53,17 +53,22 @@ typedef struct {
static EFI_HANDLE this_image;
static EFI_LOADED_IMAGE kernel_image;
-VOID __attribute__((noreturn)) error_exit(CHAR16 *message, EFI_STATUS status)
+static VOID info(CHAR16 *message)
+{
+ Print(L"Unified kernel stub: %s\n", message);
+}
+
+VOID error(CHAR16 *message, EFI_STATUS status)
{
Print(L"Unified kernel stub: %s (%r).\n", message, status);
(VOID) BS->Stall(3 * 1000 * 1000);
- (VOID) BS->Exit(this_image, status, 0, NULL);
- __builtin_unreachable();
}
-static VOID info(CHAR16 *message)
+VOID __attribute__((noreturn)) error_exit(CHAR16 *message, EFI_STATUS status)
{
- Print(L"Unified kernel stub: %s\n", message);
+ error(message, status);
+ (VOID) BS->Exit(this_image, status, 0, NULL);
+ __builtin_unreachable();
}
static const PE_HEADER *get_pe_header(const VOID *image)
@@ -93,7 +98,7 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
EFI_LOADED_IMAGE *stub_image;
const PE_HEADER *pe_header;
const SECTION *section;
- EFI_STATUS status, kernel_status;
+ EFI_STATUS status, cleanup_status;
UINTN n;
this_image = image_handle;
@@ -161,12 +166,15 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
&kernel_handle, &LoadedImageProtocol, &kernel_image,
NULL);
if (EFI_ERROR(status)) {
- uninstall_initrd_loader();
- error_exit(L"Error registering kernel image", status);
+ error(L"Error registering kernel image", status);
+ goto cleanup_initrd;
}
if (alt_fdt) {
- replace_fdt(alt_fdt);
+ status = replace_fdt(alt_fdt);
+ if (EFI_ERROR(status)) {
+ goto cleanup_protocols;
+ }
info(L"Using matched embedded device tree");
} else if (fdt_compatible) {
if (has_dtbs) {
@@ -180,15 +188,20 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
((UINT8 *) kernel_image.ImageBase +
pe_header->Opt.AddressOfEntryPoint);
- kernel_status = kernel_entry(kernel_handle, system_table);
+ status = kernel_entry(kernel_handle, system_table);
- status = BS->UninstallMultipleProtocolInterfaces(
+cleanup_protocols:
+ cleanup_status = BS->UninstallMultipleProtocolInterfaces(
kernel_handle, &LoadedImageProtocol, &kernel_image,
NULL);
- if (EFI_ERROR(status)) {
- error_exit(L"Error unregistering kernel image", status);
+ if (EFI_ERROR(cleanup_status)) {
+ error(L"Error unregistering kernel image", status);
+ if (!EFI_ERROR(status)) {
+ status = cleanup_status;
+ }
}
+cleanup_initrd:
uninstall_initrd_loader();
- return kernel_status;
+ return status;
}
--
2.35.3