19#include <Library/BaseLib.h>
20#include <Library/BaseMemoryLib.h>
21#include <Library/DebugLib.h>
42 UINT64 VirtualAddress;
49 if (ExecutableContext->Is32Bit) {
51 if (Segment32 == NULL) {
55 if (AsciiStrCmp (Segment32->
SegmentName,
"") == 0) {
61 if (Section32 == NULL) {
65 VirtualAddress = Section32->
Address;
66 FileOffset = Section32->
Offset;
92 *Address = VirtualAddress;
109 return EFI_NOT_FOUND;
127 return EFI_NOT_FOUND;
137 IN UINT32 BufferSize,
144 UINT64 VirtualAddress;
161 "OCAK: %a-bit patcher init from buffer %p %u has unsupported mach-o\n",
162 Is32Bit ?
"32" :
"64",
166 return EFI_INVALID_PARAMETER;
170 return EFI_NOT_FOUND;
173 Context->Is32Bit = Is32Bit;
174 Context->VirtualBase = VirtualAddress;
175 Context->FileOffset = FileOffset;
176 Context->VirtualKmod = 0;
177 Context->KxldState = NULL;
178 Context->KxldStateSize = 0;
179 Context->IsKernelCollection = FALSE;
182 &Context->MachContext,
185 &Context->VirtualKmod
188 if (!Context->Is32Bit) {
190 &Context->MachContext,
196 if (EFI_ERROR (Status)) {
203 "OCAK: %a-bit patcher base 0x%llX kmod 0x%llX file 0x%llX\n",
204 Is32Bit ?
"32" :
"64",
205 Context->VirtualBase,
206 Context->VirtualKmod,
216 IN CONST CHAR8 *Name,
217 IN OUT UINT8 **Address
226 IN CONST CHAR8 *Name,
236 IN CONST CHAR8 *Name,
237 IN OUT UINT8 **Address,
242 CONST CHAR8 *SymbolName;
243 UINT64 SymbolAddress;
254 if (Symbol == NULL) {
258 if ((Index == 0) && (Context->KxldState != NULL)) {
262 Context->KxldStateSize,
276 return EFI_NOT_FOUND;
280 if ((SymbolName != NULL) && (AsciiStrCmp (Name, SymbolName) == 0)) {
292 return EFI_INVALID_PARAMETER;
298 if (Address != NULL) {
303 *Value = SymbolAddress;
322 if (Patch->Base != NULL) {
324 if (EFI_ERROR (Status)) {
327 "OCAK: %a-bit %a base lookup failure %r\n",
328 Context->Is32Bit ?
"32" :
"64",
329 Patch->Comment != NULL ? Patch->Comment :
"Patch",
338 if (Patch->Find == NULL) {
342 "OCAK: %a-bit %a is borked, not found\n",
343 Context->Is32Bit ?
"32" :
"64",
344 Patch->Comment != NULL ? Patch->Comment :
"Patch"
346 return EFI_NOT_FOUND;
349 CopyMem (Base, Patch->Replace, Patch->Size);
353 if ((Patch->Limit > 0) && (Patch->Limit <
Size)) {
371 "OCAK: %a-bit %a replace count - %u\n",
372 Context->Is32Bit ?
"32" :
"64",
373 Patch->Comment != NULL ? Patch->Comment :
"Patch",
377 if ((ReplaceCount > 0) && (Patch->Count > 0) && (ReplaceCount != Patch->Count)) {
380 "OCAK: %a-bit %a performed only %u replacements out of %u\n",
381 Context->Is32Bit ?
"32" :
"64",
382 Patch->Comment != NULL ? Patch->Comment :
"Patch",
388 if (ReplaceCount > 0) {
392 return EFI_NOT_FOUND;
397 IN CONST CHAR8 *Identifier,
405 UINT64 VirtualAddress;
414 UINT32 KextPlistCount;
415 CONST CHAR8 *KextPlistKey;
417 CONST CHAR8 *KextIdentifier;
420 ASSERT (Identifier != NULL);
421 ASSERT (PatcherContext != NULL);
422 ASSERT (PrelinkedContext != NULL);
431 if ((AddressMax != 0) && (AddressMax != VirtualAddress)) {
436 AddressMax =
MAX (VirtualAddress +
Size, AddressMax);
439 MaxSize = AddressMax - PatcherContext->VirtualBase;
444 if (PatcherContext->Is32Bit) {
445 if (!
GetTextBaseOffset (&PatcherContext->MachContext, &VirtualAddress, &FileOffset)) {
446 return EFI_UNSUPPORTED;
449 VirtualAddress += FileOffset;
451 VirtualAddress = PatcherContext->VirtualBase;
458 &PatcherContext->MachContext,
462 if (KextData == NULL) {
463 return EFI_UNSUPPORTED;
468 "OCAK: Excluding %a - VirtualBase %Lx, MaxSize %Lx\n",
470 PatcherContext->VirtualBase,
473 ZeroMem (KextData, (UINTN)MaxSize);
481 KextIdentifier = NULL;
483 for (Index = 0; Index < KextCount; ++Index) {
485 if (KextPlist == NULL) {
490 for (Index2 = 0; Index2 < KextPlistCount; ++Index2) {
492 if (KextPlistKey == NULL) {
501 "OCAK: Plist value cannot be interpreted as string, or current kext identifier is null (dict index %u, plist %p, plist index %u)\n",
506 return EFI_NOT_FOUND;
509 if (AsciiStrCmp (KextIdentifier, Identifier) == 0) {
514 if (EFI_ERROR (Status)) {
517 "OCAK: Failed to drop %a under dict index %u, plist %p, plist index %u - %r\n",
529 "OCAK: Erasing %a from prelinked kext under dict index %u, plist %p, plist index %u\n",
542 return EFI_NOT_FOUND;
548 IN CONST CHAR8 *Identifier
554 CONST CHAR8 *KextIdentifier;
557 UINT32 PlistBundlesCount;
559 UINT32 PlistBundleIndex;
560 UINT32 PlistBundleCount;
561 CONST CHAR8 *PlistBundleKey;
570 ASSERT (MkextContext != NULL);
571 ASSERT (Identifier != NULL);
573 MkextHeader = MkextContext->MkextHeader;
581 if (EFI_ERROR (Status)) {
587 "OCAK: Excluding mkext v1 %a - plist %x (%x), binary %x (%x)\n",
599 ZeroMem (&MkextContext->Mkext[PlistOffset], PlistSize);
600 ZeroMem (&MkextContext->Mkext[BinOffset], BinSize);
611 for (Index = 0; Index < PlistBundlesCount; Index++) {
613 if (PlistBundle == NULL) {
618 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
620 if ((PlistBundleKey == NULL) || (PlistBundleKeyValue == NULL)) {
629 "OCAK: Plist value cannot be interpreted as string, or current kext identifier is null (dict index %u, plist %p, plist index %u)\n",
634 return EFI_NOT_FOUND;
639 if (!
PlistIntegerValue (PlistBundleKeyValue, &BinOffset,
sizeof (BinOffset), TRUE)) {
642 "OCAK: Plist value cannot be interpreted as integer (dict index %u, plist %p, plist index %u)\n",
647 return EFI_NOT_FOUND;
652 if ( (KextIdentifier != NULL)
653 && (AsciiStrCmp (KextIdentifier, Identifier) == 0)
661 KextIdentifier = NULL;
669 return EFI_NOT_FOUND;
678 return EFI_UNSUPPORTED;
681 BinSize = SwapBytes32 (MkextV2FileEntry->
FullSize);
685 "OCAK: Excluding mkext v2 %a - dict index %u, plist %p, plist index %u, binary %x (%x)\n",
705 return EFI_UNSUPPORTED;
727 if ((Context->VirtualKmod == 0) || (Context->VirtualBase > Context->VirtualKmod)) {
728 return EFI_UNSUPPORTED;
737 KmodOffset = Context->VirtualKmod - Context->VirtualBase;
738 if ( BaseOverflowAddU64 (KmodOffset, Context->FileOffset, &KmodOffset)
740 || (TmpOffset > MachSize))
742 return EFI_INVALID_PARAMETER;
745 KmodInfo = MachBase + KmodOffset;
746 if (Context->Is32Bit) {
750 if (Context->IsKernelCollection) {
755 if ((StartAddr == 0) || (Context->VirtualBase > StartAddr)) {
756 return EFI_INVALID_PARAMETER;
759 TmpOffset = StartAddr - Context->VirtualBase;
760 if ( BaseOverflowAddU64 (TmpOffset, Context->FileOffset, &TmpOffset)
761 || (TmpOffset > MachSize - 6))
763 return EFI_BUFFER_TOO_SMALL;
768 "OCAK: %a-bit blocker start @ 0x%llX\n",
769 Context->Is32Bit ?
"32" :
"64",
773 PatchAddr = MachBase + TmpOffset;
792 IN UINT64 LoadAddress,
799 CONST CHAR8 *SymbolName;
804 Is32Bit = ExecutableContext->Is32Bit;
809 if (Symbol == NULL) {
816 if (SymbolName && (AsciiStrCmp (SymbolName,
"_kmod_info") == 0)) {
834 || (Is32Bit && (Address > MAX_UINT32)))
#define KMOD_RETURN_FAILURE
EFI_STATUS PatcherGetSymbolValue(IN OUT PATCHER_CONTEXT *Context, IN CONST CHAR8 *Name, IN OUT UINT64 *Value)
EFI_STATUS PatcherBlockKext(IN OUT PATCHER_CONTEXT *Context)
EFI_STATUS PatcherGetSymbolAddressValue(IN OUT PATCHER_CONTEXT *Context, IN CONST CHAR8 *Name, IN OUT UINT8 **Address, IN OUT UINT64 *Value)
EFI_STATUS PatcherInitContextFromMkext(IN OUT PATCHER_CONTEXT *Context, IN OUT MKEXT_CONTEXT *Mkext, IN CONST CHAR8 *Name)
EFI_STATUS PatcherExcludePrelinkedKext(IN CONST CHAR8 *Identifier, IN OUT PATCHER_CONTEXT *PatcherContext, IN OUT PRELINKED_CONTEXT *PrelinkedContext)
EFI_STATUS PatcherInitContextFromBuffer(IN OUT PATCHER_CONTEXT *Context, IN OUT UINT8 *Buffer, IN UINT32 BufferSize, IN BOOLEAN Is32Bit)
EFI_STATUS PatcherExcludeMkextKext(IN OUT MKEXT_CONTEXT *MkextContext, IN CONST CHAR8 *Identifier)
STATIC BOOLEAN GetTextBaseOffset(IN OC_MACHO_CONTEXT *ExecutableContext, OUT UINT64 *Address, OUT UINT64 *Offset)
EFI_STATUS PatcherGetSymbolAddress(IN OUT PATCHER_CONTEXT *Context, IN CONST CHAR8 *Name, IN OUT UINT8 **Address)
EFI_STATUS PatcherApplyGenericPatch(IN OUT PATCHER_CONTEXT *Context, IN PATCHER_GENERIC_PATCH *Patch)
EFI_STATUS PatcherInitContextFromPrelinked(IN OUT PATCHER_CONTEXT *Context, IN OUT PRELINKED_CONTEXT *Prelinked, IN CONST CHAR8 *Name)
BOOLEAN KextFindKmodAddress(IN OC_MACHO_CONTEXT *ExecutableContext, IN UINT64 LoadAddress, IN UINT32 Size, OUT UINT64 *Kmod)
UINT64 InternalKxldSolveSymbol(IN BOOLEAN Is32Bit, IN CONST VOID *KxldState, IN UINT32 KxldStateSize, IN CONST CHAR8 *Name)
MKEXT_KEXT * InternalCachedMkextKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier)
VOID InternalDropCachedMkextKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier)
EFI_STATUS InternalGetMkextV1KextOffsets(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier, OUT UINT32 *KextIndex, OUT UINT32 *KextPlistOffset, OUT UINT32 *KextPlistSize, OUT UINT32 *KextBinOffset, OUT UINT32 *KextBinSize)
DMG_SIZE_DEVICE_PATH Size
#define MKEXT_EXECUTABLE_KEY
UINT64 KcFixupValue(IN UINT64 Value, IN CONST CHAR8 *Name OPTIONAL)
#define INFO_BUNDLE_IDENTIFIER_KEY
UINT32 MachoGetInnerSize(IN OUT OC_MACHO_CONTEXT *Context)
MACH_SECTION * MachoGetSectionByName32(IN OUT OC_MACHO_CONTEXT *Context, IN MACH_SEGMENT_COMMAND *Segment, IN CONST CHAR8 *SectionName)
MACH_SEGMENT_COMMAND * MachoGetSegmentByName32(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SegmentName)
VOID * MachoGetFileData(IN OUT OC_MACHO_CONTEXT *Context)
VOID * MachoGetFilePointerByAddress(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT UINT32 *MaxSize OPTIONAL)
MACH_SEGMENT_COMMAND_ANY * MachoGetNextSegment(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_SEGMENT_COMMAND_ANY *Segment OPTIONAL)
MACH_SEGMENT_COMMAND * MachoGetNextSegment32(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_SEGMENT_COMMAND *Segment OPTIONAL)
MACH_HEADER_ANY * MachoGetMachHeader(IN OUT OC_MACHO_CONTEXT *Context)
BOOLEAN MachoInitializeContext(OUT OC_MACHO_CONTEXT *Context, IN VOID *FileData, IN UINT32 FileSize, IN UINT32 HeaderOffset, IN UINT32 InnerSize, IN BOOLEAN Is32Bit)
MACH_NLIST_ANY * MachoGetSymbolByIndex(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
BOOLEAN MachoIsSymbolValueInRange(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
CONST CHAR8 * MachoGetSymbolName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
BOOLEAN MachoSymbolGetDirectFileOffset(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT UINT32 *FileOffset, OUT UINT32 *MaxSize OPTIONAL)
MACH_SEGMENT_COMMAND_64 * MachoGetSegmentByName64(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SegmentName)
BOOLEAN MachoSymbolGetFileOffset(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol, OUT UINT32 *FileOffset, OUT UINT32 *MaxSize OPTIONAL)
UINT32 ApplyPatch(IN CONST UINT8 *Pattern, IN CONST UINT8 *PatternMask OPTIONAL, IN CONST UINT32 PatternSize, IN CONST UINT8 *Replace, IN CONST UINT8 *ReplaceMask OPTIONAL, IN UINT8 *Data, IN UINT32 DataSize, IN UINT32 Count, IN UINT32 Skip)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
CONST CHAR8 * PlistKeyValue(IN XML_NODE *Node OPTIONAL)
UINT32 XmlNodeChildren(IN CONST XML_NODE *Node)
VOID XmlNodeRemoveByIndex(IN OUT XML_NODE *Node, IN UINT32 Index)
CONST CHAR8 * XmlNodeContent(IN CONST XML_NODE *Node)
UINT32 PlistDictChildren(IN CONST XML_NODE *Node)
BOOLEAN PlistIntegerValue(IN XML_NODE *Node OPTIONAL, OUT VOID *Value, IN UINT32 Size, IN BOOLEAN Hex)
XML_NODE * PlistNodeCast(IN XML_NODE *Node OPTIONAL, IN PLIST_NODE_TYPE Type)
XML_NODE * XmlNodeChild(IN CONST XML_NODE *Node, IN UINT32 Child)
XML_NODE * PlistDictChild(IN CONST XML_NODE *Node, IN UINT32 Child, OUT XML_NODE **Value OPTIONAL)
EFI_STATUS InternalConnectExternalSymtab(IN OUT OC_MACHO_CONTEXT *Context, OUT OC_MACHO_CONTEXT *InnerContext, IN UINT8 *Buffer, IN UINT32 BufferSize, OUT BOOLEAN *KernelCollection OPTIONAL)
PRELINKED_KEXT * InternalCachedPrelinkedKext(IN OUT PRELINKED_CONTEXT *Prelinked, IN CONST CHAR8 *Identifier)
EFI_STATUS InternalDropCachedPrelinkedKext(IN OUT PRELINKED_CONTEXT *Prelinked, IN CONST CHAR8 *Identifier)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 Value
value of this symbol (or stab offset)
UINT8 Type
type flag, see below
UINT8 Type
type flag, see below
UINT32 Value
value of this symbol (or stab offset)
UINT32 Address
memory address of this section
UINT32 Offset
file offset of this section
UINT64 FileOffset
file offset of this segment
UINT64 Size
memory size of this segment
UINT64 VirtualAddress
memory address of this segment
UINT32 FileOffset
file offset of this segment
UINT32 Size
memory size of this segment
UINT32 VirtualAddress
memory address of this segment
MACH_LOAD_COMMAND_HDR_ CHAR8 SegmentName[16]
segment Name
MACH_SEGMENT_COMMAND_64 Segment64
MACH_SEGMENT_COMMAND Segment32