OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
KextPatcher.c
Go to the documentation of this file.
1
15#include <Base.h>
16
18
19#include <Library/BaseLib.h>
20#include <Library/BaseMemoryLib.h>
21#include <Library/DebugLib.h>
23#include <Library/OcMachoLib.h>
24#include <Library/OcMiscLib.h>
25#include <Library/OcXmlLib.h>
26
27#include "MkextInternal.h"
28#include "PrelinkedInternal.h"
29
30STATIC
31BOOLEAN
33 IN OC_MACHO_CONTEXT *ExecutableContext,
34 OUT UINT64 *Address,
35 OUT UINT64 *Offset
36 )
37{
38 MACH_SEGMENT_COMMAND *Segment32;
39 MACH_SECTION *Section32;
40 MACH_SEGMENT_COMMAND_64 *Segment64;
41
42 UINT64 VirtualAddress;
43 UINT64 FileOffset;
44
45 //
46 // 32-bit can be of type MH_OBJECT, which has all sections in a single unnamed segment.
47 // We'll fallback to that if there is no __TEXT segment.
48 //
49 if (ExecutableContext->Is32Bit) {
50 Segment32 = MachoGetNextSegment32 (ExecutableContext, NULL);
51 if (Segment32 == NULL) {
52 return FALSE;
53 }
54
55 if (AsciiStrCmp (Segment32->SegmentName, "") == 0) {
56 Section32 = MachoGetSectionByName32 (
57 ExecutableContext,
58 Segment32,
59 "__text"
60 );
61 if (Section32 == NULL) {
62 return FALSE;
63 }
64
65 VirtualAddress = Section32->Address;
66 FileOffset = Section32->Offset;
67 } else {
68 Segment32 = MachoGetSegmentByName32 (
69 ExecutableContext,
70 "__TEXT"
71 );
72 if ((Segment32 == NULL) || (Segment32->VirtualAddress < Segment32->FileOffset)) {
73 return FALSE;
74 }
75
76 VirtualAddress = Segment32->VirtualAddress;
77 FileOffset = Segment32->FileOffset;
78 }
79 } else {
80 Segment64 = MachoGetSegmentByName64 (
81 ExecutableContext,
82 "__TEXT"
83 );
84 if ((Segment64 == NULL) || (Segment64->VirtualAddress < Segment64->FileOffset)) {
85 return FALSE;
86 }
87
88 VirtualAddress = Segment64->VirtualAddress;
89 FileOffset = Segment64->FileOffset;
90 }
91
92 *Address = VirtualAddress;
93 *Offset = FileOffset;
94
95 return TRUE;
96}
97
98EFI_STATUS
100 IN OUT PATCHER_CONTEXT *Context,
101 IN OUT PRELINKED_CONTEXT *Prelinked,
102 IN CONST CHAR8 *Name
103 )
104{
105 PRELINKED_KEXT *Kext;
106
107 Kext = InternalCachedPrelinkedKext (Prelinked, Name);
108 if (Kext == NULL) {
109 return EFI_NOT_FOUND;
110 }
111
112 CopyMem (Context, &Kext->Context, sizeof (*Context));
113 return EFI_SUCCESS;
114}
115
116EFI_STATUS
118 IN OUT PATCHER_CONTEXT *Context,
119 IN OUT MKEXT_CONTEXT *Mkext,
120 IN CONST CHAR8 *Name
121 )
122{
123 MKEXT_KEXT *Kext;
124
125 Kext = InternalCachedMkextKext (Mkext, Name);
126 if (Kext == NULL) {
127 return EFI_NOT_FOUND;
128 }
129
130 return PatcherInitContextFromBuffer (Context, &Mkext->Mkext[Kext->BinaryOffset], Kext->BinarySize, Mkext->Is32Bit);
131}
132
133EFI_STATUS
135 IN OUT PATCHER_CONTEXT *Context,
136 IN OUT UINT8 *Buffer,
137 IN UINT32 BufferSize,
138 IN BOOLEAN Is32Bit
139 )
140{
141 EFI_STATUS Status;
142 OC_MACHO_CONTEXT InnerContext;
143
144 UINT64 VirtualAddress;
145 UINT64 FileOffset;
146
147 ASSERT (Context != NULL);
148 ASSERT (Buffer != NULL);
149 ASSERT (BufferSize > 0);
150
151 //
152 // This interface is still used for the kernel due to the need to patch
153 // standalone kernel outside of prelinkedkernel in e.g. 10.9.
154 // Once 10.9 support is dropped one could call PatcherInitContextFromPrelinked
155 // and request PRELINK_KERNEL_IDENTIFIER.
156 //
157
158 if (!MachoInitializeContext (&Context->MachContext, Buffer, BufferSize, 0, BufferSize, Is32Bit)) {
159 DEBUG ((
160 DEBUG_INFO,
161 "OCAK: %a-bit patcher init from buffer %p %u has unsupported mach-o\n",
162 Is32Bit ? "32" : "64",
163 Buffer,
164 BufferSize
165 ));
166 return EFI_INVALID_PARAMETER;
167 }
168
169 if (!GetTextBaseOffset (&Context->MachContext, &VirtualAddress, &FileOffset)) {
170 return EFI_NOT_FOUND;
171 }
172
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;
180
182 &Context->MachContext,
183 0,
184 BufferSize,
185 &Context->VirtualKmod
186 );
187
188 if (!Context->Is32Bit) {
190 &Context->MachContext,
191 &InnerContext,
192 Buffer,
193 BufferSize,
194 NULL
195 );
196 if (EFI_ERROR (Status)) {
197 return Status;
198 }
199 }
200
201 DEBUG ((
202 DEBUG_VERBOSE,
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,
207 Context->FileOffset
208 ));
209
210 return EFI_SUCCESS;
211}
212
213EFI_STATUS
215 IN OUT PATCHER_CONTEXT *Context,
216 IN CONST CHAR8 *Name,
217 IN OUT UINT8 **Address
218 )
219{
220 return PatcherGetSymbolAddressValue (Context, Name, Address, NULL);
221}
222
223EFI_STATUS
225 IN OUT PATCHER_CONTEXT *Context,
226 IN CONST CHAR8 *Name,
227 IN OUT UINT64 *Value
228 )
229{
230 return PatcherGetSymbolAddressValue (Context, Name, NULL, Value);
231}
232
233EFI_STATUS
235 IN OUT PATCHER_CONTEXT *Context,
236 IN CONST CHAR8 *Name,
237 IN OUT UINT8 **Address,
238 IN OUT UINT64 *Value
239 )
240{
241 MACH_NLIST_ANY *Symbol;
242 CONST CHAR8 *SymbolName;
243 UINT64 SymbolAddress;
244 UINT32 Offset;
245 UINT32 Index;
246
247 Index = 0;
248 Offset = 0;
249 while (TRUE) {
250 //
251 // Try the usual way first via SYMTAB.
252 //
253 Symbol = MachoGetSymbolByIndex (&Context->MachContext, Index);
254 if (Symbol == NULL) {
255 //
256 // If we have KxldState, use it.
257 //
258 if ((Index == 0) && (Context->KxldState != NULL)) {
259 SymbolAddress = InternalKxldSolveSymbol (
260 Context->Is32Bit,
261 Context->KxldState,
262 Context->KxldStateSize,
263 Name
264 );
265 //
266 // If we have a symbol, get its ondisk offset.
267 //
268 if ((SymbolAddress != 0) && MachoSymbolGetDirectFileOffset (&Context->MachContext, SymbolAddress, &Offset, NULL)) {
269 //
270 // Proceed to success.
271 //
272 break;
273 }
274 }
275
276 return EFI_NOT_FOUND;
277 }
278
279 SymbolName = MachoGetSymbolName (&Context->MachContext, Symbol);
280 if ((SymbolName != NULL) && (AsciiStrCmp (Name, SymbolName) == 0)) {
281 //
282 // Once we have a symbol, get its ondisk offset.
283 //
284 if (MachoSymbolGetFileOffset (&Context->MachContext, Symbol, &Offset, NULL)) {
285 //
286 // Proceed to success.
287 //
288 SymbolAddress = Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value;
289 break;
290 }
291
292 return EFI_INVALID_PARAMETER;
293 }
294
295 Index++;
296 }
297
298 if (Address != NULL) {
299 *Address = (UINT8 *)MachoGetFileData (&Context->MachContext) + Offset;
300 }
301
302 if (Value != NULL) {
303 *Value = SymbolAddress;
304 }
305
306 return EFI_SUCCESS;
307}
308
309EFI_STATUS
311 IN OUT PATCHER_CONTEXT *Context,
312 IN PATCHER_GENERIC_PATCH *Patch
313 )
314{
315 EFI_STATUS Status;
316 UINT8 *Base;
317 UINT32 Size;
318 UINT32 ReplaceCount;
319
320 Base = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
321 Size = MachoGetInnerSize (&Context->MachContext);
322 if (Patch->Base != NULL) {
323 Status = PatcherGetSymbolAddress (Context, Patch->Base, &Base);
324 if (EFI_ERROR (Status)) {
325 DEBUG ((
326 DEBUG_INFO,
327 "OCAK: %a-bit %a base lookup failure %r\n",
328 Context->Is32Bit ? "32" : "64",
329 Patch->Comment != NULL ? Patch->Comment : "Patch",
330 Status
331 ));
332 return Status;
333 }
334
335 Size -= (UINT32)(Base - (UINT8 *)MachoGetMachHeader (&Context->MachContext));
336 }
337
338 if (Patch->Find == NULL) {
339 if (Size < Patch->Size) {
340 DEBUG ((
341 DEBUG_INFO,
342 "OCAK: %a-bit %a is borked, not found\n",
343 Context->Is32Bit ? "32" : "64",
344 Patch->Comment != NULL ? Patch->Comment : "Patch"
345 ));
346 return EFI_NOT_FOUND;
347 }
348
349 CopyMem (Base, Patch->Replace, Patch->Size);
350 return EFI_SUCCESS;
351 }
352
353 if ((Patch->Limit > 0) && (Patch->Limit < Size)) {
354 Size = Patch->Limit;
355 }
356
357 ReplaceCount = ApplyPatch (
358 Patch->Find,
359 Patch->Mask,
360 Patch->Size,
361 Patch->Replace,
362 Patch->ReplaceMask,
363 Base,
364 Size,
365 Patch->Count,
366 Patch->Skip
367 );
368
369 DEBUG ((
370 DEBUG_INFO,
371 "OCAK: %a-bit %a replace count - %u\n",
372 Context->Is32Bit ? "32" : "64",
373 Patch->Comment != NULL ? Patch->Comment : "Patch",
374 ReplaceCount
375 ));
376
377 if ((ReplaceCount > 0) && (Patch->Count > 0) && (ReplaceCount != Patch->Count)) {
378 DEBUG ((
379 DEBUG_INFO,
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",
383 ReplaceCount,
384 Patch->Count
385 ));
386 }
387
388 if (ReplaceCount > 0) {
389 return EFI_SUCCESS;
390 }
391
392 return EFI_NOT_FOUND;
393}
394
395EFI_STATUS
397 IN CONST CHAR8 *Identifier,
398 IN OUT PATCHER_CONTEXT *PatcherContext,
399 IN OUT PRELINKED_CONTEXT *PrelinkedContext
400 )
401{
403 VOID *KextData;
404 UINT64 AddressMax;
405 UINT64 VirtualAddress;
406 UINT64 FileOffset;
407 UINT64 Size;
408 UINT64 MaxSize;
409
410 UINT32 KextCount;
411 UINT32 Index;
412 UINT32 Index2;
413 XML_NODE *KextPlist;
414 UINT32 KextPlistCount;
415 CONST CHAR8 *KextPlistKey;
416 XML_NODE *KextPlistValue;
417 CONST CHAR8 *KextIdentifier;
418 EFI_STATUS Status;
419
420 ASSERT (Identifier != NULL);
421 ASSERT (PatcherContext != NULL);
422 ASSERT (PrelinkedContext != NULL);
423
424 Segment = NULL;
425 VirtualAddress = 0;
426 AddressMax = 0;
427 Size = 0;
428 while ((Segment = MachoGetNextSegment (&PatcherContext->MachContext, Segment)) != NULL) {
429 VirtualAddress = PatcherContext->Is32Bit ? Segment->Segment32.VirtualAddress : Segment->Segment64.VirtualAddress;
430
431 if ((AddressMax != 0) && (AddressMax != VirtualAddress)) {
432 break;
433 }
434
435 Size = PatcherContext->Is32Bit ? Segment->Segment32.Size : Segment->Segment64.Size;
436 AddressMax = MAX (VirtualAddress + Size, AddressMax);
437 }
438
439 MaxSize = AddressMax - PatcherContext->VirtualBase;
440
441 //
442 // Get file offset for 32-bit.
443 //
444 if (PatcherContext->Is32Bit) {
445 if (!GetTextBaseOffset (&PatcherContext->MachContext, &VirtualAddress, &FileOffset)) {
446 return EFI_UNSUPPORTED;
447 }
448
449 VirtualAddress += FileOffset;
450 } else {
451 VirtualAddress = PatcherContext->VirtualBase;
452 }
453
454 //
455 // Zero out kext memory through PatcherContext->MachContext.
456 //
458 &PatcherContext->MachContext,
459 VirtualAddress,
460 NULL
461 );
462 if (KextData == NULL) {
463 return EFI_UNSUPPORTED;
464 }
465
466 DEBUG ((
467 DEBUG_INFO,
468 "OCAK: Excluding %a - VirtualBase %Lx, MaxSize %Lx\n",
469 Identifier,
470 PatcherContext->VirtualBase,
471 MaxSize
472 ));
473 ZeroMem (KextData, (UINTN)MaxSize);
474
475 //
476 // Find kext info to be removed in prelinked context.
477 //
478 KextCount = XmlNodeChildren (PrelinkedContext->KextList);
479 KextPlist = NULL;
480 KextPlistKey = NULL;
481 KextIdentifier = NULL;
482
483 for (Index = 0; Index < KextCount; ++Index) {
484 KextPlist = PlistNodeCast (XmlNodeChild (PrelinkedContext->KextList, Index), PLIST_NODE_TYPE_DICT);
485 if (KextPlist == NULL) {
486 continue;
487 }
488
489 KextPlistCount = PlistDictChildren (KextPlist);
490 for (Index2 = 0; Index2 < KextPlistCount; ++Index2) {
491 KextPlistKey = PlistKeyValue (PlistDictChild (KextPlist, Index2, &KextPlistValue));
492 if (KextPlistKey == NULL) {
493 continue;
494 }
495
496 if (AsciiStrCmp (KextPlistKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
497 KextIdentifier = XmlNodeContent (KextPlistValue);
498 if ((PlistNodeCast (KextPlistValue, PLIST_NODE_TYPE_STRING) == NULL) || (KextIdentifier == NULL)) {
499 DEBUG ((
500 DEBUG_INFO,
501 "OCAK: Plist value cannot be interpreted as string, or current kext identifier is null (dict index %u, plist %p, plist index %u)\n",
502 Index2,
503 KextPlist,
504 Index
505 ));
506 return EFI_NOT_FOUND;
507 }
508
509 if (AsciiStrCmp (KextIdentifier, Identifier) == 0) {
510 //
511 // Erase kext.
512 //
513 Status = InternalDropCachedPrelinkedKext (PrelinkedContext, KextIdentifier);
514 if (EFI_ERROR (Status)) {
515 DEBUG ((
516 DEBUG_INFO,
517 "OCAK: Failed to drop %a under dict index %u, plist %p, plist index %u - %r\n",
518 KextIdentifier,
519 Index2,
520 KextPlist,
521 Index,
522 Status
523 ));
524 return Status;
525 }
526
527 DEBUG ((
528 DEBUG_INFO,
529 "OCAK: Erasing %a from prelinked kext under dict index %u, plist %p, plist index %u\n",
530 Identifier,
531 Index2,
532 KextPlist,
533 Index
534 ));
535 XmlNodeRemoveByIndex (PrelinkedContext->KextList, Index);
536 return EFI_SUCCESS;
537 }
538 }
539 }
540 }
541
542 return EFI_NOT_FOUND;
543}
544
545EFI_STATUS
547 IN OUT MKEXT_CONTEXT *MkextContext,
548 IN CONST CHAR8 *Identifier
549 )
550{
551 EFI_STATUS Status;
552 MKEXT_V2_FILE_ENTRY *MkextV2FileEntry;
553 MKEXT_HEADER_ANY *MkextHeader;
554 CONST CHAR8 *KextIdentifier;
555 BOOLEAN IsKextMatch;
556
557 UINT32 PlistBundlesCount;
558 XML_NODE *PlistBundle;
559 UINT32 PlistBundleIndex;
560 UINT32 PlistBundleCount;
561 CONST CHAR8 *PlistBundleKey;
562 XML_NODE *PlistBundleKeyValue;
563
564 UINT32 Index;
565 UINT32 PlistOffset;
566 UINT32 PlistSize;
567 UINT32 BinOffset;
568 UINT32 BinSize;
569
570 ASSERT (MkextContext != NULL);
571 ASSERT (Identifier != NULL);
572
573 MkextHeader = MkextContext->MkextHeader;
574 IsKextMatch = FALSE;
575
576 //
577 // Mkext v1.
578 //
579 if (MkextContext->MkextVersion == MKEXT_VERSION_V1) {
580 Status = InternalGetMkextV1KextOffsets (MkextContext, Identifier, &Index, &PlistOffset, &PlistSize, &BinOffset, &BinSize);
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584
585 DEBUG ((
586 DEBUG_INFO,
587 "OCAK: Excluding mkext v1 %a - plist %x (%x), binary %x (%x)\n",
588 Identifier,
589 PlistOffset,
590 PlistSize,
591 BinOffset,
592 BinSize
593 ));
594
595 //
596 // Zero out kext memory and kext list entry.
597 // A completely zero entry will be skipped by XNU, although a non-fatal error will be logged.
598 //
599 ZeroMem (&MkextContext->Mkext[PlistOffset], PlistSize);
600 ZeroMem (&MkextContext->Mkext[BinOffset], BinSize);
601 ZeroMem (&MkextHeader->V1.Kexts[Index], sizeof (MkextHeader->V1.Kexts[Index]));
602
603 //
604 // Mkext v2.
605 //
606 } else if (MkextContext->MkextVersion == MKEXT_VERSION_V2) {
607 //
608 // Enumerate bundle dicts and find kext to be removed.
609 //
610 PlistBundlesCount = XmlNodeChildren (MkextContext->MkextKexts);
611 for (Index = 0; Index < PlistBundlesCount; Index++) {
612 PlistBundle = PlistNodeCast (XmlNodeChild (MkextContext->MkextKexts, Index), PLIST_NODE_TYPE_DICT);
613 if (PlistBundle == NULL) {
614 continue;
615 }
616
617 PlistBundleCount = PlistDictChildren (PlistBundle);
618 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
619 PlistBundleKey = PlistKeyValue (PlistDictChild (PlistBundle, PlistBundleIndex, &PlistBundleKeyValue));
620 if ((PlistBundleKey == NULL) || (PlistBundleKeyValue == NULL)) {
621 continue;
622 }
623
624 if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
625 KextIdentifier = XmlNodeContent (PlistBundleKeyValue);
626 if ((PlistNodeCast (PlistBundleKeyValue, PLIST_NODE_TYPE_STRING) == NULL) || (KextIdentifier == NULL)) {
627 DEBUG ((
628 DEBUG_INFO,
629 "OCAK: Plist value cannot be interpreted as string, or current kext identifier is null (dict index %u, plist %p, plist index %u)\n",
630 PlistBundleIndex,
631 PlistBundle,
632 Index
633 ));
634 return EFI_NOT_FOUND;
635 }
636 }
637
638 if (AsciiStrCmp (PlistBundleKey, MKEXT_EXECUTABLE_KEY) == 0) {
639 if (!PlistIntegerValue (PlistBundleKeyValue, &BinOffset, sizeof (BinOffset), TRUE)) {
640 DEBUG ((
641 DEBUG_INFO,
642 "OCAK: Plist value cannot be interpreted as integer (dict index %u, plist %p, plist index %u)\n",
643 PlistBundleIndex,
644 PlistBundle,
645 Index
646 ));
647 return EFI_NOT_FOUND;
648 }
649 }
650 }
651
652 if ( (KextIdentifier != NULL)
653 && (AsciiStrCmp (KextIdentifier, Identifier) == 0)
654 && (BinOffset > 0)
655 && (BinOffset < MkextContext->MkextSize - sizeof (MKEXT_V2_FILE_ENTRY)))
656 {
657 IsKextMatch = TRUE;
658 break;
659 }
660
661 KextIdentifier = NULL;
662 BinOffset = 0;
663 }
664
665 //
666 // Bundle was not found, or invalid.
667 //
668 if (!IsKextMatch) {
669 return EFI_NOT_FOUND;
670 }
671
672 //
673 // Parse v2 binary header.
674 // We cannot support compressed binaries.
675 //
676 MkextV2FileEntry = (MKEXT_V2_FILE_ENTRY *)&MkextContext->Mkext[BinOffset];
677 if (MkextV2FileEntry->CompressedSize != 0) {
678 return EFI_UNSUPPORTED;
679 }
680
681 BinSize = SwapBytes32 (MkextV2FileEntry->FullSize);
682
683 DEBUG ((
684 DEBUG_INFO,
685 "OCAK: Excluding mkext v2 %a - dict index %u, plist %p, plist index %u, binary %x (%x)\n",
686 Identifier,
687 PlistBundleIndex,
688 PlistBundle,
689 Index,
690 BinOffset,
691 BinSize
692 ));
693
694 //
695 // Erase kext data and drop from plist.
696 //
697 ZeroMem (&MkextContext->Mkext[BinOffset], BinSize + sizeof (MKEXT_V2_FILE_ENTRY));
698 InternalDropCachedMkextKext (MkextContext, KextIdentifier);
699 XmlNodeRemoveByIndex (MkextContext->MkextKexts, Index);
700
701 //
702 // Unsupported version.
703 //
704 } else {
705 return EFI_UNSUPPORTED;
706 }
707
708 return EFI_SUCCESS;
709}
710
711EFI_STATUS
713 IN OUT PATCHER_CONTEXT *Context
714 )
715{
716 UINT8 *MachBase;
717 UINT32 MachSize;
718 UINT64 KmodOffset;
719 UINT64 StartAddr;
720 UINT64 TmpOffset;
721 UINT8 *KmodInfo;
722 UINT8 *PatchAddr;
723
724 //
725 // Kernel has 0 kmod.
726 //
727 if ((Context->VirtualKmod == 0) || (Context->VirtualBase > Context->VirtualKmod)) {
728 return EFI_UNSUPPORTED;
729 }
730
731 MachBase = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
732 MachSize = MachoGetInnerSize (&Context->MachContext);
733
734 //
735 // Determine offset of kmod within file.
736 //
737 KmodOffset = Context->VirtualKmod - Context->VirtualBase;
738 if ( BaseOverflowAddU64 (KmodOffset, Context->FileOffset, &KmodOffset)
739 || BaseOverflowAddU64 (KmodOffset, Context->Is32Bit ? sizeof (KMOD_INFO_32_V1) : sizeof (KMOD_INFO_64_V1), &TmpOffset)
740 || (TmpOffset > MachSize))
741 {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 KmodInfo = MachBase + KmodOffset;
746 if (Context->Is32Bit) {
747 StartAddr = ((KMOD_INFO_32_V1 *)KmodInfo)->StartAddr;
748 } else {
749 StartAddr = ((KMOD_INFO_64_V1 *)KmodInfo)->StartAddr;
750 if (Context->IsKernelCollection) {
751 StartAddr = KcFixupValue (StartAddr, NULL);
752 }
753 }
754
755 if ((StartAddr == 0) || (Context->VirtualBase > StartAddr)) {
756 return EFI_INVALID_PARAMETER;
757 }
758
759 TmpOffset = StartAddr - Context->VirtualBase;
760 if ( BaseOverflowAddU64 (TmpOffset, Context->FileOffset, &TmpOffset)
761 || (TmpOffset > MachSize - 6))
762 {
763 return EFI_BUFFER_TOO_SMALL;
764 }
765
766 DEBUG ((
767 DEBUG_VERBOSE,
768 "OCAK: %a-bit blocker start @ 0x%llX\n",
769 Context->Is32Bit ? "32" : "64",
770 TmpOffset
771 ));
772
773 PatchAddr = MachBase + TmpOffset;
774
775 //
776 // mov eax, KMOD_RETURN_FAILURE
777 // ret
778 //
779 PatchAddr[0] = 0xB8;
780 PatchAddr[1] = KMOD_RETURN_FAILURE;
781 PatchAddr[2] = 0x00;
782 PatchAddr[3] = 0x00;
783 PatchAddr[4] = 0x00;
784 PatchAddr[5] = 0xC3;
785
786 return EFI_SUCCESS;
787}
788
789BOOLEAN
791 IN OC_MACHO_CONTEXT *ExecutableContext,
792 IN UINT64 LoadAddress,
793 IN UINT32 Size,
794 OUT UINT64 *Kmod
795 )
796{
797 BOOLEAN Is32Bit;
798 MACH_NLIST_ANY *Symbol;
799 CONST CHAR8 *SymbolName;
800 UINT64 Address;
801 UINT64 FileOffset;
802 UINT32 Index;
803
804 Is32Bit = ExecutableContext->Is32Bit;
805 Index = 0;
806
807 while (TRUE) {
808 Symbol = MachoGetSymbolByIndex (ExecutableContext, Index);
809 if (Symbol == NULL) {
810 *Kmod = 0;
811 return TRUE;
812 }
813
814 if (((Is32Bit ? Symbol->Symbol32.Type : Symbol->Symbol64.Type) & MACH_N_TYPE_STAB) == 0) {
815 SymbolName = MachoGetSymbolName (ExecutableContext, Symbol);
816 if (SymbolName && (AsciiStrCmp (SymbolName, "_kmod_info") == 0)) {
817 if (!MachoIsSymbolValueInRange (ExecutableContext, Symbol)) {
818 return FALSE;
819 }
820
821 break;
822 }
823 }
824
825 Index++;
826 }
827
828 if (!GetTextBaseOffset (ExecutableContext, &Address, &FileOffset)) {
829 return FALSE;
830 }
831
832 if ( BaseOverflowTriAddU64 (Address, LoadAddress, Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value, &Address)
833 || (Address > LoadAddress + Size - (Is32Bit ? sizeof (KMOD_INFO_32_V1) : sizeof (KMOD_INFO_64_V1)))
834 || (Is32Bit && (Address > MAX_UINT32)))
835 {
836 return FALSE;
837 }
838
839 *Kmod = Address;
840 return TRUE;
841}
#define KMOD_RETURN_FAILURE
#define MACH_N_TYPE_STAB
#define MKEXT_VERSION_V2
Definition AppleMkext.h:45
#define MKEXT_VERSION_V1
Definition AppleMkext.h:41
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)
Definition KextPatcher.c:32
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)
Definition KextPatcher.c:99
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)
Definition KxldState.c:579
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)
Definition Header.c:55
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)
Definition Header.c:66
VOID * MachoGetFilePointerByAddress(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT UINT32 *MaxSize OPTIONAL)
Definition Header.c:627
MACH_SEGMENT_COMMAND_ANY * MachoGetNextSegment(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_SEGMENT_COMMAND_ANY *Segment OPTIONAL)
Definition Header.c:160
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)
Definition Header.c:44
BOOLEAN MachoInitializeContext(OUT OC_MACHO_CONTEXT *Context, IN VOID *FileData, IN UINT32 FileSize, IN UINT32 HeaderOffset, IN UINT32 InnerSize, IN BOOLEAN Is32Bit)
Definition Header.c:29
MACH_NLIST_ANY * MachoGetSymbolByIndex(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
Definition Symbols.c:67
BOOLEAN MachoIsSymbolValueInRange(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:106
CONST CHAR8 * MachoGetSymbolName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:80
BOOLEAN MachoSymbolGetDirectFileOffset(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT UINT32 *FileOffset, OUT UINT32 *MaxSize OPTIONAL)
Definition Symbols.c:168
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)
Definition Symbols.c:153
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]
Definition OcTypingLib.h:42
@ PLIST_NODE_TYPE_DICT
Definition OcXmlLib.h:91
@ PLIST_NODE_TYPE_STRING
Definition OcXmlLib.h:93
CONST CHAR8 * PlistKeyValue(IN XML_NODE *Node OPTIONAL)
Definition OcXmlLib.c:1841
UINT32 XmlNodeChildren(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1493
VOID XmlNodeRemoveByIndex(IN OUT XML_NODE *Node, IN UINT32 Index)
Definition OcXmlLib.c:1633
CONST CHAR8 * XmlNodeContent(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1467
UINT32 PlistDictChildren(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1813
BOOLEAN PlistIntegerValue(IN XML_NODE *Node OPTIONAL, OUT VOID *Value, IN UINT32 Size, IN BOOLEAN Hex)
Definition OcXmlLib.c:1943
XML_NODE * PlistNodeCast(IN XML_NODE *Node OPTIONAL, IN PLIST_NODE_TYPE Type)
Definition OcXmlLib.c:1760
XML_NODE * XmlNodeChild(IN CONST XML_NODE *Node, IN UINT32 Child)
Definition OcXmlLib.c:1503
XML_NODE * PlistDictChild(IN CONST XML_NODE *Node, IN UINT32 Child, OUT XML_NODE **Value OPTIONAL)
Definition OcXmlLib.c:1823
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)
#define ASSERT(x)
Definition coder.h:55
#define MAX(a, b)
Definition coder.h:59
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
UINT32 BinarySize
UINT32 BinaryOffset
MKEXT_V1_KEXT Kexts[]
Definition AppleMkext.h:144
PATCHER_CONTEXT Context
MACH_NLIST_64 Symbol64
MACH_SEGMENT_COMMAND_64 Segment64
MACH_SEGMENT_COMMAND Segment32
MKEXT_V1_HEADER V1
Definition AppleMkext.h:204