OcMachoLib: Treat container Mach-O as reference file

As of macOS 13 Developer Beta 3, the Kernel Collection's inner kernel
references a segment that precedes itself. The current model is that
a Kernel Collection is a container format and the included files are
(mostly) separate. Hence, this was treated as an out-of-bounds issue.
Kernel Collections apparently are rather an unconventional composite
format, where the sub-files are still part of the whole. Redesign
OcMachoLib to treat the Kernel Collection as the reference file.
Patches still use only the inner file, while parsing considers the
whole file.
This commit is contained in:
Marvin Häuser 2022-07-07 01:20:21 +02:00 committed by Marvin Häuser
parent 1b24da4ebb
commit d916dd65b8
16 changed files with 247 additions and 187 deletions

View File

@ -1004,16 +1004,18 @@ KcGetKextSize (
/**
Apply the delta from KC header to the file's offsets.
@param[in,out] Context The context of the KEXT to rebase.
@param[in] Delta The offset from KC header the KEXT starts at.
@param[in] PrelinkedContext Prelinked context.
@param[in,out] Context The context of the KEXT to rebase.
@param[in] Delta The offset from KC header the KEXT starts at.
@retval EFI_SUCCESS The file has beem rebased successfully.
@retval other An error has occured.
**/
EFI_STATUS
KcKextApplyFileDelta (
IN OUT OC_MACHO_CONTEXT *Context,
IN UINT32 Delta
IN PRELINKED_CONTEXT *PrelinkedContext,
IN OUT OC_MACHO_CONTEXT *Context,
IN UINT32 Delta
);
/**

View File

@ -32,10 +32,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
/// only. Members are not guaranteed to be sane.
///
typedef struct {
MACH_HEADER_ANY *MachHeader;
VOID *FileData;
UINT32 FileSize;
UINT32 ContainerOffset;
MACH_HEADER_ANY *MachHeader;
UINT32 InnerSize;
MACH_SYMTAB_COMMAND *Symtab;
MACH_NLIST_ANY *SymbolTable;
CHAR8 *StringTable;
@ -50,11 +51,12 @@ typedef struct {
/**
Initializes a 32-bit Mach-O Context.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] ContainerOffset The amount of Bytes the Mach-O header is offset
from the base (container, e.g. KC) of the file.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] HeaderOffset The amount of Bytes the Mach-O header is offset from
the base (container, e.g. KC) of the file.
@param[in] InnerSize The size, in Bytes, of the inner Mach-O file.
@return Whether Context has been initialized successfully.
@ -64,17 +66,19 @@ MachoInitializeContext32 (
OUT OC_MACHO_CONTEXT *Context,
IN VOID *FileData,
IN UINT32 FileSize,
IN UINT32 ContainerOffset
IN UINT32 HeaderOffset,
IN UINT32 InnerSize
);
/**
Initializes a 64-bit Mach-O Context.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] ContainerOffset The amount of Bytes the Mach-O header is offset
from the base (container, e.g. KC) of the file.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] HeaderOffset The amount of Bytes the Mach-O header is offset from
the base (container, e.g. KC) of the file.
@param[in] InnerSize The size, in Bytes, of the inner Mach-O file.
@return Whether Context has been initialized successfully.
@ -84,18 +88,20 @@ MachoInitializeContext64 (
OUT OC_MACHO_CONTEXT *Context,
IN VOID *FileData,
IN UINT32 FileSize,
IN UINT32 ContainerOffset
IN UINT32 HeaderOffset,
IN UINT32 InnerSize
);
/**
Initializes a Mach-O Context.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] ContainerOffset The amount of Bytes the Mach-O header is offset
from the base (container, e.g. KC) of the file.
@param[in] Is32Bit TRUE if Mach-O is 32-bit.
@param[out] Context Mach-O Context to initialize.
@param[in] FileData Pointer to the file's expected Mach-O header.
@param[in] FileSize File size of FileData.
@param[in] HeaderOffset The amount of Bytes the Mach-O header is offset from
the base (container, e.g. KC) of the file.
@param[in] InnerSize The size, in Bytes, of the inner Mach-O file.
@param[in] Is32Bit TRUE if Mach-O is 32-bit.
@return Whether Context has been initialized successfully.
@ -105,7 +111,8 @@ MachoInitializeContext (
OUT OC_MACHO_CONTEXT *Context,
IN VOID *FileData,
IN UINT32 FileSize,
IN UINT32 ContainerOffset,
IN UINT32 HeaderOffset,
IN UINT32 InnerSize,
IN BOOLEAN Is32Bit
);
@ -120,6 +127,17 @@ MachoGetMachHeader (
IN OUT OC_MACHO_CONTEXT *Context
);
/**
Returns the size of the inner Mach-O file (otherwise, the file size).
@param[in,out] Context Context of the Mach-O.
**/
UINT32
MachoGetInnerSize (
IN OUT OC_MACHO_CONTEXT *Context
);
/**
Returns the 32-bit Mach-O Header structure.
@ -142,6 +160,17 @@ MachoGetMachHeader64 (
IN OUT OC_MACHO_CONTEXT *Context
);
/**
Returns the file data of the Mach-O.
@param[in,out] Context Context of the Mach-O.
**/
VOID *
MachoGetFileData (
IN OUT OC_MACHO_CONTEXT *Context
);
/**
Returns the Mach-O's file size.

View File

@ -77,7 +77,7 @@ PatchAppleCpuPmCfgLock (
Count = 0;
Walker = (UINT8 *)MachoGetMachHeader (&Patcher->MachContext);
WalkerEnd = Walker + MachoGetFileSize (&Patcher->MachContext) - mWrmsrMaxDistance;
WalkerEnd = Walker + MachoGetInnerSize (&Patcher->MachContext) - mWrmsrMaxDistance;
//
// Thanks to Clover developers for the approach.
@ -254,7 +254,7 @@ PatchAppleXcpmCfgLock (
}
Last = (XCPM_MSR_RECORD *)((UINT8 *)MachoGetMachHeader (&Patcher->MachContext)
+ MachoGetFileSize (&Patcher->MachContext) - sizeof (XCPM_MSR_RECORD));
+ MachoGetInnerSize (&Patcher->MachContext) - sizeof (XCPM_MSR_RECORD));
Replacements = 0;
@ -381,7 +381,7 @@ PatchAppleXcpmExtraMsrs (
}
Last = (XCPM_MSR_RECORD *)((UINT8 *)MachoGetMachHeader (&Patcher->MachContext)
+ MachoGetFileSize (&Patcher->MachContext) - sizeof (XCPM_MSR_RECORD));
+ MachoGetInnerSize (&Patcher->MachContext) - sizeof (XCPM_MSR_RECORD));
Replacements = 0;
@ -509,7 +509,7 @@ PatchAppleXcpmForceBoost (
}
Start = (UINT8 *)MachoGetMachHeader (&Patcher->MachContext);
Last = Start + MachoGetFileSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2;
Last = Start + MachoGetInnerSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2;
Start += EFI_PAGE_SIZE;
Current = Start;
@ -1190,7 +1190,7 @@ PatchCustomPciSerialPmio (
Count = 0;
Walker = (UINT8 *)MachoGetMachHeader (&Patcher->MachContext);
WalkerEnd = Walker + MachoGetFileSize (&Patcher->MachContext) - mInOutMaxDistance;
WalkerEnd = Walker + MachoGetInnerSize (&Patcher->MachContext) - mInOutMaxDistance;
while (Walker < WalkerEnd) {
if ( (Walker[0] == mSerialDevicePmioFind[0])
@ -1385,7 +1385,7 @@ PatchPanicKextDump (
}
Last = ((UINT8 *)MachoGetMachHeader (&Patcher->MachContext)
+ MachoGetFileSize (&Patcher->MachContext) - EFI_PAGE_SIZE);
+ MachoGetInnerSize (&Patcher->MachContext) - EFI_PAGE_SIZE);
//
// This should work on 10.15 and all debug kernels.
@ -1811,7 +1811,7 @@ PatchSegmentJettison (
}
Last = (UINT8 *)MachoGetMachHeader (&Patcher->MachContext)
+ MachoGetFileSize (&Patcher->MachContext) - sizeof (EFI_PAGE_SIZE) * 2;
+ MachoGetInnerSize (&Patcher->MachContext) - sizeof (EFI_PAGE_SIZE) * 2;
Status = PatcherGetSymbolAddress (Patcher, "__ZN6OSKext19removeKextBootstrapEv", (UINT8 **)&RemoveBs);
if (EFI_ERROR (Status) || (RemoveBs > Last)) {
@ -2055,7 +2055,7 @@ PatchLegacyCommpage (
ASSERT (Patcher != NULL);
Start = ((UINT8 *)MachoGetMachHeader (&Patcher->MachContext));
Last = Start + MachoGetFileSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2 - (Patcher->Is32Bit ? sizeof (COMMPAGE_DESCRIPTOR) : sizeof (COMMPAGE_DESCRIPTOR_64));
Last = Start + MachoGetInnerSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2 - (Patcher->Is32Bit ? sizeof (COMMPAGE_DESCRIPTOR) : sizeof (COMMPAGE_DESCRIPTOR_64));
//
// This is a table of pointers to commpage entries.
@ -2294,7 +2294,7 @@ PatchForceSecureBootScheme (
//
Last = ((UINT8 *)MachoGetMachHeader (&Patcher->MachContext)
+ MachoGetFileSize (&Patcher->MachContext) - 64);
+ MachoGetInnerSize (&Patcher->MachContext) - 64);
Status = PatcherGetSymbolAddress (Patcher, "_img4_chip_select_effective_ap", &SelectAp);
if (EFI_ERROR (Status) || (SelectAp > Last)) {

View File

@ -815,7 +815,7 @@ PatchKernelCpuId (
);
Start = ((UINT8 *)MachoGetMachHeader (&Patcher->MachContext));
Last = Start + MachoGetFileSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2 - sizeof (mKernelCpuIdFindRelNew);
Last = Start + MachoGetInnerSize (&Patcher->MachContext) - EFI_PAGE_SIZE * 2 - sizeof (mKernelCpuIdFindRelNew);
//
// Do legacy patching for 32-bit 10.7, and 10.6 and older.

View File

@ -565,6 +565,7 @@ KcKextIndexFixups (
CONST MACH_SEGMENT_COMMAND_64 *FirstSegment;
MACH_HEADER_64 *MachHeader;
CONST MACH_RELOCATION_INFO *Relocations;
VOID *FileData;
UINT32 RelocIndex;
ASSERT (Context != NULL);
@ -616,8 +617,9 @@ KcKextIndexFixups (
//
// Convert all relocations to fixups.
//
FileData = MachoGetFileData (MachContext);
Relocations = (MACH_RELOCATION_INFO *)(
(UINTN)MachHeader + DySymtab->LocalRelocationsOffset
(UINTN)FileData + DySymtab->LocalRelocationsOffset
);
DEBUG ((
@ -643,14 +645,11 @@ KcGetKextSize (
IN UINT64 SourceAddress
)
{
MACH_HEADER_64 *KcHeader;
MACH_SEGMENT_COMMAND_64 *Segment;
ASSERT (Context != NULL);
ASSERT (Context->IsKernelCollection);
KcHeader = MachoGetMachHeader64 (&Context->PrelinkedMachContext);
ASSERT (KcHeader != NULL);
//
// Find the KC segment that contains the KEXT at SourceAddress.
//
@ -683,8 +682,9 @@ KcGetKextSize (
EFI_STATUS
KcKextApplyFileDelta (
IN OUT OC_MACHO_CONTEXT *Context,
IN UINT32 Delta
IN PRELINKED_CONTEXT *PrelinkedContext,
IN OUT OC_MACHO_CONTEXT *Context,
IN UINT32 Delta
)
{
MACH_HEADER_64 *KextHeader;
@ -695,6 +695,7 @@ KcKextApplyFileDelta (
MACH_DYSYMTAB_COMMAND *DySymtab;
UINT32 SectIndex;
ASSERT (PrelinkedContext != NULL);
ASSERT (Context != NULL);
ASSERT (Delta > 0);
@ -786,9 +787,11 @@ KcKextApplyFileDelta (
//
// Update the container offset to make sure we can link against this
// kext later as well.
// kext later as well. Context->InnerSize remains unchanged and is the actual
// size of the kext.
//
Context->ContainerOffset = Delta;
Context->FileData = PrelinkedContext->Prelinked;
Context->FileSize = PrelinkedContext->PrelinkedSize;
return EFI_SUCCESS;
}

View File

@ -155,7 +155,7 @@ PatcherInitContextFromBuffer (
// and request PRELINK_KERNEL_IDENTIFIER.
//
if (!MachoInitializeContext (&Context->MachContext, Buffer, BufferSize, 0, Is32Bit)) {
if (!MachoInitializeContext (&Context->MachContext, Buffer, BufferSize, 0, BufferSize, Is32Bit)) {
DEBUG ((
DEBUG_INFO,
"OCAK: %a-bit patcher init from buffer %p %u has unsupported mach-o\n",
@ -273,7 +273,7 @@ PatcherGetSymbolAddress (
Index++;
}
*Address = (UINT8 *)MachoGetMachHeader (&Context->MachContext) + Offset;
*Address = (UINT8 *)MachoGetFileData (&Context->MachContext) + Offset;
return EFI_SUCCESS;
}
@ -289,7 +289,7 @@ PatcherApplyGenericPatch (
UINT32 ReplaceCount;
Base = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
Size = MachoGetFileSize (&Context->MachContext);
Size = MachoGetInnerSize (&Context->MachContext);
if (Patch->Base != NULL) {
Status = PatcherGetSymbolAddress (Context, Patch->Base, &Base);
if (EFI_ERROR (Status)) {
@ -520,7 +520,7 @@ PatcherBlockKext (
}
MachBase = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
MachSize = MachoGetFileSize (&Context->MachContext);
MachSize = MachoGetInnerSize (&Context->MachContext);
//
// Determine offset of kmod within file.

View File

@ -1138,7 +1138,7 @@ InternalRelocateAndCopyRelocations (
}
if (Section32->NumRelocations > 0) {
Relocation = (MACH_RELOCATION_INFO *)((UINTN)MachoGetMachHeader32 (&Kext->Context.MachContext) + Section32->RelocationsOffset);
Relocation = (MACH_RELOCATION_INFO *)((UINTN)MachoGetFileData (&Kext->Context.MachContext) + Section32->RelocationsOffset);
for (Index = 0; Index < Section32->NumRelocations; ++Index) {
NextRelocation = &Relocation[Index + 1];
//
@ -1387,7 +1387,7 @@ InternalProcessSymbolPointers (
IN UINT64 LoadAddress
)
{
CONST MACH_HEADER_ANY *MachHeader;
CONST VOID *FileData;
UINT32 MachSize;
CONST MACH_SECTION_ANY *Section;
UINT32 NumSymbols;
@ -1434,8 +1434,8 @@ InternalProcessSymbolPointers (
return FALSE;
}
MachHeader = MachoGetMachHeader (MachoContext);
ASSERT (MachHeader != NULL);
FileData = MachoGetMachHeader (MachoContext);
ASSERT (FileData != NULL);
//
// Iterate through the indirect symbol table and fill in the section of
// symbol pointers. There are three cases:
@ -1446,14 +1446,14 @@ InternalProcessSymbolPointers (
// 3) An INDIRECT_SYMBOL_ABS - prepopulated absolute symbols. No
// action is required.
//
Tmp = (VOID *)((UINTN)MachHeader + DySymtab->IndirectSymbolsOffset);
Tmp = (VOID *)((UINTN)FileData + DySymtab->IndirectSymbolsOffset);
if (!OC_TYPE_ALIGNED (UINT32, Tmp)) {
return FALSE;
}
SymIndices = (UINT32 *)Tmp + FirstSym;
IndirectSymPtr = (VOID *)((UINTN)MachHeader + (MachoContext->Is32Bit ? Section->Section32.Offset : Section->Section64.Offset));
IndirectSymPtr = (VOID *)((UINTN)FileData + (MachoContext->Is32Bit ? Section->Section32.Offset : Section->Section64.Offset));
if (MachoContext->Is32Bit ? !OC_TYPE_ALIGNED (UINT32, IndirectSymPtr) : !OC_TYPE_ALIGNED (UINT64, IndirectSymPtr)) {
return FALSE;
}
@ -1512,6 +1512,7 @@ InternalPrelinkKext (
UINT64 LinkEditFileOffset;
UINT64 LinkEditFileSize;
VOID *FileData;
MACH_HEADER_ANY *MachHeader;
UINT32 MachSize;
BOOLEAN IsObject32;
@ -1579,9 +1580,17 @@ InternalPrelinkKext (
MachoContext = &Kext->Context.MachContext;
LinkEditSegment = Kext->LinkEditSegment;
//
// Kexts cannot be contained.
//
ASSERT ((VOID *)MachoGetMachHeader (MachoContext) == MachoGetFileData (MachoContext));
ASSERT (MachoGetInnerSize (MachoContext) == MachoGetFileSize (MachoContext));
MachHeader = MachoGetMachHeader (MachoContext);
MachSize = MachoGetFileSize (MachoContext);
FileData = (VOID *)MachHeader;
IsObject32 = Context->Is32Bit && MachHeader->Header32.FileType == MachHeaderFileTypeObject;
//
@ -1801,7 +1810,7 @@ InternalPrelinkKext (
return EFI_LOAD_ERROR;
}
KmodInfo = (KMOD_INFO_ANY *)((UINTN)MachHeader + (UINTN)KmodInfoOffset);
KmodInfo = (KMOD_INFO_ANY *)((UINTN)FileData + (UINTN)KmodInfoOffset);
FirstSegment = MachoGetNextSegment (MachoContext, NULL);
if (FirstSegment == NULL) {
@ -1934,12 +1943,12 @@ InternalPrelinkKext (
LinkEditSize = (SymbolTableSize + RelocationsSize + StringTableSize);
CopyMem (
(VOID *)((UINTN)MachHeader + (UINTN)LinkEditFileOffset),
(VOID *)((UINTN)FileData + (UINTN)LinkEditFileOffset),
LinkEdit,
LinkEditSize
);
ZeroMem (
(VOID *)((UINTN)MachHeader + (UINTN)LinkEditFileOffset + LinkEditSize),
(VOID *)((UINTN)FileData + (UINTN)LinkEditFileOffset + LinkEditSize),
(UINTN)(LinkEditFileSize - LinkEditSize)
);
@ -2000,11 +2009,11 @@ InternalPrelinkKext (
// Zero out the existing symbol table, and copy our non-undefined symbols back.
//
ZeroMem (
(VOID *)((UINTN)MachHeader + Symtab->SymbolsOffset),
(VOID *)((UINTN)FileData + Symtab->SymbolsOffset),
SymtabSize
);
CopyMem (
(VOID *)((UINTN)MachHeader + Symtab->SymbolsOffset),
(VOID *)((UINTN)FileData + Symtab->SymbolsOffset),
SymtabLinkEdit32,
SymtabSize2
);
@ -2137,7 +2146,7 @@ InternalPrelinkKext (
// Reinitialize the Mach-O context to account for the changed __LINKEDIT
// segment and file size.
//
if (!MachoInitializeContext (MachoContext, MachHeader, MachSize, MachoContext->ContainerOffset, Context->Is32Bit)) {
if (!MachoInitializeContext (MachoContext, MachoContext->FileData, MachSize, 0, MachSize, Context->Is32Bit)) {
//
// This should never failed under normal and abnormal conditions.
//

View File

@ -1166,7 +1166,7 @@ MkextReserveKextSize (
if (Executable != NULL) {
ASSERT (ExecutableSize > 0);
if (!MachoInitializeContext (&Context, Executable, ExecutableSize, 0, Is32Bit)) {
if (!MachoInitializeContext (&Context, Executable, ExecutableSize, 0, ExecutableSize, Is32Bit)) {
return EFI_INVALID_PARAMETER;
}

View File

@ -175,9 +175,10 @@ InternalConnectExternalSymtab (
if (!MachoInitializeContext64 (
InnerContext,
&Buffer[Segment->FileOffset],
(UINT32)(BufferSize - Segment->FileOffset),
(UINT32)Segment->FileOffset
Buffer,
BufferSize,
(UINT32)Segment->FileOffset,
(UINT32)(BufferSize - Segment->FileOffset)
))
{
DEBUG ((
@ -247,7 +248,7 @@ PrelinkedContextInit (
//
// Initialise primary context.
//
if (!MachoInitializeContext (&Context->PrelinkedMachContext, Prelinked, PrelinkedSize, 0, Context->Is32Bit)) {
if (!MachoInitializeContext (&Context->PrelinkedMachContext, Prelinked, PrelinkedSize, 0, PrelinkedSize, Context->Is32Bit)) {
return EFI_INVALID_PARAMETER;
}
@ -921,7 +922,7 @@ PrelinkedReserveKextSize (
if (Executable != NULL) {
ASSERT (ExecutableSize > 0);
if (!MachoInitializeContext (&Context, Executable, ExecutableSize, 0, Is32Bit)) {
if (!MachoInitializeContext (&Context, Executable, ExecutableSize, 0, ExecutableSize, Is32Bit)) {
return EFI_INVALID_PARAMETER;
}
@ -1015,7 +1016,7 @@ PrelinkedInjectKext (
//
if (Executable != NULL) {
ASSERT (ExecutableSize > 0);
if (!MachoInitializeContext (&ExecutableContext, (UINT8 *)Executable, ExecutableSize, 0, Context->Is32Bit)) {
if (!MachoInitializeContext (&ExecutableContext, (UINT8 *)Executable, ExecutableSize, 0, ExecutableSize, Context->Is32Bit)) {
DEBUG ((DEBUG_INFO, "OCAK: Injected kext %a/%a is not a supported executable\n", BundlePath, ExecutablePath));
return EFI_INVALID_PARAMETER;
}
@ -1047,7 +1048,7 @@ PrelinkedInjectKext (
AlignedExecutableSize - ExecutableSize
);
if ( !MachoInitializeContext (&ExecutableContext, &Context->Prelinked[KextOffset], ExecutableSize, 0, Context->Is32Bit)
if ( !MachoInitializeContext (&ExecutableContext, &Context->Prelinked[KextOffset], ExecutableSize, 0, ExecutableSize, Context->Is32Bit)
|| OcOverflowAddU64 (Context->PrelinkedLastLoadAddress, FileOffset, &LoadAddressOffset))
{
return EFI_INVALID_PARAMETER;
@ -1184,7 +1185,7 @@ PrelinkedInjectKext (
// ownership was transferred by InternalLinkPrelinkedKext.
//
KcKextIndexFixups (Context, &PrelinkedKext->Context.MachContext);
Status = KcKextApplyFileDelta (&PrelinkedKext->Context.MachContext, KextOffset);
Status = KcKextApplyFileDelta (Context, &PrelinkedKext->Context.MachContext, KextOffset);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_WARN,

View File

@ -56,13 +56,14 @@ InternalCreatePrelinkedKext (
UINT64 VirtualKmod;
UINT64 SourceBase;
UINT64 SourceSize;
UINT32 InnerSize;
UINT64 CalculatedSourceSize;
UINT64 SourceEnd;
MACH_SEGMENT_COMMAND_ANY *BaseSegment;
UINT64 KxldState;
UINT64 KxldOffset;
UINT32 KxldStateSize;
UINT32 ContainerOffset;
UINT32 HeaderOffset;
BOOLEAN Found;
BOOLEAN HasExe;
BOOLEAN IsKpi;
@ -214,9 +215,18 @@ InternalCreatePrelinkedKext (
return NULL;
}
ContainerOffset = 0;
HeaderOffset = 0;
InnerSize = (UINT32)SourceSize;
if (Prelinked->IsKernelCollection) {
ContainerOffset = (UINT32)SourceBase;
HeaderOffset = (UINT32)SourceBase;
//
// The Mach-O image is the entire Kernel Collection image. This is because
// as of macOS 13 Developer Beta 3, the inner kernel Mach-O references
// segments that preceed it.
//
SourceBase = 0;
SourceSize = Prelinked->PrelinkedSize;
}
}
@ -230,7 +240,7 @@ InternalCreatePrelinkedKext (
if ( (Prelinked != NULL)
&& HasExe
&& !MachoInitializeContext (&NewKext->Context.MachContext, &Prelinked->Prelinked[SourceBase], (UINT32)SourceSize, ContainerOffset, Prelinked->Is32Bit))
&& !MachoInitializeContext (&NewKext->Context.MachContext, &Prelinked->Prelinked[SourceBase], (UINT32)SourceSize, HeaderOffset, InnerSize, Prelinked->Is32Bit))
{
FreePool (NewKext);
return NULL;

View File

@ -497,16 +497,16 @@ InternalInitializeVtablePatchData (
OUT MACH_NLIST_ANY **SolveSymbols
)
{
BOOLEAN Result;
UINT32 VtableOffset;
UINT32 VtableMaxSize;
CONST MACH_HEADER_ANY *MachHeader;
VOID *VtableData;
UINT32 SymIndex;
UINT32 EntryOffset;
UINT64 FileOffset;
UINT32 MaxSymbols;
MACH_NLIST_ANY *Symbol;
BOOLEAN Result;
UINT32 VtableOffset;
UINT32 VtableMaxSize;
void *FileData;
VOID *VtableData;
UINT32 SymIndex;
UINT32 EntryOffset;
UINT64 FileOffset;
UINT32 MaxSymbols;
MACH_NLIST_ANY *Symbol;
Result = MachoSymbolGetFileOffset (
MachoContext,
@ -518,10 +518,10 @@ InternalInitializeVtablePatchData (
return FALSE;
}
MachHeader = MachoGetMachHeader (MachoContext);
ASSERT (MachHeader != NULL);
FileData = MachoGetFileData (MachoContext);
ASSERT (FileData != NULL);
VtableData = (VOID *)((UINTN)MachHeader + VtableOffset);
VtableData = (VOID *)((UINTN)FileData + VtableOffset);
if (MachoContext->Is32Bit ? !OC_TYPE_ALIGNED (UINT32, VtableData) : !OC_TYPE_ALIGNED (UINT64, VtableData)) {
return FALSE;
}
@ -591,7 +591,6 @@ InternalPatchByVtables (
UINT32 MaxSize;
OC_MACHO_CONTEXT *MachoContext;
CONST MACH_HEADER_ANY *MachHeader;
UINT32 Index;
UINT32 NumTables;
UINT32 NumEntries;
@ -620,9 +619,6 @@ InternalPatchByVtables (
MaxSize = Context->LinkBufferSize;
MachoContext = &Kext->Context.MachContext;
MachHeader = MachoGetMachHeader (MachoContext);
ASSERT (MachHeader != NULL);
//
// Retrieve all SMCPs.
//

View File

@ -30,13 +30,14 @@ MachoInitializeContext (
OUT OC_MACHO_CONTEXT *Context,
IN VOID *FileData,
IN UINT32 FileSize,
IN UINT32 ContainerOffset,
IN UINT32 HeaderOffset,
IN UINT32 InnerSize,
IN BOOLEAN Is32Bit
)
{
return Is32Bit ?
MachoInitializeContext32 (Context, FileData, FileSize, ContainerOffset) :
MachoInitializeContext64 (Context, FileData, FileSize, ContainerOffset);
MachoInitializeContext32 (Context, FileData, FileSize, HeaderOffset, InnerSize) :
MachoInitializeContext64 (Context, FileData, FileSize, HeaderOffset, InnerSize);
}
MACH_HEADER_ANY *
@ -50,6 +51,28 @@ MachoGetMachHeader (
return Context->MachHeader;
}
UINT32
MachoGetInnerSize (
IN OUT OC_MACHO_CONTEXT *Context
)
{
ASSERT (Context != NULL);
ASSERT (Context->InnerSize != 0);
return Context->InnerSize;
}
VOID *
MachoGetFileData (
IN OUT OC_MACHO_CONTEXT *Context
)
{
ASSERT (Context != NULL);
ASSERT (Context->FileData != NULL);
return Context->FileData;
}
UINT32
MachoGetFileSize (
IN OUT OC_MACHO_CONTEXT *Context
@ -233,17 +256,12 @@ InternalInitialiseSymtabs (
IN MACH_DYSYMTAB_COMMAND *DySymtab
)
{
UINTN MachoAddress;
UINTN FileDataAddress;
CHAR8 *StringTable;
UINT32 FileSize;
UINT32 SymbolsOffset;
UINT32 StringsOffset;
UINT32 OffsetTop;
BOOLEAN Result;
UINT32 IndirectSymbolsOffset;
UINT32 LocalRelocationsOffset;
UINT32 ExternalRelocationsOffset;
MACH_NLIST_ANY *SymbolTable;
MACH_NLIST_ANY *IndirectSymtab;
MACH_RELOCATION_INFO *LocalRelocations;
@ -258,37 +276,27 @@ InternalInitialiseSymtabs (
FileSize = Context->FileSize;
Result = OcOverflowSubU32 (
Result = OcOverflowMulAddU32 (
Symtab->NumSymbols,
Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64),
Symtab->SymbolsOffset,
Context->ContainerOffset,
&SymbolsOffset
&OffsetTop
);
Result |= OcOverflowMulAddU32 (
Symtab->NumSymbols,
Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64),
SymbolsOffset,
&OffsetTop
);
if (Result || (OffsetTop > FileSize)) {
return FALSE;
}
Result = OcOverflowSubU32 (
Result = OcOverflowAddU32 (
Symtab->StringsOffset,
Context->ContainerOffset,
&StringsOffset
Symtab->StringsSize,
&OffsetTop
);
Result |= OcOverflowAddU32 (
StringsOffset,
Symtab->StringsSize,
&OffsetTop
);
if (Result || (OffsetTop > FileSize)) {
return FALSE;
}
MachoAddress = (UINTN)Context->MachHeader;
StringTable = (CHAR8 *)(MachoAddress + StringsOffset);
FileDataAddress = (UINTN)Context->FileData;
StringTable = (CHAR8 *)(FileDataAddress + Symtab->StringsOffset);
if ((Symtab->StringsSize == 0) || (StringTable[Symtab->StringsSize - 1] != '\0')) {
return FALSE;
@ -296,7 +304,7 @@ InternalInitialiseSymtabs (
SymbolTable = NULL;
Tmp = (VOID *)(MachoAddress + SymbolsOffset);
Tmp = (VOID *)(FileDataAddress + Symtab->SymbolsOffset);
if (!(Context->Is32Bit ? OC_TYPE_ALIGNED (MACH_NLIST, Tmp) : OC_TYPE_ALIGNED (MACH_NLIST_64, Tmp))) {
return FALSE;
}
@ -339,22 +347,17 @@ InternalInitialiseSymtabs (
// in their DySymtab, but it is "valid" for symbols.
//
if ((DySymtab->NumIndirectSymbols > 0) && (DySymtab->IndirectSymbolsOffset != 0)) {
Result = OcOverflowSubU32 (
Result = OcOverflowMulAddU32 (
DySymtab->NumIndirectSymbols,
Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64),
DySymtab->IndirectSymbolsOffset,
Context->ContainerOffset,
&IndirectSymbolsOffset
&OffsetTop
);
Result |= OcOverflowMulAddU32 (
DySymtab->NumIndirectSymbols,
Context->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64),
IndirectSymbolsOffset,
&OffsetTop
);
if (Result || (OffsetTop > FileSize)) {
return FALSE;
}
Tmp = (VOID *)(MachoAddress + IndirectSymbolsOffset);
Tmp = (VOID *)(FileDataAddress + DySymtab->IndirectSymbolsOffset);
if (!(Context->Is32Bit ? OC_TYPE_ALIGNED (MACH_NLIST, Tmp) : OC_TYPE_ALIGNED (MACH_NLIST_64, Tmp))) {
return FALSE;
}
@ -363,22 +366,17 @@ InternalInitialiseSymtabs (
}
if ((DySymtab->NumOfLocalRelocations > 0) && (DySymtab->LocalRelocationsOffset != 0)) {
Result = OcOverflowSubU32 (
Result = OcOverflowMulAddU32 (
DySymtab->NumOfLocalRelocations,
sizeof (MACH_RELOCATION_INFO),
DySymtab->LocalRelocationsOffset,
Context->ContainerOffset,
&LocalRelocationsOffset
&OffsetTop
);
Result |= OcOverflowMulAddU32 (
DySymtab->NumOfLocalRelocations,
sizeof (MACH_RELOCATION_INFO),
LocalRelocationsOffset,
&OffsetTop
);
if (Result || (OffsetTop > FileSize)) {
return FALSE;
}
Tmp = (VOID *)(MachoAddress + LocalRelocationsOffset);
Tmp = (VOID *)(FileDataAddress + DySymtab->LocalRelocationsOffset);
if (!OC_TYPE_ALIGNED (MACH_RELOCATION_INFO, Tmp)) {
return FALSE;
}
@ -387,22 +385,17 @@ InternalInitialiseSymtabs (
}
if ((DySymtab->NumExternalRelocations > 0) && (DySymtab->ExternalRelocationsOffset != 0)) {
Result = OcOverflowSubU32 (
Result = OcOverflowMulAddU32 (
DySymtab->NumExternalRelocations,
sizeof (MACH_RELOCATION_INFO),
DySymtab->ExternalRelocationsOffset,
Context->ContainerOffset,
&ExternalRelocationsOffset
&OffsetTop
);
Result |= OcOverflowMulAddU32 (
DySymtab->NumExternalRelocations,
sizeof (MACH_RELOCATION_INFO),
ExternalRelocationsOffset,
&OffsetTop
);
if (Result || (OffsetTop > FileSize)) {
return FALSE;
}
Tmp = (VOID *)(MachoAddress + ExternalRelocationsOffset);
Tmp = (VOID *)(FileDataAddress + DySymtab->ExternalRelocationsOffset);
if (!OC_TYPE_ALIGNED (MACH_RELOCATION_INFO, Tmp)) {
return FALSE;
}

View File

@ -70,17 +70,12 @@ InternalSectionIsSane (
}
if (Section->NumRelocations != 0) {
Result = OcOverflowSubU32 (
Result = OcOverflowMulAddU32 (
Section->NumRelocations,
sizeof (MACH_RELOCATION_INFO),
Section->RelocationsOffset,
Context->ContainerOffset,
&TopOffset32
);
Result |= OcOverflowMulAddU32 (
Section->NumRelocations,
sizeof (MACH_RELOCATION_INFO),
TopOffset32,
&TopOffset32
);
if (Result || (TopOffset32 > Context->FileSize)) {
return FALSE;
}
@ -264,8 +259,8 @@ MACH_X (
*MaxSize = MACH_X_TO_UINT32 (Segment->Size - Offset);
}
Offset += Segment->FileOffset - Context->ContainerOffset;
return (VOID *)((UINTN)Context->MachHeader + (UINTN)Offset);
Offset += Segment->FileOffset;
return (VOID *)((UINTN)Context->FileData + (UINTN)Offset);
}
}
@ -323,7 +318,14 @@ MACH_X (
//
// Header is valid, copy it first.
//
Header = MACH_X (MachoGetMachHeader)(Context);
Header = MACH_X (MachoGetMachHeader)(Context);
//
// Mach-O files with an offset header (e.g., inner kernel files of Kernel
// Collections) cannot be reasonably expanded.
//
ASSERT ((CONST VOID *)Header == Context->FileData);
IsObject = Header->FileType == MachHeaderFileTypeObject;
Source = (UINT8 *)Header;
HeaderSize = sizeof (*Header) + Header->CommandsSize;
@ -387,7 +389,7 @@ MACH_X (
// Do not overwrite header. Header must be in the first segment, but not if we are MH_OBJECT.
// For objects, the header size will be aligned so we'll need to shift segments to account for this.
//
CopyFileOffset = Segment->FileOffset - Context->ContainerOffset;
CopyFileOffset = Segment->FileOffset;
CopyFileSize = Segment->FileSize;
CopyVmSize = Segment->Size;
@ -465,7 +467,7 @@ MACH_X (
CurrentDelta
));
if (!IsObject && (DstSegment->VirtualAddress - (SegmentOffset - Context->ContainerOffset) != FirstSegment->VirtualAddress)) {
if (!IsObject && (DstSegment->VirtualAddress - SegmentOffset != FirstSegment->VirtualAddress)) {
return 0;
}
@ -896,9 +898,11 @@ MACH_X (
OUT OC_MACHO_CONTEXT *Context,
IN VOID *FileData,
IN UINT32 FileSize,
IN UINT32 ContainerOffset
IN UINT32 HeaderOffset,
IN UINT32 InnerSize
) {
EFI_STATUS Status;
VOID *MachData;
MACH_HEADER_X *MachHeader;
UINTN TopOfFile;
UINTN TopOfCommands;
@ -910,27 +914,44 @@ MACH_X (
ASSERT (FileData != NULL);
ASSERT (FileSize > 0);
ASSERT (FileSize >= HeaderOffset);
ASSERT (Context != NULL);
if (HeaderOffset == 0) {
ASSERT (InnerSize == FileSize);
}
ASSERT (FileSize >= InnerSize && FileSize - InnerSize >= HeaderOffset);
TopOfFile = ((UINTN)FileData + FileSize);
ASSERT (TopOfFile > (UINTN)FileData);
MachData = (UINT8 *)FileData + HeaderOffset;
//
// Inner files of Kernel Collections cannot be FAT.
//
if (HeaderOffset == 0) {
#ifdef MACHO_LIB_32
Status = FatFilterArchitecture32 ((UINT8 **)&FileData, &FileSize);
Status = FatFilterArchitecture32 ((UINT8 **)&MachData, &FileSize);
#else
Status = FatFilterArchitecture64 ((UINT8 **)&FileData, &FileSize);
Status = FatFilterArchitecture64 ((UINT8 **)&MachData, &FileSize);
#endif
if (EFI_ERROR (Status)) {
return FALSE;
if (EFI_ERROR (Status)) {
return FALSE;
}
FileData = MachData;
InnerSize = FileSize;
}
if ( (FileSize < sizeof (*MachHeader))
|| !OC_TYPE_ALIGNED (MACH_HEADER_X, FileData))
|| !OC_TYPE_ALIGNED (MACH_HEADER_X, MachData))
{
return FALSE;
}
MachHeader = (MACH_HEADER_X *)FileData;
MachHeader = (MACH_HEADER_X *)MachData;
#ifdef MACHO_LIB_32
if (MachHeader->Signature != MACH_HEADER_SIGNATURE) {
#else
@ -1007,10 +1028,11 @@ MACH_X (
ZeroMem (Context, sizeof (*Context));
Context->MachHeader = (MACH_HEADER_ANY *)MachHeader;
Context->Is32Bit = MachHeader->CpuType == MachCpuTypeI386;
Context->FileSize = FileSize;
Context->ContainerOffset = ContainerOffset;
Context->MachHeader = (MACH_HEADER_ANY *)MachHeader;
Context->Is32Bit = MachHeader->CpuType == MachCpuTypeI386;
Context->FileData = FileData;
Context->FileSize = FileSize;
Context->InnerSize = InnerSize;
return TRUE;
}
@ -1214,16 +1236,11 @@ MACH_X (
return NULL;
}
Result = MACH_X (OcOverflowSubU)(
Result = MACH_X (OcOverflowAddU)(
NextSegment->FileOffset,
Context->ContainerOffset,
NextSegment->FileSize,
&TopOfSegment
);
Result |= MACH_X (OcOverflowAddU)(
TopOfSegment,
NextSegment->FileSize,
&TopOfSegment
);
if (Result || (TopOfSegment > Context->FileSize)) {
return NULL;
}
@ -1239,10 +1256,10 @@ MACH_SECTION_X *
MACH_X (
MachoGetNextSection
)(
IN OUT OC_MACHO_CONTEXT *Context,
IN MACH_SEGMENT_COMMAND_X *Segment,
IN MACH_SECTION_X *Section OPTIONAL
) {
IN OUT OC_MACHO_CONTEXT *Context,
IN MACH_SEGMENT_COMMAND_X *Segment,
IN MACH_SECTION_X *Section OPTIONAL
) {
ASSERT (Context != NULL);
ASSERT (Segment != NULL);
MACH_ASSERT_X (Context);

View File

@ -159,7 +159,7 @@ InternalLookupSectionRelocationByOffset (
//
RelocationCount = Context->Is32Bit ? Section->Section32.NumRelocations : Section->Section64.NumRelocations;
if (RelocationCount > 0) {
Relocations = (MACH_RELOCATION_INFO *)(((UINTN)(Context->MachHeader))
Relocations = (MACH_RELOCATION_INFO *)(((UINTN)(Context->FileData))
+ (Context->Is32Bit ? Section->Section32.RelocationsOffset : Section->Section64.RelocationsOffset));
for (Index = 0; Index < RelocationCount; Index++) {

View File

@ -235,7 +235,7 @@ MACH_X (
Base = Segment->FileOffset;
Size = Segment->Size;
*FileOffset = MACH_X_TO_UINT32 (Base - Context->ContainerOffset + Offset);
*FileOffset = MACH_X_TO_UINT32 (Base + Offset);
if (MaxSize != NULL) {
*MaxSize = MACH_X_TO_UINT32 (Size - Offset);
@ -662,7 +662,7 @@ MACH_X (
}
}
*FileOffset = MACH_X_TO_UINT32 (Base - Context->ContainerOffset + Offset);
*FileOffset = MACH_X_TO_UINT32 (Base + Offset);
if (MaxSize != NULL) {
*MaxSize = MACH_X_TO_UINT32 (Size - Offset);

View File

@ -37,7 +37,7 @@ FeedMacho (
{
OC_MACHO_CONTEXT Context;
if (!MachoInitializeContext64 (&Context, File, Size, 0)) {
if (!MachoInitializeContext64 (&Context, File, Size, 0, Size)) {
return -1;
}