]> code.delx.au - refind/commitdiff
Improved GPT support; uses CRCs to minimize the risk of damaged data wreaking
authorsrs5694 <srs5694@users.sourceforge.net>
Sat, 3 May 2014 03:30:16 +0000 (23:30 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Sat, 3 May 2014 03:30:16 +0000 (23:30 -0400)
havoc.

refind/Make.tiano
refind/Makefile
refind/gpt.c
refind/main.c

index 60fe750640be6cee245a547c8bdf5c3cbe0cbe44..d9bb1873d9c23a2b59c43aee48f50dbb566afb10 100644 (file)
@@ -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 gpt AutoGen
+SOURCE_NAMES     = config driver_support icns lib main menu screen gpt crc32 AutoGen
 OBJS             = $(SOURCE_NAMES:=.obj)
 
 all: $(BUILDME)
index 506ee116928b5c3b91b72e4fba4a3dd155a33d0b..ba39980a04e6a5e88690e759e17947423d6d9659 100644 (file)
@@ -25,7 +25,7 @@ LOCAL_CPPFLAGS  = -I$(SRCDIR) -I$(SRCDIR)/../include -I$(SRCDIR)/../libeg -I$(SR
 LOCAL_LDFLAGS   = -L$(SRCDIR)/../libeg/ -L$(SRCDIR)/../mok/
 LOCAL_LIBS      = -leg -lmok
 
-OBJS            = main.o config.o menu.o screen.o icns.o gpt.o lib.o driver_support.o
+OBJS            = main.o config.o menu.o screen.o icns.o gpt.o crc32.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)
index 4f9be225406bf031fbb8b71299d40681baba25e7..eb106b7960efa21141ac1a0d9343cbeb9b32712e 100644 (file)
@@ -14,6 +14,7 @@
 #include "gpt.h"
 #include "lib.h"
 #include "screen.h"
+#include "crc32.h"
 #include "../include/refit_call_wrapper.h"
 
 #ifdef __MAKEWITH_TIANO
 
 extern GPT_DATA *gPartitions;
 
+// Allocate data for the main GPT_DATA structure, as well as the ProtectiveMBR
+// and Header structures it contains. This function does *NOT*, however,
+// allocate memory for the Entries data structure, since its size is variable
+// and is determined by the contents of Header.
 GPT_DATA * AllocateGptData(VOID) {
    GPT_DATA *GptData;
 
@@ -39,6 +44,8 @@ GPT_DATA * AllocateGptData(VOID) {
    return GptData;
 } // GPT_DATA * AllocateGptData()
 
+// Unallocate a single GPT_DATA structure. This does NOT follow the
+// linked list, though.
 VOID ClearGptData(GPT_DATA *Data) {
    if (Data) {
       if (Data->ProtectiveMBR)
@@ -51,24 +58,49 @@ VOID ClearGptData(GPT_DATA *Data) {
    } // if
 } // VOID ClearGptData()
 
-// TODO: Add more tests, like a CRC check.
+// TODO: Make this work on big-endian systems; at the moment, it contains
+// little-endian assumptions!
 // Returns TRUE if the GPT header data appear valid, FALSE otherwise.
-static BOOLEAN GptHeaderValid(GPT_HEADER *Header) {
-   BOOLEAN IsValid = TRUE;
-
-   if ((Header->signature != 0x5452415020494645ULL) || (Header->entry_count > 2048))
-      IsValid = FALSE;
+static BOOLEAN GptHeaderValid(GPT_DATA *GptData) {
+   BOOLEAN IsValid;
+   UINT32 CrcValue, StoredCrcValue;
+   UINTN HeaderSize = sizeof(GPT_HEADER);
+
+   IsValid = ((GptData != NULL) && (GptData->ProtectiveMBR != NULL) && (GptData->Header != NULL));
+   IsValid = IsValid && (GptData->ProtectiveMBR->MBRSignature == 0xAA55);
+   IsValid = IsValid && ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[1].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[2].type == 0xEE) ||
+                         (GptData->ProtectiveMBR->partitions[3].type == 0xEE));
+   IsValid = IsValid && (GptData->Header->signature == 0x5452415020494645ULL);
+
+   // Looks good so far; check CRC value....
+   if (IsValid) {
+      if (GptData->Header->header_size < HeaderSize)
+         HeaderSize = GptData->Header->header_size;
+      StoredCrcValue = GptData->Header->header_crc32;
+      GptData->Header->header_crc32 = 0;
+      CrcValue = crc32(0x0, GptData->Header, HeaderSize);
+      if (CrcValue != StoredCrcValue)
+         IsValid = FALSE;
+      GptData->Header->header_crc32 = StoredCrcValue;
+   } // if
 
    return IsValid;
-} // BOOLEAN GptHeaderValid
+} // BOOLEAN GptHeaderValid()
 
 // Read GPT data from Volume and store it in Data. Note that this function
-// may be called on a Volume that is not in fact the protective MBR of a GPT
-// disk, in which case it will return EFI_LOAD_ERROR or some other error
-// condition. In this case, *Data will be left alone.
+// may be called on a Volume that is not in fact a GPT disk (an MBR disk,
+// a partition, etc.), in which case it will return EFI_LOAD_ERROR or some
+// other error condition. In this case, *Data will be left alone.
+// Note also that this function checks CRCs and does other sanity checks
+// on the input data, but does NOT resort to using the backup data if the
+// primary data structures are damaged.
 EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
    EFI_STATUS Status = EFI_SUCCESS;
    UINT64     BufferSize;
+   UINT32     TableCrc;
+   UINTN      i;
    GPT_DATA   *GptData; // Temporary holding storage; transferred to *Data later
 
    if ((Volume == NULL) || (Data == NULL))
@@ -80,7 +112,7 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
       if (EFI_ERROR(Status)) {
          Volume->BlockIO = NULL;
          Print(L"Warning: Can't get BlockIO protocol.\n");
-         Status = EFI_INVALID_PARAMETER;
+         Status = EFI_NOT_READY;
       }
    } // if
 
@@ -88,7 +120,7 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
       Status = EFI_NO_MEDIA;
 
    if (Status == EFI_SUCCESS) {
-      GptData = AllocateGptData();
+      GptData = AllocateGptData(); // Note: All but GptData->Entries
       if (GptData == NULL) {
          Status = EFI_OUT_OF_RESOURCES;
       } // if
@@ -100,20 +132,16 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
                                    0, 512, (VOID*) GptData->ProtectiveMBR);
    }
 
-   // If it looks like a valid protective MBR, try to do more with it....
-   if ((Status == EFI_SUCCESS) && (GptData->ProtectiveMBR->MBRSignature == 0xAA55) &&
-       ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) || (GptData->ProtectiveMBR->partitions[1].type == 0xEE) ||
-        (GptData->ProtectiveMBR->partitions[2].type = 0xEE) || (GptData->ProtectiveMBR->partitions[3].type == 0xEE))) {
+   // Read the GPT header and store it in GptData->Header.
+   if (Status == EFI_SUCCESS) {
       Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
                                    1, sizeof(GPT_HEADER), GptData->Header);
+   }
 
-      // Do basic sanity check on GPT header.
-      if ((Status == EFI_SUCCESS) && !GptHeaderValid(GptData->Header)) {
-         Status = EFI_UNSUPPORTED;
-      }
-
-      // Load actual GPT table....
-      if (Status == EFI_SUCCESS) {
+   // If it looks like a valid protective MBR, try to do more with it....
+   if (Status == EFI_SUCCESS) {
+      if (GptHeaderValid(GptData)) {
+         // Load actual GPT table....
          BufferSize = GptData->Header->entry_count * 128;
          if (GptData->Entries != NULL)
             MyFreePool(GptData->Entries);
@@ -121,16 +149,28 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) {
          if (GptData->Entries == NULL) {
             Status = EFI_OUT_OF_RESOURCES;
          } // if
-      } // if
 
-      if (Status == EFI_SUCCESS) {
-         Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
-                                      GptData->Header->header_lba, BufferSize, GptData->Entries);
-      } // if
+         if (Status == EFI_SUCCESS) {
+            Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId,
+                                         GptData->Header->entry_lba, BufferSize, GptData->Entries);
+         } // if
 
-   } else {
-      Status = EFI_LOAD_ERROR;
-   } // if/else
+         // Check CRC status of table
+         if (Status == EFI_SUCCESS) {
+            TableCrc = crc32(0x0, GptData->Entries, BufferSize);
+            if (TableCrc != GptData->Header->entry_crc32)
+               Status = EFI_CRC_ERROR;
+         } // if
+
+         // Now, ensure that every name is null-terminated....
+         if (Status == EFI_SUCCESS) {
+            for (i = 0; i < GptData->Header->entry_count; i++)
+               GptData->Entries[i].name[35] = '\0';
+         } // if
+      } else {
+         Status = EFI_UNSUPPORTED;
+      } // if/else valid header
+   } // if header read OK
 
    if (Status == EFI_SUCCESS) {
       // Everything looks OK, so copy it over
@@ -184,6 +224,7 @@ VOID ForgetPartitionTables(VOID) {
 VOID AddPartitionTable(REFIT_VOLUME *Volume) {
    GPT_DATA    *GptData = NULL, *GptList;
    EFI_STATUS  Status;
+   UINTN       NumTables = 1;
 
    Status = ReadGptData(Volume, &GptData);
    if (Status == EFI_SUCCESS) {
@@ -193,11 +234,16 @@ VOID AddPartitionTable(REFIT_VOLUME *Volume) {
          GptList = gPartitions;
          while (GptList->NextEntry != NULL) {
             GptList = GptList->NextEntry;
+            NumTables++;
          } // while
          GptList->NextEntry = GptData;
+         NumTables++;
       } // if/else
    } else if (GptData != NULL) {
       ClearGptData(GptData);
+      NumTables = 0;
    } // if/else
+   Print(L"In AddPartitionTable(), total number of tables is %d\n", NumTables);
+   PauseForKey();
 } // VOID AddPartitionTable()
 
index 3905d0073d0a785bad642d13c7548a1fa73308be..64fe8985c310f91a51b4ecfd8dcd9b3c5823c56b 100644 (file)
@@ -162,7 +162,7 @@ static VOID AboutrEFInd(VOID)
 {
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.3");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.4");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith");
@@ -2191,7 +2191,7 @@ static VOID ScanForBootloaders(VOID) {
 //       PauseForKey();
 //    }
 
-   ScanVolumes();
+//   ScanVolumes();
 
    // scan for loaders and tools, add them to the menu
    for (i = 0; i < NUM_SCAN_OPTIONS; i++) {
@@ -2512,7 +2512,7 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
        CopyMem(GlobalConfig.ScanFor, "ihebocm   ", NUM_SCAN_OPTIONS);
     SetConfigFilename(ImageHandle);
     ReadConfig(GlobalConfig.ConfigFilename);
-    ScanVolumes();
+//    ScanVolumes();
 
     InitScreen();
     WarnIfLegacyProblems();
@@ -2524,6 +2524,7 @@ efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
     // further bootstrap (now with config available)
     MokProtocol = SecureBootSetup();
     LoadDrivers();
+    ScanVolumes();
     ScanForBootloaders();
     ScanForTools();
     SetupScreen();