OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Vtables.c
Go to the documentation of this file.
1
15#include <Base.h>
16
18
19#include <Library/BaseLib.h>
20#include <Library/BaseOverflowLib.h>
21#include <Library/DebugLib.h>
22#include <Library/MemoryAllocationLib.h>
24#include <Library/OcMachoLib.h>
25
26#include "PrelinkedInternal.h"
27
28CONST PRELINKED_VTABLE *
30 IN PRELINKED_CONTEXT *Context,
31 IN PRELINKED_KEXT *Kext,
32 IN CONST CHAR8 *Name
33 )
34{
35 CONST PRELINKED_VTABLE *Vtable;
36
37 UINTN Index;
38 PRELINKED_KEXT *Dependency;
39 INTN Result;
40
41 Kext->Processed = TRUE;
42
43 for (
44 Index = 0, Vtable = Kext->LinkedVtables;
45 Index < Kext->NumberOfVtables;
46 ++Index, Vtable = GET_NEXT_PRELINKED_VTABLE (Vtable)
47 )
48 {
49 Result = AsciiStrCmp (Vtable->Name, Name);
50 if (Result == 0) {
51 return Vtable;
52 }
53 }
54
55 for (Index = 0; Index < ARRAY_SIZE (Kext->Dependencies); ++Index) {
56 Dependency = Kext->Dependencies[Index];
57 if (Dependency == NULL) {
58 break;
59 }
60
61 if (Dependency->Processed) {
62 continue;
63 }
64
65 Vtable = InternalGetOcVtableByName (Context, Dependency, Name);
66 if (Vtable != NULL) {
67 return Vtable;
68 }
69 }
70
71 return NULL;
72}
73
74CONST PRELINKED_VTABLE *
76 IN PRELINKED_CONTEXT *Context,
77 IN PRELINKED_KEXT *Kext,
78 IN CONST CHAR8 *Name
79 )
80{
81 CONST PRELINKED_VTABLE *Vtable;
82
83 Vtable = InternalGetOcVtableByNameWorker (Context, Kext, Name);
84
86
87 return Vtable;
88}
89
90STATIC
91VOID
93 IN PRELINKED_CONTEXT *Context,
94 IN OUT PRELINKED_KEXT *Kext,
95 IN CONST OC_PRELINKED_VTABLE_LOOKUP_ENTRY *VtableLookup,
96 OUT PRELINKED_VTABLE *Vtable
97 )
98{
99 CONST VOID *VtableData;
100 UINT64 Value;
101 UINT32 Index;
102 CONST PRELINKED_KEXT_SYMBOL *Symbol;
103
104 ASSERT (Kext != NULL);
105 ASSERT (VtableLookup != NULL);
106 ASSERT (Vtable != NULL);
107
108 VtableData = VtableLookup->Vtable.Data;
109 Vtable->Name = VtableLookup->Name;
110
111 //
112 // Initialize the VTable by entries.
113 //
114
115 //
116 // Assumption: Not ARM (ARM requires an alignment to the function pointer
117 // retrieved from VtableData.
118 // VTable bounds are verified in InternalGetVtableEntries() called earlier.
119 // The buffer is allocated to be able to hold all entries.
120 //
121 for (
122 Index = 0;
123 (Value = VTABLE_ENTRY_X (Context->Is32Bit, VtableData, Index + VTABLE_HEADER_LEN)) != 0;
124 ++Index
125 )
126 {
127 if (Context->IsKernelCollection) {
128 Value = KcFixupValue (Value, Kext->Identifier);
129 }
130
131 //
132 // If we can't find the symbol, it means that the virtual function was
133 // defined inline. There's not much I can do about this; it just means
134 // I can't patch this function.
135 //
136 Symbol = InternalOcGetSymbolValue (Context, Kext, Value, OcGetSymbolOnlyCxx);
137
138 if (Symbol != NULL) {
139 Vtable->Entries[Index].Address = Value;
140 Vtable->Entries[Index].Name = Symbol->Name;
141 } else {
142 Vtable->Entries[Index].Address = 0;
143 Vtable->Entries[Index].Name = NULL;
144 }
145 }
146
147 Vtable->NumEntries = Index;
148}
149
150BOOLEAN
152 IN BOOLEAN Is32Bit,
153 IN CONST VOID *VtableData,
154 IN UINT32 MaxSize,
155 OUT UINT32 *NumEntries
156 )
157{
158 UINT32 Index;
159
160 ASSERT (VtableData != NULL);
161 ASSERT (NumEntries != NULL);
162 //
163 // Assumption: Not ARM (ARM requires an alignment to the function pointer
164 // retrieved from VtableData.
165 //
166 MaxSize /= VTABLE_ENTRY_SIZE_X (Is32Bit);
167 Index = VTABLE_HEADER_LEN;
168 do {
169 if (Index >= MaxSize) {
170 return FALSE;
171 }
172 } while (VTABLE_ENTRY_X (Is32Bit, VtableData, Index++) != 0);
173
174 *NumEntries = (Index - VTABLE_HEADER_LEN);
175 return TRUE;
176}
177
178BOOLEAN
180 IN PRELINKED_KEXT *Kext,
181 IN UINT32 MaxSize,
182 OUT UINT32 *NumVtables,
184 )
185{
186 UINT32 VtableIndex;
187
188 CONST PRELINKED_KEXT_SYMBOL *Symbol;
189 UINT32 Index;
190
191 ASSERT (Kext != NULL);
192
193 VtableIndex = 0;
194
195 MaxSize /= sizeof (*Vtables);
196 for (
197 Index = (Kext->NumberOfSymbols - Kext->NumberOfCxxSymbols);
198 Index < Kext->NumberOfSymbols;
199 ++Index
200 )
201 {
202 Symbol = &Kext->LinkedSymbolTable[Index];
203 if (MachoSymbolNameIsVtable (Symbol->Name)) {
204 //
205 // This seems to be valid for KC format as some symbols may be kernel imports?!
206 // Observed with IOACPIFamily when injecting VirtualSMC:
207 // __ZTV18IODTPlatformExpert (zero value)
208 // __ZTV16IOPlatformDevice (zero value)
209 // __ZTVN20IOACPIPlatformExpert9MetaClassE
210 // __ZTVN20IOACPIPlatformDevice9MetaClassE
211 // __ZTV20IOACPIPlatformExpert
212 // __ZTV20IOACPIPlatformDevice
213 //
214 if (Symbol->Value == 0) {
215 DEBUG ((DEBUG_VERBOSE, "OCAK: Skipping %a with NULL value\n", Symbol->Name));
216 continue;
217 }
218
219 if (VtableIndex >= MaxSize) {
220 return FALSE;
221 }
222
223 Vtables[VtableIndex].Name = Symbol->Name;
224 Vtables[VtableIndex].Vtable.Value = Symbol->Value;
225 ++VtableIndex;
226 }
227 }
228
229 *NumVtables = VtableIndex;
230
231 return TRUE;
232}
233
234VOID
236 IN PRELINKED_CONTEXT *Context,
237 IN OUT PRELINKED_KEXT *Kext,
238 IN UINT32 NumVtables,
239 IN CONST OC_PRELINKED_VTABLE_LOOKUP_ENTRY *VtableLookups,
240 OUT PRELINKED_VTABLE *VtableBuffer
241 )
242{
243 UINT32 Index;
244
245 ASSERT (Kext != NULL);
246
247 for (Index = 0; Index < NumVtables; ++Index) {
249 Context,
250 Kext,
251 &VtableLookups[Index],
252 VtableBuffer
253 );
254 VtableBuffer = GET_NEXT_PRELINKED_VTABLE (VtableBuffer);
255 }
256}
257
261STATIC
262BOOLEAN
264 IN OUT OC_MACHO_CONTEXT *MachoContext,
265 IN CONST PRELINKED_VTABLE_ENTRY *ParentEntry,
266 IN CONST CHAR8 *VtableName,
267 OUT MACH_NLIST_ANY *Symbol
268 )
269{
270 CONST CHAR8 *Name;
271 INTN Result;
272 BOOLEAN Success;
273 CONST CHAR8 *ClassName;
274 CHAR8 FunctionPrefix[SYM_MAX_NAME_LEN];
275
276 ASSERT (Symbol != NULL);
277 ASSERT (ParentEntry != NULL);
278 //
279 // It's possible for the patched parent entry not to have a symbol
280 // (e.g. when the definition is inlined). We can't patch this entry no
281 // matter what, so we'll just skip it and die later if it's a problem
282 // (which is not likely).
283 //
284 if (ParentEntry->Name == NULL) {
285 return TRUE;
286 }
287
288 //
289 // 1) If the symbol is defined locally, do not patch
290 //
291 if (MachoSymbolIsLocalDefined (MachoContext, Symbol)) {
292 return TRUE;
293 }
294
295 Name = MachoGetSymbolName (MachoContext, Symbol);
296 //
297 // 2) If the child is a pure virtual function, do not patch.
298 // In general, we want to proceed with patching when the symbol is
299 // externally defined because pad slots fall into this category.
300 // The pure virtual function symbol is special case, as the pure
301 // virtual property itself overrides the parent's implementation.
302 //
303 if (MachoSymbolNameIsPureVirtual (Name)) {
304 return TRUE;
305 }
306
307 //
308 // 3) If the symbols are the same, do not patch
309 //
310 Result = AsciiStrCmp (Name, ParentEntry->Name);
311 if (Result == 0) {
312 return TRUE;
313 }
314
315 //
316 // 4) If the parent vtable entry is a pad slot, and the child does not
317 // match it, then the child was built against a newer version of the
318 // libraries, so it is binary-incompatible.
319 //
320 if (MachoSymbolNameIsPadslot (ParentEntry->Name)) {
321 return FALSE;
322 }
323
324 //
325 // 5) If we are doing strict patching, we prevent kexts from declaring
326 // virtual functions and not implementing them. We can tell if a
327 // virtual function is declared but not implemented because we resolve
328 // symbols before patching; an unimplemented function will still be
329 // undefined at this point. We then look at whether the symbol has
330 // the same class prefix as the vtable. If it does, the symbol was
331 // declared as part of the class and not inherited, which means we
332 // should not patch it.
333 //
334 if (!MachoSymbolIsDefined (MachoContext, Symbol)) {
335 ClassName = MachoGetClassNameFromVtableName (VtableName);
336
338 ClassName,
339 sizeof (FunctionPrefix),
340 FunctionPrefix
341 );
342 if (!Success) {
343 return FALSE;
344 }
345
346 Result = AsciiStrCmp (Name, FunctionPrefix);
347 if (Result == 0) {
348 //
349 // The VTable's class declares a method without providing an
350 // implementation.
351 //
352 return FALSE;
353 }
354 }
355
356 //
357 // 6) The child symbol is unresolved and different from its parent, so
358 // we need to patch it up. We do this by modifying the relocation
359 // entry of the vtable entry to point to the symbol of the parent
360 // vtable entry. If that symbol does not exist (i.e. we got the data
361 // from a link state object's vtable representation), then we create a
362 // new symbol in the symbol table and point the relocation entry to
363 // that.
364 //
365 // NOTE: The original logic has been altered significantly. Instead of
366 // declaring a symbol as "replaced" and either changing the
367 // associated relocation's index to the parent's or adding a new symbol
368 // based on a match, the symbol is actually overwritten. This looks
369 // fine for the rest of the control flow. The symbol name is not
370 // changed for the symbol value is already resolved and nothing but a
371 // VTable Relocation should reference it.
372 //
373 InternalSolveSymbolValue (MachoContext->Is32Bit, ParentEntry->Address, Symbol);
374 //
375 // The C++ ABI requires that functions be aligned on a 2-byte boundary:
376 // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
377 // If the LSB of any virtual function's link address is 1, then the
378 // compiler has violated that part of the ABI, and we're going to panic
379 // in _ptmf2ptf() (in OSMetaClass.h). Better to panic here with some
380 // context.
381 //
382 Name = ParentEntry->Name;
384 && (((MachoContext->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value) & 1U) != 0))
385 {
386 DEBUG ((DEBUG_WARN, "OCAK: Prelink: Invalid VTable symbol\n"));
387 }
388
389 return TRUE;
390}
391
392STATIC
393BOOLEAN
395 IN PRELINKED_CONTEXT *Context,
396 IN PRELINKED_KEXT *Kext,
397 IN CONST PRELINKED_VTABLE *SuperVtable,
398 IN CONST MACH_NLIST_ANY *VtableSymbol,
399 IN CONST VOID *VtableData,
400 IN UINT32 NumSolveSymbols,
401 IN OUT MACH_NLIST_ANY **SolveSymbols,
402 OUT PRELINKED_VTABLE *Vtable
403 )
404{
405 OC_MACHO_CONTEXT *MachoContext;
406 CONST CHAR8 *VtableName;
407 CONST PRELINKED_KEXT_SYMBOL *OcSymbol;
408 UINT32 Index;
409 PRELINKED_VTABLE_ENTRY *VtableEntries;
410 UINT64 EntryValue;
411 UINT32 SolveSymbolIndex;
412 BOOLEAN Result;
413 MACH_NLIST_ANY *Symbol;
414
415 MachoContext = &Kext->Context.MachContext;
416 VtableEntries = Vtable->Entries;
417
418 VtableName = MachoGetSymbolName (MachoContext, VtableSymbol);
419 SolveSymbolIndex = 0;
420 //
421 // Assumption: Not ARM (ARM requires an alignment to the function pointer
422 // retrieved from VtableData.
423 //
424 for (Index = 0; Index < SuperVtable->NumEntries; ++Index) {
425 EntryValue = VTABLE_ENTRY_X (Context->Is32Bit, VtableData, Index + VTABLE_HEADER_LEN);
426 if (EntryValue != 0) {
427 //
428 // If we can't find a symbol, it means it is a locally-defined,
429 // non-external symbol that has been stripped. We don't patch over
430 // locally-defined symbols, so we leave the symbol as NULL and just
431 // skip it. We won't be able to patch subclasses with this symbol,
432 // but there isn't much we can do about that.
433 //
434 OcSymbol = InternalOcGetSymbolValue (
435 Context,
436 Kext,
437 EntryValue,
439 );
440 if (OcSymbol != NULL) {
441 VtableEntries[Index].Name = OcSymbol->Name;
442 VtableEntries[Index].Address = OcSymbol->Value;
443 continue;
444 }
445 } else {
446 if (SolveSymbolIndex >= NumSolveSymbols) {
447 //
448 // When no more symbols are left to resolve with, this marks the end.
449 //
450 break;
451 }
452
453 Symbol = SolveSymbols[SolveSymbolIndex];
454 ++SolveSymbolIndex;
455 //
456 // The child entry can be NULL when a locally-defined, non-external
457 // symbol is stripped. We wouldn't patch this entry anyway, so we
458 // just skip it.
459 //
460 if (Symbol != NULL) {
462 MachoContext,
463 &SuperVtable->Entries[Index],
464 VtableName,
465 Symbol
466 );
467 if (!Result) {
468 DEBUG ((DEBUG_INFO, "OCAK: Failed to patch symbol %a for vtable %a\n", MachoGetSymbolName (MachoContext, Symbol), VtableName));
469 return FALSE;
470 }
471
472 VtableEntries[Index].Name = MachoGetSymbolName (MachoContext, Symbol);
473 VtableEntries[Index].Address = Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value;
474 continue;
475 }
476 }
477
478 VtableEntries[Index].Name = NULL;
479 VtableEntries[Index].Address = 0;
480 }
481
482 Vtable->Name = VtableName;
483 Vtable->NumEntries = Index;
484
485 return TRUE;
486}
487
488STATIC
489BOOLEAN
491 IN OUT OC_MACHO_CONTEXT *MachoContext,
492 IN CONST MACH_NLIST_ANY *VtableSymbol,
493 IN OUT UINT32 *MaxSize,
494 OUT VOID **VtableDataPtr,
495 OUT UINT32 *NumEntries,
496 OUT UINT32 *NumSymbols,
497 OUT MACH_NLIST_ANY **SolveSymbols
498 )
499{
500 BOOLEAN Result;
501 UINT32 VtableOffset;
502 UINT32 VtableMaxSize;
503 VOID *FileData;
504 VOID *VtableData;
505 UINT32 SymIndex;
506 UINT32 EntryOffset;
507 UINT64 FileOffset;
508 UINT32 MaxSymbols;
509 MACH_NLIST_ANY *Symbol;
510
511 Result = MachoSymbolGetFileOffset (
512 MachoContext,
513 VtableSymbol,
514 &VtableOffset,
515 &VtableMaxSize
516 );
517 if (!Result) {
518 return FALSE;
519 }
520
521 FileData = MachoGetFileData (MachoContext);
522 ASSERT (FileData != NULL);
523
524 VtableData = (VOID *)((UINTN)FileData + VtableOffset);
525 if (MachoContext->Is32Bit ? !BASE_TYPE_ALIGNED (UINT32, VtableData) : !BASE_TYPE_ALIGNED (UINT64, VtableData)) {
526 return FALSE;
527 }
528
529 //
530 // Assumption: Not ARM (ARM requires an alignment to the function pointer
531 // retrieved from VtableData.
532 //
533 MaxSymbols = (*MaxSize / (MachoContext->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64)));
534 VtableMaxSize /= VTABLE_ENTRY_SIZE_X (MachoContext->Is32Bit);
535
536 SymIndex = 0;
537
538 for (
539 EntryOffset = VTABLE_HEADER_LEN;
540 EntryOffset < VtableMaxSize;
541 ++EntryOffset
542 )
543 {
544 if (VTABLE_ENTRY_X (MachoContext->Is32Bit, VtableData, EntryOffset) == 0) {
545 Result = BaseOverflowAddU64 (
546 MachoContext->Is32Bit ? VtableSymbol->Symbol32.Value : VtableSymbol->Symbol64.Value,
547 (EntryOffset * VTABLE_ENTRY_SIZE_X (MachoContext->Is32Bit)),
548 &FileOffset
549 );
550 if (Result) {
551 return FALSE;
552 }
553
555 MachoContext,
556 FileOffset,
557 &Symbol
558 );
559 if (!Result) {
560 //
561 // If the VTable entry is 0 and it is not referenced by a Relocation,
562 // it is the end of the table.
563 //
564 *MaxSize -= (SymIndex * (MachoContext->Is32Bit ? sizeof (MACH_NLIST) : sizeof (MACH_NLIST_64)));
565 *VtableDataPtr = VtableData;
566 *NumEntries = (EntryOffset - VTABLE_HEADER_LEN);
567 *NumSymbols = SymIndex;
568 return TRUE;
569 }
570
571 if (SymIndex >= MaxSymbols) {
572 return FALSE;
573 }
574
575 SolveSymbols[SymIndex] = Symbol;
576 ++SymIndex;
577 }
578 }
579
580 return FALSE;
581}
582
583BOOLEAN
585 IN PRELINKED_CONTEXT *Context,
586 IN OUT PRELINKED_KEXT *Kext
587 )
588{
589 OC_VTABLE_PATCH_ENTRY *Entries;
590 OC_VTABLE_PATCH_ENTRY *EntryWalker;
591 UINT32 MaxSize;
592
593 OC_MACHO_CONTEXT *MachoContext;
594 UINT32 Index;
595 UINT32 NumTables;
596 UINT32 NumEntries;
597 UINT32 NumEntriesTemp;
598 UINT32 NumPatched;
599 BOOLEAN Result;
600 CONST MACH_NLIST_ANY *Smcp;
601 CONST CHAR8 *Name;
602 CONST MACH_NLIST_ANY *MetaClass;
603 CONST PRELINKED_VTABLE *SuperVtable;
604 CONST PRELINKED_VTABLE *MetaVtable;
605 CONST VOID *OcSymbolDummy;
606 MACH_NLIST_ANY *SymbolDummy;
607 CHAR8 ClassName[SYM_MAX_NAME_LEN];
608 CHAR8 SuperClassName[SYM_MAX_NAME_LEN];
609 CHAR8 VtableName[SYM_MAX_NAME_LEN];
610 CHAR8 SuperVtableName[SYM_MAX_NAME_LEN];
611 CHAR8 FinalSymbolName[SYM_MAX_NAME_LEN];
612 BOOLEAN SuccessfulIteration;
613 PRELINKED_VTABLE *CurrentVtable;
614
615 //
616 // LinkBuffer is at least as big as __LINKEDIT, so it can store all symbols.
617 //
618 Entries = Context->LinkBuffer;
619 MaxSize = Context->LinkBufferSize;
620
621 MachoContext = &Kext->Context.MachContext;
622 //
623 // Retrieve all SMCPs.
624 //
625 EntryWalker = Entries;
626 NumTables = 0;
627 NumEntries = 0;
628
629 for (
630 Index = 0;
631 (Smcp = MachoGetSymbolByIndex (MachoContext, Index)) != NULL;
632 ++Index
633 )
634 {
635 Name = MachoGetSymbolName (MachoContext, Smcp);
636 if ( (((Context->Is32Bit ? Smcp->Symbol32.Type : Smcp->Symbol64.Type) & MACH_N_TYPE_STAB) == 0)
637 && MachoSymbolNameIsSmcp (MachoContext, Name))
638 {
639 if (MaxSize < sizeof (*EntryWalker)) {
640 return FALSE;
641 }
642
643 //
644 // We walk over the super metaclass pointer symbols because classes
645 // with them are the only ones that need patching. Then we double the
646 // number of vtables we're expecting, because every pointer will have a
647 // class vtable and a MetaClass vtable.
648 //
650 MachoContext,
651 Name,
652 &EntryWalker->Vtable,
653 &EntryWalker->MetaVtable
654 );
655 if (!Result) {
656 return FALSE;
657 }
658
659 EntryWalker->Smcp = Smcp;
660
662 MachoContext,
663 EntryWalker->Vtable,
664 &MaxSize,
665 &EntryWalker->VtableData,
666 &NumEntriesTemp,
667 &EntryWalker->MetaSymsIndex,
668 EntryWalker->SolveSymbols
669 );
670 if (!Result) {
671 return FALSE;
672 }
673
674 NumEntries += NumEntriesTemp;
675
677 MachoContext,
678 EntryWalker->MetaVtable,
679 &MaxSize,
680 &EntryWalker->MetaVtableData,
681 &NumEntriesTemp,
682 &EntryWalker->NumSolveSymbols,
683 &EntryWalker->SolveSymbols[EntryWalker->MetaSymsIndex]
684 );
685 if (!Result) {
686 return FALSE;
687 }
688
689 NumEntries += NumEntriesTemp;
690
691 EntryWalker->NumSolveSymbols += EntryWalker->MetaSymsIndex;
692 ++NumTables;
693
694 EntryWalker = GET_NEXT_OC_VTABLE_PATCH_ENTRY (EntryWalker);
695 }
696 }
697
698 //
699 // One structure contains two VTables, hence (NumTables * 2).
700 //
701 Kext->LinkedVtables = AllocatePool (
702 ((NumTables * 2) * sizeof (*Kext->LinkedVtables))
703 + (NumEntries * sizeof (*Kext->LinkedVtables->Entries))
704 );
705 if (Kext->LinkedVtables == NULL) {
706 return FALSE;
707 }
708
709 CurrentVtable = Kext->LinkedVtables;
710 //
711 // Patch via the previously retrieved SMCPs.
712 //
713 NumPatched = 0;
714
715 while (NumPatched < NumTables) {
716 SuccessfulIteration = FALSE;
717
718 for (
719 Index = 0, EntryWalker = Entries;
720 Index < NumTables;
721 ++Index, EntryWalker = GET_NEXT_OC_VTABLE_PATCH_ENTRY (EntryWalker)
722 )
723 {
724 Smcp = EntryWalker->Smcp;
725 if (Smcp == NULL) {
726 continue;
727 }
728
729 Name = MachoGetSymbolName (MachoContext, Smcp);
730 //
731 // We walk over the super metaclass pointer symbols because classes
732 // with them are the only ones that need patching. Then we double the
733 // number of vtables we're expecting, because every pointer will have a
734 // class vtable and a MetaClass vtable.
735 //
736 ASSERT (MachoSymbolNameIsSmcp (MachoContext, Name));
737 //
738 // Get the class name from the smc pointer
739 //
741 MachoContext,
742 Name,
743 sizeof (ClassName),
744 ClassName
745 );
746 if (!Result) {
747 return FALSE;
748 }
749
750 //
751 // Get the vtable name from the class name
752 //
754 ClassName,
755 sizeof (VtableName),
756 VtableName
757 );
758 if (!Result) {
759 return FALSE;
760 }
761
762 //
763 // Find the SMCP's meta class symbol
764 //
766 MachoContext,
767 Smcp
768 );
769 if (MetaClass == NULL) {
770 return FALSE;
771 }
772
773 //
774 // Get the super class name from the super metaclass
775 //
777 MachoContext,
778 MachoGetSymbolName (MachoContext, MetaClass),
779 sizeof (SuperClassName),
780 SuperClassName
781 );
782 if (!Result) {
783 return FALSE;
784 }
785
787 SuperClassName,
788 sizeof (SuperVtableName),
789 SuperVtableName
790 );
791
792 if (!Result) {
793 return FALSE;
794 }
795
796 //
797 // Get the super vtable if it's been patched
798 //
799 SuperVtable = InternalGetOcVtableByName (
800 Context,
801 Kext,
802 SuperVtableName
803 );
804 if (SuperVtable == NULL) {
805 continue;
806 }
807
808 //
809 // Get the final symbol's name from the super vtable
810 //
812 SuperClassName,
813 sizeof (FinalSymbolName),
814 FinalSymbolName
815 );
816 if (!Result) {
817 return FALSE;
818 }
819
820 //
821 // Verify that the final symbol does not exist. First check
822 // all the externally defined symbols, then check locally.
823 //
824 OcSymbolDummy = InternalOcGetSymbolName (
825 Context,
826 Kext,
827 FinalSymbolName,
829 );
830 if (OcSymbolDummy != NULL) {
831 return FALSE;
832 }
833
835 MachoContext,
836 FinalSymbolName
837 );
838 if (SymbolDummy != NULL) {
839 return FALSE;
840 }
841
842 //
843 // Patch the class's vtable
844 //
846 Context,
847 Kext,
848 SuperVtable,
849 EntryWalker->Vtable,
850 EntryWalker->VtableData,
851 EntryWalker->MetaSymsIndex,
852 EntryWalker->SolveSymbols,
853 CurrentVtable
854 );
855 if (!Result) {
856 DEBUG ((DEBUG_INFO, "OCAK: Failed to patch vtable for superclass %a\n", SuperClassName));
857 return FALSE;
858 }
859
860 CurrentVtable = GET_NEXT_PRELINKED_VTABLE (CurrentVtable);
861 //
862 // Get the meta vtable name from the class name
863 //
865 ClassName,
866 sizeof (VtableName),
867 VtableName
868 );
869 if (!Result) {
870 return FALSE;
871 }
872
873 MetaVtable = InternalGetOcVtableByName (
874 Context,
875 Kext,
876 VtableName
877 );
878 if (MetaVtable != NULL) {
879 return FALSE;
880 }
881
882 //
883 // There is no way to look up a metaclass vtable at runtime, but
884 // we know that every class's metaclass inherits directly from
885 // OSMetaClass, so we just hardcode that vtable name here.
886 //
887 SuperVtable = InternalGetOcVtableByName (
888 Context,
889 Kext,
891 );
892 if (SuperVtable == NULL) {
893 return FALSE;
894 }
895
896 //
897 // meta_vtable_sym will be null when we don't support strict
898 // patching and can't find the metaclass vtable. If that's the
899 // case, we just reduce the expect number of vtables by 1.
900 // Only i386 does not support strict patchting.
901 //
903 Context,
904 Kext,
905 SuperVtable,
906 EntryWalker->MetaVtable,
907 EntryWalker->MetaVtableData,
908 (EntryWalker->NumSolveSymbols - EntryWalker->MetaSymsIndex),
909 &EntryWalker->SolveSymbols[EntryWalker->MetaSymsIndex],
910 CurrentVtable
911 );
912 if (!Result) {
913 DEBUG ((DEBUG_INFO, "OCAK: Failed to patch meta vtable for superclass %a\n", SuperClassName));
914 return FALSE;
915 }
916
917 CurrentVtable = GET_NEXT_PRELINKED_VTABLE (CurrentVtable);
918
919 Kext->NumberOfVtables += 2;
920
921 EntryWalker->Smcp = NULL;
922
923 ++NumPatched;
924 SuccessfulIteration = TRUE;
925 }
926
927 //
928 // Exit when there are unpatched VTables left, but there are none patched
929 // in a full iteration.
930 //
931 if (!SuccessfulIteration) {
932 return FALSE;
933 }
934 }
935
936 return TRUE;
937}
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
#define MACH_N_TYPE_STAB
UINT64 KcFixupValue(IN UINT64 Value, IN CONST CHAR8 *Name OPTIONAL)
MACH_NLIST_ANY * MachoGetLocalDefinedSymbolByName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *Name)
Definition Symbols.c:54
BOOLEAN MachoSymbolNameIsPadslot(IN CONST CHAR8 *Name)
Definition CxxSymbols.c:51
BOOLEAN MachoGetClassNameFromMetaClassPointer(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *MetaClassName, IN UINTN ClassNameSize, OUT CHAR8 *ClassName)
Definition CxxSymbols.c:204
BOOLEAN MachoGetClassNameFromSuperMetaClassPointer(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SmcpName, IN UINTN ClassNameSize, OUT CHAR8 *ClassName)
Definition CxxSymbols.c:116
BOOLEAN MachoSymbolIsLocalDefined(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:41
CONST CHAR8 * MachoGetClassNameFromVtableName(IN CONST CHAR8 *VtableName)
Definition CxxSymbols.c:152
BOOLEAN MachoGetVtableSymbolsFromSmcp(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SmcpName, OUT CONST MACH_NLIST_ANY **Vtable, OUT CONST MACH_NLIST_ANY **MetaVtable)
Definition CxxSymbols.c:413
BOOLEAN MachoGetFunctionPrefixFromClassName(IN CONST CHAR8 *ClassName, IN UINTN FunctionPrefixSize, OUT CHAR8 *FunctionPrefix)
Definition CxxSymbols.c:165
VOID * MachoGetFileData(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:66
BOOLEAN MachoGetSymbolByExternRelocationOffset(IN OUT OC_MACHO_CONTEXT *Context, IN UINT64 Address, OUT MACH_NLIST_ANY **Symbol)
Definition Symbols.c:119
BOOLEAN MachoGetFinalSymbolNameFromClassName(IN CONST CHAR8 *ClassName, IN UINTN FinalSymbolNameSize, OUT CHAR8 *FinalSymbolName)
Definition CxxSymbols.c:327
MACH_NLIST_ANY * MachoGetMetaclassSymbolFromSmcpSymbol(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Smcp)
Definition CxxSymbols.c:400
MACH_NLIST_ANY * MachoGetSymbolByIndex(IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Index)
Definition Symbols.c:67
CONST CHAR8 * MachoGetSymbolName(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:80
BOOLEAN MachoSymbolNameIsVtable(IN CONST CHAR8 *SymbolName)
Definition CxxSymbols.c:379
BOOLEAN MachoGetVtableNameFromClassName(IN CONST CHAR8 *ClassName, IN UINTN VtableNameSize, OUT CHAR8 *VtableName)
Definition CxxSymbols.c:239
BOOLEAN MachoSymbolNameIsSmcp(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SymbolName)
Definition CxxSymbols.c:60
BOOLEAN MachoSymbolIsDefined(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_NLIST_ANY *Symbol)
Definition Symbols.c:28
BOOLEAN MachoSymbolNameIsPureVirtual(IN CONST CHAR8 *Name)
Definition CxxSymbols.c:42
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
BOOLEAN MachoGetMetaVtableNameFromClassName(IN CONST CHAR8 *ClassName, IN UINTN VtableNameSize, OUT CHAR8 *VtableName)
Definition CxxSymbols.c:279
#define OS_METACLASS_VTABLE_NAME
#define SYM_MAX_NAME_LEN
#define VTABLE_ENTRY_SIZE_X(a)
#define VTABLE_HEADER_LEN
#define VTABLE_ENTRY_X(a, b, c)
#define GET_NEXT_OC_VTABLE_PATCH_ENTRY(Entry)
#define GET_NEXT_PRELINKED_VTABLE(This)
@ OcGetSymbolOnlyCxx
@ OcGetSymbolAnyLevel
VOID InternalUnlockContextKexts(IN PRELINKED_CONTEXT *Context)
CONST PRELINKED_VTABLE * InternalGetOcVtableByName(IN PRELINKED_CONTEXT *Context, IN PRELINKED_KEXT *Kext, IN CONST CHAR8 *Name)
Definition Vtables.c:75
VOID InternalCreateVtablesPrelinked(IN PRELINKED_CONTEXT *Context, IN OUT PRELINKED_KEXT *Kext, IN UINT32 NumVtables, IN CONST OC_PRELINKED_VTABLE_LOOKUP_ENTRY *VtableLookups, OUT PRELINKED_VTABLE *VtableBuffer)
Definition Vtables.c:235
STATIC BOOLEAN InternalInitializeVtablePatchData(IN OUT OC_MACHO_CONTEXT *MachoContext, IN CONST MACH_NLIST_ANY *VtableSymbol, IN OUT UINT32 *MaxSize, OUT VOID **VtableDataPtr, OUT UINT32 *NumEntries, OUT UINT32 *NumSymbols, OUT MACH_NLIST_ANY **SolveSymbols)
Definition Vtables.c:490
BOOLEAN InternalPatchByVtables(IN PRELINKED_CONTEXT *Context, IN OUT PRELINKED_KEXT *Kext)
Definition Vtables.c:584
CONST PRELINKED_VTABLE * InternalGetOcVtableByNameWorker(IN PRELINKED_CONTEXT *Context, IN PRELINKED_KEXT *Kext, IN CONST CHAR8 *Name)
Definition Vtables.c:29
STATIC BOOLEAN InternalPatchVtableSymbol(IN OUT OC_MACHO_CONTEXT *MachoContext, IN CONST PRELINKED_VTABLE_ENTRY *ParentEntry, IN CONST CHAR8 *VtableName, OUT MACH_NLIST_ANY *Symbol)
Definition Vtables.c:263
STATIC BOOLEAN InternalInitializeVtableByEntriesAndRelocations(IN PRELINKED_CONTEXT *Context, IN PRELINKED_KEXT *Kext, IN CONST PRELINKED_VTABLE *SuperVtable, IN CONST MACH_NLIST_ANY *VtableSymbol, IN CONST VOID *VtableData, IN UINT32 NumSolveSymbols, IN OUT MACH_NLIST_ANY **SolveSymbols, OUT PRELINKED_VTABLE *Vtable)
Definition Vtables.c:394
BOOLEAN InternalGetVtableEntries(IN BOOLEAN Is32Bit, IN CONST VOID *VtableData, IN UINT32 MaxSize, OUT UINT32 *NumEntries)
Definition Vtables.c:151
STATIC VOID InternalConstructVtablePrelinked(IN PRELINKED_CONTEXT *Context, IN OUT PRELINKED_KEXT *Kext, IN CONST OC_PRELINKED_VTABLE_LOOKUP_ENTRY *VtableLookup, OUT PRELINKED_VTABLE *Vtable)
Definition Vtables.c:92
BOOLEAN InternalPrepareCreateVtablesPrelinked(IN PRELINKED_KEXT *Kext, IN UINT32 MaxSize, OUT UINT32 *NumVtables, OUT OC_PRELINKED_VTABLE_LOOKUP_ENTRY *Vtables)
Definition Vtables.c:179
#define ASSERT(x)
Definition coder.h:55
UINT64 Value
value of this symbol (or stab offset)
UINT32 Value
value of this symbol (or stab offset)
CONST MACH_NLIST_ANY * MetaVtable
CONST MACH_NLIST_ANY * Smcp
CONST MACH_NLIST_ANY * Vtable
MACH_NLIST_ANY * SolveSymbols[]
PRELINKED_KEXT * Dependencies[MAX_KEXT_DEPEDENCIES]
UINT64 Address
The symbol's address.
CONST CHAR8 * Name
The symbol's name.
MACH_NLIST_64 Symbol64