From a0bab7e95672ae7438f7fdb806b9b167a5b04e07 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Fri, 28 Dec 2012 11:01:18 -0500 Subject: [PATCH] Changes related to new shim/MOK code. --- BUILDING.txt | 45 ++++++------ Make.common | 10 +-- Make.tiano | 3 +- Makefile | 4 ++ NEWS.txt | 13 +++- docs/refind/configfile.html | 12 ++-- libeg/screen.c | 26 ++++--- mkdistrib | 2 +- refind/Make.tiano | 8 +-- refind/Makefile | 10 +-- refind/lib.c | 30 ++++---- refind/lib.h | 2 +- refind/main.c | 133 ++++++++++++++++++++---------------- 13 files changed, 171 insertions(+), 127 deletions(-) diff --git a/BUILDING.txt b/BUILDING.txt index b69df9b..fb93136 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -15,9 +15,10 @@ rEFIt package (http://packages.debian.org/sid/refit) that includes extensive patches to enable the program to compile under Linux using the GNU-EFI package (http://sourceforge.net/projects/gnu-efi/). Although GNU-EFI is less sophisticated than recent versions of TianoCore's toolkit, -GNU-EFI is my preferred environment because it's provided with many Linux -distributions and it was easy to get started with rEFInd development by -using GNU-EFI and the Debian rEFIt package as a starting point. +GNU-EFI was initially my preferred environment because it's provided with +many Linux distributions and it was easy to get started with rEFInd +development by using GNU-EFI and the Debian rEFIt package as a starting +point. Over time, though, I've found that the recent TianoCore EDK2 toolkit has its advantages. Two features, in particular, require the TianoCore EDK2 @@ -73,13 +74,17 @@ To compile rEFInd, you'll need the following: install this from a package called "gnu-efi"; however, rEFInd relies on features that were added in (I think) 3.0l to provide driver-loading capabilities. The versions I've used and that work are 3.0p and 3.0q. - As of 5/2012, most Linux distributions seem to deliver rather elderly - versions of GNU-EFI, so you may need to download the latest source - code, compile it, and install it locally. Since rEFInd version 0.2.7, - the Makefiles assume this (see below). The legacy BIOS boot support on - UEFI-based PCs doesn't work when GNU-EFI is compiled under GNU-EFI, so - as of rEFInd 0.4.6, GNU-EFI is no longer the primary build environment, - although it's easier to set up on a Linux system. + Through mid-to-late 2012, most Linux distributions delivered rather + elderly versions of GNU-EFI, but many are catching up by late 2012. You + should check your GNU-EFI version number; you may need to download the + latest source code, compile it, and install it locally. Between rEFInd + version 0.2.7 and 0.6.1, the Makefiles assumed a locally-compiled + GNU-EFI package, but older and more recent versions assume GNU-EFI + installation in typical locations for distribution-provided packages. + The legacy BIOS boot support on UEFI-based PCs doesn't work when + GNU-EFI is compiled under GNU-EFI, so as of rEFInd 0.4.6, GNU-EFI is no + longer the primary build environment, although it's easier to set up on + a Linux system. It's possible to use a non-Linux platform to compile rEFInd. To the best of my knowledge, the rEFInd code doesn't rely on anything Linux-specific in @@ -232,19 +237,19 @@ You may also need to adjust the Makefile, Make.common file, or Make.tiano file for your system. (The main Makefile controls the process for both toolkits, while Make.common holds GNU-EFI options and Make.tiano holds TianoCore options.) The most likely thing you'll need to change is the path -to the various GNU-EFI include files and libraries. Since rEFInd 0.2.7, the +to the various GNU-EFI include files and libraries. Since rEFInd 0.6.2, the default Make.common file includes the following definitions: -EFIINC = /usr/local/include/efi -GNUEFILIB = /usr/local/lib -EFILIB = /usr/local/lib -EFICRT0 = /usr/local/lib +EFIINC = /usr/include/efi +GNUEFILIB = /usr/lib +EFILIB = /usr/lib +EFICRT0 = /usr/lib -If you've installed GNU-EFI from a distribution's package, you may need to -remove "local" from those paths, and perhaps change references to "lib" to -"lib64". As noted earlier, though, as of 5/2012, most distributions provide -out-of-date GNU-EFI implementations that will not work with rEFInd 0.2.7 -and later. +If you've installed GNU-EFI from source code, you may need to add "local" +to those paths, as in "/usr/local/include/efi". You might need to change +references to "lib" to "lib64" on some systems. Recall that you need at +least GNU-EFI version 3.0l to build rEFInd, and until very recently, most +distributions provided out-of-date versions of this package. If you're using TianoCore's EDK2, as noted earlier, you may need to adjust the EDK2BASE variable in Make.tiano and filesystems/Make.tiano. diff --git a/Make.common b/Make.common index 405fb95..2cf75b8 100644 --- a/Make.common +++ b/Make.common @@ -3,15 +3,15 @@ # Common make rules for building with gnu-efi # -EFIINC = /usr/local/include/efi -GNUEFILIB = /usr/local/lib -EFILIB = /usr/local/lib -EFICRT0 = /usr/local/lib +EFIINC = /usr/include/efi +GNUEFILIB = /usr/lib +EFILIB = /usr/lib +EFICRT0 = /usr/lib HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) ARCH := $(HOSTARCH) OS = $(shell uname -s) -CPPFLAGS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -DCONFIG_$(ARCH) -D__MAKEWITH_GNUEFI +CPPFLAGS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I../include -I../refind -I../libeg -DCONFIG_$(ARCH) -D__MAKEWITH_GNUEFI OPTIMFLAGS = -O2 -fno-strict-aliasing DEBUGFLAGS = -Wall diff --git a/Make.tiano b/Make.tiano index c02e7ff..6884a07 100644 --- a/Make.tiano +++ b/Make.tiano @@ -42,7 +42,8 @@ INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \ -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \ -I .. \ -I ../refind \ - -I ../libeg + -I ../libeg \ + -I ../mok OPTIMFLAGS = -fno-strict-aliasing -mno-red-zone -Wno-address -Os DEBUGFLAGS = -Wall -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections diff --git a/Makefile b/Makefile index a742dc9..f78ad3d 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ HEADERS=$(NAMES:=.h) LOADER_DIR=refind FS_DIR=filesystems LIBEG_DIR=libeg +MOK_DIR=mok EFILIB_DIR=EfiLib # Build rEFInd, including libeg @@ -16,6 +17,7 @@ all: tiano gnuefi: make -C $(LIBEG_DIR) + make -C $(MOK_DIR) make -C $(LOADER_DIR) # make -C $(FS_DIR) @@ -25,10 +27,12 @@ fs: tiano: make AR_TARGET=EfiLib -C $(EFILIB_DIR) -f Make.tiano make AR_TARGET=libeg -C $(LIBEG_DIR) -f Make.tiano + make AR_TARGET=mok -C $(MOK_DIR) -f Make.tiano make BUILDME=refind DLL_TARGET=refind -C $(LOADER_DIR) -f Make.tiano clean: make -C $(LIBEG_DIR) clean + make -C $(MOK_DIR) clean make -C $(LOADER_DIR) clean make -C $(EFILIB_DIR) clean -f Make.tiano make -C $(FS_DIR) clean diff --git a/NEWS.txt b/NEWS.txt index 50ee4fb..e9c8f1e 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,17 @@ -0.6.2 (??/??/201?): +0.6.2 (12/??/2012): ------------------- +- Fixed bug that prevented Secure Boot launches from working when rEFInd + was built with GNU-EFI rather than the TianoCore EDK2. + +- Substantial reworking of Secure Boot code, based on James Bottomley's + PreLoader program. This new code eliminates the limitation of launching + just one driver in Secure Boot mode and is likely to be more reliable + with future or obscure boot loaders. The basic features are the same as + before, though -- rEFInd relies on shim for authentication functions and + will launch programs that are signed by Secure Boot keys, shim keys, or + MOKs. + - Altered default for "textmode" option to not adjust the text mode at all. (Prior versions set it to mode 0 by default.) diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html index 89fcf3b..3200ed8 100644 --- a/docs/refind/configfile.html +++ b/docs/refind/configfile.html @@ -179,7 +179,7 @@ timeout 20 textonly - None or 0 + none or 0 rEFInd defaults to a graphical mode; however, if you prefer to do without the flashy graphics, you can run it in text mode by including this option. Passing any option but 0 causes text mode to be used; passing a 0 causes graphics mode to be used. (This could be useful if you want to override a text-mode setting in an included secondary configuration file.) @@ -229,17 +229,17 @@ timeout 20 dont_scan_files or don't_scan_files - Filename(s) + filename(s) Adds the specified filename or filenames to a filename "blacklist"—these files are not included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as shim.efi and MokManager.efi) and drivers from your OS list. The default value is shim.efi, MokManager.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi. scan_all_linux_kernels - None or 0 + none or 0 When set, causes rEFInd to add Linux kernels (files with names that begin with vmlinuz or bzImage) to the list of EFI boot loaders, even if they lack .efi filename extensions. The hope is that this will simplify use of rEFInd on distributions that provide kernels with EFI stub loader support but that don't give those kernels names that end in .efi. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (Drivers and the also_scan_dirs options can help with those issues.) Note that this option can cause unwanted files to be improperly detected and given loader tags, such as older kernels without EFI stub loader support. Versions of rEFInd prior to 0.5.0 left this option commented out in the refind.conf-sample file, but as of version 0.5.0, this option is enabled in the default configuration file. The program default remains to not scan for such kernels, though, so you can delete or uncomment this option to keep them from appearing in your boot menu. Passing any option but 0 causes scans for all kernels to occur; passing a 0 causes these kernels to not be scanned. (This could be useful if you want to override a setting of scan_all_linux_kernels in an included secondary configuration file.) default_selection - A substring of a boot loader's title; or a numeric position + a substring of a boot loader's title; or a numeric position Sets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. You can enter any substring of the title as the default_selection, so long as it's two or more characters in length. It's best to use a unique substring, since rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the default_selection, the most recent loader in that directory will be the default. One-character entries are matched against the first character of the title, except for digits, which refer to the numeric order of the boot loader entries. @@ -328,7 +328,7 @@ default_selection elilo disabled - None + none Disable an entry. This is often easier than commenting out an entire entry if you want to temporarily disable it. @@ -420,7 +420,7 @@ fs0:\EFI\Microsoft\Boot\bootmgfw.efi disabled - None + none Disable a submenu entry. This is often easier than commenting out an entire entry if you want to temporarily disable it. diff --git a/libeg/screen.c b/libeg/screen.c index 24b7652..1856cbd 100644 --- a/libeg/screen.c +++ b/libeg/screen.c @@ -137,11 +137,13 @@ BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) { EFI_STATUS Status; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL; - Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info); - if ((Status == EFI_SUCCESS) && (Info != NULL)) { - *ModeWidth = Info->HorizontalResolution; - *Height = Info->VerticalResolution; - return TRUE; + if ((ModeWidth != NULL) && (Height != NULL)) { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, *ModeWidth, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Info != NULL)) { + *ModeWidth = Info->HorizontalResolution; + *Height = Info->VerticalResolution; + return TRUE; + } } return FALSE; } // BOOLEAN egGetResFromMode() @@ -158,10 +160,13 @@ BOOLEAN egGetResFromMode(UINTN *ModeWidth, UINTN *Height) { BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) { EFI_STATUS Status = EFI_SUCCESS; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; - UINT32 ModeNum = 0; UINTN Size; - BOOLEAN ModeSet = FALSE; + UINT32 ModeNum = 0; UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; + BOOLEAN ModeSet = FALSE; + + if ((ScreenWidth == NULL) || (ScreenHeight == NULL)) + return FALSE; if (GraphicsOutput != NULL) { // GOP mode (UEFI) if (*ScreenHeight == 0) { // User specified a mode number (stored in *ScreenWidth); use it directly @@ -177,7 +182,7 @@ BOOLEAN egSetScreenSize(IN OUT UINTN *ScreenWidth, IN OUT UINTN *ScreenHeight) { // and if so, switch to it.... do { Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); - if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info)) && + if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info) && (Info != NULL)) && (Info->HorizontalResolution == *ScreenWidth) && (Info->VerticalResolution == *ScreenHeight)) { Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum); ModeSet = (Status == EFI_SUCCESS); @@ -230,19 +235,20 @@ BOOLEAN egSetTextMode(UINT32 RequestedMode) { EFI_STATUS Status; BOOLEAN ChangedIt = FALSE; - if ((RequestedMode != ST->ConOut->Mode->Mode) && (RequestedMode != DONT_CHANGE_TEXT_MODE)) { + if ((RequestedMode != DONT_CHANGE_TEXT_MODE) && (RequestedMode != ST->ConOut->Mode->Mode)) { // SwitchToGraphics(); Status = refit_call2_wrapper(ST->ConOut->SetMode, ST->ConOut, RequestedMode); if (Status == EFI_SUCCESS) { ChangedIt = TRUE; } else { SwitchToText(FALSE); - Print(L"Error setting text mode %d; available modes are:\n", RequestedMode); + Print(L"\nError setting text mode %d; available modes are:\n", RequestedMode); do { Status = refit_call4_wrapper(ST->ConOut->QueryMode, ST->ConOut, i, &Width, &Height); if (Status == EFI_SUCCESS) Print(L"Mode %d: %d x %d\n", i, Width, Height); } while (++i < ST->ConOut->Mode->MaxMode); + Print(L"Mode %d: Use default mode\n", DONT_CHANGE_TEXT_MODE); PauseForKey(); SwitchToGraphics(); diff --git a/mkdistrib b/mkdistrib index c2942e7..7a83fee 100755 --- a/mkdistrib +++ b/mkdistrib @@ -47,7 +47,7 @@ make clean # Prepare a place and copy files there.... mkdir -p ../snapshots/$1/refind-$1/icons cp --preserve=timestamps icons/*icns ../snapshots/$1/refind-$1/icons/ -cp -a docs images keys include EfiLib libeg refind filesystems install.sh mkrlconf.sh CREDITS.txt NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt refind.inf Make.tiano Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1 +cp -a docs images keys include EfiLib libeg mok refind filesystems install.sh mkrlconf.sh CREDITS.txt NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt refind.inf Make.tiano Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1 # Go there and prepare a souce code zip file.... cd ../snapshots/$1/ diff --git a/refind/Make.tiano b/refind/Make.tiano index 4d5fd91..538b3dd 100644 --- a/refind/Make.tiano +++ b/refind/Make.tiano @@ -1,7 +1,7 @@ # # refind/Make.tiano # Build control file for rEFInd, using TianoCore EDK2 -# Requires that EfiLib and libeg subdirectories be built before this +# Requires that EfiLib, mok, and libeg subdirectories be built before this # file is used. # @@ -34,7 +34,7 @@ ALL_EFILIBS = $(EFILIB)/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevel # /usr/local/UDK2010/MyWorkSpace/Build/MdeModule/RELEASE_GCC46/X64/MdeModulePkg/Core/Dxe/DxeMain/OUTPUT/DxeMain/DxeMain.obj -SOURCE_NAMES = config driver_support icns lib main menu screen mok AutoGen +SOURCE_NAMES = config driver_support icns lib main menu screen AutoGen OBJS = $(SOURCE_NAMES:=.obj) all: $(BUILDME) @@ -42,8 +42,8 @@ all: $(BUILDME) $(AR_TARGET): $(OBJS) $(AR) -cr $(AR_TARGET).lib $(OBJS) -$(DLL_TARGET)_$(FILENAME_CODE).dll: $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib - $(LD) -o $(DLL_TARGET)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib --end-group +$(DLL_TARGET)_$(FILENAME_CODE).dll: $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib + $(LD) -o $(DLL_TARGET)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) ../libeg/libeg.lib ../EfiLib/EfiLib.lib ../mok/mok.lib --end-group $(BUILDME): $(DLL_TARGET)_$(FILENAME_CODE).dll $(OBJCOPY) --strip-unneeded $(DLL_TARGET)_$(FILENAME_CODE).dll diff --git a/refind/Makefile b/refind/Makefile index eb98140..844c443 100644 --- a/refind/Makefile +++ b/refind/Makefile @@ -21,12 +21,12 @@ ifeq ($(ARCH),x86_64) TARGET = refind_x64.efi endif -LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -#LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/$(LIBEG) -LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/ -LOCAL_LIBS = -leg +LOCAL_CPPFLAGS = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -I$(SRCDIR)/../mok +LOCAL_LDFLAGS = -L$(SRCDIR)/../libeg/ -L$(SRCDIR)/../mok/ +LOCAL_LIBS = -leg -lmok -OBJS = main.o config.o menu.o screen.o icns.o lib.o mok.o driver_support.o +OBJS = main.o config.o menu.o screen.o icns.o lib.o driver_support.o +#OBJS = main.o config.o menu.o screen.o icns.o lib.o mok.o driver_support.o variables.o sha256.o pecoff.o simple_file.o security_policy.o guid.o all: $(TARGET) diff --git a/refind/lib.c b/refind/lib.c index 958bb52..b04b2d4 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -1636,18 +1636,18 @@ BOOLEAN EjectMedia(VOID) { } // VOID EjectMedia() -// // Return the GUID as a string, suitable for display to the user. Note that the calling -// // function is responsible for freeing the allocated memory. -// CHAR16 * GuidAsString(EFI_GUID *GuidData) { -// CHAR16 *TheString; -// -// TheString = AllocateZeroPool(42 * sizeof(CHAR16)); -// if (TheString != 0) { -// SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", -// (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3, -// (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2], -// (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5], -// (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]); -// } -// return TheString; -// } // GuidAsString(EFI_GUID *GuidData) +// Return the GUID as a string, suitable for display to the user. Note that the calling +// function is responsible for freeing the allocated memory. +CHAR16 * GuidAsString(EFI_GUID *GuidData) { + CHAR16 *TheString; + + TheString = AllocateZeroPool(42 * sizeof(CHAR16)); + if (TheString != 0) { + SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3, + (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2], + (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5], + (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]); + } + return TheString; +} // GuidAsString(EFI_GUID *GuidData) diff --git a/refind/lib.h b/refind/lib.h index 4e936a8..f1e2885 100644 --- a/refind/lib.h +++ b/refind/lib.h @@ -116,6 +116,6 @@ VOID MyFreePool(IN OUT VOID *Pointer); BOOLEAN EjectMedia(VOID); -//CHAR16 * GuidAsString(EFI_GUID *GuidData); +CHAR16 * GuidAsString(EFI_GUID *GuidData); #endif \ No newline at end of file diff --git a/refind/main.c b/refind/main.c index c7564c6..109aa65 100644 --- a/refind/main.c +++ b/refind/main.c @@ -49,6 +49,7 @@ #include "icns.h" #include "menu.h" #include "mok.h" +#include "security_policy.h" #include "../include/Handle.h" #include "../include/refit_call_wrapper.h" #include "driver_support.h" @@ -127,7 +128,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.1.1"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.1.3"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -179,15 +180,9 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle; EFI_LOADED_IMAGE *ChildLoadedImage = NULL; - REFIT_FILE File; - VOID *ImageData = NULL; - UINTN ImageSize; - REFIT_VOLUME *DeviceVolume = NULL; UINTN DevicePathIndex; CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; - CHAR16 *loader = NULL; - BOOLEAN UseMok = FALSE; if (ErrorInStep != NULL) *ErrorInStep = 0; @@ -195,7 +190,6 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, // set load options if (LoadOptions != NULL) { if (LoadOptionsPrefix != NULL) { -// MergeStrings(&FullLoadOptions, LoadOptionsPrefix, 0); MergeStrings(&FullLoadOptions, LoadOptions, L' '); if (OSType == 'M') { MergeStrings(&FullLoadOptions, L" ", 0); @@ -217,8 +211,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, // load the image into memory (and execute it, in the case of a shim/MOK image). ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) { - // NOTE: Below commented-out line could be more efficient if the ReadFile() and - // FindVolumeAndFilename() calls were moved earlier, but it doesn't work on my + // NOTE: Below commented-out line could be more efficient iffile were read ahead of + // time and passed as a pre-loaded image to LoadImage(), but it doesn't work on my // 32-bit Mac Mini or my 64-bit Intel box when launching a Linux kernel; the // kernel returns a "Failed to handle fs_proto" error message. // TODO: Track down the cause of this error and fix it, if possible. @@ -226,25 +220,6 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, // ImageData, ImageSize, &ChildImageHandle); ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle); - if (((Status == EFI_ACCESS_DENIED) || (Status == EFI_SECURITY_VIOLATION)) && (ShimLoaded())) { - FindVolumeAndFilename(DevicePaths[DevicePathIndex], &DeviceVolume, &loader); - if (DeviceVolume != NULL) { - Status = ReadFile(DeviceVolume->RootDir, loader, &File, &ImageSize); - ImageData = File.Buffer; - } else { - Status = EFI_NOT_FOUND; - Print(L"Error: device volume not found!\n"); - } // if/else - if (Status != EFI_NOT_FOUND) { - ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions, - DeviceVolume, FileDevicePath(DeviceVolume->DeviceHandle, loader)); -// ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions, -// DeviceVolume, DevicePaths[DevicePathIndex]); - } - if (ReturnStatus == EFI_SUCCESS) { - UseMok = TRUE; - } // if - } // if (UEFI SB failed; use shim) if (ReturnStatus != EFI_NOT_FOUND) { break; } @@ -256,37 +231,35 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, goto bailout; } - if (!UseMok) { - ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, - (VOID **) &ChildLoadedImage); - if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { - if (ErrorInStep != NULL) - *ErrorInStep = 2; - goto bailout_unload; - } - ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; - ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16); - // turn control over to the image - // TODO: (optionally) re-enable the EFI watchdog timer! - - // close open file handles - UninitRefitLib(); - ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); - // control returns here when the child image calls Exit() - SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); - if (CheckError(Status, ErrorInfo)) { - if (ErrorInStep != NULL) - *ErrorInStep = 3; - } + ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, + (VOID **) &ChildLoadedImage); + if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) { + if (ErrorInStep != NULL) + *ErrorInStep = 2; + goto bailout_unload; + } + ChildLoadedImage->LoadOptions = (VOID *)FullLoadOptions; + ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(FullLoadOptions) + 1) * sizeof(CHAR16); + // turn control over to the image + // TODO: (optionally) re-enable the EFI watchdog timer! - // re-open file handles - ReinitRefitLib(); - } // if + // close open file handles + UninitRefitLib(); + ReturnStatus = Status = refit_call3_wrapper(BS->StartImage, ChildImageHandle, NULL, NULL); + + // control returns here when the child image calls Exit() + SPrint(ErrorInfo, 255, L"returned from %s", ImageTitle); + if (CheckError(Status, ErrorInfo)) { + if (ErrorInStep != NULL) + *ErrorInStep = 3; + } + + // re-open file handles + ReinitRefitLib(); bailout_unload: // unload the image, we don't care if it works or not... - if (!UseMok) - Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); + Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle); bailout: MyFreePool(FullLoadOptions); @@ -1944,6 +1917,43 @@ static VOID InitializeLib(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *System #endif +// Set up our own Secure Boot extensions.... +// Returns TRUE on success, FALSE otherwise +static BOOLEAN SecureBootSetup(VOID) { + EFI_STATUS Status; + BOOLEAN Success = FALSE; + + if (secure_mode()) { + Status = security_policy_install(); + if (Status == EFI_SUCCESS) { + Success = TRUE; + } else { + Print(L"Failed to install MOK Secure Boot extensions"); +// PauseForKey(); + } + } + return Success; +} // VOID SecureBootSetup() + +// Remove our own Secure Boot extensions.... +// Returns TRUE on success, FALSE otherwise +static BOOLEAN SecureBootUninstall(VOID) { + EFI_STATUS Status; + BOOLEAN Success = TRUE; + + if (secure_mode()) { + Status = security_policy_uninstall(); + if (Status != EFI_SUCCESS) { + Success = FALSE; + BeginTextScreen(L"Secure Boot Policy Failure"); + Print(L"Failed to uninstall MOK Secure Boot extensions; forcing a reboot."); + PauseForKey(); + refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + return Success; +} // VOID SecureBootUninstall + // // main entry point // @@ -1953,6 +1963,7 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { EFI_STATUS Status; BOOLEAN MainLoopRunning = TRUE; + BOOLEAN MokProtocol; REFIT_MENU_ENTRY *ChosenEntry; UINTN MenuExit, i; CHAR16 *Selection; @@ -1980,8 +1991,10 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) // further bootstrap (now with config available) SetupScreen(); + MokProtocol = SecureBootSetup(); ScanVolumes(); LoadDrivers(); + PauseForKey(); ScanForBootloaders(); ScanForTools(); @@ -2043,8 +2056,12 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) break; case TAG_EXIT: // Terminate rEFInd - BeginTextScreen(L" "); - return EFI_SUCCESS; + if ((MokProtocol) && !SecureBootUninstall()) { + MainLoopRunning = FALSE; // just in case we get this far + } else { + BeginTextScreen(L" "); + return EFI_SUCCESS; + } break; } // switch() -- 2.39.2