OcAppleKernelLib: Implement KXLD link state handling (#101)

This commit is contained in:
vit9696 2020-08-16 00:33:56 +03:00 committed by GitHub
parent 399f05c361
commit b5dcbd32d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1011 additions and 38 deletions

View File

@ -24,10 +24,14 @@
#define PRELINK_KERNEL_IDENTIFIER "__kernel__"
#define PRELINK_KPI_IDENTIFIER_PREFIX "com.apple.kpi."
#define PRELINK_INFO_SEGMENT "__PRELINK_INFO"
#define PRELINK_INFO_SECTION "__info"
#define PRELINK_TEXT_SEGMENT "__PRELINK_TEXT"
#define PRELINK_TEXT_SECTION "__text"
#define PRELINK_INFO_SEGMENT "__PRELINK_INFO"
#define PRELINK_INFO_SECTION "__info"
#define PRELINK_TEXT_SEGMENT "__PRELINK_TEXT"
#define PRELINK_TEXT_SECTION "__text"
#define PRELINK_STATE_SEGMENT "__PRELINK_STATE"
#define PRELINK_STATE_SECTION_KERNEL "__kernel"
#define PRELINK_STATE_SECTION_KEXTS "__kexts"
#define PRELINK_INFO_DICTIONARY_KEY "_PrelinkInfoDictionary"
#define PRELINK_INFO_KMOD_INFO_KEY "_PrelinkKmodInfo"
@ -36,6 +40,8 @@
#define PRELINK_INFO_EXECUTABLE_LOAD_ADDR_KEY "_PrelinkExecutableLoadAddr"
#define PRELINK_INFO_EXECUTABLE_SOURCE_ADDR_KEY "_PrelinkExecutableSourceAddr"
#define PRELINK_INFO_EXECUTABLE_SIZE_KEY "_PrelinkExecutableSize"
#define PRELINK_INFO_LINK_STATE_ADDR_KEY "_PrelinkLinkState"
#define PRELINK_INFO_LINK_STATE_SIZE_KEY "_PrelinkLinkStateSize"
#define INFO_BUNDLE_IDENTIFIER_KEY "CFBundleIdentifier"
#define INFO_BUNDLE_EXECUTABLE_KEY "CFBundleExecutable"
@ -126,6 +132,38 @@ typedef struct {
//
MACH_SECTION_64 *PrelinkedTextSection;
//
// Pointer to PRELINK_STATE_SEGMENT (for 10.6.8).
//
MACH_SEGMENT_COMMAND_64 *PrelinkedStateSegment;
//
// Pointer to PRELINK_STATE_SECTION_KERNEL (for 10.6.8).
//
MACH_SECTION_64 *PrelinkedStateSectionKernel;
//
// Pointer to PRELINK_STATE_SECTION_KEXTS (for 10.6.8).
//
MACH_SECTION_64 *PrelinkedStateSectionKexts;
//
// Contents of PRELINK_STATE_SECTION_KERNEL section (for 10.6.8).
//
VOID *PrelinkedStateKernel;
//
// Contents of PRELINK_STATE_SECTION_KEXTS (for 10.6.8).
//
VOID *PrelinkedStateKexts;
//
// PRELINK_STATE_SECTION_KEXTS original load address.
//
UINT64 PrelinkedStateKextsAddress;
//
// PRELINK_STATE_SECTION_KERNEL section size (for 10.6.8).
//
UINT32 PrelinkedStateKernelSize;
//
// PRELINK_STATE_SECTION_KEXTS section size (for 10.6.8).
//
UINT32 PrelinkedStateKextsSize;
//
// Pointer to KC_LINKEDIT_SEGMENT (for KC mode).
//
MACH_SEGMENT_COMMAND_64 *LinkEditSegment;
@ -160,6 +198,10 @@ typedef struct {
//
XML_NODE *KextList;
//
// Plist scratch buffer used when updating values.
//
CHAR8 *KextScratchBuffer;
//
// Buffers allocated from pool for internal needs.
//
VOID **PooledBuffers;

View File

@ -84,6 +84,8 @@ AsciiStrCopyToUnicode (
@param[out] Buffer Destination buffer.
@param[in] BufferSize Destination buffer size in bytes.
@param[in] Value Value to convert.
@retval TRUE on fit
**/
BOOLEAN
AsciiUint64ToLowerHex (

View File

@ -0,0 +1,107 @@
/** @file
Copyright (C) 2020, vit9696. 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 APPLE_KXLD_STATE_H
#define APPLE_KXLD_STATE_H
#include <IndustryStandard/AppleMachoImage.h>
/**
The format of the link state object is as follows:
*****************************************************
* Field *** Type *
*****************************************************
* Link state header *** KXLD_LINK_STATE_HEADER *
*****************************************************
* Section order entries *** KXLD_SECTION_NAME *
*****************************************************
* Vtable headers *** KXLD_VTABLE_HEADER *
*****************************************************
* VTables *** KXLD_SYM_ENTRY_[32|64] *
*****************************************************
* Exported symbols *** KXLD_SYM_ENTRY_[32|64] *
*****************************************************
* String table *** CHAR8[] *
*****************************************************
**/
/**
Normal KXLD state state signature.
**/
#define KXLD_LINK_STATE_SIGNATURE 0xF00DD00D
#define KXLD_LINK_STATE_INVERT_SIGNATURE 0x0DD00DF0
/**
64-bit signature was never used even for 64-bit state
as 64-bit KXLD state header had never been defined.
**/
#define KXLD_LINK_STATE_SIGNATURE_64 0xCAFEF00D
#define KXLD_LINK_STATE_INVERT_SIGNATURE_64 0x0DF0FECA
/**
The only existent KXLD state version.
**/
#define KXLD_LINK_STATE_VERSION 1
/**
Link state header.
**/
typedef struct {
UINT32 Signature; ///< Always KXLD_LINK_STATE_SIGNATURE.
UINT32 Version; ///< Always LINK_STATE_VERSION.
MACH_CPU_TYPE CpuType; ///< Processor type as in Mach-O.
MACH_CPU_SUBTYPE CpuSubtype; ///< Processor subtype as in Mach-O.
UINT32 NumSections; ///< Unused for kernel objects.
UINT32 SectionOffset; ///< Unused for kernel objects.
UINT32 NumVtables; ///< Number of virtual table headers.
UINT32 VtableOffset; ///< Offset to virtual table headers.
UINT32 NumSymbols; ///< Number of normal symbols.
UINT32 SymbolOffset; ///< Offset to normal symbols.
} KXLD_LINK_STATE_HEADER;
#pragma pack(push, 1)
typedef struct {
UINT32 NameOffset;
UINT32 EntryOffset;
UINT32 NumEntries;
} KXLD_VTABLE_HEADER;
typedef struct {
CHAR8 SegmentName[16];
CHAR8 SectionName[16];
} KXLD_SECTION_NAME;
typedef struct {
UINT32 Address;
UINT32 NameOffset;
UINT32 Flags;
} KXLD_SYM_ENTRY_32;
typedef struct {
UINT64 Address;
UINT32 NameOffset;
UINT32 Flags;
} KXLD_SYM_ENTRY_64;
STATIC_ASSERT (sizeof (KXLD_SYM_ENTRY_32) == 12, "Invalid KXLD_SYM_ENTRY_32 size");
STATIC_ASSERT (sizeof (KXLD_SYM_ENTRY_64) == 16, "Invalid KXLD_SYM_ENTRY_64 size");
#pragma pack(pop)
/**
Symbol marked with this flag is obsolete (deprecated).
**/
#define KXLD_SYM_OBSOLETE BIT0
#endif // APPLE_KXLD_STATE_H

View File

@ -17,6 +17,7 @@
#define CACHELESS_INTERNAL_H
#include <Library/OcAppleKernelLib.h>
#include <Library/OcStringLib.h>
//
// Names are of format OcXXXXXXXX.kext, where XXXXXXXX is a 32-bit hexadecimal number.

View File

@ -0,0 +1,524 @@
/** @file
Copyright (C) 2020, vit9696. All rights reserved.
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.
**/
#include <Base.h>
#include <IndustryStandard/AppleKxldState.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcAppleKernelLib.h>
#include <Library/OcMachoLib.h>
#include <Library/OcStringLib.h>
#include <Library/OcXmlLib.h>
#include "PrelinkedInternal.h"
STATIC
CONST KXLD_LINK_STATE_HEADER *
InternalGetKxldHeader (
IN CONST VOID *KxldState,
IN UINT32 KxldStateSize,
IN MACH_CPU_TYPE CpuType
)
{
CONST KXLD_LINK_STATE_HEADER *Header;
if (KxldStateSize < sizeof (KXLD_LINK_STATE_HEADER)
|| !OC_TYPE_ALIGNED (KXLD_LINK_STATE_HEADER, KxldState)) {
return NULL;
}
Header = KxldState;
if (Header->Signature != KXLD_LINK_STATE_SIGNATURE
|| Header->Version != KXLD_LINK_STATE_VERSION
|| Header->CpuType != CpuType) {
return NULL;
}
return Header;
}
STATIC
CONST KXLD_VTABLE_HEADER *
InternalGetKxldVtables (
IN CONST VOID *KxldState,
IN UINT32 KxldStateSize,
IN MACH_CPU_TYPE CpuType,
OUT UINT32 *NumVtables
)
{
CONST KXLD_LINK_STATE_HEADER *Header;
CONST KXLD_VTABLE_HEADER *Vtables;
UINT32 SymbolSize;
UINT32 Index;
UINT32 End;
Header = InternalGetKxldHeader (KxldState, KxldStateSize, CpuType);
if (Header == NULL) {
return NULL;
}
if (Header->NumVtables == 0) {
return NULL;
}
if (CpuType == MachCpuTypeX86) {
SymbolSize = sizeof (KXLD_SYM_ENTRY_32);
if (!OC_TYPE_ALIGNED (UINT32, Header->VtableOffset)) {
return NULL;
}
} else if (CpuType == MachCpuTypeX8664) {
SymbolSize = sizeof (KXLD_SYM_ENTRY_64);
if (!OC_TYPE_ALIGNED (UINT64, Header->VtableOffset)) {
return NULL;
}
} else {
return NULL;
}
if (OcOverflowMulAddU32 (Header->NumVtables, sizeof (KXLD_VTABLE_HEADER), Header->VtableOffset, &End)
|| End > KxldStateSize) {
return NULL;
}
Vtables = (KXLD_VTABLE_HEADER *) ((UINT8 *) KxldState + Header->VtableOffset);
for (Index = 0; Index < Header->NumVtables; ++Index) {
if (OcOverflowMulAddU32 (Vtables[Index].NumEntries, SymbolSize, Vtables[Index].EntryOffset, &End)
|| End > KxldStateSize) {
return NULL;
}
}
*NumVtables = Header->NumVtables;
return Vtables;
}
STATIC
CONST VOID *
InternalGetKxldSymbols (
IN CONST VOID *KxldState,
IN UINT32 KxldStateSize,
IN MACH_CPU_TYPE CpuType,
OUT UINT32 *NumSymbols
)
{
CONST KXLD_LINK_STATE_HEADER *Header;
UINT32 SymbolSize;
UINT32 End;
Header = InternalGetKxldHeader (KxldState, KxldStateSize, CpuType);
if (Header == NULL) {
return NULL;
}
if (Header->NumSymbols == 0) {
return NULL;
}
if (CpuType == MachCpuTypeX86) {
SymbolSize = sizeof (KXLD_SYM_ENTRY_32);
if (!OC_TYPE_ALIGNED (UINT32, Header->SymbolOffset)) {
return NULL;
}
} else if (CpuType == MachCpuTypeX8664) {
SymbolSize = sizeof (KXLD_SYM_ENTRY_64);
if (!OC_TYPE_ALIGNED (UINT64, Header->SymbolOffset)) {
return NULL;
}
} else {
return NULL;
}
if (OcOverflowMulAddU32 (Header->NumSymbols, SymbolSize, Header->SymbolOffset, &End)
|| End > KxldStateSize) {
return NULL;
}
*NumSymbols = Header->NumSymbols;
return ((UINT8 *) KxldState + Header->SymbolOffset);
}
STATIC
CONST CHAR8 *
InternalGetKxldString (
IN CONST VOID *KxldState,
IN UINT32 KxldStateSize,
IN UINT32 Offset
)
{
CONST CHAR8 *SymbolWalker;
CONST CHAR8 *SymbolWalkerEnd;
if (Offset >= KxldStateSize) {
return NULL;
}
SymbolWalker = (CONST CHAR8*) KxldState + Offset;
SymbolWalkerEnd = (CONST CHAR8*) KxldState + KxldStateSize;
while (SymbolWalker < SymbolWalkerEnd) {
if (*SymbolWalker == '\0') {
return (CONST CHAR8*) KxldState + Offset;
}
++SymbolWalker;
}
return NULL;
}
EFI_STATUS
InternalKxldStateBuildLinkedSymbolTable (
IN OUT PRELINKED_KEXT *Kext,
IN PRELINKED_CONTEXT *Context
)
{
PRELINKED_KEXT_SYMBOL *SymbolTable;
PRELINKED_KEXT_SYMBOL *WalkerBottom;
PRELINKED_KEXT_SYMBOL *WalkerTop;
CONST CHAR8 *Name;
CONST KXLD_SYM_ENTRY_64 *KxldSymbols;
UINT32 Index;
UINT32 NumSymbols;
UINT32 NumCxxSymbols;
BOOLEAN Result;
ASSERT (Kext->KxldState != NULL);
ASSERT (Kext->KxldStateSize > 0);
if (Kext->LinkedSymbolTable != NULL) {
return EFI_SUCCESS;
}
KxldSymbols = InternalGetKxldSymbols (
Kext->KxldState,
Kext->KxldStateSize,
MachCpuTypeX8664,
&NumSymbols
);
if (KxldSymbols == NULL) {
return EFI_UNSUPPORTED;
}
SymbolTable = AllocatePool (NumSymbols * sizeof (*SymbolTable));
if (SymbolTable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
WalkerBottom = &SymbolTable[0];
WalkerTop = &SymbolTable[NumSymbols - 1];
NumCxxSymbols = 0;
DEBUG ((
DEBUG_VERBOSE,
"OCAK: Processing %a KXLD state with %u symbols\n",
Kext->Identifier,
NumSymbols
));
for (Index = 0; Index < NumSymbols; ++Index) {
Name = InternalGetKxldString (
Kext->KxldState,
Kext->KxldStateSize,
KxldSymbols->NameOffset
);
if (Name == NULL) {
return EFI_INVALID_PARAMETER;
}
Result = MachoSymbolNameIsCxx (Name);
DEBUG ((
DEBUG_VERBOSE,
"OCAK: Adding symbol %a with %Lx value (flags %u)\n",
Name,
KxldSymbols->Address,
KxldSymbols->Flags
));
if (!Result) {
WalkerBottom->Value = KxldSymbols->Address;
WalkerBottom->Name = Name;
WalkerBottom->Length = (UINT32)AsciiStrLen (WalkerBottom->Name);
++WalkerBottom;
} else {
WalkerTop->Value = KxldSymbols->Address;
WalkerTop->Name = Name;
WalkerTop->Length = (UINT32)AsciiStrLen (WalkerTop->Name);
--WalkerTop;
++NumCxxSymbols;
}
++KxldSymbols;
}
Kext->NumberOfSymbols = NumSymbols;
Kext->NumberOfCxxSymbols = NumCxxSymbols;
Kext->LinkedSymbolTable = SymbolTable;
return EFI_SUCCESS;
}
EFI_STATUS
InternalKxldStateBuildLinkedVtables (
IN OUT PRELINKED_KEXT *Kext,
IN PRELINKED_CONTEXT *Context
)
{
PRELINKED_VTABLE *LinkedVtables;
PRELINKED_VTABLE *CurrentVtable;
CONST KXLD_SYM_ENTRY_64 *KxldSymbols;
CONST KXLD_VTABLE_HEADER *KxldVtables;
UINT32 Index;
UINT32 Index2;
UINT32 NumVtables;
UINT32 NumEntries;
UINT32 ResultingSize;
ASSERT (Kext->KxldState != NULL);
ASSERT (Kext->KxldStateSize > 0);
if (Kext->LinkedVtables != NULL) {
return EFI_SUCCESS;
}
KxldVtables = InternalGetKxldVtables (
Kext->KxldState,
Kext->KxldStateSize,
MachCpuTypeX8664,
&NumVtables
);
if (KxldVtables == NULL) {
return EFI_UNSUPPORTED;
}
NumEntries = 0;
for (Index = 0; Index < NumVtables; ++Index) {
if (OcOverflowAddU32 (NumEntries, KxldVtables[Index].NumEntries, &NumEntries)) {
return EFI_OUT_OF_RESOURCES;
}
}
if (OcOverflowMulU32 (NumVtables, sizeof (*LinkedVtables), &ResultingSize)
|| OcOverflowMulAddU32 (NumEntries, sizeof (*LinkedVtables->Entries), ResultingSize, &ResultingSize)) {
return EFI_OUT_OF_RESOURCES;
}
LinkedVtables = AllocatePool (ResultingSize);
if (LinkedVtables == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CurrentVtable = LinkedVtables;
for (Index = 0; Index < NumVtables; ++Index) {
CurrentVtable->Name = InternalGetKxldString (
Kext->KxldState,
Kext->KxldStateSize,
KxldVtables[Index].NameOffset
);
if (CurrentVtable->Name == NULL) {
FreePool (LinkedVtables);
return EFI_INVALID_PARAMETER;
}
KxldSymbols = (KXLD_SYM_ENTRY_64 *) ((UINT8 *) Kext->KxldState + KxldVtables[Index].EntryOffset);
CurrentVtable->NumEntries = KxldVtables[Index].NumEntries;
DEBUG ((
DEBUG_VERBOSE,
"OCAK: Adding vtable %a (%u/%u) for %a of %u entries\n",
CurrentVtable->Name,
Index + 1,
NumVtables,
Kext->Identifier,
CurrentVtable->NumEntries
));
for (Index2 = 0; Index2 < CurrentVtable->NumEntries; ++Index2) {
CurrentVtable->Entries[Index2].Address = KxldSymbols->Address;
CurrentVtable->Entries[Index2].Name = InternalGetKxldString (
Kext->KxldState,
Kext->KxldStateSize,
KxldSymbols->NameOffset
);
if (CurrentVtable->Entries[Index2].Name == NULL) {
FreePool (LinkedVtables);
return EFI_INVALID_PARAMETER;
}
++KxldSymbols;
}
CurrentVtable = GET_NEXT_PRELINKED_VTABLE (CurrentVtable);
}
Kext->LinkedVtables = LinkedVtables;
Kext->NumberOfVtables = NumVtables;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InternalKxldStateRebasePlist (
IN OUT PRELINKED_CONTEXT *Context,
IN INT64 Delta
)
{
UINT32 Index;
UINT32 KextCount;
UINT32 FieldIndex;
UINT32 FieldCount;
XML_NODE *KextPlist;
CONST CHAR8 *KextPlistKey;
CHAR8 *ScratchWalker;
XML_NODE *KextPlistValue;
UINT64 KxldState;
KextCount = XmlNodeChildren (Context->KextList);
Context->KextScratchBuffer = ScratchWalker = AllocatePool (KextCount * KEXT_OFFSET_STR_LEN);
if (Context->KextScratchBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < KextCount; ++Index) {
KextPlist = PlistNodeCast (XmlNodeChild (Context->KextList, Index), PLIST_NODE_TYPE_DICT);
if (KextPlist == NULL) {
continue;
}
FieldCount = PlistDictChildren (KextPlist);
for (FieldIndex = 0; FieldIndex < FieldCount; ++FieldIndex) {
KextPlistKey = PlistKeyValue (PlistDictChild (KextPlist, FieldIndex, &KextPlistValue));
if (KextPlistKey == NULL) {
continue;
}
if (AsciiStrCmp (KextPlistKey, PRELINK_INFO_LINK_STATE_ADDR_KEY) == 0) {
if (!PlistIntegerValue (KextPlistValue, &KxldState, sizeof (KxldState), TRUE)) {
return EFI_INVALID_PARAMETER;
}
DEBUG ((DEBUG_VERBOSE, "OCAK: Shifting 0x%Lx to 0x%Lx\n", KxldState, KxldState + Delta));
KxldState += Delta;
AsciiUint64ToLowerHex (ScratchWalker, KEXT_OFFSET_STR_LEN, KxldState);
XmlNodeChangeContent (KextPlistValue, ScratchWalker);
ScratchWalker += AsciiStrSize (ScratchWalker);
}
}
}
return EFI_SUCCESS;
}
EFI_STATUS
InternalKxldStateRebuild (
IN OUT PRELINKED_CONTEXT *Context
)
{
EFI_STATUS Status;
UINT32 AlignedSize;
UINT32 NewSize;
//
// This is a requirement from 10.6.8, should be guaranteed?
//
ASSERT (OC_POT_ALIGNED (MACHO_PAGE_SIZE, Context->PrelinkedLastAddress));
//
// Append prelink state for 10.6.8
//
AlignedSize = MACHO_ALIGN (Context->PrelinkedStateKernelSize);
if (OcOverflowAddU32 (Context->PrelinkedSize, AlignedSize, &NewSize)
|| NewSize > Context->PrelinkedAllocSize) {
return EFI_BUFFER_TOO_SMALL;
}
Context->PrelinkedStateSegment->VirtualAddress = Context->PrelinkedLastAddress;
Context->PrelinkedStateSegment->Size = AlignedSize;
Context->PrelinkedStateSegment->FileOffset = Context->PrelinkedSize;
Context->PrelinkedStateSegment->FileSize = AlignedSize;
Context->PrelinkedStateSectionKernel->Address = Context->PrelinkedLastAddress;
Context->PrelinkedStateSectionKernel->Offset = Context->PrelinkedSize;
Context->PrelinkedStateSectionKernel->Size = Context->PrelinkedStateKernelSize;
CopyMem (
&Context->Prelinked[Context->PrelinkedSize],
Context->PrelinkedStateKernel,
Context->PrelinkedStateKernelSize
);
ZeroMem (
&Context->Prelinked[Context->PrelinkedSize + Context->PrelinkedStateKernelSize],
AlignedSize - Context->PrelinkedStateKernelSize
);
Context->PrelinkedLastAddress += AlignedSize;
Context->PrelinkedSize += AlignedSize;
AlignedSize = MACHO_ALIGN (Context->PrelinkedStateKextsSize);
if (OcOverflowAddU32 (Context->PrelinkedSize, AlignedSize, &NewSize)
|| NewSize > Context->PrelinkedAllocSize) {
return EFI_BUFFER_TOO_SMALL;
}
Context->PrelinkedStateSegment->Size += AlignedSize;
Context->PrelinkedStateSegment->FileSize += AlignedSize;
Context->PrelinkedStateSectionKexts->Address = Context->PrelinkedLastAddress;
Context->PrelinkedStateSectionKexts->Offset = Context->PrelinkedSize;
Context->PrelinkedStateSectionKexts->Size = Context->PrelinkedStateKextsSize;
CopyMem (
&Context->Prelinked[Context->PrelinkedSize],
Context->PrelinkedStateKexts,
Context->PrelinkedStateKextsSize
);
ZeroMem (
&Context->Prelinked[Context->PrelinkedSize + Context->PrelinkedStateKextsSize],
AlignedSize - Context->PrelinkedStateKextsSize
);
Context->PrelinkedLastAddress += AlignedSize;
Context->PrelinkedSize += AlignedSize;
if (Context->PrelinkedStateSectionKexts->Address != Context->PrelinkedStateKextsAddress) {
Status = InternalKxldStateRebasePlist (
Context,
(INT64) (Context->PrelinkedStateSectionKexts->Address - Context->PrelinkedStateKextsAddress)
);
DEBUG ((
DEBUG_INFO,
"OCAK: Rebasing KXLD state from %Lx to %Lx - %r\n",
Context->PrelinkedStateKextsAddress,
Context->PrelinkedStateSectionKexts->Address,
Status
));
} else {
Status = EFI_SUCCESS;
}
return Status;
}

View File

@ -17,7 +17,6 @@
#include <IndustryStandard/AppleFatBinaryImage.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@ -28,7 +27,7 @@
#include <Library/OcGuardLib.h>
#include <Library/OcStringLib.h>
#define MKEXT_OFFSET_STR_LEN 24
#include "PrelinkedInternal.h"
//
// Alignment to 8 bytes.
@ -472,7 +471,7 @@ MkextDecompress (
BinaryOffsetStrings = NULL;
if (Decompress) {
if (OcOverflowTriMulU32 (PlistBundlesCount, MKEXT_OFFSET_STR_LEN, sizeof (CHAR8), &BinaryOffsetStringsSize)) {
if (OcOverflowTriMulU32 (PlistBundlesCount, KEXT_OFFSET_STR_LEN, sizeof (CHAR8), &BinaryOffsetStringsSize)) {
XmlDocumentFree (PlistXml);
FreePool (PlistBuffer);
return EFI_INVALID_PARAMETER;
@ -577,8 +576,8 @@ MkextDecompress (
}
if (!AsciiUint64ToLowerHex (
&BinaryOffsetStrings[Index * MKEXT_OFFSET_STR_LEN],
MKEXT_OFFSET_STR_LEN,
&BinaryOffsetStrings[Index * KEXT_OFFSET_STR_LEN],
KEXT_OFFSET_STR_LEN,
CurrentOffset
)) {
XmlDocumentFree (PlistXml);
@ -586,7 +585,7 @@ MkextDecompress (
FreePool (BinaryOffsetStrings);
return EFI_INVALID_PARAMETER;
}
XmlNodeChangeContent (BundleExecutable, &BinaryOffsetStrings[Index * MKEXT_OFFSET_STR_LEN]);
XmlNodeChangeContent (BundleExecutable, &BinaryOffsetStrings[Index * KEXT_OFFSET_STR_LEN]);
}
//

View File

@ -34,6 +34,7 @@
Link.c
CommonPatches.c
KernelCollection.c
KxldState.c
PrelinkedContext.c
PrelinkedInternal.h
PrelinkedKext.c

View File

@ -353,10 +353,10 @@ PrelinkedContextInit (
return EFI_NOT_FOUND;
}
//
// Additionally process special entries for KC.
//
if (Context->IsKernelCollection) {
//
// Additionally process special entries for KC.
//
Status = PrelinkedGetSegmentsFromMacho (
&Context->InnerMachContext,
&Context->InnerInfoSegment,
@ -388,6 +388,7 @@ PrelinkedContextInit (
&Context->Prelinked[Context->PrelinkedInfoSection->Offset]
);
if (Context->PrelinkedInfo == NULL) {
PrelinkedContextFree (Context);
return EFI_OUT_OF_RESOURCES;
}
@ -468,6 +469,11 @@ PrelinkedContextFree (
Context->PrelinkedInfoDocument = NULL;
}
if (Context->KextScratchBuffer != NULL) {
FreePool (Context->KextScratchBuffer);
Context->KextScratchBuffer = NULL;
}
if (Context->PrelinkedInfo != NULL) {
FreePool (Context->PrelinkedInfo);
Context->PrelinkedInfo = NULL;
@ -487,6 +493,16 @@ PrelinkedContextFree (
Context->LinkBuffer = NULL;
}
if (Context->PrelinkedStateKernel != NULL) {
FreePool (Context->PrelinkedStateKernel);
Context->PrelinkedStateKernel = NULL;
}
if (Context->PrelinkedStateKexts != NULL) {
FreePool (Context->PrelinkedStateKexts);
Context->PrelinkedStateKexts = NULL;
}
while (!IsListEmpty (&Context->PrelinkedKexts)) {
Link = GetFirstNode (&Context->PrelinkedKexts);
Kext = GET_PRELINKED_KEXT_FROM_LINK (Link);
@ -573,7 +589,40 @@ PrelinkedInjectPrepare (
// For older variant of the prelinkedkernel plist info is normally
// the last segment, so we may potentially save some data by removing
// it and then appending new kexts over. This is different for KC,
// where plist info is in the middle of the file.
// where plist info is in the middle of the file. For 10.6.8 we will
// also need to move __PRELINK_STATE, which is just some blob for kextd.
//
// 10.6.8
//
// ffffff8000200000 - ffffff8000600000 (at 0000000000000000 - 0000000000400000) - __TEXT
// ffffff8000600000 - ffffff80006da000 (at 0000000000400000 - 000000000046f000) - __DATA
// ffffff8000106000 - ffffff8000107000 (at 000000000046f000 - 0000000000470000) - __INITGDT
// ffffff8000100000 - ffffff8000106000 (at 0000000000470000 - 0000000000476000) - __INITPT
// ffffff80006da000 - ffffff80006db000 (at 0000000000476000 - 0000000000477000) - __DESC
// ffffff80006db000 - ffffff80006dc000 (at 0000000000477000 - 0000000000478000) - __VECTORS
// ffffff8000108000 - ffffff800010e000 (at 0000000000478000 - 000000000047d000) - __HIB
// ffffff8000107000 - ffffff8000108000 (at 000000000047d000 - 000000000047e000) - __SLEEP
// ffffff80006dc000 - ffffff80006de000 (at 000000000047e000 - 0000000000480000) - __KLD
// ffffff80006de000 - ffffff80006de000 (at 0000000000480000 - 0000000000480000) - __LAST
// ffffff8000772000 - ffffff800100a000 (at 0000000000514000 - 0000000000dac000) - __PRELINK_TEXT
// ffffff800100a000 - ffffff800155c000 (at 0000000000dac000 - 00000000012fe000) - __PRELINK_STATE
// ffffff800155c000 - ffffff8001612000 (at 00000000012fe000 - 00000000013b4000) - __PRELINK_INFO
// 0000000000000000 - 0000000000000000 (at 0000000000513018 - 0000000000551269) - __CTF
// ffffff80006de000 - ffffff8000771018 (at 0000000000480000 - 0000000000513018) - __LINKEDIT
//
// 10.15.6
//
// ffffff8000200000 - ffffff8000c00000 (at 0000000000000000 - 0000000000a00000) - __TEXT
// ffffff8000c00000 - ffffff8000e70000 (at 0000000000a00000 - 0000000000c70000) - __DATA
// ffffff8000e70000 - ffffff8000ea9000 (at 0000000000c70000 - 0000000000ca9000) - __DATA_CONST
// ffffff8000100000 - ffffff800019e000 (at 0000000000ca9000 - 0000000000d47000) - __HIB
// ffffff8000ea9000 - ffffff8000eaa000 (at 0000000000d47000 - 0000000000d48000) - __VECTORS
// ffffff8000eaa000 - ffffff8000ec4000 (at 0000000000d48000 - 0000000000d62000) - __KLD
// ffffff8000ec4000 - ffffff8000ec5000 (at 0000000000d62000 - 0000000000d63000) - __LAST
// ffffff8001036000 - ffffff8002e24000 (at 0000000000f48000 - 0000000002d36000) - __PRELINK_TEXT
// ffffff8002e24000 - ffffff80030d2000 (at 0000000002d36000 - 0000000002fe3389) - __PRELINK_INFO
// ffffff8000ec5000 - ffffff8000ec5000 (at 0000000000d63000 - 0000000000dd7000) - __CTF
// ffffff8000ec5000 - ffffff80010358a8 (at 0000000000dd7000 - 0000000000f478a8) - __LINKEDIT
//
SegmentEndOffset = Context->PrelinkedInfoSegment->FileOffset + Context->PrelinkedInfoSegment->FileSize;
@ -581,7 +630,7 @@ PrelinkedInjectPrepare (
DEBUG ((
DEBUG_INFO,
"OCAK: Reducing prelink size from %X to %X via plist\n",
Context->PrelinkedSize,
Context->PrelinkedSize,
(UINT32) MACHO_ALIGN (Context->PrelinkedInfoSegment->FileOffset)
));
Context->PrelinkedSize = (UINT32) MACHO_ALIGN (Context->PrelinkedInfoSegment->FileOffset);
@ -589,11 +638,47 @@ PrelinkedInjectPrepare (
DEBUG ((
DEBUG_INFO,
"OCAK:Leaving unchanged prelink size %X due to %LX plist\n",
Context->PrelinkedSize,
Context->PrelinkedSize,
SegmentEndOffset
));
}
if (Context->PrelinkedStateSegment != NULL) {
SegmentEndOffset = Context->PrelinkedStateSegment->FileOffset + Context->PrelinkedStateSegment->FileSize;
if (MACHO_ALIGN (SegmentEndOffset) == Context->PrelinkedSize) {
DEBUG ((
DEBUG_INFO,
"OCAK: Reducing prelink size from %X to %X via state\n",
Context->PrelinkedSize,
(UINT32) MACHO_ALIGN (Context->PrelinkedStateSegment->FileOffset)
));
Context->PrelinkedSize = (UINT32) MACHO_ALIGN (Context->PrelinkedStateSegment->FileOffset);
//
// Need to NULL this, as they are used in address calculations
// in e.g. MachoGetLastAddress64.
//
Context->PrelinkedStateSegment->VirtualAddress = 0;
Context->PrelinkedStateSegment->Size = 0;
Context->PrelinkedStateSegment->FileOffset = 0;
Context->PrelinkedStateSegment->FileSize = 0;
Context->PrelinkedStateSectionKernel->Address = 0;
Context->PrelinkedStateSectionKernel->Size = 0;
Context->PrelinkedStateSectionKernel->Offset = 0;
Context->PrelinkedStateSectionKexts->Address = 0;
Context->PrelinkedStateSectionKexts->Size = 0;
Context->PrelinkedStateSectionKexts->Offset = 0;
} else {
DEBUG ((
DEBUG_INFO,
"OCAK:Leaving unchanged prelink size %X due to %LX state\n",
Context->PrelinkedSize,
SegmentEndOffset
));
}
}
Context->PrelinkedInfoSegment->VirtualAddress = 0;
Context->PrelinkedInfoSegment->Size = 0;
Context->PrelinkedInfoSegment->FileOffset = 0;
@ -666,6 +751,11 @@ PrelinkedInjectComplete (
if (EFI_ERROR (Status)) {
return Status;
}
} else if (Context->PrelinkedStateSegment != NULL && Context->PrelinkedStateSegment->VirtualAddress == 0) {
Status = InternalKxldStateRebuild (Context);
if (EFI_ERROR (Status)) {
return Status;
}
}
ExportedInfo = XmlDocumentExport (Context->PrelinkedInfoDocument, &ExportedInfoSize, 0, FALSE);

View File

@ -27,6 +27,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
#define MAX_KEXT_DEPEDENCIES 16
//
// Aligned maximum virtual address size with 0x prefix and \0 terminator.
//
#define KEXT_OFFSET_STR_LEN 24
typedef struct PRELINKED_KEXT_ PRELINKED_KEXT;
typedef struct {
@ -113,6 +118,14 @@ struct PRELINKED_KEXT_ {
//
UINT32 NumberOfCxxSymbols;
//
// Pointer to KXLD state (read only, it is allocated in PrelinkedStateKexts).
//
CONST VOID *KxldState;
//
// Pointer to KXLD state (read only, it is allocated in PrelinkedStateKexts).
//
UINT32 KxldStateSize;
//
// Sorted symbol table used only for dependencies.
//
PRELINKED_KEXT_SYMBOL *LinkedSymbolTable;
@ -417,4 +430,44 @@ InternalPrelinkKext64 (
IN UINT64 LoadAddress
);
/**
Build symbol table from KXLD state.
@param[in,out] Kext Kext dependency.
@param[in] Context Prelinking context.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
InternalKxldStateBuildLinkedSymbolTable (
IN OUT PRELINKED_KEXT *Kext,
IN PRELINKED_CONTEXT *Context
);
/**
Build virtual tables from KXLD state.
@param[in,out] Kext Kext dependency.
@param[in] Context Prelinking context.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
InternalKxldStateBuildLinkedVtables (
IN OUT PRELINKED_KEXT *Kext,
IN PRELINKED_CONTEXT *Context
);
/**
Update KXLD state in the resulting image.
@param[in,out] Context Prelinking context.
@retval EFI_SUCCESS on success.
**/
EFI_STATUS
InternalKxldStateRebuild (
IN OUT PRELINKED_CONTEXT *Context
);
#endif // PRELINKED_INTERNAL_H

View File

@ -58,6 +58,9 @@ InternalCreatePrelinkedKext (
UINT64 CalculatedSourceSize;
UINT64 SourceEnd;
MACH_SEGMENT_COMMAND_64 *BaseSegment;
UINT64 KxldState;
UINT64 KxldOffset;
UINT32 KxldStateSize;
UINT32 ContainerOffset;
BOOLEAN Found;
@ -69,6 +72,8 @@ InternalCreatePrelinkedKext (
VirtualKmod = 0;
SourceBase = 0;
SourceSize = 0;
KxldState = 0;
KxldStateSize = 0;
Found = Identifier == NULL;
@ -121,10 +126,27 @@ InternalCreatePrelinkedKext (
if (!PlistIntegerValue (KextPlistValue, &SourceSize, sizeof (SourceSize), TRUE)) {
break;
}
} else if (Prelinked != NULL && KxldState == 0 && AsciiStrCmp (KextPlistKey, PRELINK_INFO_LINK_STATE_ADDR_KEY) == 0) {
if (!PlistIntegerValue (KextPlistValue, &KxldState, sizeof (KxldState), TRUE)) {
break;
}
} else if (Prelinked != NULL && KxldStateSize == 0 && AsciiStrCmp (KextPlistKey, PRELINK_INFO_LINK_STATE_SIZE_KEY) == 0) {
if (!PlistIntegerValue (KextPlistValue, &KxldStateSize, sizeof (KxldStateSize), TRUE)) {
break;
}
}
if (KextIdentifier != NULL && BundleLibraries64 != NULL && CompatibleVersion != NULL
&& (Prelinked == NULL || (Prelinked != NULL && VirtualBase != 0 && VirtualKmod != 0 && SourceBase != 0 && SourceSize != 0))) {
if (KextIdentifier != NULL
&& BundleLibraries64 != NULL
&& CompatibleVersion != NULL
&& (Prelinked == NULL
|| (Prelinked != NULL
&& VirtualBase != 0
&& VirtualKmod != 0
&& SourceBase != 0
&& SourceSize != 0
&& KxldState != 0
&& KxldStateSize != 0))) {
break;
}
}
@ -132,8 +154,14 @@ InternalCreatePrelinkedKext (
//
// BundleLibraries, CompatibleVersion, and KmodInfo are optional and thus not checked.
//
if (!Found || KextIdentifier == NULL || SourceBase < VirtualBase
|| (Prelinked != NULL && (VirtualBase == 0 || SourceBase == 0 || SourceSize == 0 || SourceSize > MAX_UINT32))) {
if (!Found
|| KextIdentifier == NULL
|| SourceBase < VirtualBase
|| (Prelinked != NULL
&& (VirtualBase == 0
|| SourceBase == 0
|| SourceSize == 0
|| SourceSize > MAX_UINT32))) {
return NULL;
}
@ -192,6 +220,22 @@ InternalCreatePrelinkedKext (
NewKext->Context.VirtualBase = VirtualBase;
NewKext->Context.VirtualKmod = VirtualKmod;
//
// Provide pointer to 10.6.8 KXLD state.
//
if (Prelinked != NULL
&& KxldState != 0
&& KxldStateSize != 0
&& Prelinked->PrelinkedStateKextsAddress != 0
&& Prelinked->PrelinkedStateKextsAddress <= KxldState
&& Prelinked->PrelinkedStateKextsSize >= KxldStateSize) {
KxldOffset = KxldState - Prelinked->PrelinkedStateKextsAddress;
if (KxldOffset <= Prelinked->PrelinkedStateKextsSize - KxldStateSize) {
NewKext->KxldState = (UINT8 *)Prelinked->PrelinkedStateKexts + KxldOffset;
NewKext->KxldStateSize = KxldStateSize;
}
}
return NewKext;
}
@ -202,8 +246,14 @@ InternalScanCurrentPrelinkedKextLinkInfo (
IN PRELINKED_CONTEXT *Context
)
{
if (Kext->LinkEditSegment == NULL) {
DEBUG ((DEBUG_VERBOSE, "OCAK: Requesting __LINKEDIT for %a\n", Kext->Identifier));
//
// Prefer KXLD state when available.
//
if (Kext->KxldState != NULL) {
return;
}
if (Kext->LinkEditSegment == NULL && Kext->NumberOfSymbols == 0) {
if (AsciiStrCmp (Kext->Identifier, PRELINK_KERNEL_IDENTIFIER) == 0) {
Kext->LinkEditSegment = Context->LinkEditSegment;
} else {
@ -212,10 +262,16 @@ InternalScanCurrentPrelinkedKextLinkInfo (
"__LINKEDIT"
);
}
DEBUG ((
DEBUG_VERBOSE,
"OCAK: Requesting __LINKEDIT for %a - %p at %p\n",
Kext->Identifier,
Kext->LinkEditSegment,
(UINT8 *) MachoGetMachHeader64 (&Kext->Context.MachContext) - Context->Prelinked
));
}
if (Kext->SymbolTable == NULL) {
DEBUG ((DEBUG_VERBOSE, "OCAK: Requesting SymbolTable for %a\n", Kext->Identifier));
if (Kext->SymbolTable == NULL && Kext->NumberOfSymbols == 0) {
Kext->NumberOfSymbols = MachoGetSymbolTable (
&Kext->Context.MachContext,
&Kext->SymbolTable,
@ -227,6 +283,12 @@ InternalScanCurrentPrelinkedKextLinkInfo (
NULL,
NULL
);
DEBUG ((
DEBUG_VERBOSE,
"OCAK: Requesting SymbolTable for %a - %u\n",
Kext->Identifier,
Kext->NumberOfSymbols
));
}
}
@ -367,6 +429,7 @@ InternalScanBuildLinkedVtables (
UINT32 NumEntriesTemp;
UINT32 Index;
UINT32 VtableMaxSize;
UINT32 ResultingSize;
CONST UINT64 *VtableData;
PRELINKED_VTABLE *LinkedVtables;
@ -418,13 +481,17 @@ InternalScanBuildLinkedVtables (
VtableLookups[Index].Vtable.Data = VtableData;
NumEntries += NumEntriesTemp;
if (OcOverflowAddU32 (NumEntries, NumEntriesTemp, &NumEntries)) {
return EFI_OUT_OF_RESOURCES;
}
}
LinkedVtables = AllocatePool (
(NumVtables * sizeof (*LinkedVtables))
+ (NumEntries * sizeof (*LinkedVtables->Entries))
);
if (OcOverflowMulU32 (NumVtables, sizeof (*LinkedVtables), &ResultingSize)
|| OcOverflowMulAddU32 (NumEntries, sizeof (*LinkedVtables->Entries), ResultingSize, &ResultingSize)) {
return EFI_OUT_OF_RESOURCES;
}
LinkedVtables = AllocatePool (ResultingSize);
if (LinkedVtables == NULL) {
return EFI_OUT_OF_RESOURCES;
}
@ -662,6 +729,68 @@ InternalCachedPrelinkedKernel (
NewKext->Context.VirtualBase = Segment->VirtualAddress - Segment->FileOffset;
NewKext->Context.VirtualKmod = 0;
if (!Prelinked->IsKernelCollection) {
//
// Find optional __PRELINK_STATE segment, present in 10.6.8
//
Prelinked->PrelinkedStateSegment = MachoGetSegmentByName64 (
&Prelinked->PrelinkedMachContext,
PRELINK_STATE_SEGMENT
);
if (Prelinked->PrelinkedStateSegment != NULL) {
Prelinked->PrelinkedStateSectionKernel = MachoGetSectionByName64 (
&Prelinked->PrelinkedMachContext,
Prelinked->PrelinkedStateSegment,
PRELINK_STATE_SECTION_KERNEL
);
Prelinked->PrelinkedStateSectionKexts = MachoGetSectionByName64 (
&Prelinked->PrelinkedMachContext,
Prelinked->PrelinkedStateSegment,
PRELINK_STATE_SECTION_KEXTS
);
if (Prelinked->PrelinkedStateSectionKernel != NULL
&& Prelinked->PrelinkedStateSectionKexts != NULL
&& Prelinked->PrelinkedStateSectionKernel->Size > 0
&& Prelinked->PrelinkedStateSectionKexts->Size > 0) {
Prelinked->PrelinkedStateKernelSize = (UINT32) Prelinked->PrelinkedStateSectionKernel->Size;
Prelinked->PrelinkedStateKextsSize = (UINT32) Prelinked->PrelinkedStateSectionKexts->Size;
Prelinked->PrelinkedStateKernel = AllocateCopyPool (
Prelinked->PrelinkedStateKernelSize,
&Prelinked->Prelinked[Prelinked->PrelinkedStateSectionKernel->Offset]
);
Prelinked->PrelinkedStateKexts = AllocateCopyPool (
Prelinked->PrelinkedStateKextsSize,
&Prelinked->Prelinked[Prelinked->PrelinkedStateSectionKexts->Offset]
);
}
if (Prelinked->PrelinkedStateKernel != NULL
&& Prelinked->PrelinkedStateKexts != NULL) {
Prelinked->PrelinkedStateKextsAddress = Prelinked->PrelinkedStateSectionKexts->Address;
NewKext->KxldState = Prelinked->PrelinkedStateKernel;
NewKext->KxldStateSize = Prelinked->PrelinkedStateKernelSize;
} else {
DEBUG ((
DEBUG_INFO,
"OCAK: Ignoring unused PK state __kernel %p __kexts %p\n",
Prelinked->PrelinkedStateSectionKernel,
Prelinked->PrelinkedStateSectionKexts
));
if (Prelinked->PrelinkedStateKernel != NULL) {
FreePool (Prelinked->PrelinkedStateKernel);
}
if (Prelinked->PrelinkedStateKexts != NULL) {
FreePool (Prelinked->PrelinkedStateKexts);
}
Prelinked->PrelinkedStateSectionKernel = NULL;
Prelinked->PrelinkedStateSectionKexts = NULL;
Prelinked->PrelinkedStateSegment = NULL;
}
}
}
InsertTailList (&Prelinked->PrelinkedKexts, &NewKext->Link);
return NewKext;
@ -758,9 +887,9 @@ InternalScanPrelinkedKext (
// _PrelinkExecutableLoadAddr / _PrelinkExecutableSourceAddr values equal to MAX_INT64.
// Skip them early to improve performance.
//
if (Context->IsKernelCollection
if ((Context->IsKernelCollection || Context->PrelinkedStateSegment != NULL)
&& AsciiStrnCmp (DependencyId, "com.apple.kpi.", L_STR_LEN ("com.apple.kpi.")) == 0) {
DEBUG ((DEBUG_VERBOSE, "OCAK: Ignoring KPI %a for kext %a in KC mode\n", DependencyId, Kext->Identifier));
DEBUG ((DEBUG_VERBOSE, "OCAK: Ignoring KPI %a for kext %a in KC/state mode\n", DependencyId, Kext->Identifier));
continue;
}
@ -810,14 +939,38 @@ InternalScanPrelinkedKext (
// Collect data to enable linking against this KEXT.
//
if (Dependency) {
Status = InternalScanBuildLinkedSymbolTable (Kext, Context);
if (EFI_ERROR (Status)) {
return Status;
}
if (Kext->KxldState != NULL) {
//
// Use KXLD state as is for 10.6.8 kernel.
//
Status = InternalKxldStateBuildLinkedSymbolTable (
Kext,
Context
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = InternalScanBuildLinkedVtables (Kext, Context);
if (EFI_ERROR (Status)) {
return Status;
Status = InternalKxldStateBuildLinkedVtables (
Kext,
Context
);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
//
// Use normal LINKEDIT building for newer kernels and all kexts.
//
Status = InternalScanBuildLinkedSymbolTable (Kext, Context);
if (EFI_ERROR (Status)) {
return Status;
}
Status = InternalScanBuildLinkedVtables (Kext, Context);
if (EFI_ERROR (Status)) {
return Status;
}
}
}

View File

@ -9,6 +9,7 @@ OBJS = $(PROJECT).o \
Lilu.o \
Vsmc.o \
KextPatcher.o \
KxldState.o \
PrelinkedKext.o \
PrelinkedContext.o \
Vtables.o \