From: Jan Kiszka <[email protected]>

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.

Signed-off-by: Jan Kiszka <[email protected]>
---
 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

-- 
You received this message because you are subscribed to the Google Groups "EFI 
Boot Guard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/efibootguard-dev/5d756ee460a94269b0ca8a4f5b786a255c1715b1.1657110125.git.jan.kiszka%40siemens.com.

Reply via email to