]> code.delx.au - refind/blobdiff - refind/main.c
Protection against loading invalid EFI drivers; bug fix for using
[refind] / refind / main.c
index f71af08105d18e86a22e9a004ec8e54ed17891c7..f7e7616f41caee7e5991aad7951004b657338236 100644 (file)
@@ -147,7 +147,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.1");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.1.2");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith");
@@ -210,6 +210,34 @@ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) {
    } // if
 } // VOID WarnSecureBootError()
 
+// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH
+static BOOLEAN IsValidLoader(EFI_FILE *RootDir, CHAR16 *FileName) {
+    BOOLEAN         IsValid = TRUE;
+#if defined (EFIX64) | defined (EFI32)
+    EFI_STATUS      Status;
+    EFI_FILE_HANDLE FileHandle;
+    CHAR8           Header[512];
+    UINTN           Size = sizeof(Header);
+
+    Status = refit_call5_wrapper(RootDir->Open, RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+    if (EFI_ERROR(Status))
+       return 0;
+
+    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header);
+    refit_call1_wrapper(FileHandle->Close, FileHandle);
+
+    IsValid = !EFI_ERROR(Status) &&
+              Size == sizeof(Header) &&
+              ((Header[0] == 'M' && Header[1] == 'Z' &&
+               (Size = *(UINT32 *)&Header[0x3c]) < 0x180 &&
+               Header[Size] == 'P' && Header[Size+1] == 'E' &&
+               Header[Size+2] == 0 && Header[Size+3] == 0 &&
+               *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) ||
+              (*(UINT32 *)&Header == FAT_ARCH));
+#endif
+    return IsValid;
+} // BOOLEAN IsValidLoader()
+
 // Launch an EFI binary.
 static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
                                     IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
@@ -220,9 +248,11 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
     EFI_STATUS              Status, ReturnStatus;
     EFI_HANDLE              ChildImageHandle;
     EFI_LOADED_IMAGE        *ChildLoadedImage = NULL;
+    REFIT_VOLUME            *Volume = NULL;
     UINTN                   DevicePathIndex;
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
+    CHAR16                  *Filename = NULL;
 
     if (ErrorInStep != NULL)
         *ErrorInStep = 0;
@@ -251,15 +281,23 @@ 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 file 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.
-       // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
-       //                                            ImageData, ImageSize, &ChildImageHandle);
-       ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
-                                                   NULL, 0, &ChildImageHandle);
+       FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename);
+       // Some EFIs crash if attempting to load driver for invalid architecture, so
+       // protect for this condition....
+       if (IsValidLoader(Volume->RootDir, Filename)) {
+          // NOTE: Below commented-out line could be more efficient if file 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.
+          // ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+          //                                            ImageData, ImageSize, &ChildImageHandle);
+          ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
+                                                      NULL, 0, &ChildImageHandle);
+       } else {
+          Print(L"Invalid loader file!\n");
+          ReturnStatus = EFI_LOAD_ERROR;
+       }
        if (ReturnStatus != EFI_NOT_FOUND) {
           break;
        }
@@ -377,7 +415,6 @@ static EFI_STATUS RebootIntoFirmware(VOID) {
    refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
    Print(L"Error calling ResetSystem: %r", err);
    PauseForKey();
-//   uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
    return err;
 }
 
@@ -1186,34 +1223,6 @@ static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO
    return (DirEntry->FileSize != FileSize2);
 } // BOOLEAN IsSymbolicLink()
 
-// Returns TRUE if this file is a valid EFI loader file, and is proper ARCH
-static BOOLEAN IsValidLoader(REFIT_VOLUME *Volume, CHAR16 *FileName) {
-    BOOLEAN         IsValid = TRUE;
-#if defined (EFIX64) | defined (EFI32)
-    EFI_STATUS      Status;
-    EFI_FILE_HANDLE FileHandle;
-    CHAR8           Header[512];
-    UINTN           Size = sizeof(Header);
-
-    Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
-    if (EFI_ERROR(Status))
-       return 0;
-
-    Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &Size, Header);
-    refit_call1_wrapper(FileHandle->Close, FileHandle);
-
-    IsValid = !EFI_ERROR(Status) &&
-              Size == sizeof(Header) &&
-              ((Header[0] == 'M' && Header[1] == 'Z' &&
-               (Size = *(UINT32 *)&Header[0x3c]) < 0x180 &&
-               Header[Size] == 'P' && Header[Size+1] == 'E' &&
-               Header[Size+2] == 0 && Header[Size+3] == 0 &&
-               *(UINT16 *)&Header[Size+4] == EFI_STUB_ARCH) ||
-              (*(UINT32 *)&Header == FAT_ARCH));
-#endif
-    return IsValid;
-} // BOOLEAN IsValidLoader()
-
 // Scan an individual directory for EFI boot loader files and, if found,
 // add them to the list. Exception: Ignores FALLBACK_FULLNAME, which is picked
 // up in ScanEfiFiles(). Sorts the entries within the loader directory so that
@@ -1250,7 +1259,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
              SPrint(FileName, 255, L"\\%s", DirEntry->FileName);
           CleanUpPathNameSlashes(FileName);
 
-          if(!IsValidLoader(Volume, FileName))
+          if(!IsValidLoader(Volume->RootDir, FileName))
              continue;
 
           NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST));
@@ -1366,9 +1375,9 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
             Length = StrLen(Directory);
             if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns))
                ScanFallbackLoader = FALSE;
-         } // if
+            MyFreePool(VolName);
+         } // if should scan dir
          MyFreePool(Directory);
-         MyFreePool(VolName);
       } // while
 
       // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself....
@@ -2376,8 +2385,8 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     FindLegacyBootType();
     if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC)
        CopyMem(GlobalConfig.ScanFor, "ihebocm   ", NUM_SCAN_OPTIONS);
-    ScanVolumes();
     ReadConfig(CONFIG_FILE_NAME);
+    ScanVolumes();
 
     InitScreen();
     WarnIfLegacyProblems();