From d916dd65b8cad8647101cddef2f38efd071ebbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20H=C3=A4user?= Date: Thu, 7 Jul 2022 01:20:21 +0200 Subject: [PATCH] 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. --- .../Acidanthera/Library/OcAppleKernelLib.h | 10 +- Include/Acidanthera/Library/OcMachoLib.h | 71 +++++++---- Library/OcAppleKernelLib/CommonPatches.c | 18 +-- Library/OcAppleKernelLib/CpuidPatches.c | 2 +- Library/OcAppleKernelLib/KernelCollection.c | 19 +-- Library/OcAppleKernelLib/KextPatcher.c | 8 +- Library/OcAppleKernelLib/Link.c | 33 ++++-- Library/OcAppleKernelLib/MkextContext.c | 2 +- Library/OcAppleKernelLib/PrelinkedContext.c | 17 +-- Library/OcAppleKernelLib/PrelinkedKext.c | 18 ++- Library/OcAppleKernelLib/Vtables.c | 30 ++--- Library/OcMachoLib/Header.c | 111 ++++++++---------- Library/OcMachoLib/HeaderX.h | 87 ++++++++------ Library/OcMachoLib/Relocations.c | 2 +- Library/OcMachoLib/SymbolsX.h | 4 +- Utilities/TestMacho/Macho.c | 2 +- 16 files changed, 247 insertions(+), 187 deletions(-) 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; }