mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-30 12:43:41 +01:00
665 lines
18 KiB
C
665 lines
18 KiB
C
/**
|
|
|
|
Allows to choose a random KASLR slide offset,
|
|
when some offsets cannot be used.
|
|
|
|
by Download-Fritz & vit9696
|
|
|
|
**/
|
|
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/OcDeviceTreeLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/RngLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <IndustryStandard/AppleCsrConfig.h>
|
|
#include <Register/Microcode.h>
|
|
|
|
#include "Config.h"
|
|
#include "CustomSlide.h"
|
|
#include "BootArgs.h"
|
|
#include "BootFixes.h"
|
|
#include "MemoryMap.h"
|
|
#include "RtShims.h"
|
|
#include "ServiceOverrides.h"
|
|
|
|
//
|
|
// Modified boot-args buffer with an additional slide parameter, when custom slide is used.
|
|
//
|
|
STATIC BOOLEAN mStoredBootArgsVarSet;
|
|
STATIC UINTN mStoredBootArgsVarSize;
|
|
STATIC CHAR8 mStoredBootArgsVar[BOOT_LINE_LENGTH];
|
|
|
|
//
|
|
// Memory map slide availability analysis status.
|
|
//
|
|
STATIC BOOLEAN mAnalyzeMemoryMapDone;
|
|
|
|
//
|
|
// Original csr-active-config value to be restored before kernel handoff.
|
|
//
|
|
STATIC BOOLEAN mCsrActiveConfigSet;
|
|
STATIC UINT32 mCsrActiveConfig;
|
|
|
|
//
|
|
// List of KASLR slides that do not conflict with the previously allocated memory.
|
|
//
|
|
STATIC UINT8 mValidSlides[TOTAL_SLIDE_NUM];
|
|
STATIC UINT32 mValidSlidesNum = TOTAL_SLIDE_NUM;
|
|
|
|
//
|
|
// Detect Sandy or Ivy Bridge CPUs, since they use a different slide formula.
|
|
//
|
|
STATIC BOOLEAN mSandyOrIvy;
|
|
STATIC BOOLEAN mSandyOrIvySet;
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
IsSandyOrIvy (
|
|
VOID
|
|
)
|
|
{
|
|
CPU_MICROCODE_PROCESSOR_SIGNATURE Sig;
|
|
UINT32 CpuFamily;
|
|
UINT32 CpuModel;
|
|
|
|
if (!mSandyOrIvySet) {
|
|
Sig.Uint32 = 0;
|
|
|
|
AsmCpuid (1, &Sig.Uint32, NULL, NULL, NULL);
|
|
|
|
CpuFamily = Sig.Bits.Family;
|
|
if (CpuFamily == 15) {
|
|
CpuFamily += Sig.Bits.ExtendedFamily;
|
|
}
|
|
|
|
CpuModel = Sig.Bits.Model;
|
|
if (CpuFamily == 15 || CpuFamily == 6) {
|
|
CpuModel |= Sig.Bits.ExtendedModel << 4;
|
|
}
|
|
|
|
mSandyOrIvy = CpuFamily == 6 && (CpuModel == 0x2A || CpuModel == 0x3A);
|
|
mSandyOrIvySet = TRUE;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "Discovered CpuFamily %d CpuModel %d SandyOrIvy %d\n", CpuFamily, CpuModel, mSandyOrIvy));
|
|
}
|
|
|
|
return mSandyOrIvy;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
GetSlideRangeForValue (
|
|
UINT8 Slide,
|
|
UINTN *StartAddr,
|
|
UINTN *EndAddr
|
|
)
|
|
{
|
|
*StartAddr = (UINTN)Slide * SLIDE_GRANULARITY + BASE_KERNEL_ADDR;
|
|
|
|
//
|
|
// Skip ranges used by Intel HD 2000/3000.
|
|
//
|
|
if (Slide >= 0x80 && IsSandyOrIvy ()) {
|
|
*StartAddr += 0x10200000;
|
|
}
|
|
|
|
*EndAddr = *StartAddr + APTIOFIX_SPECULATED_KERNEL_SIZE;
|
|
}
|
|
|
|
STATIC
|
|
UINT8
|
|
GenerateRandomSlideValue (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Clock = 0;
|
|
UINT32 Ecx = 0;
|
|
UINT8 Slide = 0;
|
|
UINT16 Value = 0;
|
|
BOOLEAN RdRandSupport;
|
|
|
|
AsmCpuid (0x1, NULL, NULL, &Ecx, NULL);
|
|
RdRandSupport = (Ecx & 0x40000000) != 0;
|
|
|
|
do {
|
|
if (RdRandSupport && GetRandomNumber16 (&Value) == EFI_SUCCESS && (UINT8) Value != 0) {
|
|
Slide = (UINT8) Value;
|
|
} else {
|
|
Clock = (UINT32) AsmReadTsc ();
|
|
Slide = (Clock & 0xFF) ^ ((Clock >> 8) & 0xFF);
|
|
}
|
|
} while (Slide == 0);
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "Generated slide index %d value %d\n", Slide, mValidSlides[Slide % mValidSlidesNum]));
|
|
|
|
//
|
|
//FIXME: This is bad due to uneven distribution, but let's use it for now.
|
|
//
|
|
return mValidSlides[Slide % mValidSlidesNum];
|
|
}
|
|
|
|
#if APTIOFIX_CLEANUP_SLIDE_BOOT_ARGUMENT == 1
|
|
STATIC
|
|
VOID
|
|
HideSlideFromOS (
|
|
AMF_BOOT_ARGUMENTS *BootArgs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DTEntry Chosen;
|
|
CHAR8 *ArgsStr;
|
|
UINT32 ArgsSize;
|
|
|
|
//
|
|
// First, there is a BootArgs entry for XNU
|
|
//
|
|
RemoveArgumentFromCommandLine (BootArgs->CommandLine, "slide=");
|
|
|
|
//
|
|
// Second, there is a DT entry
|
|
//
|
|
DTInit ((VOID *)(UINTN)(*BootArgs->deviceTreeP), BootArgs->deviceTreeLength);
|
|
Status = DTLookupEntry (NULL, "/chosen", &Chosen);
|
|
if (!EFI_ERROR(Status)) {
|
|
DEBUG ((DEBUG_VERBOSE, "Found /chosen\n"));
|
|
Status = DTGetProperty(Chosen, "boot-args", (VOID **)&ArgsStr, &ArgsSize);
|
|
if (!EFI_ERROR(Status) && ArgsSize > 0) {
|
|
DEBUG ((DEBUG_VERBOSE, "Found boot-args in /chosen\n"));
|
|
RemoveArgumentFromCommandLine (ArgsStr, "slide=");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Third, clean the boot args just in case
|
|
//
|
|
mValidSlidesNum = 0;
|
|
mStoredBootArgsVarSize = 0;
|
|
ZeroMem (mValidSlides, sizeof(mValidSlides));
|
|
ZeroMem (mStoredBootArgsVar, sizeof(mStoredBootArgsVar));
|
|
}
|
|
#endif
|
|
|
|
STATIC
|
|
VOID
|
|
DecideOnCustomSlideImplementation (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN AllocatedMapPages;
|
|
UINTN MemoryMapSize;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
|
UINTN MapKey;
|
|
EFI_STATUS Status;
|
|
UINTN DescriptorSize;
|
|
UINT32 DescriptorVersion;
|
|
UINTN Index;
|
|
UINTN Slide;
|
|
UINTN NumEntries;
|
|
UINTN MaxAvailableSize = 0;
|
|
UINT8 FallbackSlide = 0;
|
|
|
|
Status = GetMemoryMapAlloc (
|
|
&AllocatedMapPages,
|
|
&MemoryMapSize,
|
|
&MemoryMap,
|
|
&MapKey,
|
|
&DescriptorSize,
|
|
&DescriptorVersion
|
|
);
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
Print (L"AMF: Failed to obtain memory map for KASLR - %r\n", Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// At this point we have a memory map that we could use to determine what slide values are allowed.
|
|
//
|
|
NumEntries = MemoryMapSize / DescriptorSize;
|
|
|
|
//
|
|
// Reset valid slides to zero and find actually working ones.
|
|
//
|
|
mValidSlidesNum = 0;
|
|
|
|
for (Slide = 0; Slide < TOTAL_SLIDE_NUM; Slide++) {
|
|
EFI_MEMORY_DESCRIPTOR *Desc = MemoryMap;
|
|
BOOLEAN Supported = TRUE;
|
|
UINTN StartAddr;
|
|
UINTN EndAddr;
|
|
UINTN DescEndAddr;
|
|
UINTN AvailableSize;
|
|
|
|
GetSlideRangeForValue ((UINT8)Slide, &StartAddr, &EndAddr);
|
|
|
|
AvailableSize = 0;
|
|
|
|
for (Index = 0; Index < NumEntries; Index++) {
|
|
DescEndAddr = (Desc->PhysicalStart + EFI_PAGES_TO_SIZE (Desc->NumberOfPages));
|
|
|
|
if ((Desc->PhysicalStart < EndAddr) && (DescEndAddr > StartAddr)) {
|
|
//
|
|
// The memory overlaps with the slide region.
|
|
//
|
|
if (Desc->Type != EfiConventionalMemory) {
|
|
//
|
|
// The memory is unusable atm.
|
|
//
|
|
Supported = FALSE;
|
|
break;
|
|
} else {
|
|
//
|
|
// The memory will be available for the kernel.
|
|
//
|
|
AvailableSize += EFI_PAGES_TO_SIZE (Desc->NumberOfPages);
|
|
|
|
if (Desc->PhysicalStart < StartAddr) {
|
|
//
|
|
// The region starts before the slide region.
|
|
// Subtract the memory that is located before the slide region.
|
|
//
|
|
AvailableSize -= (StartAddr - Desc->PhysicalStart);
|
|
}
|
|
|
|
if (DescEndAddr > EndAddr) {
|
|
//
|
|
// The region ends after the slide region.
|
|
// Subtract the memory that is located after the slide region.
|
|
//
|
|
AvailableSize -= (DescEndAddr - EndAddr);
|
|
}
|
|
}
|
|
}
|
|
|
|
Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
|
|
}
|
|
|
|
if (AvailableSize > MaxAvailableSize) {
|
|
MaxAvailableSize = AvailableSize;
|
|
FallbackSlide = (UINT8)Slide;
|
|
}
|
|
|
|
if ((StartAddr + AvailableSize) != EndAddr) {
|
|
//
|
|
// The slide region is not continuous.
|
|
//
|
|
Supported = FALSE;
|
|
}
|
|
|
|
if (Supported) {
|
|
DEBUG ((DEBUG_VERBOSE, "Slide %03d at %08x:%08x should be ok.\n", (UINT32)Slide, (UINT32)StartAddr, (UINT32)EndAddr));
|
|
mValidSlides[mValidSlidesNum++] = (UINT8)Slide;
|
|
} else {
|
|
DEBUG ((DEBUG_VERBOSE, "Slide %03d at %08x:%08x cannot be used!\n", (UINT32)Slide, (UINT32)StartAddr, (UINT32)EndAddr));
|
|
}
|
|
}
|
|
|
|
gBS->FreePages ((EFI_PHYSICAL_ADDRESS)MemoryMap, AllocatedMapPages);
|
|
|
|
if (mValidSlidesNum != TOTAL_SLIDE_NUM) {
|
|
if (mValidSlidesNum == 0) {
|
|
Print (L"AMF: No slide values are usable! Falling back to %d with 0x%08X bytes!\n", FallbackSlide, MaxAvailableSize);
|
|
mValidSlides[mValidSlidesNum++] = (UINT8)FallbackSlide;
|
|
} else {
|
|
//
|
|
// Pretty-print valid slides as ranges.
|
|
// For example, 1, 2, 3, 4, 5 will become 1-5.
|
|
//
|
|
Print (L"AMF: Only %d/%d slide values are usable!\n", mValidSlidesNum, TOTAL_SLIDE_NUM);
|
|
NumEntries = 0;
|
|
for (Index = 0; Index <= mValidSlidesNum; Index++) {
|
|
if (Index == 0) {
|
|
Print (L"Valid slides: %d", mValidSlides[Index]);
|
|
} else if (Index == mValidSlidesNum || mValidSlides[Index - 1] + 1 != mValidSlides[Index]) {
|
|
if (NumEntries == 1) {
|
|
Print (L", %d", mValidSlides[Index - 1]);
|
|
} else if (NumEntries > 1) {
|
|
Print (L"-%d", mValidSlides[Index - 1]);
|
|
}
|
|
if (Index == mValidSlidesNum) {
|
|
Print (L"\n");
|
|
} else {
|
|
Print (L", %d", mValidSlides[Index]);
|
|
}
|
|
NumEntries = 0;
|
|
} else {
|
|
NumEntries++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetVariableCsrActiveConfig (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 *Config;
|
|
|
|
//
|
|
// If we were asked for the size, just return it right away.
|
|
//
|
|
if (!Data || *DataSize < sizeof(UINT32)) {
|
|
*DataSize = sizeof(UINT32);
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
Config = (UINT32 *)Data;
|
|
|
|
//
|
|
// Otherwise call the original function.
|
|
//
|
|
Status = OrgGetVariable (VariableName, VendorGuid, Attributes, DataSize, Data);
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG ((DEBUG_INFO, "GetVariable csr-active-config returned %r\n", Status));
|
|
|
|
*Config = 0;
|
|
Status = EFI_SUCCESS;
|
|
if (Attributes) {
|
|
*Attributes =
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS |
|
|
EFI_VARIABLE_NON_VOLATILE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We must unrestrict NVRAM from SIP or slide=X will not be supported.
|
|
//
|
|
mCsrActiveConfig = *Config;
|
|
mCsrActiveConfigSet = TRUE;
|
|
*Config |= CSR_ALLOW_UNRESTRICTED_NVRAM;
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetVariableBootArgs (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN StoredBootArgsSize = BOOT_LINE_LENGTH;
|
|
UINT8 Slide;
|
|
CHAR8 SlideArgument[10];
|
|
CONST UINTN SlideArgumentLength = ARRAY_SIZE (SlideArgument)-1;
|
|
|
|
if (!mStoredBootArgsVarSet) {
|
|
Slide = GenerateRandomSlideValue ();
|
|
Status = OrgGetVariable (VariableName, VendorGuid, Attributes, &StoredBootArgsSize, mStoredBootArgsVar);
|
|
if (EFI_ERROR(Status)) {
|
|
mStoredBootArgsVar[0] = '\0';
|
|
}
|
|
|
|
//
|
|
// Note, the point is to always pass 3 characters to avoid side attacks on value length.
|
|
//
|
|
AsciiSPrint (SlideArgument, ARRAY_SIZE (SlideArgument), "slide=%-03d", Slide);
|
|
|
|
if (!AppendArgumentToCommandLine (mStoredBootArgsVar, SlideArgument, SlideArgumentLength)) {
|
|
//
|
|
// Broken boot-args, try to overwrite.
|
|
//
|
|
AsciiStrnCpyS (mStoredBootArgsVar, SlideArgumentLength + 1, SlideArgument, SlideArgumentLength + 1);;
|
|
}
|
|
|
|
mStoredBootArgsVarSize = AsciiStrLen(mStoredBootArgsVar) + 1;
|
|
mStoredBootArgsVarSet = TRUE;
|
|
}
|
|
|
|
if (Attributes) {
|
|
*Attributes =
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS |
|
|
EFI_VARIABLE_NON_VOLATILE;
|
|
}
|
|
|
|
if (*DataSize >= mStoredBootArgsVarSize && Data) {
|
|
AsciiStrnCpyS (Data, *DataSize, mStoredBootArgsVar, mStoredBootArgsVarSize);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*DataSize = mStoredBootArgsVarSize;
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UnlockSlideSupportForSafeMode (
|
|
UINT8 *ImageBase,
|
|
UINTN ImageSize
|
|
)
|
|
{
|
|
//
|
|
// boot.efi performs the following check:
|
|
// if (State & (BOOT_MODE_SAFE | BOOT_MODE_ASLR)) == (BOOT_MODE_SAFE | BOOT_MODE_ASLR)) {
|
|
// * Disable KASLR *
|
|
// }
|
|
// We do not care about the asm it will use for it, but we could assume that the constants
|
|
// will be used twice and their location will be very close to each other.
|
|
//
|
|
// BOOT_MODE_SAFE | BOOT_MODE_ASLR constant is 0x4001 in hex.
|
|
// It has not changed since its appearance, so is most likely safe to look for.
|
|
// Furthermore, since boot.efi state mask uses higher bits, it is safe to assume that
|
|
// the comparison will be at least 32-bit.
|
|
//
|
|
//
|
|
// The new way patch is a workaround for 10.13.5 and newer, where the code got finally changed.
|
|
// if (State & BOOT_MODE_SAFE) {
|
|
// ReportFeature(FEATURE_BOOT_MODE_SAFE);
|
|
// if (State & BOOT_MODE_ASLR) {
|
|
// * Disable KASLR *
|
|
// }
|
|
// }
|
|
//
|
|
CONST UINT8 SearchSeqNew[] = {0xF6, 0xC4, 0x40, 0x75};
|
|
CONST UINT8 SearchSeq[] = {0x01, 0x40, 0x00, 0x00};
|
|
|
|
//
|
|
// This is a reasonable maximum distance to expect between the instructions.
|
|
//
|
|
CONST UINTN MaxDist = 0x10;
|
|
|
|
UINT8 *StartOff = ImageBase;
|
|
UINT8 *EndOff = StartOff + ImageSize - sizeof (SearchSeq) - MaxDist;
|
|
|
|
UINTN FirstOff = 0;
|
|
UINTN SecondOff = 0;
|
|
|
|
BOOLEAN NewWay = FALSE;
|
|
|
|
do {
|
|
while (StartOff + FirstOff <= EndOff) {
|
|
if (!CompareMem (StartOff + FirstOff, SearchSeqNew, sizeof (SearchSeqNew))) {
|
|
NewWay = TRUE;
|
|
break;
|
|
} else if (!CompareMem (StartOff + FirstOff, SearchSeq, sizeof (SearchSeq))) {
|
|
break;
|
|
}
|
|
FirstOff++;
|
|
}
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "Found first %d at off %X\n", (UINT32)NewWay, (UINT32)FirstOff));
|
|
|
|
if (StartOff + FirstOff > EndOff) {
|
|
DEBUG ((DEBUG_INFO, "Failed to find first BOOT_MODE_SAFE | BOOT_MODE_ASLR sequence\n"));
|
|
break;
|
|
}
|
|
|
|
if (NewWay) {
|
|
//
|
|
// Here we just patch the comparison code and the check by straight nopping.
|
|
//
|
|
DEBUG ((DEBUG_VERBOSE, "Patching new safe mode aslr check...\n"));
|
|
SetMem(StartOff + FirstOff, sizeof (SearchSeqNew) + 1, 0x90);
|
|
return;
|
|
}
|
|
|
|
SecondOff = FirstOff + sizeof (SearchSeq);
|
|
|
|
while (
|
|
StartOff + SecondOff <= EndOff && FirstOff + MaxDist >= SecondOff &&
|
|
CompareMem (StartOff + SecondOff, SearchSeq, sizeof (SearchSeq))) {
|
|
SecondOff++;
|
|
}
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "Found second at off %X\n", (UINT32)SecondOff));
|
|
|
|
if (FirstOff + MaxDist < SecondOff) {
|
|
DEBUG ((DEBUG_VERBOSE, "Trying next match...\n"));
|
|
SecondOff = 0;
|
|
FirstOff += sizeof (SearchSeq);
|
|
}
|
|
} while (SecondOff == 0);
|
|
|
|
if (SecondOff != 0) {
|
|
//
|
|
// Here we use 0xFFFFFFFF constant as a replacement value.
|
|
// Since the state values are contradictive (e.g. safe & single at the same time)
|
|
// We are allowed to use this instead of to simulate if (false).
|
|
//
|
|
DEBUG ((DEBUG_VERBOSE, "Patching safe mode aslr check...\n"));
|
|
SetMem(StartOff + FirstOff, sizeof (SearchSeq), 0xFF);
|
|
SetMem(StartOff + SecondOff, sizeof (SearchSeq), 0xFF);
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
OverlapsWithSlide (
|
|
EFI_PHYSICAL_ADDRESS Address,
|
|
UINTN Size
|
|
)
|
|
{
|
|
BOOLEAN SandyOrIvy;
|
|
EFI_PHYSICAL_ADDRESS Start;
|
|
EFI_PHYSICAL_ADDRESS End;
|
|
UINTN Slide = 0xFF;
|
|
|
|
SandyOrIvy = IsSandyOrIvy ();
|
|
|
|
if (SandyOrIvy) {
|
|
Slide = 0x7F;
|
|
}
|
|
|
|
Start = BASE_KERNEL_ADDR;
|
|
End = Start + Slide * SLIDE_GRANULARITY + APTIOFIX_SPECULATED_KERNEL_SIZE;
|
|
|
|
if (End >= Address && Start <= Address + Size) {
|
|
return TRUE;
|
|
} else if (SandyOrIvy) {
|
|
Start = 0x80 * SLIDE_GRANULARITY + BASE_KERNEL_ADDR + 0x10200000;
|
|
End = Start + Slide * SLIDE_GRANULARITY + APTIOFIX_SPECULATED_KERNEL_SIZE;
|
|
if (End >= Address && Start <= Address + Size) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetVariableCustomSlide (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
if (gMacOSBootNestedCount > 0 && VariableName && VendorGuid && DataSize &&
|
|
CompareGuid (VendorGuid, &gEfiAppleBootGuid)) {
|
|
//
|
|
// We override csr-active-config with CSR_ALLOW_UNRESTRICTED_NVRAM bit set
|
|
// to allow one to pass a custom slide value even when SIP is on.
|
|
// This original value of csr-active-config is returned to OS at XNU boot.
|
|
// This allows SIP to be fully enabled in the operating system.
|
|
//
|
|
if (!StrCmp (VariableName, L"csr-active-config")) {
|
|
return GetVariableCsrActiveConfig (
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
DataSize,
|
|
Data
|
|
);
|
|
}
|
|
#if APTIOFIX_ALLOW_CUSTOM_ASLR_IMPLEMENTATION == 1
|
|
//
|
|
// When we cannot allow some KASLR values due to used address we generate
|
|
// a random slide value among the valid options, which we we pass via boot-args.
|
|
// See DecideOnCustomSlideImplementation for more details.
|
|
//
|
|
else if (!StrCmp (VariableName, L"boot-args")) {
|
|
//
|
|
// We delay memory map analysis as much as we can, in case boot.efi or anything else allocates
|
|
// stuff with gBS->AllocatePool and it overlaps with the kernel area.
|
|
// Overriding AllocatePool with a custom allocator does not really improve the situation,
|
|
// because on older boards allocated memory above BASE_4GB causes instant reboots, and
|
|
// on the only (so far) problematic X99 and X299 we have no free region for our pool anyway.
|
|
// In any case, the current APTIOFIX_SPECULATED_KERNEL_SIZE value appears to work reliably.
|
|
//
|
|
if (!gSlideArgPresent && !mAnalyzeMemoryMapDone) {
|
|
DecideOnCustomSlideImplementation ();
|
|
mAnalyzeMemoryMapDone = TRUE;
|
|
}
|
|
//
|
|
// Only return custom boot-args if mValidSlidesNum were determined to be less than TOTAL_SLIDE_NUM
|
|
// And thus we have to use a custom slide implementation to boot reliably.
|
|
//
|
|
if (mValidSlidesNum != TOTAL_SLIDE_NUM && mValidSlidesNum > 0) {
|
|
return GetVariableBootArgs (
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
DataSize,
|
|
Data
|
|
);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return OrgGetVariable (VariableName, VendorGuid, Attributes, DataSize, Data);
|
|
}
|
|
|
|
VOID
|
|
RestoreCustomSlideOverrides (
|
|
AMF_BOOT_ARGUMENTS *BA
|
|
)
|
|
{
|
|
//
|
|
// Restore csr-active-config to a value it was before our slide=X alteration.
|
|
//
|
|
if (BA->csrActiveConfig && mCsrActiveConfigSet) {
|
|
*BA->csrActiveConfig = mCsrActiveConfig;
|
|
}
|
|
|
|
#if APTIOFIX_CLEANUP_SLIDE_BOOT_ARGUMENT == 1
|
|
//
|
|
// Having slide=X values visible in the operating system defeats the purpose of KASLR.
|
|
// Since our custom implementation works by passing random KASLR slide via boot-args,
|
|
// this is especially important.
|
|
//
|
|
HideSlideFromOS(BA);
|
|
#endif
|
|
}
|