diff --git a/Include/Acidanthera/Library/OcAppleKernelLib.h b/Include/Acidanthera/Library/OcAppleKernelLib.h index fb8d1239..f15fb4d5 100644 --- a/Include/Acidanthera/Library/OcAppleKernelLib.h +++ b/Include/Acidanthera/Library/OcAppleKernelLib.h @@ -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 ); /** diff --git a/Include/Acidanthera/Library/OcMachoLib.h b/Include/Acidanthera/Library/OcMachoLib.h index 6800abbc..0f60a284 100644 --- a/Include/Acidanthera/Library/OcMachoLib.h +++ b/Include/Acidanthera/Library/OcMachoLib.h @@ -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. diff --git a/Library/OcAppleKernelLib/CommonPatches.c b/Library/OcAppleKernelLib/CommonPatches.c index 267445c0..cd50dd53 100644 --- a/Library/OcAppleKernelLib/CommonPatches.c +++ b/Library/OcAppleKernelLib/CommonPatches.c @@ -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)) { diff --git a/Library/OcAppleKernelLib/CpuidPatches.c b/Library/OcAppleKernelLib/CpuidPatches.c index bbfe212b..46e06b7d 100644 --- a/Library/OcAppleKernelLib/CpuidPatches.c +++ b/Library/OcAppleKernelLib/CpuidPatches.c @@ -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. diff --git a/Library/OcAppleKernelLib/KernelCollection.c b/Library/OcAppleKernelLib/KernelCollection.c index 3ee2425d..2e73fdb7 100644 --- a/Library/OcAppleKernelLib/KernelCollection.c +++ b/Library/OcAppleKernelLib/KernelCollection.c @@ -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; } diff --git a/Library/OcAppleKernelLib/KextPatcher.c b/Library/OcAppleKernelLib/KextPatcher.c index ff2e80dc..382d62d5 100644 --- a/Library/OcAppleKernelLib/KextPatcher.c +++ b/Library/OcAppleKernelLib/KextPatcher.c @@ -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. diff --git a/Library/OcAppleKernelLib/Link.c b/Library/OcAppleKernelLib/Link.c index e7b63913..c290e059 100644 --- a/Library/OcAppleKernelLib/Link.c +++ b/Library/OcAppleKernelLib/Link.c @@ -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. // diff --git a/Library/OcAppleKernelLib/MkextContext.c b/Library/OcAppleKernelLib/MkextContext.c index 9dd7b03c..042a8650 100644 --- a/Library/OcAppleKernelLib/MkextContext.c +++ b/Library/OcAppleKernelLib/MkextContext.c @@ -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; } diff --git a/Library/OcAppleKernelLib/PrelinkedContext.c b/Library/OcAppleKernelLib/PrelinkedContext.c index 722ef267..9ba976e2 100644 --- a/Library/OcAppleKernelLib/PrelinkedContext.c +++ b/Library/OcAppleKernelLib/PrelinkedContext.c @@ -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, diff --git a/Library/OcAppleKernelLib/PrelinkedKext.c b/Library/OcAppleKernelLib/PrelinkedKext.c index fa9c8136..096845dc 100644 --- a/Library/OcAppleKernelLib/PrelinkedKext.c +++ b/Library/OcAppleKernelLib/PrelinkedKext.c @@ -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; diff --git a/Library/OcAppleKernelLib/Vtables.c b/Library/OcAppleKernelLib/Vtables.c index 391bbb31..9480bb93 100644 --- a/Library/OcAppleKernelLib/Vtables.c +++ b/Library/OcAppleKernelLib/Vtables.c @@ -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. // diff --git a/Library/OcMachoLib/Header.c b/Library/OcMachoLib/Header.c index fa4dff65..6723b622 100644 --- a/Library/OcMachoLib/Header.c +++ b/Library/OcMachoLib/Header.c @@ -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; } diff --git a/Library/OcMachoLib/HeaderX.h b/Library/OcMachoLib/HeaderX.h index 415a7922..4f1b32ce 100644 --- a/Library/OcMachoLib/HeaderX.h +++ b/Library/OcMachoLib/HeaderX.h @@ -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); diff --git a/Library/OcMachoLib/Relocations.c b/Library/OcMachoLib/Relocations.c index de82cd88..38cb0593 100644 --- a/Library/OcMachoLib/Relocations.c +++ b/Library/OcMachoLib/Relocations.c @@ -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++) { diff --git a/Library/OcMachoLib/SymbolsX.h b/Library/OcMachoLib/SymbolsX.h index 9b899fa4..a7d1ad21 100644 --- a/Library/OcMachoLib/SymbolsX.h +++ b/Library/OcMachoLib/SymbolsX.h @@ -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); diff --git a/Utilities/TestMacho/Macho.c b/Utilities/TestMacho/Macho.c index 444285f8..1928788d 100644 --- a/Utilities/TestMacho/Macho.c +++ b/Utilities/TestMacho/Macho.c @@ -37,7 +37,7 @@ FeedMacho ( { OC_MACHO_CONTEXT Context; - if (!MachoInitializeContext64 (&Context, File, Size, 0)) { + if (!MachoInitializeContext64 (&Context, File, Size, 0, Size)) { return -1; }