mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcAppleKernelLib: Implement KXLD link state handling (#101)
This commit is contained in:
parent
399f05c361
commit
b5dcbd32d1
@ -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;
|
||||
|
||||
@ -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 (
|
||||
|
||||
107
Include/Apple/IndustryStandard/AppleKxldState.h
Normal file
107
Include/Apple/IndustryStandard/AppleKxldState.h
Normal 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
|
||||
@ -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.
|
||||
|
||||
524
Library/OcAppleKernelLib/KxldState.c
Normal file
524
Library/OcAppleKernelLib/KxldState.c
Normal 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;
|
||||
}
|
||||
@ -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]);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
Link.c
|
||||
CommonPatches.c
|
||||
KernelCollection.c
|
||||
KxldState.c
|
||||
PrelinkedContext.c
|
||||
PrelinkedInternal.h
|
||||
PrelinkedKext.c
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ OBJS = $(PROJECT).o \
|
||||
Lilu.o \
|
||||
Vsmc.o \
|
||||
KextPatcher.o \
|
||||
KxldState.o \
|
||||
PrelinkedKext.o \
|
||||
PrelinkedContext.o \
|
||||
Vtables.o \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user