diff --git a/Include/Acidanthera/Library/OcAppleKernelLib.h b/Include/Acidanthera/Library/OcAppleKernelLib.h index 8826943a..ee350eb5 100644 --- a/Include/Acidanthera/Library/OcAppleKernelLib.h +++ b/Include/Acidanthera/Library/OcAppleKernelLib.h @@ -275,7 +275,7 @@ typedef struct { // typedef struct { // - // Comment or NULL (0 base is used then). + // Comment or NULL. // CONST CHAR8 *Comment; // @@ -329,14 +329,18 @@ typedef struct { // CONST CHAR16 *ExtensionsDirFileName; // - // Injected kext list. + // List of injected kexts. // LIST_ENTRY InjectedKexts; // - // Dependency bundle list for injected kexts. + // List of dependencies that need to be injected. // LIST_ENTRY InjectedDependencies; // + // List of kext patches for built-in shipping kexts. + // + LIST_ENTRY PatchedKexts; + // // List of built-in shipping kexts. // LIST_ENTRY BuiltInKexts; @@ -400,8 +404,121 @@ typedef struct { // Array of kexts. // XML_NODE *MkextKexts; + // + // List of cached kexts, used for patching and blocking. + // + LIST_ENTRY CachedKexts; } MKEXT_CONTEXT; +// +// Kernel quirk names. +// +typedef enum { + // + // Apply MSR E2 patches to AppleIntelCPUPowerManagement kext. + // + KernelQuirkAppleCpuPmCfgLock, + // + // Apply MSR E2 patches to XNU kernel (XCPM). + // + KernelQuirkAppleXcpmCfgLock, + // + // Apply extra MSR patches to XNU kernel (XCPM). + // + KernelQuirkAppleXcpmExtraMsrs, + // + // Apply max MSR_IA32_PERF_CONTROL patches to XNU kernel (XCPM). + // + KernelQuirkAppleXcpmForceBoost, + // + // Apply custom AppleSMBIOS kext GUID patch for Custom UpdateSMBIOSMode. + // + KernelQuirkCustomSmbiosGuid1, + KernelQuirkCustomSmbiosGuid2, + // + // Apply VT-d disabling patches to IOPCIFamily kext to disable IOMapper in macOS. + // + KernelQuirkDisableIoMapper, + // + // Disable AppleRTC checksum writing. + // + KernelQuirkDisableRtcChecksum, + // + // Apply dummy power management patches to AppleIntelCpuPowerManagement in macOS. + // + KernelQuirkDummyPowerManagement, + // + // Apply icon type patches to IOAHCIPort kext to force internal disk icons. + // + KernelQuirkExternalDiskIcons, + // + // Apply PCI bar size patches to IOPCIFamily kext for compatibility with select configuration. + // + KernelQuirkIncreasePciBarSize, + // + // Disable LAPIC interrupt kernel panic on AP cores. + // + KernelQuirkLapicKernelPanic, + // + // Apply kernel patches to remove kext dumping in the panic log. + // + KernelQuirkPanicNoKextDump, + // + // Disable power state change timeout kernel panic (10.15+). + // + KernelQuirkPowerTimeoutKernelPanic, + // + // Apply vendor patches to IOAHCIFamily kext to enable native features for third-party drives, + // such as TRIM on SSDs or hibernation support on 10.15. + // + KernelQuirkThirdPartyDrives, + // + // Apply port limit patches to AppleUSBXHCI and AppleUSBXHCIPCI kexts. + // + KernelQuirkXhciPortLimit1, + KernelQuirkXhciPortLimit2, + KernelQuirkXhciPortLimit3, + + KernelQuirkMax +} KERNEL_QUIRK_NAME; + +// +// Kernel quirk patch function. +// +typedef +EFI_STATUS +(KERNEL_QUIRK_PATCH_FUNCTION)( + IN OUT PATCHER_CONTEXT *Patcher + ); + +// +// Kernel quirk. +// +typedef struct { + // + // Target bundle ID. NULL for kernel. + // + CONST CHAR8 *BundleId; + // + // Quirk patch function. + // + KERNEL_QUIRK_PATCH_FUNCTION *PatchFunction; +} KERNEL_QUIRK; + +/** + Applies the specified quirk. + + @param[in] Name KERNEL_QUIRK_NAME specifying the quirk name. + @param[in,out] Patcher PATCHER_CONTEXT instance. + + @returns EFI_SUCCESS on success. +**/ +EFI_STATUS +KernelQuirkApply ( + IN KERNEL_QUIRK_NAME Name, + IN OUT PATCHER_CONTEXT *Patcher + ); + /** Read Apple kernel for target architecture (possibly decompressing) into pool allocated buffer. @@ -587,6 +704,36 @@ PrelinkedInjectKext ( IN UINT32 ExecutableSize OPTIONAL ); +/** + Apply kext patch to prelinked. + + @param[in,out] Context Prelinked context. + @param[in] BundleId Kext bundle ID. + @param[in] Patch Patch to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +PrelinkedContextApplyPatch ( + IN OUT PRELINKED_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ); + +/** + Apply kext quirk to prelinked. + + @param[in,out] Context Prelinked context. + @param[in] Quirk Kext quirk to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +PrelinkedContextApplyQuirk ( + IN OUT PRELINKED_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ); + EFI_STATUS KcRebuildMachHeader ( IN OUT PRELINKED_CONTEXT *Context @@ -681,6 +828,22 @@ PatcherInitContextFromPrelinked ( IN CONST CHAR8 *Name ); +/** + Initialize patcher from mkext context for kext patching. + + @param[in,out] Context Patcher context. + @param[in,out] Mkext Mkext context. + @param[in] Name Kext bundle identifier. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +PatcherInitContextFromMkext( + IN OUT PATCHER_CONTEXT *Context, + IN OUT MKEXT_CONTEXT *Mkext, + IN CONST CHAR8 *Name + ); + /** Initialize patcher from buffer for e.g. kernel patching. @@ -739,127 +902,6 @@ PatcherBlockKext ( IN OUT PATCHER_CONTEXT *Context ); -/** - Apply MSR E2 patches to AppleIntelCPUPowerManagement kext. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleCpuPmCfgLock ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply MSR E2 patches to XNU kernel (XCPM). - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleXcpmCfgLock ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Apply extra MSR patches to XNU kernel (XCPM). - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleXcpmExtraMsrs ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Apply max MSR_IA32_PERF_CONTROL patches to XNU kernel (XCPM). - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleXcpmForceBoost ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Apply port limit patches to AppleUSBXHCI and AppleUSBXHCIPCI kexts. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchUsbXhciPortLimit ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply vendor patches to IOAHCIFamily kext to enable native features for third-party drives, - such as TRIM on SSDs or hibernation support on 10.15. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchThirdPartyDriveSupport ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply icon type patches to IOAHCIPort kext to force internal disk icons. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchForceInternalDiskIcons ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply VT-d disabling patches to IOPCIFamily kext to disable IOMapper in macOS. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleIoMapperSupport ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply dummy power management patches to AppleIntelCpuPowerManagement in macOS. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchDummyPowerManagement ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply PCI bar size patches to IOPCIFamily kext for compatibility with select configuration. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchIncreasePciBarSize ( - IN OUT PRELINKED_CONTEXT *Context - ); - /** Apply modification to CPUID 1. @@ -878,66 +920,6 @@ PatchKernelCpuId ( IN UINT32 *DataMask ); -/** - Apply custom AppleSMBIOS kext GUID patch for Custom UpdateSMBIOSMode. - - @param Context Prelinked kernel context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchCustomSmbiosGuid ( - IN OUT PRELINKED_CONTEXT *Context - ); - -/** - Apply kernel patches to remove kext dumping in the panic log. - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchPanicKextDump ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Disable LAPIC interrupt kernel panic on AP cores. - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchLapicKernelPanic ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Disable power state change timeout kernel panic (10.15+). - - @param Patcher Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchPowerStateTimeout ( - IN OUT PATCHER_CONTEXT *Patcher - ); - -/** - Disable AppleRTC checksum writing. - - @param Context Patcher context. - - @return EFI_SUCCESS on success. -**/ -EFI_STATUS -PatchAppleRtcChecksum ( - IN OUT PRELINKED_CONTEXT *Context - ); - /** Initializes cacheless context for later modification. Must be freed with CachelessContextFree on success. @@ -987,6 +969,36 @@ CachelessContextAddKext ( IN UINT32 ExecutableSize OPTIONAL ); +/** + Add patch to cacheless context to be applied later on. + + @param[in,out] Context Cacheless context. + @param[in] BundleId Kext bundle ID. + @param[in] Patch Patch to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +CachelessContextAddPatch ( + IN OUT CACHELESS_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ); + +/** + Add kernel quirk to cacheless context to be applied later on. + + @param[in,out] Context Cacheless context. + @param[in] Quirk Quirk to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +CachelessContextAddQuirk ( + IN OUT CACHELESS_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ); + /** Creates virtual directory overlay EFI_FILE_PROTOCOL from cacheless context. @@ -1151,6 +1163,36 @@ MkextInjectKext ( IN UINT32 ExecutableSize OPTIONAL ); +/** + Apply kext patch to mkext. + + @param[in,out] Context Mkext context. + @param[in] BundleId Kext bundle ID. + @param[in] Patch Patch to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +MkextContextApplyPatch ( + IN OUT MKEXT_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ); + +/** + Apply kext quirk to mkext. + + @param[in,out] Context Mkext context. + @param[in] Quirk Kext quirk to apply. + + @return EFI_SUCCESS on success. +**/ +EFI_STATUS +MkextContextApplyQuirk ( + IN OUT MKEXT_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ); + /** Refresh plist and checksum after kext injection and/or patching. diff --git a/Library/OcAppleKernelLib/CachelessContext.c b/Library/OcAppleKernelLib/CachelessContext.c index bdc4c433..ebd3754e 100644 --- a/Library/OcAppleKernelLib/CachelessContext.c +++ b/Library/OcAppleKernelLib/CachelessContext.c @@ -27,6 +27,7 @@ #include #include "CachelessInternal.h" +#include "PrelinkedInternal.h" STATIC VOID @@ -46,6 +47,9 @@ FreeBuiltInKext ( if (BuiltinKext->BinaryFileName != NULL) { FreePool (BuiltinKext->BinaryFileName); } + if (BuiltinKext->BinaryPath != NULL) { + FreePool (BuiltinKext->BinaryPath); + } while (!IsListEmpty (&BuiltinKext->Dependencies)) { KextLink = GetFirstNode (&BuiltinKext->Dependencies); @@ -298,6 +302,9 @@ ScanExtensions ( return EFI_INVALID_PARAMETER; } + // + // Create plist path. + // Status = OcUnicodeSafeSPrint ( TmpPath, sizeof (TmpPath), @@ -323,13 +330,44 @@ ScanExtensions ( return EFI_OUT_OF_RESOURCES; } + // + // Create binary path. If plist is in root of kext, binary is also there. + // + if (BuiltinKext->BinaryFileName != NULL) { + Status = OcUnicodeSafeSPrint ( + TmpPath, + sizeof (TmpPath), + L"%s\\%s\\%s%s", + FilePath, + FileInfo->FileName, + UseContents ? L"Contents\\MacOS\\" : L"\\", + BuiltinKext->BinaryFileName + ); + if (EFI_ERROR (Status)) { + FreeBuiltInKext (BuiltinKext); + FileKext->Close (FileKext); + File->SetPosition (File, 0); + FreePool (FileInfo); + return EFI_INVALID_PARAMETER; + } + + BuiltinKext->BinaryPath = AllocateCopyPool (StrSize (TmpPath), TmpPath); + if (BuiltinKext->BinaryPath == NULL) { + FreeBuiltInKext (BuiltinKext); + FileKext->Close (FileKext); + File->SetPosition (File, 0); + FreePool (FileInfo); + return EFI_OUT_OF_RESOURCES; + } + } + InsertTailList (&Context->BuiltInKexts, &BuiltinKext->Link); DEBUG (( DEBUG_VERBOSE, "OCAK: Discovered bundle %a %s %s %u\n", BuiltinKext->BundleId, - BuiltinKext->BinaryFileName, BuiltinKext->PlistPath, + BuiltinKext->BinaryPath, BuiltinKext->OSBundleRequiredValue )); @@ -376,6 +414,30 @@ ScanExtensions ( return EFI_SUCCESS; } +STATIC +PATCHED_KEXT* +LookupPatchedKextForBundleId ( + IN OUT CACHELESS_CONTEXT *Context, + IN CONST CHAR8 *BundleId + ) +{ + PATCHED_KEXT *PatchedKext; + LIST_ENTRY *KextLink; + + KextLink = GetFirstNode (&Context->PatchedKexts); + while (!IsNull (&Context->PatchedKexts, KextLink)) { + PatchedKext = GET_PATCHED_KEXT_FROM_LINK (KextLink); + + if (AsciiStrCmp (BundleId, PatchedKext->BundleId) == 0) { + return PatchedKext; + } + + KextLink = GetNextNode (&Context->PatchedKexts, KextLink); + } + + return NULL; +} + STATIC BUILTIN_KEXT* LookupBuiltinKextForBundleId ( @@ -424,6 +486,31 @@ LookupBuiltinKextForPlistPath ( return NULL; } +STATIC +BUILTIN_KEXT* +LookupBuiltinKextForBinaryPath ( + IN OUT CACHELESS_CONTEXT *Context, + IN CONST CHAR16 *BinaryPath + ) +{ + BUILTIN_KEXT *BuiltinKext; + LIST_ENTRY *KextLink; + + KextLink = GetFirstNode (&Context->BuiltInKexts); + while (!IsNull (&Context->BuiltInKexts, KextLink)) { + BuiltinKext = GET_BUILTIN_KEXT_FROM_LINK (KextLink); + + if (BuiltinKext->BinaryPath != NULL + && StrCmp (BinaryPath, BuiltinKext->BinaryPath) == 0) { + return BuiltinKext; + } + + KextLink = GetNextNode (&Context->BuiltInKexts, KextLink); + } + + return NULL; +} + STATIC EFI_STATUS ScanDependencies ( @@ -492,6 +579,72 @@ ScanDependencies ( return EFI_SUCCESS; } +STATIC +EFI_STATUS +InternalAddKextPatch ( + IN OUT CACHELESS_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch OPTIONAL, + IN KERNEL_QUIRK_NAME QuirkName + ) +{ + PATCHED_KEXT *PatchedKext; + KEXT_PATCH *KextPatch; + KERNEL_QUIRK *KernelQuirk; + + if (Patch == NULL) { + KernelQuirk = &gKernelQuirks[QuirkName]; + ASSERT (KernelQuirk->BundleId != NULL); + + BundleId = KernelQuirk->BundleId; + } + + // + // Check if bundle is already present. If not, add to list. + // + PatchedKext = LookupPatchedKextForBundleId (Context, BundleId); + if (PatchedKext == NULL) { + PatchedKext = AllocateZeroPool (sizeof (*PatchedKext)); + if (PatchedKext == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PatchedKext->Signature = PATCHED_KEXT_SIGNATURE; + PatchedKext->BundleId = AllocateCopyPool (AsciiStrSize (BundleId), BundleId); + if (PatchedKext->BundleId == NULL) { + FreePool (PatchedKext); + return EFI_OUT_OF_RESOURCES; + } + InitializeListHead (&PatchedKext->Patches); + + InsertTailList (&Context->PatchedKexts, &PatchedKext->Link); + } + + // + // Add new patch. + // + KextPatch = AllocateZeroPool (sizeof (*KextPatch)); + if (KextPatch == NULL) { + return EFI_OUT_OF_RESOURCES; + } + KextPatch->Signature = KEXT_PATCH_SIGNATURE; + + if (Patch != NULL) { + CopyMem (&KextPatch->Patch, Patch, sizeof (KextPatch->Patch)); + + } else { + // + // Apply quirk if no Patch. + // + KextPatch->ApplyQuirk = TRUE; + KextPatch->QuirkName = QuirkName; + } + + InsertTailList (&PatchedKext->Patches, &KextPatch->Link); + + return EFI_SUCCESS; +} + EFI_STATUS CachelessContextInit ( IN OUT CACHELESS_CONTEXT *Context, @@ -510,6 +663,7 @@ CachelessContextInit ( InitializeListHead (&Context->InjectedKexts); InitializeListHead (&Context->InjectedDependencies); + InitializeListHead (&Context->PatchedKexts); InitializeListHead (&Context->BuiltInKexts); return EFI_SUCCESS; @@ -520,9 +674,12 @@ CachelessContextFree ( IN OUT CACHELESS_CONTEXT *Context ) { - CACHELESS_KEXT *CachelessKext; - BUILTIN_KEXT *BuiltinKext; - LIST_ENTRY *KextLink; + CACHELESS_KEXT *CachelessKext; + PATCHED_KEXT *PatchedKext; + KEXT_PATCH *KextPatch; + BUILTIN_KEXT *BuiltinKext; + LIST_ENTRY *KextLink; + LIST_ENTRY *PatchLink; ASSERT (Context != NULL); @@ -543,6 +700,22 @@ CachelessContextFree ( FreePool (CachelessKext); } + while (!IsListEmpty (&Context->PatchedKexts)) { + KextLink = GetFirstNode (&Context->PatchedKexts); + PatchedKext = GET_PATCHED_KEXT_FROM_LINK (KextLink); + RemoveEntryList (KextLink); + + while (!IsListEmpty (&PatchedKext->Patches)) { + PatchLink = GetFirstNode (&PatchedKext->Patches); + KextPatch = GET_KEXT_PATCH_FROM_LINK (PatchLink); + RemoveEntryList (PatchLink); + + FreePool (KextPatch); + } + + FreePool (PatchedKext); + } + while (!IsListEmpty (&Context->BuiltInKexts)) { KextLink = GetFirstNode (&Context->BuiltInKexts); BuiltinKext = GET_BUILTIN_KEXT_FROM_LINK (KextLink); @@ -759,6 +932,31 @@ CachelessContextAddKext ( return EFI_SUCCESS; } +EFI_STATUS +CachelessContextAddPatch ( + IN OUT CACHELESS_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ) +{ + ASSERT (Context != NULL); + ASSERT (BundleId != NULL); + ASSERT (Patch != NULL); + + return InternalAddKextPatch (Context, BundleId, Patch, 0); +} + +EFI_STATUS +CachelessContextAddQuirk ( + IN OUT CACHELESS_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ) +{ + ASSERT (Context != NULL); + + return InternalAddKextPatch (Context, NULL, NULL, Quirk); +} + EFI_STATUS CachelessContextOverlayExtensionsDir ( IN OUT CACHELESS_CONTEXT *Context, @@ -1012,12 +1210,17 @@ CachelessContextHookBuiltin ( ) { EFI_STATUS Status; + EFI_TIME ModificationTime; BUILTIN_KEXT *BuiltinKext; + KEXT_PATCH *KextPatch; + PATCHED_KEXT *PatchedKext; DEPEND_KEXT *DependKext; LIST_ENTRY *KextLink; - CHAR8 *InfoPlist; - UINT32 InfoPlistSize; + PATCHER_CONTEXT Patcher; + + VOID *Buffer; + UINT32 BufferSize; XML_DOCUMENT *InfoPlistDocument; XML_NODE *InfoPlistRoot; XML_NODE *InfoPlistValue; @@ -1048,6 +1251,31 @@ CachelessContextHookBuiltin ( return Status; } + // + // Ensure all kexts to be patched will be loaded. + // + KextLink = GetFirstNode (&Context->PatchedKexts); + while (!IsNull (&Context->PatchedKexts, KextLink)) { + PatchedKext = GET_PATCHED_KEXT_FROM_LINK (KextLink); + + BuiltinKext = LookupBuiltinKextForBundleId (Context, PatchedKext->BundleId); + if (BuiltinKext == NULL) { + // + // Kext is not present, skip. + // + DEBUG ((DEBUG_WARN, "OCAK: Attempted to patch non-existent kext %a\n", PatchedKext->BundleId)); + + } else { + BuiltinKext->PatchKext = TRUE; + Status = ScanDependencies (Context, PatchedKext->BundleId); + if (EFI_ERROR (Status)) { + return Status; + } + } + + KextLink = GetNextNode (&Context->PatchedKexts, KextLink); + } + // // Scan dependencies, adding any others besides ones being injected. // @@ -1066,31 +1294,31 @@ CachelessContextHookBuiltin ( } // - // Info.plist. + // Try to get Info.plist. // if (OcUnicodeEndsWith (FileName, L"Info.plist")) { BuiltinKext = LookupBuiltinKextForPlistPath (Context, FileName); if (BuiltinKext != NULL && BuiltinKext->PatchValidOSBundleRequired) { - DEBUG ((DEBUG_INFO, "OCAK: Processing patches for %s\n", FileName)); + DEBUG ((DEBUG_INFO, "OCAK: Processing plist patches for %s\n", FileName)); // // Open Info.plist // - Status = AllocateCopyFileData (File, (UINT8**)&InfoPlist, &InfoPlistSize); + Status = AllocateCopyFileData (File, (UINT8 **) &Buffer, &BufferSize); if (EFI_ERROR (Status)) { return Status; } - InfoPlistDocument = XmlDocumentParse (InfoPlist, InfoPlistSize, FALSE); + InfoPlistDocument = XmlDocumentParse (Buffer, BufferSize, FALSE); if (InfoPlistDocument == NULL) { - FreePool (InfoPlist); + FreePool (Buffer); return EFI_INVALID_PARAMETER; } InfoPlistRoot = PlistNodeCast (PlistDocumentRoot (InfoPlistDocument), PLIST_NODE_TYPE_DICT); if (InfoPlistRoot == NULL) { XmlDocumentFree (InfoPlistDocument); - FreePool (InfoPlist); + FreePool (Buffer); return EFI_INVALID_PARAMETER; } @@ -1117,7 +1345,7 @@ CachelessContextHookBuiltin ( Failed |= XmlNodeAppend (InfoPlistRoot, "string", NULL, OS_BUNDLE_REQUIRED_ROOT) == NULL; if (Failed) { XmlDocumentFree (InfoPlistDocument); - FreePool (InfoPlist); + FreePool (Buffer); return EFI_OUT_OF_RESOURCES; } } @@ -1128,29 +1356,102 @@ CachelessContextHookBuiltin ( NewPlistData = XmlDocumentExport (InfoPlistDocument, &NewPlistDataSize, 0, TRUE); if (NewPlistData == NULL) { XmlDocumentFree (InfoPlistDocument); - FreePool (InfoPlist); + FreePool (Buffer); return EFI_OUT_OF_RESOURCES; } XmlDocumentFree (InfoPlistDocument); - FreePool (InfoPlist); + FreePool (Buffer); // // Virtualize newly created Info.plist. // - Status = CreateVirtualFileFileNameCopy (FileName, NewPlistData, NewPlistDataSize, NULL, VirtualFile); + Status = GetFileModificationTime (File, &ModificationTime); + if (EFI_ERROR (Status)) { + ZeroMem (&ModificationTime, sizeof (ModificationTime)); + } + + Status = CreateVirtualFileFileNameCopy (FileName, NewPlistData, NewPlistDataSize, &ModificationTime, VirtualFile); if (EFI_ERROR (Status)) { *VirtualFile = NULL; FreePool (NewPlistData); } return Status; } + } else { + // + // Try to get binary for built-in kext. + // + BuiltinKext = LookupBuiltinKextForBinaryPath (Context, FileName); + if (BuiltinKext != NULL && BuiltinKext->PatchKext) { + DEBUG ((DEBUG_INFO, "OCAK: Processing binary patches for %s\n", FileName)); + + PatchedKext = LookupPatchedKextForBundleId (Context, BuiltinKext->BundleId); + if (PatchedKext == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = AllocateCopyFileData (File, (UINT8 **) &Buffer, &BufferSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PatcherInitContextFromBuffer (&Patcher, Buffer, BufferSize); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + // + // Apply patches. + // + KextLink = GetFirstNode (&PatchedKext->Patches); + while (!IsNull (&PatchedKext->Patches, KextLink)) { + KextPatch = GET_KEXT_PATCH_FROM_LINK (KextLink); + + if (KextPatch->ApplyQuirk) { + Status = KernelQuirkApply (KextPatch->QuirkName, &Patcher); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, + "OCAK: Kernel quirk result for %a (%u) - %r\n", + PatchedKext->BundleId, + KextPatch->QuirkName, + Status + )); + } else { + Status = PatcherApplyGenericPatch (&Patcher, &KextPatch->Patch); + DEBUG (( + EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, + "OCAK: Kext patcher result for %a (%a) - %r\n", + PatchedKext->BundleId, + KextPatch->Patch.Comment, + Status + )); + } + + KextLink = GetNextNode (&PatchedKext->Patches, KextLink); + } + + // + // Virtualize patched binary. + // + Status = GetFileModificationTime (File, &ModificationTime); + if (EFI_ERROR (Status)) { + ZeroMem (&ModificationTime, sizeof (ModificationTime)); + } + + Status = CreateVirtualFileFileNameCopy (FileName, Buffer, BufferSize, &ModificationTime, VirtualFile); + if (EFI_ERROR (Status)) { + *VirtualFile = NULL; + FreePool (Buffer); + } + return Status; + } } // - // TODO: hook binaries for patches here. + // No file hooked. // - *VirtualFile = NULL; return EFI_SUCCESS; diff --git a/Library/OcAppleKernelLib/CachelessInternal.h b/Library/OcAppleKernelLib/CachelessInternal.h index 98e237c8..fd1c253c 100644 --- a/Library/OcAppleKernelLib/CachelessInternal.h +++ b/Library/OcAppleKernelLib/CachelessInternal.h @@ -89,6 +89,54 @@ typedef struct { CHAR16 *BinaryFileName; } CACHELESS_KEXT; +// +// Kext patch. +// +typedef struct { + // + // Signature. + // + UINT32 Signature; + // + // Link for global list (PATCHED_BUILTIN_KEXT -> Patches). + // + LIST_ENTRY Link; + // + // Generic patch. + // + PATCHER_GENERIC_PATCH Patch; + // + // Apply Quirk instead of Patch. + // + BOOLEAN ApplyQuirk; + // + // Kernel quirk to apply. + // + KERNEL_QUIRK_NAME QuirkName; +} KEXT_PATCH; + +// +// Built-in kext in SLE requiring patches. +// +typedef struct { + // + // Signature. + // + UINT32 Signature; + // + // Link for global list (CACHELESS_CONTEXT -> PatchedKexts). + // + LIST_ENTRY Link; + // + // Bundle ID. + // + CHAR8 *BundleId; + // + // List of patches to apply. + // + LIST_ENTRY Patches; +} PATCHED_KEXT; + // // Built-in kexts in SLE. // @@ -114,6 +162,10 @@ typedef struct { // CHAR16 *BinaryFileName; // + // Binary file path. + // + CHAR16 *BinaryPath; + // // Dependencies. // LIST_ENTRY Dependencies; @@ -167,13 +219,49 @@ typedef struct { CACHELESS_KEXT_SIGNATURE \ )) +// +// KEXT_PATCH signature for list identification. +// +#define KEXT_PATCH_SIGNATURE SIGNATURE_32 ('K', 'x', 't', 'P') + +/** + Gets the next element in Patches list of KEXT_PATCH. + + @param[in] This The current ListEntry. +**/ +#define GET_KEXT_PATCH_FROM_LINK(This) \ + (CR ( \ + (This), \ + KEXT_PATCH, \ + Link, \ + KEXT_PATCH_SIGNATURE \ + )) + +// +// PATCHED_KEXT signature for list identification. +// +#define PATCHED_KEXT_SIGNATURE SIGNATURE_32 ('S', 'l', 'e', 'P') + +/** + Gets the next element in PatchedKexts list of PATCHED_KEXT. + + @param[in] This The current ListEntry. +**/ +#define GET_PATCHED_KEXT_FROM_LINK(This) \ + (CR ( \ + (This), \ + PATCHED_KEXT, \ + Link, \ + PATCHED_KEXT_SIGNATURE \ + )) + // // BUILTIN_KEXT signature for list identification. // #define BUILTIN_KEXT_SIGNATURE SIGNATURE_32 ('S', 'l', 'e', 'B') /** - Gets the next element in BuiltInKexts list of CACHELESS_KEXT. + Gets the next element in BuiltInKexts list of BUILTIN_KEXT. @param[in] This The current ListEntry. **/ diff --git a/Library/OcAppleKernelLib/CommonPatches.c b/Library/OcAppleKernelLib/CommonPatches.c index 3da8d4e7..c68a86a3 100644 --- a/Library/OcAppleKernelLib/CommonPatches.c +++ b/Library/OcAppleKernelLib/CommonPatches.c @@ -1,5 +1,5 @@ /** @file - Commonly used kext patches. + Commonly used kext and kernel patches. Copyright (c) 2018, vit9696. All rights reserved.
This program and the accompanying materials @@ -96,38 +96,27 @@ mAppleIntelCPUPowerManagementPatch2 = { .Skip = 0 }; +STATIC EFI_STATUS PatchAppleCpuPmCfgLock ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; EFI_STATUS Status2; - PATCHER_CONTEXT Patcher; - - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.AppleIntelCPUPowerManagement" - ); + Status = PatcherApplyGenericPatch (Patcher, &mAppleIntelCPUPowerManagementPatch); if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mAppleIntelCPUPowerManagementPatch); - if (!EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Patch v1 success com.apple.driver.AppleIntelCPUPowerManagement\n")); - } + DEBUG ((DEBUG_INFO, "OCAK: Patch v1 success com.apple.driver.AppleIntelCPUPowerManagement\n")); + } - Status2 = PatcherApplyGenericPatch (&Patcher, &mAppleIntelCPUPowerManagementPatch2); - if (!EFI_ERROR (Status2)) { - DEBUG ((DEBUG_INFO, "OCAK: Patch v2 success com.apple.driver.AppleIntelCPUPowerManagement\n")); - } + Status2 = PatcherApplyGenericPatch (Patcher, &mAppleIntelCPUPowerManagementPatch2); + if (!EFI_ERROR (Status2)) { + DEBUG ((DEBUG_INFO, "OCAK: Patch v2 success com.apple.driver.AppleIntelCPUPowerManagement\n")); + } - if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patches com.apple.driver.AppleIntelCPUPowerManagement - %r/%r\n", Status, Status2)); - } - } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.driver.AppleIntelCPUPowerManagement - %r\n", Status)); - Status2 = Status; + if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patches com.apple.driver.AppleIntelCPUPowerManagement - %r/%r\n", Status, Status2)); } // @@ -207,9 +196,10 @@ mXcpmCfgLockDbgPatch = { .Limit = 4096 }; +STATIC EFI_STATUS PatchAppleXcpmCfgLock ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; @@ -330,9 +320,10 @@ mMiscPwrMgmtDbgPatch = { .Limit = 0 }; +STATIC EFI_STATUS PatchAppleXcpmExtraMsrs ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; @@ -449,9 +440,10 @@ mPerfCtrlMax[] = { 0xC3 ///< ret }; +STATIC EFI_STATUS PatchAppleXcpmForceBoost ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { UINT8 *Start; @@ -587,35 +579,36 @@ mRemoveUsbLimitIoP1Patch = { .Limit = 4096 }; +STATIC EFI_STATUS -PatchUsbXhciPortLimit ( - IN OUT PRELINKED_CONTEXT *Context +PatchUsbXhciPortLimit1 ( + IN OUT PATCHER_CONTEXT *Patcher ) { - EFI_STATUS Status; - PATCHER_CONTEXT Patcher; + EFI_STATUS Status; // // On 10.14.4 and newer IOUSBHostFamily also needs limit removal. // Thanks to ydeng discovering this. // - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.iokit.IOUSBHostFamily" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mRemoveUsbLimitIoP1Patch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply P1 patch com.apple.iokit.IOUSBHostFamily - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOUSBHostFamily\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mRemoveUsbLimitIoP1Patch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply P1 patch com.apple.iokit.IOUSBHostFamily - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.iokit.IOUSBHostFamily - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOUSBHostFamily\n")); } + return Status; +} + +STATIC +EFI_STATUS +PatchUsbXhciPortLimit2 ( + IN OUT PATCHER_CONTEXT *Patcher + ) +{ + EFI_STATUS Status; + // // TODO: Implement some locationID hack in IOUSBHFamily. // The location ID is a 32 bit number which is unique among all USB devices in the system, @@ -637,47 +630,36 @@ PatchUsbXhciPortLimit ( // // C~F are filled as many times as many USB Hubs are there on the port. // - - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.usb.AppleUSBXHCI" - ); - + Status = PatcherApplyGenericPatch (Patcher, &mRemoveUsbLimitV2Patch); if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mRemoveUsbLimitV2Patch); - if (!EFI_ERROR (Status)) { - // - // We do not need to patch com.apple.driver.usb.AppleUSBXHCI if this patch was successful. - // Only legacy systems require com.apple.driver.usb.AppleUSBXHCI to be patched. - // - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.usb.AppleUSBXHCI\n")); - return EFI_SUCCESS; - } - - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.usb.AppleUSBXHCI - %r\n", Status)); + // + // We do not need to patch com.apple.driver.usb.AppleUSBXHCI if this patch was successful. + // Only legacy systems require com.apple.driver.usb.AppleUSBXHCI to be patched. + // + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.usb.AppleUSBXHCI\n")); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.driver.usb.AppleUSBXHCI - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.usb.AppleUSBXHCI - %r\n", Status)); } + return Status; +} + +STATIC +EFI_STATUS +PatchUsbXhciPortLimit3 ( + IN OUT PATCHER_CONTEXT *Patcher + ) +{ + EFI_STATUS Status; + // // If we are here, we are on legacy 10.13 or below, try the oldest patch. // - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.usb.AppleUSBXHCIPCI" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mRemoveUsbLimitV1Patch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.usb.AppleUSBXHCIPCI - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.usb.AppleUSBXHCIPCI\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mRemoveUsbLimitV1Patch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.usb.AppleUSBXHCIPCI - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.driver.usb.AppleUSBXHCIPCI - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.usb.AppleUSBXHCIPCI\n")); } return Status; @@ -735,37 +717,27 @@ mIOAHCIBlockStoragePatchV2 = { .Skip = 0 }; +STATIC EFI_STATUS PatchThirdPartyDriveSupport ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.iokit.IOAHCIBlockStorage" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mIOAHCIBlockStoragePatchV1); + Status = PatcherApplyGenericPatch (Patcher, &mIOAHCIBlockStoragePatchV1); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOAHCIBlockStorage V1 - %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOAHCIBlockStorage V1\n")); } - Status = PatcherApplyGenericPatch (&Patcher, &mIOAHCIBlockStoragePatchV2); + Status = PatcherApplyGenericPatch (Patcher, &mIOAHCIBlockStoragePatchV2); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOAHCIBlockStorage V2 - %r\n", Status)); } else { DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOAHCIBlockStorage V2\n")); } - } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.iokit.IOAHCIBlockStorage - %r\n", Status)); - } return Status; } @@ -785,40 +757,30 @@ mIOAHCIPortPatchReplace[] = { STATIC PATCHER_GENERIC_PATCH mIOAHCIPortPatch = { - .Comment = DEBUG_POINTER ("IOAHCIPort"), - .Base = NULL, - .Find = mIOAHCIPortPatchFind, - .Mask = NULL, - .Replace = mIOAHCIPortPatchReplace, - .ReplaceMask = NULL, - .Size = sizeof (mIOAHCIPortPatchFind), - .Count = 1, - .Skip = 0 + .Comment = DEBUG_POINTER ("IOAHCIPort"), + .Base = NULL, + .Find = mIOAHCIPortPatchFind, + .Mask = NULL, + .Replace = mIOAHCIPortPatchReplace, + .ReplaceMask = NULL, + .Size = sizeof (mIOAHCIPortPatchFind), + .Count = 1, + .Skip = 0 }; +STATIC EFI_STATUS PatchForceInternalDiskIcons ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.AppleAHCIPort" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mIOAHCIPortPatch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.AppleAHCIPort - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.AppleAHCIPort\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mIOAHCIPortPatch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.AppleAHCIPort - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.driver.AppleAHCIPort - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.AppleAHCIPort\n")); } return Status; @@ -850,29 +812,19 @@ mAppleIoMapperPatch = { .Skip = 0 }; +STATIC EFI_STATUS PatchAppleIoMapperSupport ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.iokit.IOPCIFamily" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mAppleIoMapperPatch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOPCIFamily AppleIoMapper - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOPCIFamily AppleIoMapper\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mAppleIoMapperPatch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOPCIFamily AppleIoMapper - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.iokit.IOPCIFamily for AppleIoMapper - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOPCIFamily AppleIoMapper\n")); } return Status; @@ -898,29 +850,19 @@ mAppleDummyCpuPmPatch = { .Skip = 0 }; +STATIC EFI_STATUS PatchDummyPowerManagement ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.AppleIntelCPUPowerManagement" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mAppleDummyCpuPmPatch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch dummy AppleIntelCPUPowerManagement - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success dummy AppleIntelCPUPowerManagement\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mAppleDummyCpuPmPatch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch dummy AppleIntelCPUPowerManagement - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find AppleIntelCPUPowerManagement for dummy - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success dummy AppleIntelCPUPowerManagement\n")); } return Status; @@ -953,34 +895,25 @@ mIncreasePciBarSizePatch = { .Limit = EFI_PAGE_SIZE }; +STATIC EFI_STATUS PatchIncreasePciBarSize ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.iokit.IOPCIFamily" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mIncreasePciBarSizePatch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOPCIFamily IncreasePciBarSize - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOPCIFamily IncreasePciBarSize\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mIncreasePciBarSizePatch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.iokit.IOPCIFamily IncreasePciBarSize - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.iokit.IOPCIFamily for IncreasePciBarSize - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.iokit.IOPCIFamily IncreasePciBarSize\n")); } return Status; } + STATIC CONST UINT8 mKernelCpuIdFindRelNew[] = { @@ -1027,6 +960,8 @@ mKernelCpuidFindMcRel[] = { cpu->cpuid_cpufamily = 0xAAAAAAAA; return 0xAAAAAAAA; **/ + + STATIC CONST UINT8 mKernelCpuidReplaceDbg[] = { @@ -1454,48 +1389,30 @@ mCustomSmbiosGuidPatchReplace[] = { STATIC PATCHER_GENERIC_PATCH mCustomSmbiosGuidPatch = { - .Comment = DEBUG_POINTER ("CustomSmbiosGuid"), - .Base = NULL, - .Find = mCustomSmbiosGuidPatchFind, - .Mask = NULL, - .Replace = mCustomSmbiosGuidPatchReplace, - .ReplaceMask = NULL, - .Size = sizeof (mCustomSmbiosGuidPatchFind), - .Count = 1, - .Skip = 0 + .Comment = DEBUG_POINTER ("CustomSmbiosGuid"), + .Base = NULL, + .Find = mCustomSmbiosGuidPatchFind, + .Mask = NULL, + .Replace = mCustomSmbiosGuidPatchReplace, + .ReplaceMask = NULL, + .Size = sizeof (mCustomSmbiosGuidPatchFind), + .Count = 1, + .Skip = 0 }; +STATIC EFI_STATUS PatchCustomSmbiosGuid ( - IN OUT PRELINKED_CONTEXT *Context + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; - UINT32 Index; - STATIC CONST CHAR8 *Kexts[] = { - "com.apple.driver.AppleSMBIOS", - "com.apple.driver.AppleACPIPlatform" - }; - - for (Index = 0; Index < ARRAY_SIZE (Kexts); ++Index) { - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - Kexts[Index] - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mCustomSmbiosGuidPatch); - if (!EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: SMBIOS Patch success %a\n", Kexts[Index])); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply SMBIOS patch %a - %r\n", Kexts[Index], Status)); - } - } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find SMBIOS kext %a - %r\n", Kexts[Index], Status)); - } + Status = PatcherApplyGenericPatch (Patcher, &mCustomSmbiosGuidPatch); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: SMBIOS Patch success\n")); + } else { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply SMBIOS patch - %r\n", Status)); } return Status; @@ -1527,9 +1444,10 @@ mPanicKextDumpPatch = { .Skip = 0 }; +STATIC EFI_STATUS PatchPanicKextDump ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; @@ -1676,9 +1594,10 @@ mLapicKernelPanicMasterPatch = { .Limit = 4096 }; +STATIC EFI_STATUS PatchLapicKernelPanic ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; @@ -1744,9 +1663,10 @@ mPowerStateTimeoutPanicMasterPatch = { .Limit = 0 }; +STATIC EFI_STATUS PatchPowerStateTimeout ( - IN OUT PATCHER_CONTEXT *Patcher + IN OUT PATCHER_CONTEXT *Patcher ) { EFI_STATUS Status; @@ -1806,30 +1726,55 @@ mAppleRtcChecksumPatch = { .Limit = 0 }; +STATIC EFI_STATUS PatchAppleRtcChecksum ( - IN OUT PRELINKED_CONTEXT *Context + IN PATCHER_CONTEXT *Patcher ) { - EFI_STATUS Status; - PATCHER_CONTEXT Patcher; + EFI_STATUS Status; - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - "com.apple.driver.AppleRTC" - ); - - if (!EFI_ERROR (Status)) { - Status = PatcherApplyGenericPatch (&Patcher, &mAppleRtcChecksumPatch); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.AppleRTC DisableRtcChecksum - %r\n", Status)); - } else { - DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.AppleRTC DisableRtcChecksum\n")); - } + Status = PatcherApplyGenericPatch (Patcher, &mAppleRtcChecksumPatch); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to apply patch com.apple.driver.AppleRTC DisableRtcChecksum - %r\n", Status)); } else { - DEBUG ((DEBUG_INFO, "OCAK: Failed to find com.apple.driver.AppleRTC for DisableRtcChecksum - %r\n", Status)); + DEBUG ((DEBUG_INFO, "OCAK: Patch success com.apple.driver.AppleRTC DisableRtcChecksum\n")); } return Status; } + +// +// Quirks table. +// +KERNEL_QUIRK gKernelQuirks[] = { + [KernelQuirkAppleCpuPmCfgLock] = { "com.apple.driver.AppleIntelCPUPowerManagement", PatchAppleCpuPmCfgLock }, + [KernelQuirkAppleXcpmCfgLock] = { NULL, PatchAppleXcpmCfgLock }, + [KernelQuirkAppleXcpmExtraMsrs] = { NULL, PatchAppleXcpmExtraMsrs }, + [KernelQuirkAppleXcpmForceBoost] = { NULL, PatchAppleXcpmForceBoost }, + [KernelQuirkCustomSmbiosGuid1] = { "com.apple.driver.AppleSMBIOS", PatchCustomSmbiosGuid }, + [KernelQuirkCustomSmbiosGuid2] = { "com.apple.driver.AppleACPIPlatform", PatchCustomSmbiosGuid }, + [KernelQuirkDisableIoMapper] = { "com.apple.iokit.IOPCIFamily", PatchAppleIoMapperSupport }, + [KernelQuirkDisableRtcChecksum] = { "com.apple.driver.AppleRTC", PatchAppleRtcChecksum }, + [KernelQuirkDummyPowerManagement] = { "com.apple.driver.AppleIntelCPUPowerManagement", PatchDummyPowerManagement }, + [KernelQuirkExternalDiskIcons] = { "com.apple.driver.AppleAHCIPort", PatchForceInternalDiskIcons }, + [KernelQuirkIncreasePciBarSize] = { "com.apple.iokit.IOPCIFamily", PatchIncreasePciBarSize }, + [KernelQuirkLapicKernelPanic] = { NULL, PatchLapicKernelPanic }, + [KernelQuirkPanicNoKextDump] = { NULL, PatchPanicKextDump }, + [KernelQuirkPowerTimeoutKernelPanic] = { NULL, PatchPowerStateTimeout }, + [KernelQuirkThirdPartyDrives] = { "com.apple.iokit.IOAHCIBlockStorage", PatchThirdPartyDriveSupport }, + [KernelQuirkXhciPortLimit1] = { "com.apple.iokit.IOUSBHostFamily", PatchUsbXhciPortLimit1 }, + [KernelQuirkXhciPortLimit2] = { "com.apple.driver.usb.AppleUSBXHCI", PatchUsbXhciPortLimit2 }, + [KernelQuirkXhciPortLimit3] = { "com.apple.driver.usb.AppleUSBXHCIPCI", PatchUsbXhciPortLimit3 }, +}; + +EFI_STATUS +KernelQuirkApply ( + IN KERNEL_QUIRK_NAME Name, + IN OUT PATCHER_CONTEXT *Patcher + ) +{ + ASSERT (Patcher != NULL); + + return gKernelQuirks[Name].PatchFunction (Patcher); +} diff --git a/Library/OcAppleKernelLib/KextPatcher.c b/Library/OcAppleKernelLib/KextPatcher.c index 4f034fa5..82d9759f 100644 --- a/Library/OcAppleKernelLib/KextPatcher.c +++ b/Library/OcAppleKernelLib/KextPatcher.c @@ -24,6 +24,7 @@ #include #include +#include "MkextInternal.h" #include "PrelinkedInternal.h" EFI_STATUS @@ -44,6 +45,23 @@ PatcherInitContextFromPrelinked ( return EFI_SUCCESS; } +EFI_STATUS +PatcherInitContextFromMkext( + IN OUT PATCHER_CONTEXT *Context, + IN OUT MKEXT_CONTEXT *Mkext, + IN CONST CHAR8 *Name + ) +{ + MKEXT_KEXT *Kext; + + Kext = InternalCachedMkextKext (Mkext, Name); + if (Kext == NULL) { + return EFI_NOT_FOUND; + } + + return PatcherInitContextFromBuffer (Context, &Mkext->Mkext[Kext->BinaryOffset], Kext->BinarySize); +} + EFI_STATUS PatcherInitContextFromBuffer ( IN OUT PATCHER_CONTEXT *Context, diff --git a/Library/OcAppleKernelLib/MkextContext.c b/Library/OcAppleKernelLib/MkextContext.c index fb6893c8..1cda5705 100644 --- a/Library/OcAppleKernelLib/MkextContext.c +++ b/Library/OcAppleKernelLib/MkextContext.c @@ -15,18 +15,16 @@ #include -#include - #include #include #include #include #include #include -#include #include #include +#include "MkextInternal.h" #include "PrelinkedInternal.h" // @@ -82,6 +80,7 @@ BOOLEAN ParseMkextV2Plist ( IN MKEXT_V2_HEADER *Mkext, OUT UINT8 **Plist, + OUT UINT32 *PlistSize, OUT XML_DOCUMENT **PlistDoc, OUT XML_NODE **PlistBundles ) @@ -169,6 +168,7 @@ ParseMkextV2Plist ( if (AsciiStrCmp (BundleArrayKey, MKEXT_INFO_DICTIONARIES_KEY) == 0) { *Plist = PlistBuffer; + *PlistSize = PlistFullSize; *PlistDoc = PlistXml; *PlistBundles = PlistBundleArray; @@ -213,16 +213,249 @@ UpdateMkextV2Plist ( return 0; } - MkextBuffer = (UINT8*)Mkext; + MkextBuffer = (UINT8 *) Mkext; CopyMem (&MkextBuffer[Offset], ExportedInfo, ExportedInfoSize); FreePool (ExportedInfo); - Mkext->PlistOffset = SwapBytes32 (Offset); - Mkext->PlistFullSize = SwapBytes32 (ExportedInfoSize); - Mkext->PlistCompressedSize = 0; + Mkext->PlistOffset = SwapBytes32 (Offset); + Mkext->PlistFullSize = SwapBytes32 (ExportedInfoSize); + Mkext->PlistCompressedSize = 0; return ExportedInfoSize; } +MKEXT_KEXT * +InternalCachedMkextKext ( + IN OUT MKEXT_CONTEXT *Context, + IN CONST CHAR8 *BundleId + ) +{ + MKEXT_HEADER_ANY *MkextHeader; + MKEXT_V2_FILE_ENTRY *MkextV2FileEntry; + + MKEXT_KEXT *MkextKext; + LIST_ENTRY *KextLink; + UINT32 Index; + UINT32 PlistOffsetSize; + UINT32 BinOffsetSize; + BOOLEAN IsKextMatch; + + UINT32 PlistOffset; + UINT32 PlistSize; + CHAR8 *PlistBuffer; + XML_DOCUMENT *PlistXml; + XML_NODE *PlistRoot; + + UINT32 PlistBundlesCount; + XML_NODE *PlistBundle; + UINT32 PlistBundleIndex; + UINT32 PlistBundleCount; + CONST CHAR8 *PlistBundleKey; + XML_NODE *PlistBundleKeyValue; + + CONST CHAR8 *KextBundleId; + UINT32 KextBinOffset; + UINT32 KextBinSize; + + MkextHeader = Context->MkextHeader; + + // + // Try to get cached kext. + // + KextLink = GetFirstNode (&Context->CachedKexts); + while (!IsNull (&Context->CachedKexts, KextLink)) { + MkextKext = GET_MKEXT_KEXT_FROM_LINK (KextLink); + + if (AsciiStrCmp (BundleId, MkextKext->BundleId) == 0) { + return MkextKext; + } + + KextLink = GetNextNode (&Context->CachedKexts, KextLink); + } + + // + // Search mkext and add kext to cache. + // + IsKextMatch = FALSE; + + // + // Mkext v1. + // + if (Context->MkextVersion == MKEXT_VERSION_V1) { + for (Index = 0; Index < Context->NumKexts; Index++) { + // + // Do not cache binaryless or compressed kexts. + // + if (MkextHeader->V1.Kexts[Index].Plist.CompressedSize != 0 + || MkextHeader->V1.Kexts[Index].Binary.CompressedSize != 0 + || MkextHeader->V1.Kexts[Index].Binary.Offset == 0) { + continue; + } + + PlistOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.Offset); + PlistSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.FullSize); + KextBinOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.Offset); + KextBinSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.FullSize); + + // + // Verify plist and binary are within bounds. + // + if (OcOverflowAddU32 (PlistOffset, PlistSize, &PlistOffsetSize) + || PlistOffsetSize > Context->MkextSize + || OcOverflowAddU32 (KextBinOffset, KextBinSize, &BinOffsetSize) + || BinOffsetSize > Context->MkextSize) { + return NULL; + } + + PlistBuffer = AllocateCopyPool (PlistSize, &Context->Mkext[PlistOffset]); + if (PlistBuffer == NULL) { + return NULL; + } + + PlistXml = XmlDocumentParse (PlistBuffer, PlistSize, FALSE); + if (PlistXml == NULL) { + FreePool (PlistBuffer); + return NULL; + } + + PlistRoot = PlistNodeCast (PlistDocumentRoot (PlistXml), PLIST_NODE_TYPE_DICT); + if (PlistRoot == NULL) { + XmlDocumentFree (PlistXml); + FreePool (PlistBuffer); + return NULL; + } + + KextBundleId = NULL; + PlistBundleCount = PlistDictChildren (PlistRoot); + for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) { + PlistBundleKey = PlistKeyValue (PlistDictChild (PlistRoot, PlistBundleIndex, &PlistBundleKeyValue)); + if (PlistBundleKey == NULL || PlistBundleKeyValue == NULL) { + continue; + } + + if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) { + KextBundleId = XmlNodeContent (PlistBundleKeyValue); + break; + } + } + + IsKextMatch = KextBundleId != NULL && AsciiStrCmp (KextBundleId, BundleId) == 0; + XmlDocumentFree (PlistXml); + FreePool (PlistBuffer); + + if (IsKextMatch && KextBinOffset > 0 && KextBinSize > 0) { + break; + } + } + + // + // Bundle was not found, or invalid. + // + if (!IsKextMatch) { + return NULL; + } + + // + // Mkext v2. + // + } else if (Context->MkextVersion == MKEXT_VERSION_V2) { + KextBundleId = NULL; + KextBinOffset = 0; + + // + // Enumerate bundle dicts. + // + PlistBundlesCount = XmlNodeChildren (Context->MkextKexts); + for (Index = 0; Index < PlistBundlesCount; Index++) { + PlistBundle = PlistNodeCast (XmlNodeChild (Context->MkextKexts, Index), PLIST_NODE_TYPE_DICT); + if (PlistBundle == NULL) { + return NULL; + } + + PlistBundleCount = PlistDictChildren (PlistBundle); + for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) { + PlistBundleKey = PlistKeyValue (PlistDictChild (PlistBundle, PlistBundleIndex, &PlistBundleKeyValue)); + if (PlistBundleKey == NULL || PlistBundleKeyValue == NULL) { + continue; + } + + if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) { + KextBundleId = XmlNodeContent (PlistBundleKeyValue); + } + + if (AsciiStrCmp (PlistBundleKey, MKEXT_EXECUTABLE_KEY) == 0) { + // + // Ensure binary offset is before plist offset. + // + if (!PlistIntegerValue (PlistBundleKeyValue, &KextBinOffset, sizeof (KextBinOffset), TRUE)) { + return NULL; + } + } + } + + if (KextBundleId != NULL + && AsciiStrCmp (KextBundleId, BundleId) == 0 + && KextBinOffset > 0 + && KextBinOffset < Context->MkextSize - sizeof (MKEXT_V2_FILE_ENTRY)) { + IsKextMatch = TRUE; + break; + } + + KextBundleId = NULL; + KextBinOffset = 0; + } + + // + // Bundle was not found, or invalid. + // + if (!IsKextMatch) { + return NULL; + } + + // + // Parse v2 binary header. + // We cannot support compressed binaries. + // + MkextV2FileEntry = (MKEXT_V2_FILE_ENTRY *) &Context->Mkext[KextBinOffset]; + if (MkextV2FileEntry->CompressedSize != 0) { + return NULL; + } + KextBinOffset += OFFSET_OF (MKEXT_V2_FILE_ENTRY, Data); + KextBinSize = SwapBytes32 (MkextV2FileEntry->FullSize); + + // + // Ensure binary is within mkext bounds. + // + if (OcOverflowAddU32 (KextBinOffset, KextBinSize, &BinOffsetSize) + || BinOffsetSize > Context->MkextSize) { + return NULL; + } + + // + // Unsupported version. + // + } else { + return NULL; + } + + MkextKext = AllocateZeroPool (sizeof (*MkextKext)); + if (MkextKext == NULL) { + return NULL; + } + + MkextKext->Signature = MKEXT_KEXT_SIGNATURE; + MkextKext->BinaryOffset = KextBinOffset; + MkextKext->BinarySize = KextBinSize; + MkextKext->BundleId = AllocateCopyPool (AsciiStrSize (BundleId), BundleId); + if (MkextKext->BundleId == NULL) { + FreePool (MkextKext); + return NULL; + } + + InsertTailList (&Context->CachedKexts, &MkextKext->Link); + + return MkextKext; +} + EFI_STATUS MkextDecompress ( IN CONST UINT8 *Buffer, @@ -296,6 +529,8 @@ MkextDecompress ( return EFI_INVALID_PARAMETER; } + MkextHeaderOut = NULL; + // // Mkext v1. // @@ -367,7 +602,7 @@ MkextDecompress ( || DecompressLZSS ( &OutBuffer[CurrentOffset], PlistFullSize, - &((UINT8*)Buffer)[PlistOffset], + &((UINT8 *) Buffer)[PlistOffset], PlistCompSize ) != PlistFullSize) { return EFI_INVALID_PARAMETER; @@ -396,7 +631,7 @@ MkextDecompress ( || DecompressLZSS ( &OutBuffer[CurrentOffset], BinFullSize, - &((UINT8*)Buffer)[BinOffset], + &((UINT8 *) Buffer)[BinOffset], BinCompSize ) != BinFullSize) { return EFI_INVALID_PARAMETER; @@ -460,7 +695,7 @@ MkextDecompress ( MkextHeaderOut = (MKEXT_HEADER_ANY *) OutBuffer; } - if (!ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistXml, &PlistBundles)) { + if (!ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistFullSize, &PlistXml, &PlistBundles)) { return EFI_INVALID_PARAMETER; } @@ -689,18 +924,14 @@ MkextContextInit ( UINT8 *PlistBuffer; XML_DOCUMENT *PlistXml; UINT32 PlistOffset; + UINT32 PlistFullSize; XML_NODE *PlistBundles; - UINT32 PlistBundlesCount; - XML_NODE *PlistBundle; - UINT32 PlistBundleIndex; - UINT32 PlistBundleCount; - CONST CHAR8 *PlistBundleKey; - XML_NODE *BundleExecutable; - UINT32 BinOffset; // // Assumptions: - // Kexts are fully decompressed and aligned to 8 bytes with plist (for v2) at end of mkext. + // Kexts are aligned to 8 bytes. + // Patching or blocking requires kexts to be decompressed. + // Plist (for v2) is at end of mkext. // Mkext is big-endian per XNU requirements. // @@ -754,9 +985,6 @@ MkextContextInit ( StartingOffset = 0; for (Index = 0; Index < NumKexts; Index++) { CurrentOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.Offset); - if (MkextHeader->V1.Kexts[Index].Plist.CompressedSize != 0) { - return EFI_UNSUPPORTED; - } if (StartingOffset == 0 || CurrentOffset < StartingOffset) { StartingOffset = CurrentOffset; } @@ -766,9 +994,6 @@ MkextContextInit ( // if (MkextHeader->V1.Kexts[Index].Binary.FullSize > 0) { CurrentOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.Offset); - if (MkextHeader->V1.Kexts[Index].Binary.CompressedSize != 0) { - return EFI_UNSUPPORTED; - } if (CurrentOffset < StartingOffset) { StartingOffset = CurrentOffset; } @@ -791,43 +1016,14 @@ MkextContextInit ( // } else if (MkextVersion == MKEXT_VERSION_V2) { if (MkextSize < sizeof (MKEXT_V2_HEADER) - || !ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistXml, &PlistBundles)) { + || !ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistFullSize, &PlistXml, &PlistBundles)) { return EFI_INVALID_PARAMETER; } PlistOffset = SwapBytes32 (MkextHeader->V2.PlistOffset); - // - // Enumerate bundle dicts. - // - PlistBundlesCount = XmlNodeChildren (PlistBundles); - for (Index = 0; Index < PlistBundlesCount; Index++) { - PlistBundle = PlistNodeCast (XmlNodeChild (PlistBundles, Index), PLIST_NODE_TYPE_DICT); - if (PlistBundle == NULL) { - XmlDocumentFree (PlistXml); - FreePool (PlistBuffer); - return EFI_INVALID_PARAMETER; - } - - PlistBundleCount = PlistDictChildren (PlistBundle); - for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) { - PlistBundleKey = PlistKeyValue (PlistDictChild (PlistBundle, PlistBundleIndex, &BundleExecutable)); - if (PlistBundleKey == NULL) { - continue; - } - - if (AsciiStrCmp (PlistBundleKey, MKEXT_EXECUTABLE_KEY) == 0) { - // - // Ensure binary offset is before plist offset. - // - if (!PlistIntegerValue (BundleExecutable, &BinOffset, sizeof (BinOffset), TRUE) - || BinOffset == 0 - || BinOffset >= PlistOffset) { - XmlDocumentFree (PlistXml); - FreePool (PlistBuffer); - return EFI_INVALID_PARAMETER; - } - } - } + if (OcOverflowAddU32 (PlistOffset, PlistFullSize, &Tmp) + || Tmp != MkextSize) { + return EFI_INVALID_PARAMETER; } // @@ -845,6 +1041,7 @@ MkextContextInit ( Context->MkextVersion = MkextVersion; Context->Is64Bit = Is64Bit; Context->NumKexts = NumKexts; + InitializeListHead (&Context->CachedKexts); if (MkextVersion == MKEXT_VERSION_V1) { Context->NumMaxKexts = NumMaxKexts; @@ -863,8 +1060,20 @@ MkextContextFree ( IN OUT MKEXT_CONTEXT *Context ) { + MKEXT_KEXT *MkextKext; + LIST_ENTRY *KextLink; + ASSERT (Context != NULL); + while (!IsListEmpty (&Context->CachedKexts)) { + KextLink = GetFirstNode (&Context->CachedKexts); + MkextKext = GET_MKEXT_KEXT_FROM_LINK (KextLink); + RemoveEntryList (KextLink); + + FreePool (MkextKext->BundleId); + FreePool (MkextKext); + } + if (Context->MkextInfoDocument != NULL) { XmlDocumentFree (Context->MkextInfoDocument); } @@ -949,6 +1158,8 @@ MkextInjectKext ( ASSERT (InfoPlist != NULL); ASSERT (InfoPlistSize > 0); + BinOffset = 0; + // // Mkext v1. // @@ -1131,6 +1342,53 @@ MkextInjectKext ( return EFI_SUCCESS; } +EFI_STATUS +MkextContextApplyPatch ( + IN OUT MKEXT_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ) +{ + EFI_STATUS Status; + PATCHER_CONTEXT Patcher; + + ASSERT (Context != NULL); + ASSERT (BundleId != NULL); + ASSERT (Patch != NULL); + + Status = PatcherInitContextFromMkext (&Patcher, Context, BundleId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to find %a - %r\n", BundleId, Status)); + return Status; + } + + return PatcherApplyGenericPatch (&Patcher, Patch); +} + +EFI_STATUS +MkextContextApplyQuirk ( + IN OUT MKEXT_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ) +{ + EFI_STATUS Status; + KERNEL_QUIRK *KernelQuirk; + PATCHER_CONTEXT Patcher; + + ASSERT (Context != NULL); + + KernelQuirk = &gKernelQuirks[Quirk]; + ASSERT (KernelQuirk->BundleId != NULL); + + Status = PatcherInitContextFromMkext (&Patcher, Context, KernelQuirk->BundleId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to find %a - %r\n", KernelQuirk->BundleId, Status)); + return Status; + } + + return KernelQuirk->PatchFunction (&Patcher); +} + EFI_STATUS MkextInjectPatchComplete ( IN OUT MKEXT_CONTEXT *Context diff --git a/Library/OcAppleKernelLib/MkextInternal.h b/Library/OcAppleKernelLib/MkextInternal.h new file mode 100644 index 00000000..1ebcd3ec --- /dev/null +++ b/Library/OcAppleKernelLib/MkextInternal.h @@ -0,0 +1,72 @@ +/** @file + Mkext support. + + Copyright (c) 2020, Goldfish64. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef MKEXT_INTERNAL_H +#define MKEXT_INTERNAL_H + +#include + +// +// Cached mkext kext. +// +typedef struct { + // + // Signature. + // + UINT32 Signature; + // + // Link for global list (MKEXT_CONTEXT -> CachedKexts). + // + LIST_ENTRY Link; + // + // Kext bundle ID. + // + CHAR8 *BundleId; + // + // Offset of binary in mkext. + // + UINT32 BinaryOffset; + // + // Size of binary in mkext. + // + UINT32 BinarySize; +} MKEXT_KEXT; + +// +// MKEXT_KEXT signature for list identification. +// +#define MKEXT_KEXT_SIGNATURE SIGNATURE_32 ('M', 'k', 'x', 'T') + +/** + Gets the next element in CachedKexts list of MKEXT_KEXT. + + @param[in] This The current ListEntry. +**/ +#define GET_MKEXT_KEXT_FROM_LINK(This) \ + (CR ( \ + (This), \ + MKEXT_KEXT, \ + Link, \ + MKEXT_KEXT_SIGNATURE \ + )) + + +MKEXT_KEXT * +InternalCachedMkextKext ( + IN OUT MKEXT_CONTEXT *Context, + IN CONST CHAR8 *BundleId + ); + +#endif // MKEXT_INTERNAL_H diff --git a/Library/OcAppleKernelLib/PrelinkedContext.c b/Library/OcAppleKernelLib/PrelinkedContext.c index 0356ee21..0d77b767 100644 --- a/Library/OcAppleKernelLib/PrelinkedContext.c +++ b/Library/OcAppleKernelLib/PrelinkedContext.c @@ -1134,3 +1134,50 @@ PrelinkedInjectKext ( return EFI_SUCCESS; } + +EFI_STATUS +PrelinkedContextApplyPatch ( + IN OUT PRELINKED_CONTEXT *Context, + IN CONST CHAR8 *BundleId, + IN PATCHER_GENERIC_PATCH *Patch + ) +{ + EFI_STATUS Status; + PATCHER_CONTEXT Patcher; + + ASSERT (Context != NULL); + ASSERT (BundleId != NULL); + ASSERT (Patch != NULL); + + Status = PatcherInitContextFromPrelinked (&Patcher, Context, BundleId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to find %a - %r\n", BundleId, Status)); + return Status; + } + + return PatcherApplyGenericPatch (&Patcher, Patch); +} + +EFI_STATUS +PrelinkedContextApplyQuirk ( + IN OUT PRELINKED_CONTEXT *Context, + IN KERNEL_QUIRK_NAME Quirk + ) +{ + EFI_STATUS Status; + KERNEL_QUIRK *KernelQuirk; + PATCHER_CONTEXT Patcher; + + ASSERT (Context != NULL); + + KernelQuirk = &gKernelQuirks[Quirk]; + ASSERT (KernelQuirk->BundleId != NULL); + + Status = PatcherInitContextFromPrelinked (&Patcher, Context, KernelQuirk->BundleId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCAK: Failed to find %a - %r\n", KernelQuirk->BundleId, Status)); + return Status; + } + + return KernelQuirk->PatchFunction (&Patcher); +} diff --git a/Library/OcAppleKernelLib/PrelinkedInternal.h b/Library/OcAppleKernelLib/PrelinkedInternal.h index 5db4ea79..11714088 100644 --- a/Library/OcAppleKernelLib/PrelinkedInternal.h +++ b/Library/OcAppleKernelLib/PrelinkedInternal.h @@ -32,6 +32,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // #define KEXT_OFFSET_STR_LEN 24 +// +// Kernel quirks array. +// +extern KERNEL_QUIRK gKernelQuirks[]; + typedef struct PRELINKED_KEXT_ PRELINKED_KEXT; typedef struct { diff --git a/Platform/OpenCore/OpenCoreKernel.c b/Platform/OpenCore/OpenCoreKernel.c index 3b40bc9c..a89a4b58 100644 --- a/Platform/OpenCore/OpenCoreKernel.c +++ b/Platform/OpenCore/OpenCoreKernel.c @@ -221,18 +221,48 @@ OcKernelLoadKextsAndReserve ( return EFI_SUCCESS; } +STATIC +EFI_STATUS +OcKernelApplyQuirk ( + IN KERNEL_QUIRK_NAME Quirk, + IN KERNEL_CACHE_TYPE CacheType, + IN OUT VOID *Context, + IN OUT PATCHER_CONTEXT *KernelPatcher + ) +{ + // + // Apply kernel quirks to kernel, kext patches to context. + // + if (Context == NULL) { + ASSERT (KernelPatcher != NULL); + + return KernelQuirkApply (Quirk, KernelPatcher); + } else { + if (CacheType == CacheTypeCacheless) { + return CachelessContextAddQuirk ((CACHELESS_CONTEXT *) Context, Quirk); + } else if (CacheType == CacheTypeMkext) { + return MkextContextApplyQuirk ((MKEXT_CONTEXT *) Context, Quirk); + } else if (CacheType == CacheTypePrelinked) { + return PrelinkedContextApplyQuirk ((PRELINKED_CONTEXT *) Context, Quirk); + } + } + + return EFI_UNSUPPORTED; +} + STATIC VOID OcKernelApplyPatches ( IN OC_GLOBAL_CONFIG *Config, IN UINT32 DarwinVersion, - IN PRELINKED_CONTEXT *Context, + IN KERNEL_CACHE_TYPE CacheType, + IN VOID *Context, IN OUT UINT8 *Kernel, IN UINT32 Size ) { EFI_STATUS Status; - PATCHER_CONTEXT Patcher; + PATCHER_CONTEXT KernelPatcher; UINT32 Index; PATCHER_GENERIC_PATCH Patch; OC_KERNEL_PATCH_ENTRY *UserPatch; @@ -248,7 +278,7 @@ OcKernelApplyPatches ( ASSERT (Kernel != NULL); Status = PatcherInitContextFromBuffer ( - &Patcher, + &KernelPatcher, Kernel, Size ); @@ -285,21 +315,6 @@ OcKernelApplyPatches ( continue; } - if (!IsKernelPatch) { - Status = PatcherInitContextFromPrelinked ( - &Patcher, - Context, - Target - ); - - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "OC: Kernel patcher %a (%a) init failure - %r\n", Target, Comment, Status)); - continue; - } else { - DEBUG ((DEBUG_INFO, "OC: Kernel patcher %a (%a) init succeed\n", Target, Comment)); - } - } - // // Ignore patch if: // - There is nothing to replace. @@ -344,7 +359,18 @@ OcKernelApplyPatches ( Patch.Skip = UserPatch->Skip; Patch.Limit = UserPatch->Limit; - Status = PatcherApplyGenericPatch (&Patcher, &Patch); + if (IsKernelPatch) { + Status = PatcherApplyGenericPatch (&KernelPatcher, &Patch); + } else { + if (CacheType == CacheTypeCacheless) { + Status = CachelessContextAddPatch ((CACHELESS_CONTEXT *) Context, Target, &Patch); + } else if (CacheType == CacheTypeMkext) { + Status = MkextContextApplyPatch ((MKEXT_CONTEXT *) Context, Target, &Patch); + } else if (CacheType == CacheTypePrelinked) { + Status = PrelinkedContextApplyPatch ((PRELINKED_CONTEXT *) Context, Target, &Patch); + } + } + DEBUG (( EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO, "OC: Kernel patcher result %u for %a (%a) - %r\n", @@ -357,55 +383,58 @@ OcKernelApplyPatches ( if (!IsKernelPatch) { if (Config->Kernel.Quirks.AppleCpuPmCfgLock) { - PatchAppleCpuPmCfgLock (Context); + OcKernelApplyQuirk (KernelQuirkAppleCpuPmCfgLock, CacheType, Context, NULL); } if (Config->Kernel.Quirks.ExternalDiskIcons) { - PatchForceInternalDiskIcons (Context); + OcKernelApplyQuirk (KernelQuirkExternalDiskIcons, CacheType, Context, NULL); } if (Config->Kernel.Quirks.ThirdPartyDrives) { - PatchThirdPartyDriveSupport (Context); + OcKernelApplyQuirk (KernelQuirkThirdPartyDrives, CacheType, Context, NULL); } if (Config->Kernel.Quirks.XhciPortLimit) { - PatchUsbXhciPortLimit (Context); + OcKernelApplyQuirk (KernelQuirkXhciPortLimit1, CacheType, Context, NULL); + OcKernelApplyQuirk (KernelQuirkXhciPortLimit2, CacheType, Context, NULL); + OcKernelApplyQuirk (KernelQuirkXhciPortLimit3, CacheType, Context, NULL); } if (Config->Kernel.Quirks.DisableIoMapper) { - PatchAppleIoMapperSupport (Context); + OcKernelApplyQuirk (KernelQuirkDisableIoMapper, CacheType, Context, NULL); } if (Config->Kernel.Quirks.DisableRtcChecksum) { - PatchAppleRtcChecksum (Context); + OcKernelApplyQuirk (KernelQuirkDisableRtcChecksum, CacheType, Context, NULL); } if (Config->Kernel.Quirks.IncreasePciBarSize) { - PatchIncreasePciBarSize (Context); + OcKernelApplyQuirk (KernelQuirkIncreasePciBarSize, CacheType, Context, NULL); } if (Config->Kernel.Quirks.CustomSmbiosGuid) { - PatchCustomSmbiosGuid (Context); + OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid1, CacheType, Context, NULL); + OcKernelApplyQuirk (KernelQuirkCustomSmbiosGuid2, CacheType, Context, NULL); } if (Config->Kernel.Quirks.DummyPowerManagement) { - PatchDummyPowerManagement (Context); + OcKernelApplyQuirk (KernelQuirkDummyPowerManagement, CacheType, Context, NULL); } } else { if (Config->Kernel.Quirks.AppleXcpmCfgLock) { - PatchAppleXcpmCfgLock (&Patcher); + OcKernelApplyQuirk (KernelQuirkAppleXcpmCfgLock, CacheType, NULL, &KernelPatcher); } if (Config->Kernel.Quirks.AppleXcpmExtraMsrs) { - PatchAppleXcpmExtraMsrs (&Patcher); + OcKernelApplyQuirk (KernelQuirkAppleXcpmExtraMsrs, CacheType, NULL, &KernelPatcher); } if (Config->Kernel.Quirks.AppleXcpmForceBoost) { - PatchAppleXcpmForceBoost (&Patcher); + OcKernelApplyQuirk (KernelQuirkAppleXcpmForceBoost, CacheType, NULL, &KernelPatcher); } if (Config->Kernel.Quirks.PanicNoKextDump) { - PatchPanicKextDump (&Patcher); + OcKernelApplyQuirk (KernelQuirkPanicNoKextDump, CacheType, NULL, &KernelPatcher); } if (Config->Kernel.Emulate.Cpuid1Data[0] != 0 @@ -413,7 +442,7 @@ OcKernelApplyPatches ( || Config->Kernel.Emulate.Cpuid1Data[2] != 0 || Config->Kernel.Emulate.Cpuid1Data[3] != 0) { PatchKernelCpuId ( - &Patcher, + &KernelPatcher, mOcCpuInfo, Config->Kernel.Emulate.Cpuid1Data, Config->Kernel.Emulate.Cpuid1Mask @@ -421,11 +450,11 @@ OcKernelApplyPatches ( } if (Config->Kernel.Quirks.LapicKernelPanic) { - PatchLapicKernelPanic (&Patcher); + OcKernelApplyQuirk (KernelQuirkLapicKernelPanic, CacheType, NULL, &KernelPatcher); } if (Config->Kernel.Quirks.PowerTimeoutKernelPanic) { - PatchPowerStateTimeout (&Patcher); + OcKernelApplyQuirk (KernelQuirkPowerTimeoutKernelPanic, CacheType, NULL, &KernelPatcher); } } } @@ -522,7 +551,7 @@ OcKernelProcessPrelinked ( Status = PrelinkedContextInit (&Context, Kernel, *KernelSize, AllocatedSize); if (!EFI_ERROR (Status)) { - OcKernelApplyPatches (Config, DarwinVersion, &Context, NULL, 0); + OcKernelApplyPatches (Config, DarwinVersion, CacheTypePrelinked, &Context, NULL, 0); OcKernelBlockKexts (Config, DarwinVersion, &Context); @@ -640,6 +669,8 @@ OcKernelProcessMkext ( return Status; } + OcKernelApplyPatches (Config, DarwinVersion, CacheTypeMkext, &Context, NULL, 0); + for (Index = 0; Index < Config->Kernel.Add.Count; ++Index) { Kext = Config->Kernel.Add.Values[Index]; @@ -768,6 +799,11 @@ OcKernelInitCacheless ( } } + // + // Process patches and blocks. + // + OcKernelApplyPatches (Config, DarwinVersion, CacheTypeCacheless, Context, NULL, 0); + return CachelessContextOverlayExtensionsDir (Context, File); } @@ -884,7 +920,7 @@ OcKernelFileOpen ( if (!EFI_ERROR (Status)) { mOcDarwinVersion = OcKernelReadDarwinVersion (Kernel, KernelSize); - OcKernelApplyPatches (mOcConfiguration, mOcDarwinVersion, NULL, Kernel, KernelSize); + OcKernelApplyPatches (mOcConfiguration, mOcDarwinVersion, 0, NULL, Kernel, KernelSize); PrelinkedStatus = OcKernelProcessPrelinked ( mOcConfiguration, diff --git a/Utilities/TestKextInject/Makefile b/Utilities/TestKextInject/Makefile index b3452fef..e5e5a7b3 100644 --- a/Utilities/TestKextInject/Makefile +++ b/Utilities/TestKextInject/Makefile @@ -12,15 +12,29 @@ OBJS = $(PROJECT).o \ KxldState.o \ PrelinkedKext.o \ PrelinkedContext.o \ + MkextContext.o \ + MkextReader.o \ Vtables.o \ Link.o \ KernelReader.o \ KernelCollection.o \ DataPatcher.o \ lzss.o \ - lzvn.o + lzvn.o \ + adler32.o \ + compress.o \ + crc32.o \ + deflate.o \ + infback.o \ + inffast.o \ + inflate.o \ + inftrees.o \ + trees.o \ + uncompr.o \ + zlib_uefi.o VPATH = ../../Library/OcAppleKernelLib:$\ ../../Library/OcMiscLib:$\ ../../Library/OcCompressionLib/lzss:$\ - ../../Library/OcCompressionLib/lzvn + ../../Library/OcCompressionLib/lzvn:$\ + ../../Library/OcCompressionLib/zlib include ../../User/Makefile