mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
662 lines
17 KiB
C
662 lines
17 KiB
C
/** @file
|
|
Copyright (C) 2019, 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/AppleKmodInfo.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/OcAppleKernelLib.h>
|
|
#include <Library/OcMachoLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/OcXmlLib.h>
|
|
|
|
#include "MkextInternal.h"
|
|
#include "PrelinkedInternal.h"
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
GetTextBaseOffset (
|
|
IN OC_MACHO_CONTEXT *ExecutableContext,
|
|
OUT UINT64 *Address,
|
|
OUT UINT64 *Offset
|
|
)
|
|
{
|
|
MACH_SEGMENT_COMMAND *Segment32;
|
|
MACH_SECTION *Section32;
|
|
MACH_SEGMENT_COMMAND_64 *Segment64;
|
|
|
|
UINT64 VirtualAddress;
|
|
UINT64 FileOffset;
|
|
|
|
//
|
|
// 32-bit can be of type MH_OBJECT, which has all sections in a single unnamed segment.
|
|
// We'll fallback to that if there is no __TEXT segment.
|
|
//
|
|
if (ExecutableContext->Is32Bit) {
|
|
Segment32 = MachoGetNextSegment32 (ExecutableContext, NULL);
|
|
if (Segment32 == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (AsciiStrCmp (Segment32->SegmentName, "") == 0) {
|
|
Section32 = MachoGetSectionByName32 (
|
|
ExecutableContext,
|
|
Segment32,
|
|
"__text"
|
|
);
|
|
if (Section32 == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
VirtualAddress = Section32->Address;
|
|
FileOffset = Section32->Offset;
|
|
} else {
|
|
Segment32 = MachoGetSegmentByName32 (
|
|
ExecutableContext,
|
|
"__TEXT"
|
|
);
|
|
if ((Segment32 == NULL) || (Segment32->VirtualAddress < Segment32->FileOffset)) {
|
|
return FALSE;
|
|
}
|
|
|
|
VirtualAddress = Segment32->VirtualAddress;
|
|
FileOffset = Segment32->FileOffset;
|
|
}
|
|
} else {
|
|
Segment64 = MachoGetSegmentByName64 (
|
|
ExecutableContext,
|
|
"__TEXT"
|
|
);
|
|
if ((Segment64 == NULL) || (Segment64->VirtualAddress < Segment64->FileOffset)) {
|
|
return FALSE;
|
|
}
|
|
|
|
VirtualAddress = Segment64->VirtualAddress;
|
|
FileOffset = Segment64->FileOffset;
|
|
}
|
|
|
|
*Address = VirtualAddress;
|
|
*Offset = FileOffset;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherInitContextFromPrelinked (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN OUT PRELINKED_CONTEXT *Prelinked,
|
|
IN CONST CHAR8 *Name
|
|
)
|
|
{
|
|
PRELINKED_KEXT *Kext;
|
|
|
|
Kext = InternalCachedPrelinkedKext (Prelinked, Name);
|
|
if (Kext == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
CopyMem (Context, &Kext->Context, sizeof (*Context));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherInitContextFromMkext (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN OUT MKEXT_CONTEXT *Mkext,
|
|
IN CONST CHAR8 *Name
|
|
)
|
|
{
|
|
MKEXT_KEXT *Kext;
|
|
|
|
Kext = InternalCachedMkextKext (Mkext, Name);
|
|
if (Kext == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return PatcherInitContextFromBuffer (Context, &Mkext->Mkext[Kext->BinaryOffset], Kext->BinarySize, Mkext->Is32Bit);
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherInitContextFromBuffer (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN OUT UINT8 *Buffer,
|
|
IN UINT32 BufferSize,
|
|
IN BOOLEAN Is32Bit
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
OC_MACHO_CONTEXT InnerContext;
|
|
|
|
UINT64 VirtualAddress;
|
|
UINT64 FileOffset;
|
|
|
|
ASSERT (Context != NULL);
|
|
ASSERT (Buffer != NULL);
|
|
ASSERT (BufferSize > 0);
|
|
|
|
//
|
|
// This interface is still used for the kernel due to the need to patch
|
|
// standalone kernel outside of prelinkedkernel in e.g. 10.9.
|
|
// Once 10.9 support is dropped one could call PatcherInitContextFromPrelinked
|
|
// and request PRELINK_KERNEL_IDENTIFIER.
|
|
//
|
|
|
|
if (!MachoInitializeContext (&Context->MachContext, Buffer, BufferSize, 0, BufferSize, Is32Bit)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: %a-bit patcher init from buffer %p %u has unsupported mach-o\n",
|
|
Is32Bit ? "32" : "64",
|
|
Buffer,
|
|
BufferSize
|
|
));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!GetTextBaseOffset (&Context->MachContext, &VirtualAddress, &FileOffset)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Context->Is32Bit = Is32Bit;
|
|
Context->VirtualBase = VirtualAddress;
|
|
Context->FileOffset = FileOffset;
|
|
Context->VirtualKmod = 0;
|
|
Context->KxldState = NULL;
|
|
Context->KxldStateSize = 0;
|
|
Context->IsKernelCollection = FALSE;
|
|
|
|
KextFindKmodAddress (
|
|
&Context->MachContext,
|
|
0,
|
|
BufferSize,
|
|
&Context->VirtualKmod
|
|
);
|
|
|
|
if (!Context->Is32Bit) {
|
|
Status = InternalConnectExternalSymtab (
|
|
&Context->MachContext,
|
|
&InnerContext,
|
|
Buffer,
|
|
BufferSize,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_VERBOSE,
|
|
"OCAK: %a-bit patcher base 0x%llX kmod 0x%llX file 0x%llX\n",
|
|
Is32Bit ? "32" : "64",
|
|
Context->VirtualBase,
|
|
Context->VirtualKmod,
|
|
Context->FileOffset
|
|
));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherGetSymbolAddress (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN CONST CHAR8 *Name,
|
|
IN OUT UINT8 **Address
|
|
)
|
|
{
|
|
return PatcherGetSymbolAddressValue (Context, Name, Address, NULL);
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherGetSymbolValue (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN CONST CHAR8 *Name,
|
|
IN OUT UINT64 *Value
|
|
)
|
|
{
|
|
return PatcherGetSymbolAddressValue (Context, Name, NULL, Value);
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherGetSymbolAddressValue (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN CONST CHAR8 *Name,
|
|
IN OUT UINT8 **Address,
|
|
IN OUT UINT64 *Value
|
|
)
|
|
{
|
|
MACH_NLIST_ANY *Symbol;
|
|
CONST CHAR8 *SymbolName;
|
|
UINT64 SymbolAddress;
|
|
UINT32 Offset;
|
|
UINT32 Index;
|
|
|
|
Index = 0;
|
|
Offset = 0;
|
|
while (TRUE) {
|
|
//
|
|
// Try the usual way first via SYMTAB.
|
|
//
|
|
Symbol = MachoGetSymbolByIndex (&Context->MachContext, Index);
|
|
if (Symbol == NULL) {
|
|
//
|
|
// If we have KxldState, use it.
|
|
//
|
|
if ((Index == 0) && (Context->KxldState != NULL)) {
|
|
SymbolAddress = InternalKxldSolveSymbol (
|
|
Context->Is32Bit,
|
|
Context->KxldState,
|
|
Context->KxldStateSize,
|
|
Name
|
|
);
|
|
//
|
|
// If we have a symbol, get its ondisk offset.
|
|
//
|
|
if ((SymbolAddress != 0) && MachoSymbolGetDirectFileOffset (&Context->MachContext, SymbolAddress, &Offset, NULL)) {
|
|
//
|
|
// Proceed to success.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
SymbolName = MachoGetSymbolName (&Context->MachContext, Symbol);
|
|
if ((SymbolName != NULL) && (AsciiStrCmp (Name, SymbolName) == 0)) {
|
|
//
|
|
// Once we have a symbol, get its ondisk offset.
|
|
//
|
|
if (MachoSymbolGetFileOffset (&Context->MachContext, Symbol, &Offset, NULL)) {
|
|
//
|
|
// Proceed to success.
|
|
//
|
|
SymbolAddress = Context->Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value;
|
|
break;
|
|
}
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Index++;
|
|
}
|
|
|
|
if (Address != NULL) {
|
|
*Address = (UINT8 *)MachoGetFileData (&Context->MachContext) + Offset;
|
|
}
|
|
|
|
if (Value != NULL) {
|
|
*Value = SymbolAddress;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherApplyGenericPatch (
|
|
IN OUT PATCHER_CONTEXT *Context,
|
|
IN PATCHER_GENERIC_PATCH *Patch
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Base;
|
|
UINT32 Size;
|
|
UINT32 ReplaceCount;
|
|
|
|
Base = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
|
|
Size = MachoGetInnerSize (&Context->MachContext);
|
|
if (Patch->Base != NULL) {
|
|
Status = PatcherGetSymbolAddress (Context, Patch->Base, &Base);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: %a-bit %a base lookup failure %r\n",
|
|
Context->Is32Bit ? "32" : "64",
|
|
Patch->Comment != NULL ? Patch->Comment : "Patch",
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
Size -= (UINT32)(Base - (UINT8 *)MachoGetMachHeader (&Context->MachContext));
|
|
}
|
|
|
|
if (Patch->Find == NULL) {
|
|
if (Size < Patch->Size) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: %a-bit %a is borked, not found\n",
|
|
Context->Is32Bit ? "32" : "64",
|
|
Patch->Comment != NULL ? Patch->Comment : "Patch"
|
|
));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
CopyMem (Base, Patch->Replace, Patch->Size);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if ((Patch->Limit > 0) && (Patch->Limit < Size)) {
|
|
Size = Patch->Limit;
|
|
}
|
|
|
|
ReplaceCount = ApplyPatch (
|
|
Patch->Find,
|
|
Patch->Mask,
|
|
Patch->Size,
|
|
Patch->Replace,
|
|
Patch->ReplaceMask,
|
|
Base,
|
|
Size,
|
|
Patch->Count,
|
|
Patch->Skip
|
|
);
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: %a-bit %a replace count - %u\n",
|
|
Context->Is32Bit ? "32" : "64",
|
|
Patch->Comment != NULL ? Patch->Comment : "Patch",
|
|
ReplaceCount
|
|
));
|
|
|
|
if ((ReplaceCount > 0) && (Patch->Count > 0) && (ReplaceCount != Patch->Count)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: %a-bit %a performed only %u replacements out of %u\n",
|
|
Context->Is32Bit ? "32" : "64",
|
|
Patch->Comment != NULL ? Patch->Comment : "Patch",
|
|
ReplaceCount,
|
|
Patch->Count
|
|
));
|
|
}
|
|
|
|
if (ReplaceCount > 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherExcludePrelinkedKext (
|
|
IN CONST CHAR8 *Identifier,
|
|
IN OUT PATCHER_CONTEXT *PatcherContext,
|
|
IN OUT PRELINKED_CONTEXT *PrelinkedContext
|
|
)
|
|
{
|
|
MACH_SEGMENT_COMMAND_ANY *Segment;
|
|
VOID *KextData;
|
|
UINT64 AddressMax;
|
|
UINT64 VirtualAddress;
|
|
UINT64 Size;
|
|
UINT64 MaxSize;
|
|
|
|
UINT32 KextCount;
|
|
UINT32 Index;
|
|
UINT32 Index2;
|
|
XML_NODE *KextPlist;
|
|
UINT32 KextPlistCount;
|
|
CONST CHAR8 *KextPlistKey;
|
|
XML_NODE *KextPlistValue;
|
|
CONST CHAR8 *KextIdentifier;
|
|
EFI_STATUS Status;
|
|
|
|
ASSERT (Identifier != NULL);
|
|
ASSERT (PatcherContext != NULL);
|
|
ASSERT (PrelinkedContext != NULL);
|
|
|
|
Segment = NULL;
|
|
VirtualAddress = 0;
|
|
AddressMax = 0;
|
|
Size = 0;
|
|
while ((Segment = MachoGetNextSegment (&PatcherContext->MachContext, Segment)) != NULL) {
|
|
VirtualAddress = PatcherContext->Is32Bit ? Segment->Segment32.VirtualAddress : Segment->Segment64.VirtualAddress;
|
|
|
|
if ((AddressMax != 0) && (AddressMax != VirtualAddress)) {
|
|
break;
|
|
}
|
|
|
|
Size = PatcherContext->Is32Bit ? Segment->Segment32.Size : Segment->Segment64.Size;
|
|
AddressMax = MAX (VirtualAddress + Size, AddressMax);
|
|
}
|
|
|
|
MaxSize = AddressMax - PatcherContext->VirtualBase;
|
|
|
|
//
|
|
// Zero out kext memory through PatcherContext->MachContext.
|
|
//
|
|
KextData = MachoGetFilePointerByAddress (
|
|
&PatcherContext->MachContext,
|
|
PatcherContext->VirtualBase,
|
|
NULL
|
|
);
|
|
if (KextData == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: Excluding %a - VirtualBase %Lx, MaxSize %Lx\n",
|
|
Identifier,
|
|
PatcherContext->VirtualBase,
|
|
MaxSize
|
|
));
|
|
ZeroMem (KextData, (UINTN)MaxSize);
|
|
|
|
//
|
|
// Find kext info to be removed in prelinked context.
|
|
//
|
|
KextCount = XmlNodeChildren (PrelinkedContext->KextList);
|
|
KextPlist = NULL;
|
|
KextPlistKey = NULL;
|
|
KextIdentifier = NULL;
|
|
|
|
for (Index = 0; Index < KextCount; ++Index) {
|
|
KextPlist = PlistNodeCast (XmlNodeChild (PrelinkedContext->KextList, Index), PLIST_NODE_TYPE_DICT);
|
|
if (KextPlist == NULL) {
|
|
continue;
|
|
}
|
|
|
|
KextPlistCount = PlistDictChildren (KextPlist);
|
|
for (Index2 = 0; Index2 < KextPlistCount; ++Index2) {
|
|
KextPlistKey = PlistKeyValue (PlistDictChild (KextPlist, Index2, &KextPlistValue));
|
|
if (KextPlistKey == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (AsciiStrCmp (KextPlistKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
|
|
KextIdentifier = XmlNodeContent (KextPlistValue);
|
|
if ((PlistNodeCast (KextPlistValue, PLIST_NODE_TYPE_STRING) == NULL) || (KextIdentifier == NULL)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: Plist value cannot be interpreted as string, or current kext identifier is null (dict index %u, plist %p, plist index %u)\n",
|
|
Index2,
|
|
KextPlist,
|
|
Index
|
|
));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (AsciiStrCmp (KextIdentifier, Identifier) == 0) {
|
|
//
|
|
// Erase kext.
|
|
//
|
|
Status = InternalDropCachedPrelinkedKext (PrelinkedContext, KextIdentifier);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: Failed to drop %a under dict index %u, plist %p, plist index %u - %r\n",
|
|
KextIdentifier,
|
|
Index2,
|
|
KextPlist,
|
|
Index,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAK: Erasing %a from prelinked kext under dict index %u, plist %p, plist index %u\n",
|
|
Identifier,
|
|
Index2,
|
|
KextPlist,
|
|
Index
|
|
));
|
|
XmlNodeRemoveByIndex (PrelinkedContext->KextList, Index);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
EFI_STATUS
|
|
PatcherBlockKext (
|
|
IN OUT PATCHER_CONTEXT *Context
|
|
)
|
|
{
|
|
UINT8 *MachBase;
|
|
UINT32 MachSize;
|
|
UINT64 KmodOffset;
|
|
UINT64 StartAddr;
|
|
UINT64 TmpOffset;
|
|
UINT8 *KmodInfo;
|
|
UINT8 *PatchAddr;
|
|
|
|
//
|
|
// Kernel has 0 kmod.
|
|
//
|
|
if ((Context->VirtualKmod == 0) || (Context->VirtualBase > Context->VirtualKmod)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
MachBase = (UINT8 *)MachoGetMachHeader (&Context->MachContext);
|
|
MachSize = MachoGetInnerSize (&Context->MachContext);
|
|
|
|
//
|
|
// Determine offset of kmod within file.
|
|
//
|
|
KmodOffset = Context->VirtualKmod - Context->VirtualBase;
|
|
if ( OcOverflowAddU64 (KmodOffset, Context->FileOffset, &KmodOffset)
|
|
|| OcOverflowAddU64 (KmodOffset, Context->Is32Bit ? sizeof (KMOD_INFO_32_V1) : sizeof (KMOD_INFO_64_V1), &TmpOffset)
|
|
|| (TmpOffset > MachSize))
|
|
{
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
KmodInfo = MachBase + KmodOffset;
|
|
if (Context->Is32Bit) {
|
|
StartAddr = ((KMOD_INFO_32_V1 *)KmodInfo)->StartAddr;
|
|
} else {
|
|
StartAddr = ((KMOD_INFO_64_V1 *)KmodInfo)->StartAddr;
|
|
if (Context->IsKernelCollection) {
|
|
StartAddr = KcFixupValue (StartAddr, NULL);
|
|
}
|
|
}
|
|
|
|
if ((StartAddr == 0) || (Context->VirtualBase > StartAddr)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TmpOffset = StartAddr - Context->VirtualBase;
|
|
if ( OcOverflowAddU64 (TmpOffset, Context->FileOffset, &TmpOffset)
|
|
|| (TmpOffset > MachSize - 6))
|
|
{
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
DEBUG ((
|
|
DEBUG_VERBOSE,
|
|
"OCAK: %a-bit blocker start @ 0x%llX\n",
|
|
Context->Is32Bit ? "32" : "64",
|
|
TmpOffset
|
|
));
|
|
|
|
PatchAddr = MachBase + TmpOffset;
|
|
|
|
//
|
|
// mov eax, KMOD_RETURN_FAILURE
|
|
// ret
|
|
//
|
|
PatchAddr[0] = 0xB8;
|
|
PatchAddr[1] = KMOD_RETURN_FAILURE;
|
|
PatchAddr[2] = 0x00;
|
|
PatchAddr[3] = 0x00;
|
|
PatchAddr[4] = 0x00;
|
|
PatchAddr[5] = 0xC3;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
KextFindKmodAddress (
|
|
IN OC_MACHO_CONTEXT *ExecutableContext,
|
|
IN UINT64 LoadAddress,
|
|
IN UINT32 Size,
|
|
OUT UINT64 *Kmod
|
|
)
|
|
{
|
|
BOOLEAN Is32Bit;
|
|
MACH_NLIST_ANY *Symbol;
|
|
CONST CHAR8 *SymbolName;
|
|
UINT64 Address;
|
|
UINT64 FileOffset;
|
|
UINT32 Index;
|
|
|
|
Is32Bit = ExecutableContext->Is32Bit;
|
|
Index = 0;
|
|
|
|
while (TRUE) {
|
|
Symbol = MachoGetSymbolByIndex (ExecutableContext, Index);
|
|
if (Symbol == NULL) {
|
|
*Kmod = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
if (((Is32Bit ? Symbol->Symbol32.Type : Symbol->Symbol64.Type) & MACH_N_TYPE_STAB) == 0) {
|
|
SymbolName = MachoGetSymbolName (ExecutableContext, Symbol);
|
|
if (SymbolName && (AsciiStrCmp (SymbolName, "_kmod_info") == 0)) {
|
|
if (!MachoIsSymbolValueInRange (ExecutableContext, Symbol)) {
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Index++;
|
|
}
|
|
|
|
if (!GetTextBaseOffset (ExecutableContext, &Address, &FileOffset)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( OcOverflowTriAddU64 (Address, LoadAddress, Is32Bit ? Symbol->Symbol32.Value : Symbol->Symbol64.Value, &Address)
|
|
|| (Address > LoadAddress + Size - (Is32Bit ? sizeof (KMOD_INFO_32_V1) : sizeof (KMOD_INFO_64_V1)))
|
|
|| (Is32Bit && (Address > MAX_UINT32)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*Kmod = Address;
|
|
return TRUE;
|
|
}
|