]> code.delx.au - refind/blobdiff - refind/main.c
Refinements, mostly to shim/MOK support.
[refind] / refind / main.c
index acc37cb648d19b3317cc748e0c240b64acdaa5e3..7297c629f4ef0663f2d0ace4ff7a708d96640cf8 100644 (file)
@@ -48,7 +48,7 @@
 #include "lib.h"
 #include "icns.h"
 #include "menu.h"
-#include "mok2.h"
+#include "mok.h"
 #include "../include/Handle.h"
 #include "../include/refit_call_wrapper.h"
 #include "driver_support.h"
@@ -73,7 +73,7 @@
 #define DRIVER_DIRS             L"drivers"
 #endif
 
-#define MOK_NAMES               L"\\EFI\\tools\\MokManager.efi,\\EFI\\redhat\\MokManager.efi"
+#define MOK_NAMES               L"\\EFI\\tools\\MokManager.efi,\\EFI\\redhat\\MokManager.efi,\\EFI\\ubuntu\\MokManager.efi,\\EFI\\suse\\MokManager"
 
 // Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or
 // L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive
@@ -97,7 +97,7 @@ static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL
 static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL };
 
 REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 0, 0, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0,
-                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               {TAG_SHELL, TAG_APPLE_RECOVERY, TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
 
 // Structure used to hold boot loader filenames and time stamps in
@@ -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.7");
+        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;
@@ -865,17 +885,15 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *P
     struct LOADER_LIST      *LoaderList = NULL, *NewLoader;
 
     if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && Volume->DeviceHandle != SelfVolume->DeviceHandle) ||
-        (StriCmp(Path, SelfDirPath) != 0)) && (!IsIn(Path, GlobalConfig.DontScan))) {
+        (StriCmp(Path, SelfDirPath) != 0)) && (!IsIn(Path, GlobalConfig.DontScanDirs))) {
        // look through contents of the directory
        DirIterOpen(Volume->RootDir, Path, &DirIter);
        while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) {
           Extension = FindExtension(DirEntry->FileName);
           if (DirEntry->FileName[0] == '.' ||
-              StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 ||
-              StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 ||
-              StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0 ||
               StriCmp(Extension, L".icns") == 0 ||
-              StriSubCmp(L"shell", DirEntry->FileName))
+              StriSubCmp(L"shell", DirEntry->FileName) ||
+              IsIn(DirEntry->FileName, GlobalConfig.DontScanFiles))
                 continue;   // skip this
 
           if (Path)
@@ -921,22 +939,23 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
 
    if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
       // check for Mac OS X boot loader
-      if (!IsIn(L"\\System\\Library\\CoreServices", GlobalConfig.DontScan)) {
+      if (!IsIn(L"\\System\\Library\\CoreServices", GlobalConfig.DontScanDirs)) {
          StrCpy(FileName, MACOSX_LOADER_PATH);
-         if (FileExists(Volume->RootDir, FileName)) {
+         if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) {
             AddLoaderEntry(FileName, L"Mac OS X", Volume);
          }
 
          // check for XOM
          StrCpy(FileName, L"\\System\\Library\\CoreServices\\xom.efi");
-         if (FileExists(Volume->RootDir, FileName)) {
+         if (FileExists(Volume->RootDir, FileName) && !IsIn(L"boot.efi", GlobalConfig.DontScanFiles)) {
             AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume);
          }
-      } // if Mac directory not in GlobalConfig.DontScan list
+      } // if Mac directory not in GlobalConfig.DontScanDirs list
 
       // check for Microsoft boot loader/menu
       StrCpy(FileName, L"\\EFI\\Microsoft\\Boot\\Bootmgfw.efi");
-      if (FileExists(Volume->RootDir, FileName) && !IsIn(L"\\EFI\\Microsoft\\Boot", GlobalConfig.DontScan)) {
+      if (FileExists(Volume->RootDir, FileName) && !IsIn(L"\\EFI\\Microsoft\\Boot", GlobalConfig.DontScanDirs) &&
+          !IsIn(L"bootmgfw.efi", GlobalConfig.DontScanFiles)) {
          AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume);
       }