]> code.delx.au - refind/commitdiff
Protection against loading invalid EFI drivers; bug fix for using
authorsrs5694 <srs5694@users.sourceforge.net>
Wed, 24 Jul 2013 23:40:35 +0000 (19:40 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Wed, 24 Jul 2013 23:40:35 +0000 (19:40 -0400)
volume specification in also_scan_dirs token.

NEWS.txt
docs/refind/configfile.html
refind/config.h
refind/lib.c
refind/main.c

index 23545371fd459f51c6a8b3c525aca6c91d7eeef6..016b9a556f5edcad45fa6964b9e1c37e73272b10 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,9 +1,16 @@
 0.7.2 (?/??/2013):
 ------------------
 
 0.7.2 (?/??/2013):
 ------------------
 
-- Added PreLoader.efi to default dont_scan_files list; it's now "shim.efi,
-  PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi,
-  MokManager.efi, HashTool.efi, HashTool-signed.efi".
+- Fixed bug that could cause incorrect scanning or even a rEFInd crash when
+  using volume specification in also_scan_dirs token.
+
+- Added protection against loading invalid drivers and other EFI programs.
+  (Some EFIs crash when attempting to load such drivers and programs.)
+
+- Added PreLoader.efi and shim-fedora.efi to default dont_scan_files list;
+  it's now "shim.efi, shim-fedora.efi, PreLoader.efi, TextMode.efi,
+  ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi,
+  HashTool-signed.efi".
 
 - Added icon for Funtoo Linux.
 
 
 - Added icon for Funtoo Linux.
 
index f6c05b3b4ebf3adab2889e1ee24ac4903c97470d..361087a65e2f79a2ff024b2c7ac4b45949d395f1 100644 (file)
@@ -304,7 +304,7 @@ timeout 20
 <tr>
    <td><tt>dont_scan_files</tt> or <tt>don't_scan_files</tt></td>
    <td>filename(s)</td>
 <tr>
    <td><tt>dont_scan_files</tt> or <tt>don't_scan_files</tt></td>
    <td>filename(s)</td>
-   <td>Adds the specified filename or filenames to a filename "blacklist"&mdash;these files are <i>not</i> included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as <tt>shim.efi</tt> and <tt>MokManager.efi</tt>) and drivers from your OS list. The default value is <tt>shim.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi</tt>, <tt>MokManager.efi</tt>, <tt>HashTool.efi</tt>, <tt>HashTool-signed.efi</tt>.</td>
+   <td>Adds the specified filename or filenames to a filename "blacklist"&mdash;these files are <i>not</i> included as boot loader options even if they're found on the disk. This is useful to exclude support programs (such as <tt>shim.efi</tt> and <tt>MokManager.efi</tt>) and drivers from your OS list. The default value is <tt>shim.efi, shim-fedora.efi, PreLoader.efi, TextMode.efi, ebounce.efi, GraphicsConsole.efi, MokManager.efi, HashTool.efi, HashTool-signed.efi</tt>.</td>
 </tr>
 <tr>
    <td><tt>scan_all_linux_kernels</tt></td>
 </tr>
 <tr>
    <td><tt>scan_all_linux_kernels</tt></td>
index 58f04ea9797ebdd3a173d83ff4ecf64b2d6b3d41..aad46a69b54f3f4e61bd7fd4ae44ffbcd552b696 100644 (file)
@@ -80,7 +80,7 @@ typedef struct {
 
 #define CONFIG_FILE_NAME         L"refind.conf"
 // Note: Below is combined with MOK_NAMES to make default
 
 #define CONFIG_FILE_NAME         L"refind.conf"
 // Note: Below is combined with MOK_NAMES to make default
-#define DONT_SCAN_FILES L"shim.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi"
+#define DONT_SCAN_FILES L"shim.efi,shim-fedora.efi,PreLoader.efi,TextMode.efi,ebounce.efi,GraphicsConsole.efi"
 #define DONT_SCAN_VOLUMES L"Recovery HD"
 #define ALSO_SCAN_DIRS L"boot"
 
 #define DONT_SCAN_VOLUMES L"Recovery HD"
 #define ALSO_SCAN_DIRS L"boot"
 
index d0af83baf4e592500c8bcd9cdf85686e76453fed..f0b0e6f169fd0dd882cf650090d75bd65be1e195 100644 (file)
@@ -115,10 +115,11 @@ static VOID UninitVolumes(VOID);
 // isn't present.
 VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
    CHAR16   *NewName;
 // isn't present.
 VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
    CHAR16   *NewName;
-   UINTN    i, FinalChar = 0;
+   UINTN    i, Length, FinalChar = 0;
    BOOLEAN  LastWasSlash = FALSE;
 
    BOOLEAN  LastWasSlash = FALSE;
 
-   NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 2));
+   Length = StrLen(PathName);
+   NewName = AllocateZeroPool(sizeof(CHAR16) * (Length + 2));
    if (NewName != NULL) {
       for (i = 0; i < StrLen(PathName); i++) {
          if ((PathName[i] == L'/') || (PathName[i] == L'\\')) {
    if (NewName != NULL) {
       for (i = 0; i < StrLen(PathName); i++) {
          if ((PathName[i] == L'/') || (PathName[i] == L'\\')) {
index 250ff1ba63dba933fc6a1134b4bf6019c93adfba..f7e7616f41caee7e5991aad7951004b657338236 100644 (file)
@@ -210,6 +210,34 @@ static VOID WarnSecureBootError(CHAR16 *Name, BOOLEAN Verbose) {
    } // if
 } // VOID WarnSecureBootError()
 
    } // 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,
 // 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;
     EFI_STATUS              Status, ReturnStatus;
     EFI_HANDLE              ChildImageHandle;
     EFI_LOADED_IMAGE        *ChildLoadedImage = NULL;
+    REFIT_VOLUME            *Volume = NULL;
     UINTN                   DevicePathIndex;
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
     UINTN                   DevicePathIndex;
     CHAR16                  ErrorInfo[256];
     CHAR16                  *FullLoadOptions = NULL;
+    CHAR16                  *Filename = NULL;
 
     if (ErrorInStep != NULL)
         *ErrorInStep = 0;
 
     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++) {
     // 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;
        }
        if (ReturnStatus != EFI_NOT_FOUND) {
           break;
        }
@@ -1185,34 +1223,6 @@ static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO
    return (DirEntry->FileSize != FileSize2);
 } // BOOLEAN IsSymbolicLink()
 
    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
 // 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
@@ -1249,7 +1259,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16
              SPrint(FileName, 255, L"\\%s", DirEntry->FileName);
           CleanUpPathNameSlashes(FileName);
 
              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));
              continue;
 
           NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST));
@@ -1365,9 +1375,9 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
             Length = StrLen(Directory);
             if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns))
                ScanFallbackLoader = FALSE;
             Length = StrLen(Directory);
             if ((Length > 0) && ScanLoaderDir(Volume, Directory, MatchPatterns))
                ScanFallbackLoader = FALSE;
-         } // if
+            MyFreePool(VolName);
+         } // if should scan dir
          MyFreePool(Directory);
          MyFreePool(Directory);
-         MyFreePool(VolName);
       } // while
 
       // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself....
       } // while
 
       // Don't scan the fallback loader if it's on the same volume and a duplicate of rEFInd itself....