summaryrefslogtreecommitdiff
path: root/loader-proto.c
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2025-07-06 21:59:18 +0200
committerChristian Breunig <christian@breunig.cc>2025-07-06 21:59:18 +0200
commit02acad285c74015e8120ade2b41d51b39ae66b63 (patch)
tree980533ac963ac23bc9e090e3e4212bdb9e225a05 /loader-proto.c
parent1c1d50da810e6c49e804a74719c2675b88b033a6 (diff)
parent18d98bfb34be583a5fe2987542e4b15e0db9cb61 (diff)
downloadefi-boot-shim-02acad285c74015e8120ade2b41d51b39ae66b63.tar.gz
efi-boot-shim-02acad285c74015e8120ade2b41d51b39ae66b63.zip
Merge tag '16.0' into vyos/current
shim-16.0 What's Changed * Validate that a supplied vendor cert is not in PEM format by @steve-mcintyre in https://github.com/rhboot/shim/pull/646 * sbat: Add grub.peimage,2 to latest (CVE-2024-2312) by @julian-klode in https://github.com/rhboot/shim/pull/651 * sbat: Also bump latest for grub,4 (and to todays date) by @julian-klode in https://github.com/rhboot/shim/pull/653 * undo change that limits certificate files to a single file by @jsetje in https://github.com/rhboot/shim/pull/659 * shim: don't set second_stage to the empty string by @jjd27 in https://github.com/rhboot/shim/pull/640 * Fix SBAT.md for today's consensus about numbers by @aronowski in https://github.com/rhboot/shim/pull/672 * Update Code of Conduct contact address by @aronowski in https://github.com/rhboot/shim/pull/683 * make-certs: Handle missing OpenSSL installation by @aronowski in https://github.com/rhboot/shim/pull/595 * Update MokVars.txt by @mikebeaton in https://github.com/rhboot/shim/pull/598 * export DEFINES for sub makefile by @bryteise in https://github.com/rhboot/shim/pull/600 * Drop unused EFI_IMAGE_SECURITY_DATABASE_GUID definition by @vittyvk in https://github.com/rhboot/shim/pull/609 * Null-terminate 'arguments' in fallback by @vittyvk in https://github.com/rhboot/shim/pull/611 * Fix "Verifiying" typo in error message by @chrisbainbridge in https://github.com/rhboot/shim/pull/706 * Update Fedora CI targets by @vathpela in https://github.com/rhboot/shim/pull/708 * Force gcc to produce DWARF4 so that gdb can use it by @mikebeaton in https://github.com/rhboot/shim/pull/607 * Minor housekeeping 2024121700 by @vathpela in https://github.com/rhboot/shim/pull/709 * Discard load-options that start with WINDOWS by @Metabolix in https://github.com/rhboot/shim/pull/621 * Fix the issue that the gBS->LoadImage pointer was empty. by @15058718379 in https://github.com/rhboot/shim/pull/703 * shim: Allow data after the end of device path node in load options by @dbnicholson in https://github.com/rhboot/shim/pull/694 * Handle network file not found like disks by @dbnicholson in https://github.com/rhboot/shim/pull/695 * Update gnu-efi submodule for EFI_HTTP_ERROR by @vathpela in https://github.com/rhboot/shim/pull/674 * Increase EFI file alignment by @lumag in https://github.com/rhboot/shim/pull/673 * avoid EFIv2 runtime services on Apple x86 machines by @eduardacatrinei in https://github.com/rhboot/shim/pull/690 * Improve shortcut performance when comparing two boolean expressions by @dennis-tseng99 in https://github.com/rhboot/shim/pull/667 * Provide better error message when MokManager is not found by @rmetrich in https://github.com/rhboot/shim/pull/663 * tpm: Boot with a warning if the event log is full by @kukrimate in https://github.com/rhboot/shim/pull/657 * MokManager: remove redundant logical constraints by @xypron in https://github.com/rhboot/shim/pull/409 * Test import_mok_state() when MokListRT would be bigger than available size by @vathpela in https://github.com/rhboot/shim/pull/417 * test-mok-mirror: minor bug fix by @vathpela in https://github.com/rhboot/shim/pull/715 * Fix file system browser hang when enrolling MOK from disk by @miczyg1 in https://github.com/rhboot/shim/pull/622 * Ignore a minor clang-tidy nit by @vathpela in https://github.com/rhboot/shim/pull/716 * Allow fallback to default loader when encountering errors on network boot by @nathan-omeara in https://github.com/rhboot/shim/pull/666 * test.mk: don't use a temporary random.bin by @vathpela in https://github.com/rhboot/shim/pull/718 * pe: Enhance debug report for update_mem_attrs by @jongwu in https://github.com/rhboot/shim/pull/594 * Multiple certificate handling improvements by @rosslagerwall in https://github.com/rhboot/shim/pull/644 * Generate SbatLevel Metadata from SbatLevel_Variable.txt by @jsetje in https://github.com/rhboot/shim/pull/711 * Apply EKU check with compile option by @dennis-tseng99 in https://github.com/rhboot/shim/pull/664 * Add configuration option to boot an alternative 2nd stage by @esnowberg in https://github.com/rhboot/shim/pull/608 * Loader protocol (with Device Path resolution support) by @kukrimate in https://github.com/rhboot/shim/pull/656 * netboot cleanup for additional files by @jsetje in https://github.com/rhboot/shim/pull/686 * Document how revocations can be delivered by @jsetje in https://github.com/rhboot/shim/pull/722 * post-process-pe: add tests to validate NX compliance by @vathpela in https://github.com/rhboot/shim/pull/705 * regression: CopyMem() in ad8692e copies out of bounds by @jsetje in https://github.com/rhboot/shim/pull/725 * Save the debug and error logs in mok-variables by @vathpela in https://github.com/rhboot/shim/pull/726 * Add features for the Host Security ID program by @vathpela in https://github.com/rhboot/shim/pull/660 * Mirror some more efi variables to mok-variables by @vathpela in https://github.com/rhboot/shim/pull/723 * This adds DXE Services measurements to HSI and uses them for NX by @vathpela in https://github.com/rhboot/shim/pull/724 * Add shim's current NX_COMPAT status to HSIStatus by @vathpela in https://github.com/rhboot/shim/pull/727 * README.tpm: reflect that vendor_db is in fact logged as "vendor_db" by @jsetje in https://github.com/rhboot/shim/pull/728 * Reject HTTP message with duplicate Content-Length header fields by @dennis-tseng99 in https://github.com/rhboot/shim/pull/637 * Disable log saving by @vathpela in https://github.com/rhboot/shim/pull/729 * fallback: don't add new boot order entries backwards by @vathpela in https://github.com/rhboot/shim/pull/730 * Misc fixes... by @vathpela in https://github.com/rhboot/shim/pull/735 * README.tpm: Update MokList entry to MokListRT by @trungams in https://github.com/rhboot/shim/pull/732 * SBAT Level update for February 2025 GRUB CVEs by @jsetje in https://github.com/rhboot/shim/pull/736 New Contributors * @jjd27 made their first contribution in https://github.com/rhboot/shim/pull/640 * @mikebeaton made their first contribution in https://github.com/rhboot/shim/pull/598 * @bryteise made their first contribution in https://github.com/rhboot/shim/pull/600 * @vittyvk made their first contribution in https://github.com/rhboot/shim/pull/609 * @chrisbainbridge made their first contribution in https://github.com/rhboot/shim/pull/706 * @Metabolix made their first contribution in https://github.com/rhboot/shim/pull/621 * @15058718379 made their first contribution in https://github.com/rhboot/shim/pull/703 * @dbnicholson made their first contribution in https://github.com/rhboot/shim/pull/694 * @lumag made their first contribution in https://github.com/rhboot/shim/pull/673 * @eduardacatrinei made their first contribution in https://github.com/rhboot/shim/pull/690 * @kukrimate made their first contribution in https://github.com/rhboot/shim/pull/657 * @miczyg1 made their first contribution in https://github.com/rhboot/shim/pull/622 * @nathan-omeara made their first contribution in https://github.com/rhboot/shim/pull/666 * @jongwu made their first contribution in https://github.com/rhboot/shim/pull/594 * @rosslagerwall made their first contribution in https://github.com/rhboot/shim/pull/644 * @trungams made their first contribution in https://github.com/rhboot/shim/pull/732 **Full Changelog**: https://github.com/rhboot/shim/compare/15.8...16.0 * tag '16.0': (451 commits) Update version to 16.0 SBAT Level update for February 2025 GRUB CVEs README.tpm: Update MokList entry to MokListRT Make 'make fanalyzer' work again. simple_dir_filter(): test our 'next' pointer shim_load_image(): initialize the buffer fully mirror_mok_db(): Free our mok variable name correctly mirror_one_mok_variable(): fix a memory leak on TPM log error. mirror_mok_db(): get rid of an unused variable+allocation generate_sbat_var_defs: Ensure revlistentry->revocations is initialized. generate_sbat_var_defs: Fix memory leak on realloc failure and fd leak. generate_sbat_var_defs: run clang-format on readfile() SetSecureVariable(): free Cert on failure Update version to 16.0~rc1 make-archive: some minor housekeeping makefiles: Make GITTAG swizzle tildes to dashes fallback: don't add new boot order entries backwards Disable log saving for now. Some save_logs() improvements. reject message with different values in multiple Content-Length header field ...
Diffstat (limited to 'loader-proto.c')
-rw-r--r--loader-proto.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/loader-proto.c b/loader-proto.c
new file mode 100644
index 00000000..4581664b
--- /dev/null
+++ b/loader-proto.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * loader-proto.c - shim's loader protocol
+ *
+ * Copyright Red Hat, Inc
+ * Copyright Canonical, Ltd
+ */
+
+#include "shim.h"
+
+static EFI_SYSTEM_TABLE *systab;
+
+EFI_SYSTEM_TABLE *
+get_active_systab(void)
+{
+ if (systab)
+ return systab;
+ return ST;
+}
+
+static typeof(systab->BootServices->LoadImage) system_load_image;
+static typeof(systab->BootServices->StartImage) system_start_image;
+static typeof(systab->BootServices->UnloadImage) system_unload_image;
+static typeof(systab->BootServices->Exit) system_exit;
+
+void
+unhook_system_services(void)
+{
+ if (!systab)
+ return;
+
+ systab->BootServices->LoadImage = system_load_image;
+ systab->BootServices->StartImage = system_start_image;
+ systab->BootServices->Exit = system_exit;
+ systab->BootServices->UnloadImage = system_unload_image;
+ BS = systab->BootServices;
+}
+
+typedef struct {
+ EFI_HANDLE hnd;
+ EFI_DEVICE_PATH *dp;
+ void *buffer;
+ size_t size;
+} buffer_properties_t;
+
+static EFI_STATUS
+try_load_from_sfs(EFI_DEVICE_PATH *dp, buffer_properties_t *bprop)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *sfs = NULL;
+ EFI_FILE_HANDLE root = NULL;
+ EFI_FILE_HANDLE file = NULL;
+ UINT64 tmpsz = 0;
+
+ bprop->buffer = NULL;
+
+ /* look for a handle with SFS support from the input DP */
+ bprop->dp = dp;
+ status = BS->LocateDevicePath(&EFI_SIMPLE_FILE_SYSTEM_GUID, &bprop->dp, &bprop->hnd);
+ if (EFI_ERROR(status)) {
+ goto out;
+ }
+
+ /* make sure the remaining DP portion is really a file path */
+ if (DevicePathType(bprop->dp) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType(bprop->dp) != MEDIA_FILEPATH_DP) {
+ status = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ /* find protocol, open the root directory, then open file */
+ status = BS->HandleProtocol(bprop->hnd, &EFI_SIMPLE_FILE_SYSTEM_GUID, (void **)&sfs);
+ if (EFI_ERROR(status))
+ goto out;
+ status = sfs->OpenVolume(sfs, &root);
+ if (EFI_ERROR(status))
+ goto out;
+ status = root->Open(root, &file, ((FILEPATH_DEVICE_PATH *) bprop->dp)->PathName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* get file size */
+ status = file->SetPosition(file, -1ULL);
+ if (EFI_ERROR(status))
+ goto out;
+ status = file->GetPosition(file, &tmpsz);
+ if (EFI_ERROR(status))
+ goto out;
+ bprop->size = (size_t)tmpsz;
+ status = file->SetPosition(file, 0);
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* allocate buffer */
+ bprop->buffer = AllocatePool(bprop->size);
+ if (bprop->buffer == NULL) {
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ /* read file */
+ status = file->Read(file, &bprop->size, bprop->buffer);
+
+out:
+ if (EFI_ERROR(status) && bprop->buffer)
+ FreePool(bprop->buffer);
+ if (file)
+ file->Close(file);
+ if (root)
+ root->Close(root);
+ return status;
+}
+
+
+static EFI_STATUS
+try_load_from_lf2(EFI_DEVICE_PATH *dp, buffer_properties_t *bprop)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ EFI_LOAD_FILE2_PROTOCOL *lf2 = NULL;
+
+ bprop->buffer = NULL;
+
+ /* look for a handle with LF2 support from the input DP */
+ bprop->dp = dp;
+ status = BS->LocateDevicePath(&gEfiLoadFile2ProtocolGuid, &bprop->dp, &bprop->hnd);
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* find protocol */
+ status = BS->HandleProtocol(bprop->hnd, &gEfiLoadFile2ProtocolGuid, (void **) &lf2);
+ if (EFI_ERROR(status))
+ goto out;
+
+ /* get file size */
+ bprop->size = 0; /* this shouldn't be read when Buffer=NULL but better be safe */
+ status = lf2->LoadFile(lf2, bprop->dp, /*BootPolicy=*/false, &bprop->size, NULL);
+ /*
+ * NOTE: the spec is somewhat ambiguous what is the correct return
+ * status code when asking for the buffer size with Buffer=NULL. I am
+ * assuming EFI_SUCCESS and EFI_BUFFER_TOO_SMALL are the only
+ * reasonable interpretations.
+ */
+ if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL) {
+ status = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ /* allocate buffer */
+ bprop->buffer = AllocatePool(bprop->size);
+ if (!bprop->buffer) {
+ status = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ /* read file */
+ status = lf2->LoadFile(lf2, bprop->dp, /*BootPolicy=*/false, &bprop->size, bprop->buffer);
+ if (EFI_ERROR(status))
+ goto out;
+
+out:
+ if (EFI_ERROR(status) && bprop->buffer)
+ FreePool(bprop->buffer);
+ return status;
+}
+
+static EFI_STATUS EFIAPI
+shim_load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
+ EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
+ UINTN SourceSize, EFI_HANDLE *ImageHandle)
+{
+ SHIM_LOADED_IMAGE *image;
+ EFI_STATUS efi_status;
+ buffer_properties_t bprop = { NULL, NULL, NULL, 0 };
+
+ if (BootPolicy)
+ return EFI_UNSUPPORTED;
+
+ if (!SourceBuffer || !SourceSize) {
+ if (!DevicePath) /* Both SourceBuffer and DevicePath are NULL */
+ return EFI_NOT_FOUND;
+
+ if (try_load_from_sfs(DevicePath, &bprop) == EFI_SUCCESS)
+ ;
+ else if (try_load_from_lf2(DevicePath, &bprop) == EFI_SUCCESS)
+ ;
+ else
+ /* no buffer given and we cannot load from this device */
+ return EFI_LOAD_ERROR;
+
+ SourceBuffer = bprop.buffer;
+ SourceSize = bprop.size;
+ } else {
+ bprop.buffer = NULL;
+ /*
+ * Even if we are using a buffer, try populating the
+ * device_handle and file_path fields the best we can
+ */
+
+ bprop.dp = DevicePath;
+
+ if (bprop.dp) {
+ efi_status = BS->LocateDevicePath(&gEfiDevicePathProtocolGuid,
+ &bprop.dp,
+ &bprop.hnd);
+ if (efi_status != EFI_SUCCESS) {
+ /* can't seem to pull apart this DP */
+ bprop.dp = DevicePath;
+ bprop.hnd = NULL;
+ }
+ }
+ }
+
+ image = AllocatePool(sizeof(*image));
+ if (!image) {
+ efi_status = EFI_OUT_OF_RESOURCES;
+ goto free_buffer;
+ }
+
+ SetMem(image, sizeof(*image), 0);
+
+ image->li.Revision = 0x1000;
+ image->li.ParentHandle = ParentImageHandle;
+ image->li.SystemTable = systab;
+ image->li.DeviceHandle = bprop.hnd;
+ if (bprop.dp) {
+ image->li.FilePath = DuplicateDevicePath(bprop.dp);
+ if (!image->li.FilePath) {
+ efi_status = EFI_OUT_OF_RESOURCES;
+ goto free_image;
+ }
+ }
+ if (DevicePath) {
+ image->loaded_image_device_path = DuplicateDevicePath(DevicePath);
+ if (!image->loaded_image_device_path) {
+ efi_status = EFI_OUT_OF_RESOURCES;
+ goto free_image;
+ }
+ }
+
+ in_protocol = 1;
+ efi_status = handle_image(SourceBuffer, SourceSize, &image->li,
+ &image->entry_point, &image->alloc_address,
+ &image->alloc_pages);
+ in_protocol = 0;
+ if (EFI_ERROR(efi_status))
+ goto free_image;
+
+ *ImageHandle = NULL;
+ efi_status = BS->InstallMultipleProtocolInterfaces(ImageHandle,
+ &SHIM_LOADED_IMAGE_GUID, image,
+ &EFI_LOADED_IMAGE_GUID, &image->li,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ image->loaded_image_device_path,
+ NULL);
+ if (EFI_ERROR(efi_status))
+ goto free_alloc;
+
+ if (bprop.buffer)
+ FreePool(bprop.buffer);
+
+ return EFI_SUCCESS;
+
+free_alloc:
+ BS->FreePages(image->alloc_address, image->alloc_pages);
+free_image:
+ if (image->loaded_image_device_path)
+ FreePool(image->loaded_image_device_path);
+ if (image->li.FilePath)
+ FreePool(image->li.FilePath);
+ FreePool(image);
+free_buffer:
+ if (bprop.buffer)
+ FreePool(bprop.buffer);
+ return efi_status;
+}
+
+static EFI_STATUS EFIAPI
+shim_start_image(IN EFI_HANDLE ImageHandle, OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL)
+{
+ SHIM_LOADED_IMAGE *image;
+ EFI_STATUS efi_status;
+
+ efi_status = BS->HandleProtocol(ImageHandle, &SHIM_LOADED_IMAGE_GUID,
+ (void **)&image);
+
+ /*
+ * This image didn't come from shim_load_image(), so it must have come
+ * from something before shim was involved.
+ */
+ if (efi_status == EFI_UNSUPPORTED)
+ return system_start_image(ImageHandle, ExitDataSize, ExitData);
+
+ if (EFI_ERROR(efi_status) || image->started)
+ return EFI_INVALID_PARAMETER;
+
+ if (!setjmp(image->longjmp_buf)) {
+ image->started = true;
+ efi_status =
+ image->entry_point(ImageHandle, image->li.SystemTable);
+ } else {
+ if (ExitData) {
+ *ExitDataSize = image->exit_data_size;
+ *ExitData = (CHAR16 *)image->exit_data;
+ }
+ efi_status = image->exit_status;
+ }
+
+ //
+ // We only support EFI applications, so we can unload and free the
+ // image unconditionally.
+ //
+ BS->UninstallMultipleProtocolInterfaces(ImageHandle,
+ &EFI_LOADED_IMAGE_GUID, image,
+ &SHIM_LOADED_IMAGE_GUID, &image->li,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ image->loaded_image_device_path,
+ NULL);
+
+ BS->FreePages(image->alloc_address, image->alloc_pages);
+ if (image->li.FilePath)
+ BS->FreePool(image->li.FilePath);
+ if (image->loaded_image_device_path)
+ BS->FreePool(image->loaded_image_device_path);
+ FreePool(image);
+
+ return efi_status;
+}
+
+static EFI_STATUS EFIAPI
+shim_unload_image(EFI_HANDLE ImageHandle)
+{
+ SHIM_LOADED_IMAGE *image;
+ EFI_STATUS efi_status;
+
+ efi_status = BS->HandleProtocol(ImageHandle, &SHIM_LOADED_IMAGE_GUID,
+ (void **)&image);
+
+ if (efi_status == EFI_UNSUPPORTED)
+ return system_unload_image(ImageHandle);
+
+ BS->FreePages(image->alloc_address, image->alloc_pages);
+ FreePool(image);
+
+ return EFI_SUCCESS;
+}
+
+static EFI_STATUS EFIAPI
+shim_exit(EFI_HANDLE ImageHandle,
+ EFI_STATUS ExitStatus,
+ UINTN ExitDataSize,
+ CHAR16 *ExitData)
+{
+ EFI_STATUS efi_status;
+ SHIM_LOADED_IMAGE *image;
+
+ efi_status = BS->HandleProtocol(ImageHandle, &SHIM_LOADED_IMAGE_GUID,
+ (void **)&image);
+
+ /*
+ * If this happens, something above us on the stack of running
+ * applications called Exit(), and we're getting aborted along with
+ * it.
+ */
+ if (efi_status == EFI_UNSUPPORTED) {
+ shim_fini();
+ return system_exit(ImageHandle, ExitStatus, ExitDataSize,
+ ExitData);
+ }
+
+ if (EFI_ERROR(efi_status))
+ return efi_status;
+
+ image->exit_status = ExitStatus;
+ image->exit_data_size = ExitDataSize;
+ image->exit_data = ExitData;
+
+ longjmp(image->longjmp_buf, 1);
+}
+
+void
+init_image_loader(void)
+{
+ shim_image_loader_interface.LoadImage = shim_load_image;
+ shim_image_loader_interface.StartImage = shim_start_image;
+ shim_image_loader_interface.Exit = shim_exit;
+ shim_image_loader_interface.UnloadImage = shim_unload_image;
+}
+
+void
+hook_system_services(EFI_SYSTEM_TABLE *local_systab)
+{
+ systab = local_systab;
+ BS = systab->BootServices;
+
+ /* We need to hook various calls to make this work... */
+
+ /*
+ * We need LoadImage() hooked so that we can guarantee everything is
+ * verified.
+ */
+ system_load_image = systab->BootServices->LoadImage;
+ systab->BootServices->LoadImage = shim_load_image;
+
+ /*
+ * We need StartImage() hooked because the system's StartImage()
+ * doesn't know about our structure layout.
+ */
+ system_start_image = systab->BootServices->StartImage;
+ systab->BootServices->StartImage = shim_start_image;
+
+ /*
+ * We need Exit() hooked so that we make sure to use the right jmp_buf
+ * when an application calls Exit(), but that happens in a separate
+ * function.
+ */
+
+ /*
+ * We need UnloadImage() to match our LoadImage()
+ */
+ system_unload_image = systab->BootServices->UnloadImage;
+ systab->BootServices->UnloadImage = shim_unload_image;
+}
+
+void
+unhook_exit(void)
+{
+ systab->BootServices->Exit = system_exit;
+ BS = systab->BootServices;
+}
+
+void
+hook_exit(EFI_SYSTEM_TABLE *local_systab)
+{
+ systab = local_systab;
+ BS = local_systab->BootServices;
+
+ /*
+ * We need to hook Exit() so that we can allow users to quit the
+ * bootloader and still e.g. start a new one or run an internal
+ * shell.
+ */
+ system_exit = systab->BootServices->Exit;
+ systab->BootServices->Exit = shim_exit;
+}