]> code.delx.au - refind/commitdiff
Refinements, mostly to shim/MOK support.
authorsrs5694 <srs5694@users.sourceforge.net>
Thu, 6 Dec 2012 01:49:23 +0000 (20:49 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Thu, 6 Dec 2012 01:49:23 +0000 (20:49 -0500)
NEWS.txt
docs/refind/configfile.html
docs/refind/todo.html
filesystems/fsw_efi.c
install.sh
refind.conf-sample
refind/config.c
refind/lib.c
refind/main.c
refind/mok.c
refind/mok.h

index 60a94c16b29763128e6505ae94271205ab188111..c8adbff5b846b1e148c01547e0c99ad98a4dcca9 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,6 +1,13 @@
 0.5.0 (??/??/2012):
 -------------------
 
+- Changed refind.conf-sample to uncomment the scan_all_linux_kernels
+  option by default. If this option is deleted or commented out, the
+  program default remains to not scan all Linux kernels; but with
+  increasing numbers of distributions shipping with kernels that include
+  EFI stub loader support, setting the configuration file default to scan
+  for them makes sense.
+
 - Modified the "resolution" token so that it affects text mode as well
   as graphics mode. On my systems, though, the actual text area is still
   restricted to an 80x25 area. (This seems to be a firmware limitation; my
index ce7b8934f4385c685c355dea533f9846b9554b91..583e601b35057fcfe87adf4620d004d6ddef1e94 100644 (file)
@@ -221,7 +221,7 @@ timeout 20
 <tr>
    <td><tt>scan_all_linux_kernels</tt></td>
    <td>None</td>
-   <td>When set, causes rEFInd to add Linux kernels (files with names that begin with <tt>vmlinuz</tt> or <tt>bzImage</tt>) to the list of EFI boot loaders, even if they lack <tt>.efi</tt> 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 <tt>.efi</tt>. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (<a href="drivers.html">Drivers</a> and the <tt>also_scan_dirs</tt> 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. For this reason, it's disabled by default, but that may change in the future.</td>
+   <td>When set, causes rEFInd to add Linux kernels (files with names that begin with <tt>vmlinuz</tt> or <tt>bzImage</tt>) to the list of EFI boot loaders, even if they lack <tt>.efi</tt> 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 <tt>.efi</tt>. Of course, the kernels must still be stored on a filesystem that rEFInd can read, and in a directory that it scans. (<a href="drivers.html">Drivers</a> and the <tt>also_scan_dirs</tt> 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 <tt>refind.conf-sample</tt> 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.</td>
 </tr>
 <tr>
    <td><tt>default_selection</tt></td>
index 5919dbc63f9171c187a57e665d4946d52f072c6b..cf9de2dcb69c77e117c8d027b2be1fc4e974d0e3 100644 (file)
@@ -195,6 +195,20 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com</a></p>
 
     <ul>
 
+    <li>When in Secure Boot mode, rEFInd can launch just one driver that's
+       signed with a shim key or MOK. The second and later drivers
+       generate "access denied" errors. <!-- I think this is because of
+       the fast-and-loose sample code I borrowed from shim, which re-uses
+       rEFInd's own image handle (the <tt>image_handle</tt> variable in
+       <tt>start_image()</tt>) for launching shim/MOK-signed binaries. The
+       result is that when the second driver is loaded, it can't register
+       itself with the firmware because the firmware believes it's already
+       been registered. The solution is likely to involve creating a child
+       image handle rather than re-using rEFInd's own image handle, but
+       this is likely to be tedious to do&mdash;see
+       <tt>/usr/local/UDK2010/MyWorkSpace/MdeModulePkg/Core/Dxe/Image/Image.c</tt>
+       for the reference UEFI implementation. --> </li>
+
     <li>The <a href="http://www.rodsbooks.com/gb-hybrid-efi/">Gigabyte
        Hybrid EFI</a> has a bug that causes the allegedly case-insensitive
        <tt>StriCmp()</tt> function to perform a case-sensitive comparison.
index a24bf2efc5bf989863023b74eb0ca6c7a252406b..1193684f3dd6a2bb2e49d2997415905f27dc68ec 100644 (file)
@@ -80,7 +80,7 @@
 /** Helper macro for stringification. */
 #define FSW_EFI_STRINGIFY(x) #x
 /** Expands to the EFI driver name given the file system type name. */
-#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.4.6 " FSW_EFI_STRINGIFY(t) L" File System Driver"
+#define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.5.0 " FSW_EFI_STRINGIFY(t) L" File System Driver"
 
 // function prototypes
 
index 4e32b90a203f19693e102d44c7965d569eea0ae8..6328ea538b0459f3f43ab84f99bac334e3e1921f 100755 (executable)
@@ -4,7 +4,16 @@
 #
 # Usage:
 #
-# ./install.sh [esp]
+# ./install.sh [options]
+#
+# options include:
+#    "--esp" to install to the ESP rather than to the system's root
+#           filesystem. This is the default on Linux
+#    "--usedefault {devicefile}" to install as default
+#           (/EFI/BOOT/BOOTX64.EFI and similar) to the specified
+#           device (/dev/sdd1 or whatever) without registering with
+#           the NVRAM
+#    "--drivers" to install drivers along with regular files
 #
 # The "esp" option is valid only on Mac OS X; it causes
 # installation to the EFI System Partition (ESP) rather than
index 736afa08ab0e20f54a7b100e3ea27065d1a27e9a..42c73fce309ee5b97a7670dfcc016d8bd7083c2e 100644 (file)
@@ -101,7 +101,7 @@ timeout 20
 #  reboot          - a tag to reboot the computer
 # Default is shell,apple_recovery,mok_tool,about,shutdown,reboot
 #
-#showtools shell, about, reboot
+#showtools shell, mok_tool, about, reboot, exit
 
 # Directories in which to search for EFI drivers. These drivers can
 # provide filesystem support, give access to hard disks on plug-in
@@ -190,7 +190,7 @@ timeout 20
 # option will cause the icon file to show up as a non-functional loader tag.
 # Default is to NOT scan for kernels without ".efi" extensions.
 #
-#scan_all_linux_kernels
+scan_all_linux_kernels
 
 # Set the maximum number of tags that can be displayed on the screen at
 # any time. If more loaders are discovered than this value, rEFInd shows
index c22b8307e8ffb96f1ad6fee429267f435e73a8bc..764d444125dd29533708017a000b9cd890870275 100644 (file)
@@ -325,7 +325,7 @@ VOID ReadConfig(VOID)
     MyFreePool(GlobalConfig.DontScanDirs);
     GlobalConfig.DontScanDirs = StrDuplicate(SelfDirPath);
     MyFreePool(GlobalConfig.DontScanFiles);
-    GlobalConfig.DontScanFiles = DONT_SCAN_FILES;
+    GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES);
 
     for (;;) {
         TokenCount = ReadTokenLine(&File, &TokenList);
index 03d90d595690928367d3f52f6e73c1d39551a238..77e6842404b4cfe7a7ffb56f4c74d3e9bb1d39d2 100644 (file)
@@ -134,10 +134,40 @@ VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
    } // if allocation OK
 } // CleanUpPathNameSlashes()
 
+// Splits an EFI device path into device and filename components. For instance, if InString is
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi,
+// this function will truncate that input to
+// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)
+// and return bzImage-3.5.1.efi as its return value.
+// It does this by searching for the last ")" character in InString, copying everything
+// after that string (after some cleanup) as the return value, and truncating the original
+// input value.
+// If InString contains no ")" character, this function leaves the original input string
+// unmodified and also returns that string.
+static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) {
+   INTN i;
+   CHAR16 *FileName = NULL;
+   BOOLEAN Found = FALSE;
+
+   i = StrLen(InString) - 1;
+   while ((i >= 0) && (!Found)) {
+      if (InString[i] == L')') {
+         Found = TRUE;
+         FileName = StrDuplicate(&InString[i + 1]);
+         CleanUpPathNameSlashes(FileName);
+         InString[i + 1] = '\0';
+      } // if
+      i--;
+   } // while
+   if (FileName == NULL)
+      FileName = StrDuplicate(InString);
+   return FileName;
+} // static CHAR16* SplitDeviceString()
+
 EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
 {
     EFI_STATUS  Status;
-    CHAR16      *DevicePathAsString;
+    CHAR16      *DevicePathAsString, *Temp;
 
     SelfImageHandle = ImageHandle;
     Status = refit_call3_wrapper(BS->HandleProtocol, SelfImageHandle, &LoadedImageProtocol, (VOID **) &SelfLoadedImage);
@@ -148,8 +178,10 @@ EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
     DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath);
     CleanUpPathNameSlashes(DevicePathAsString);
     MyFreePool(SelfDirPath);
-    SelfDirPath = FindPath(DevicePathAsString);
+    Temp = FindPath(DevicePathAsString);
+    SelfDirPath = SplitDeviceString(Temp);
     MyFreePool(DevicePathAsString);
+    MyFreePool(Temp);
 
     return FinishInitRefitLib();
 }
@@ -581,9 +613,7 @@ VOID ScanVolume(IN OUT REFIT_VOLUME *Volume)
 
             // get the handle for that path
             RemainingDevicePath = DiskDevicePath;
-            //Print(L"  * looking at %s\n", DevicePathToStr(RemainingDevicePath));
             Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle);
-            //Print(L"  * remaining: %s\n", DevicePathToStr(RemainingDevicePath));
             FreePool(DiskDevicePath);
 
             if (!EFI_ERROR(Status)) {
@@ -1289,34 +1319,6 @@ CHAR16 *FindPath(IN CHAR16* FullPath) {
    return (PathOnly);
 }
 
-// Splits an EFI device path into device and filename components. For instance, if InString is
-// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi,
-// this function will truncate that input to
-// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)
-// and return bzImage-3.5.1.efi as its return value.
-// It does this by searching for the last ")" character in InString, copying everything
-// after that string (after some cleanup) as the return value, and truncating the original
-// input value.
-// If InString contains no ")" character, this function leaves the original input string
-// unmodified and returns a NULL value.
-static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) {
-   INTN i;
-   CHAR16 *FileName = NULL;
-   BOOLEAN Found = FALSE;
-
-   i = StrLen(InString) - 1;
-   while ((i >= 0) && (!Found)) {
-      if (InString[i] == L')') {
-         Found = TRUE;
-         FileName = StrDuplicate(&InString[i + 1]);
-         CleanUpPathNameSlashes(FileName);
-         InString[i + 1] = '\0';
-      } // if
-      i--;
-   } // while
-   return FileName;
-} // static CHAR16* SplitDeviceString()
-
 // Takes an input loadpath, splits it into disk and filename components, finds a matching
 // DeviceVolume, and returns that and the filename (*loader).
 VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) {
index ebb9fdd9e07b22f23e9dab53c0b63063019bd321..7297c629f4ef0663f2d0ace4ff7a708d96640cf8 100644 (file)
@@ -118,7 +118,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.7.9");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.4.7.10");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
@@ -132,7 +132,9 @@ static VOID AboutrEFInd(VOID)
 #if defined(EFI32)
         AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)");
 #elif defined(EFIX64)
-        AddMenuInfoLine(&AboutMenu, L" Platform: x86_64 (64 bit)");
+        TempStr = AllocateZeroPool(256 * sizeof(CHAR16));
+        SPrint(TempStr, 255, L" Platform: x86_64 (64 bit); Secure Boot %s", secure_mode() ? L"active" : L"inactive");
+        AddMenuInfoLine(&AboutMenu, TempStr);
 #else
         AddMenuInfoLine(&AboutMenu, L" Platform: unknown");
 #endif
@@ -158,6 +160,7 @@ static VOID AboutrEFInd(VOID)
     RunMenu(&AboutMenu, NULL);
 } /* VOID AboutrEFInd() */
 
+// Launch an EFI binary.
 static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
                                     IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
                                     IN CHAR16 *ImageTitle, IN CHAR8 OSType,
@@ -175,7 +178,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
     CHAR16                  *loader = NULL;
-    BOOLEAN                 UseMok = FALSE;
+    BOOLEAN                 UseMok = FALSE, SecureMode;
 
     if (ErrorInStep != NULL)
         *ErrorInStep = 0;
@@ -198,20 +201,27 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     if (Verbose)
        Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions);
 
-    // load the image into memory (and execute it, in the case of a MOK image).
+    // 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
+    SecureMode = secure_mode();
+//    SecureMode = TRUE;
     for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
-       ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
-                                                   NULL, 0, &ChildImageHandle);
+       // NOTE: Below commented-out line could simplify logic by loading the image once, 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.
        // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
        //                                            ImageData, ImageSize, &ChildImageHandle);
-       // TODO: Commented-out version above is more efficient if the below FindVolumeAndFilename()
-       // and ReadFile() calls (and surrounding logic) are moved earlier; however, this causes
-       // some computers, including my 32-bit Mac Mini and 64-bit Intel machine, to fail when
-       // launching a Linux kernel, with a "Failed to handle fs_proto" error message from the
-       // kernel. Find out what's causing this and fix it.
-       if (ReturnStatus == EFI_ACCESS_DENIED) {
-          // TODO: I originally had the next few lines a
+       // In Secure Boot mode, try to use shim/MOK-style loading first, and if
+       // that fails, try the standard EFI system call (LoadImage()). This is
+       // done for efficiency, to prevent loading a binary twice, which can
+       // take several seconds to load a Linux kernel with EFI stub support on
+       // some systems. Linux kernels are likely to be shim/MOK signed, so
+       // this is quickest for them; and delays for most other boot loaders
+       // will be unnoticeably short. To prevent delays or failures in case
+       // of buggy shim/MOK code on non-SB systems, skip that attempt and
+       // call LoadImage() directly when not in SB mode.
+       if (SecureMode) {
           FindVolumeAndFilename(DevicePaths[DevicePathIndex], &DeviceVolume, &loader);
           if (DeviceVolume != NULL) {
              Status = ReadFile(DeviceVolume->RootDir, loader, &File, &ImageSize);
@@ -220,11 +230,23 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
              Status = EFI_NOT_FOUND;
              Print(L"Error: device volume not found!\n");
           } // if/else
-          ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions, DeviceVolume);
+          if (Status != EFI_NOT_FOUND) {
+             ReturnStatus = Status = start_image(SelfImageHandle, loader, ImageData, ImageSize, FullLoadOptions,
+                                                 DeviceVolume, DevicePaths[DevicePathIndex]);
+          }
           if (ReturnStatus == EFI_SUCCESS) {
              UseMok = TRUE;
           } // if
-       }
+          // If shim/MOK load fails, try regular EFI load, in case it's an unsupported
+          // binary type....
+          if (!UseMok) {
+             ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+                                                         NULL, 0, &ChildImageHandle);
+          } // if (!UseMok)
+       } else { // Secure Boot inactive; only do standard call....
+          ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+                                                      NULL, 0, &ChildImageHandle);
+       } // if/else (SecureMode)
        if (ReturnStatus != EFI_NOT_FOUND) {
           break;
        }
@@ -236,40 +258,38 @@ 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 (!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 = 2;
-           goto bailout_unload;
-        }
-     }
-
-     if (!UseMok) {
-        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;
-        }
+               *ErrorInStep = 3;
+       }
 
-        // re-open file handles
-        ReinitRefitLib();
+       // re-open file handles
+       ReinitRefitLib();
     } // if
 
 bailout_unload:
     // unload the image, we don't care if it works or not...
     if (!UseMok)
        Status = refit_call1_wrapper(BS->UnloadImage, ChildImageHandle);
+
 bailout:
     MyFreePool(FullLoadOptions);
     return ReturnStatus;
index ddfe27f90fced6846b49903f8fca0f2f373c039d..6c4ef38e20f021b845ada1fb6b4438e84a742884 100644 (file)
 
 static EFI_STATUS (EFIAPI *entry_point) (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
 
-/*
- * The vendor certificate used for validating the second stage loader
- */
-extern UINT8 vendor_cert[];
-extern UINT32 vendor_cert_size;
-extern UINT32 vendor_dbx_size;
+// /*
+//  * The vendor certificate used for validating the second stage loader
+//  */
+// extern UINT8 vendor_cert[];
+// extern UINT32 vendor_cert_size;
+// extern UINT32 vendor_dbx_size;
 
 #define EFI_IMAGE_SECURITY_DATABASE_GUID { 0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f }}
 
@@ -79,6 +79,66 @@ typedef struct {
    UINT8 *Mok;
 } MokListNode;
 
+
+static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer)
+{
+   EFI_STATUS efi_status;
+   char allocate = !(*size);
+
+   efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, buffer);
+
+   if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) {
+      return efi_status;
+   }
+
+   *buffer = AllocatePool(*size);
+
+   if (!*buffer) {
+      Print(L"Unable to allocate variable buffer\n");
+      return EFI_OUT_OF_RESOURCES;
+   }
+
+   efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, *buffer);
+
+   return efi_status;
+} // get_variable()
+
+/*
+ * Check whether we're in Secure Boot and user mode
+ */
+BOOLEAN secure_mode (VOID)
+{
+   EFI_STATUS status;
+   EFI_GUID global_var = EFI_GLOBAL_VARIABLE;
+   UINTN charsize = sizeof(char);
+   UINT8 sb, setupmode;
+   UINT32 attributes;
+
+   status = get_variable(L"SecureBoot", global_var, &attributes, &charsize, (VOID *)&sb);
+
+   /* FIXME - more paranoia here? */
+   if (status != EFI_SUCCESS || sb != 1) {
+      return FALSE;
+   }
+
+   status = get_variable(L"SetupMode", global_var, &attributes, &charsize, (VOID *)&setupmode);
+
+   if (status == EFI_SUCCESS && setupmode == 1) {
+      return FALSE;
+   }
+
+   return TRUE;
+} // secure_mode()
+
+/*
+ * Currently, shim/MOK only works on x86-64 (X64) systems, and some of this code
+ * generates warnings on x86 (IA32) builds, so don't bother compiling it at all
+ * on such systems.
+ *
+ */
+
+#if defined(EFIX64)
+
 /*
  * Perform basic bounds checking of the intra-image pointers
  */
@@ -93,8 +153,7 @@ static void *ImageAddress (void *image, int size, unsigned int address)
 /*
  * Perform the actual relocation
  */
-static EFI_STATUS relocate_coff (GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
-             void *data)
+static EFI_STATUS relocate_coff (GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context, void *data)
 {
    EFI_IMAGE_BASE_RELOCATION *RelocBase, *RelocBaseEnd;
    UINT64 Adjust;
@@ -108,11 +167,6 @@ static EFI_STATUS relocate_coff (GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
 
    context->PEHdr->Pe32Plus.OptionalHeader.ImageBase = (UINT64)data;
 
-   if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
-      Print(L"Image has no relocation entry\n");
-      return EFI_UNSUPPORTED;
-   }
-
    // Linux kernels with EFI stub support don't have relocation information, so
    // we can skip all this stuff....
    if (((context->RelocDir->VirtualAddress == 0) && (context->RelocDir->Size == 0)) ||
@@ -120,6 +174,11 @@ static EFI_STATUS relocate_coff (GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
       return EFI_SUCCESS;
    }
 
+   if (context->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+      Print(L"Image has no relocation entry\n");
+      return EFI_UNSUPPORTED;
+   }
+
    RelocBase = ImageAddress(data, size, context->RelocDir->VirtualAddress);
    RelocBaseEnd = ImageAddress(data, size, context->RelocDir->VirtualAddress + context->RelocDir->Size - 1);
 
@@ -199,7 +258,7 @@ static EFI_STATUS relocate_coff (GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
    }
 
    return EFI_SUCCESS;
-}
+} /* relocate_coff() */
 
 /*
  * Read the binary header and grab appropriate information from it
@@ -288,8 +347,8 @@ static BOOLEAN ShimValidate (VOID *data, UINT32 size)
 /*
  * Once the image has been loaded it needs to be validated and relocated
  */
-static EFI_STATUS handle_image (void *data, unsigned int datasize,
-            EFI_LOADED_IMAGE *li, CHAR16 *Options, REFIT_VOLUME *DeviceVolume)
+static EFI_STATUS handle_image (void *data, unsigned int datasize, EFI_LOADED_IMAGE *li,
+                                CHAR16 *Options, REFIT_VOLUME *DeviceVolume, IN EFI_DEVICE_PATH *DevicePath)
 {
    EFI_STATUS efi_status;
    char *buffer;
@@ -366,12 +425,12 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
     * grub needs to know its location and size in memory, its location on
     * disk, and its load options, so fix up the loaded image protocol values
     */
-   li->ImageBase = buffer;
-   li->ImageSize = context.ImageSize;
    li->DeviceHandle = DeviceVolume->DeviceHandle;
-   li->FilePath = DeviceVolume->DevicePath;
-   li->LoadOptions = (VOID *)Options;
+   li->FilePath = DevicePath;
    li->LoadOptionsSize = ((UINT32)StrLen(Options) + 1) * sizeof(CHAR16);
+   li->LoadOptions = (VOID *)Options;
+   li->ImageBase = buffer;
+   li->ImageSize = context.ImageSize;
 
    if (!entry_point) {
       Print(L"Invalid entry point\n");
@@ -382,14 +441,22 @@ static EFI_STATUS handle_image (void *data, unsigned int datasize,
    return EFI_SUCCESS;
 }
 
+#endif /* defined(EFIX64) */
+
 /*
- * Load and run an EFI executable
+ * Load and run an EFI executable.
+ * Note that most of this function compiles only on x86-64 (X64) systems, since
+ * shim/MOK works only on those systems. I'm leaving just enough to get the
+ * function to return EFI_ACCESS_DENIED on x86 (IA32) systems, which should
+ * let the calling function work in case it somehow ends up calling this
+ * function inappropriately.
  */
 EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, VOID *data, UINTN datasize,
-                       CHAR16 *Options, REFIT_VOLUME *DeviceVolume)
+                       CHAR16 *Options, REFIT_VOLUME *DeviceVolume, IN EFI_DEVICE_PATH *DevicePath)
 {
+   EFI_STATUS efi_status = EFI_ACCESS_DENIED;
+#if defined(EFIX64)
    EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
-   EFI_STATUS efi_status;
    EFI_LOADED_IMAGE *li, li_bak;
    CHAR16 *PathName = NULL;
 
@@ -400,8 +467,7 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, VOID *data, U
     * We need to refer to the loaded image protocol on the running
     * binary in order to find our path
     */
-   efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle,
-                   &loaded_image_protocol, (void **)&li);
+   efi_status = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &loaded_image_protocol, (void **)&li);
 
    if (efi_status != EFI_SUCCESS) {
       Print(L"Unable to init protocol\n");
@@ -417,7 +483,7 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, VOID *data, U
    /*
     * Verify and, if appropriate, relocate and execute the executable
     */
-   efi_status = handle_image(data, datasize, li, Options, DeviceVolume);
+   efi_status = handle_image(data, datasize, li, Options, DeviceVolume, DevicePath);
 
    if (efi_status != EFI_SUCCESS) {
       Print(L"Failed to load image\n");
@@ -430,6 +496,8 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, VOID *data, U
     */
    efi_status = refit_call2_wrapper(entry_point, image_handle, ST);
 
+//   efi_status = refit_call1_wrapper(BS->UnloadImage, li);
+
    /*
     * Restore our original loaded image values
     */
@@ -441,5 +509,6 @@ done:
    if (data)
       FreePool(data);
 
+#endif
    return efi_status;
-}
+} // EFI_STATUS start_image()
index 8a1967007f90fcf35da0b8d78a85c63cba7314df..c398353b52de263485177c3d5ae4aae974a63269 100644 (file)
@@ -4,40 +4,7 @@
 #define SHIM_LOCK_GUID \
    { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
 
-//#define INTERFACE_DECL(x)
-
-// INTERFACE_DECL(_SHIM_LOCK);
-// 
-// typedef
-// EFI_STATUS
-// (*EFI_SHIM_LOCK_VERIFY) (
-//    IN VOID *buffer,
-//    IN UINT32 size
-//    );
-// 
-// typedef
-// EFI_STATUS
-// (*EFI_SHIM_LOCK_HASH) (
-//    IN char *data,
-//    IN int datasize,
-//    GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context,
-//    UINT8 *sha256hash,
-//    UINT8 *sha1hash
-//    );
-// 
-// typedef
-// EFI_STATUS
-// (*EFI_SHIM_LOCK_CONTEXT) (
-//    IN VOID *data,
-//    IN unsigned int datasize,
-//    GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context
-//    );
-// 
-// typedef struct _SHIM_LOCK {
-//    EFI_SHIM_LOCK_VERIFY Verify;
-//    EFI_SHIM_LOCK_HASH Hash;
-//    EFI_SHIM_LOCK_CONTEXT Context;
-// } SHIM_LOCK;
+#if defined(EFIX64)
 
 typedef struct _SHIM_LOCK
 {
@@ -49,5 +16,8 @@ typedef struct _SHIM_LOCK
                                                         GNUEFI_PE_COFF_LOADER_IMAGE_CONTEXT *context);
 } SHIM_LOCK;
 
+#endif
+
+BOOLEAN secure_mode (VOID);
 EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath, VOID *data, UINTN datasize,
-                       CHAR16 *Options, REFIT_VOLUME *DeviceVolume);
+                       CHAR16 *Options, REFIT_VOLUME *DeviceVolume, IN EFI_DEVICE_PATH *DevicePath);