20#include <Library/BaseLib.h>
21#include <Library/BaseMemoryLib.h>
22#include <Library/BaseOverflowLib.h>
23#include <Library/DebugLib.h>
24#include <Library/MemoryAllocationLib.h>
44 Kext = GetFirstNode (&Context->InjectedKexts);
45 while (!IsNull (&Context->InjectedKexts, Kext)) {
52 Size += ALIGN_VALUE (CommandSize, 8);
54 Kext = GetNextNode (&Context->InjectedKexts, Kext);
73 Command.Address = (UINTN)MachHeader->
Commands + MachHeader->CommandsSize;
75 Kext = GetFirstNode (&Context->InjectedKexts);
77 while (!IsNull (&Context->InjectedKexts, Kext)) {
80 StringSize = AsciiStrSize (PrelinkedKext->
Identifier);
89 ASSERT (KextHeader != NULL);
91 (UINTN)KextHeader > (UINTN)Context->Prelinked
92 && (UINTN)KextHeader < (UINTN)Context->Prelinked + Context->PrelinkedSize
94 Command.FilesetEntry->FileOffset = (UINTN)KextHeader - (UINTN)Context->Prelinked;
96 Command.FilesetEntry->Reserved = 0;
99 &
Command.FilesetEntry->Payload[StringSize],
100 Command.FilesetEntry->CommandSize -
Command.FilesetEntry->EntryId.Offset - StringSize
106 MachHeader->NumCommands++;
107 MachHeader->CommandsSize +=
Command.FilesetEntry->CommandSize;
114 Kext = GetNextNode (&Context->InjectedKexts, Kext);
127 Command.Segment64->VirtualAddress = Context->KextsVmAddress;
128 Command.Segment64->FileOffset = Context->KextsFileOffset;
133 Command.Segment64->Size = Context->PrelinkedLastAddress - Context->KextsVmAddress;
134 Command.Segment64->FileSize = Context->PrelinkedSize - Context->KextsFileOffset;
139 Command.Segment64->NumSections = 0;
145 MachHeader->NumCommands++;
164 &Context->PrelinkedInfoSegment->Segment64,
165 Context->PrelinkedInfoSegment->Segment64.CommandSize
171 CopyMem (Context->PrelinkedInfoSegment->Segment64.SegmentName,
"__KREMLIN_START", sizeof (
"__KREMLIN_START"));
172 CopyMem (Context->PrelinkedInfoSection->Section64.SegmentName,
"__KREMLIN_START", sizeof (
"__KREMLIN_START"));
173 CopyMem (Context->PrelinkedInfoSection->Section64.SectionName,
"__kremlin_start", sizeof (
"__kremlin_start"));
178 MachHeader->NumCommands++;
179 MachHeader->CommandsSize += Context->PrelinkedInfoSegment->Segment64.CommandSize;
185 Context->PrelinkedInfoSection = (
MACH_SECTION_ANY *)&Context->PrelinkedInfoSegment->Segment64.Sections[0];
200 &Context->PrelinkedMachContext
203 CurrentSize = MachHeader->
CommandsSize +
sizeof (*MachHeader);
205 RequiredSize = FilesetSize +
sizeof (
MACH_SEGMENT_COMMAND_64) + Context->PrelinkedInfoSegment->Segment64.CommandSize;
208 &Context->PrelinkedMachContext,
214 "OCAK: KC TEXT is %u bytes with %u Mach-O headers need %u\n",
215 (UINT32)(TextSegment != NULL ? TextSegment->
FileSize : 0),
220 if ( (TextSegment == NULL)
223 || (TextSegment->
FileSize < CurrentSize))
225 return EFI_INVALID_PARAMETER;
228 if (CurrentSize + RequiredSize > TextSegment->
FileSize) {
244 DEBUG ((DEBUG_INFO,
"OCAK: Segment expansion failure\n"));
245 return EFI_UNSUPPORTED;
248 CurrentSize = MachHeader->
CommandsSize +
sizeof (*MachHeader);
255 if (CurrentSize + RequiredSize > TextSegment->
FileSize) {
256 DEBUG ((DEBUG_INFO,
"OCAK: Used header %u is still too large\n", (UINT32)CurrentSize));
257 return EFI_UNSUPPORTED;
271 IN UINT32 SegmentSize
282 return (UINT32)(
sizeof (*Dummy)
289 IN UINT32 SegChainSize,
290 IN UINT32 ReservedSize
297 UINT32 DyldChainedStartsSize;
303 ASSERT (Context->KextsFixupChains != NULL);
305 ASSERT (SegChainSize != 0);
314 "Alignment is not guaranteed."
318 &Context->PrelinkedMachContext,
329 "Alignment is not guaranteed."
332 if ( (DyldChainedFixups == NULL)
333 || (DyldChainedFixups->CommandSize != sizeof (*DyldChainedFixups))
335 || (DyldChainedFixups->DataOffset < Context->LinkEditSegment->Segment64.FileOffset)
336 || ((Context->LinkEditSegment->Segment64.FileOffset + Context->LinkEditSegment->Segment64.FileSize)
337 - DyldChainedFixups->DataOffset < DyldChainedFixups->DataSize)
340 DEBUG ((DEBUG_WARN,
"ChainedFixups insane\n"));
341 return EFI_UNSUPPORTED;
345 Context->Prelinked + DyldChainedFixups->DataOffset
347 if (DyldChainedFixupsHdr->FixupsVersion != 0) {
348 DEBUG ((DEBUG_WARN,
"Unrecognised version\n"));
353 "Alignment is not guaranteed."
358 "The subtraction below is unsafe."
365 DEBUG ((DEBUG_WARN,
"ChainedFixupsHdr insane\n"));
366 return EFI_UNSUPPORTED;
370 (UINTN)DyldChainedFixupsHdr + DyldChainedFixupsHdr->StartsOffset
373 Result = BaseOverflowMulAddU32 (
376 sizeof (*DyldChainedStarts),
377 &DyldChainedStartsSize
379 if (Result || (DyldChainedStartsSize > DyldChainedFixups->DataSize - DyldChainedFixupsHdr->StartsOffset)) {
380 DEBUG ((DEBUG_WARN,
"DyldChainedFixups insane\n"));
381 return EFI_UNSUPPORTED;
384 for (SegIndex = 0; SegIndex < DyldChainedStarts->
NumSegments; ++SegIndex) {
391 DEBUG ((DEBUG_WARN,
"No free start\n"));
392 return EFI_UNSUPPORTED;
395 ASSERT ((UINTN)Context->KextsFixupChains > (UINTN)DyldChainedStarts);
397 (UINTN)Context->KextsFixupChains - (UINTN)DyldChainedStarts
400 Context->KextsFixupChains->Size = SegChainSize;
403 Context->KextsFixupChains->SegmentOffset = Context->KextsVmAddress - Context->VirtualBase;
404 Context->KextsFixupChains->MaxValidPointer = 0;
405 Context->KextsFixupChains->PageCount = (UINT16)(ReservedSize /
MACHO_PAGE_SIZE);
411 Context->KextsFixupChains->PageStart,
412 (UINT32)Context->KextsFixupChains->PageCount
413 * sizeof (Context->KextsFixupChains->PageStart[0]),
439 UINT8 *SegmentPageData;
442 UINT32 RelocOffsetInSeg;
446 UINT16 NewFixupPageOffset;
449 UINT16 IterFixupPageOffset;
452 UINT16 NextIterFixupPageOffset;
457 ASSERT (MachContext != NULL);
458 ASSERT (RelocInfo != NULL);
460 ASSERT (Context->KextsFixupChains != NULL);
466 RelocAddress = RelocBase + (UINT32)RelocInfo->Address;
467 RelocOffsetInSeg = (UINT32)(RelocAddress - Context->KextsVmAddress);
471 ASSERT (RelocInfo->Extern == 0);
473 ASSERT (RelocAddress >= Context->KextsVmAddress);
474 ASSERT (RelocOffsetInSeg <= Context->PrelinkedSize - Context->KextsFileOffset);
475 ASSERT (Context->KextsFileOffset - RelocOffsetInSeg >= 8);
479 SegmentData = Context->Prelinked + Context->KextsFileOffset;
480 RelocDest = SegmentData + RelocOffsetInSeg;
486 ZeroMem (&NewFixup,
sizeof (NewFixup));
496 IterFixupPageOffset = Context->KextsFixupChains->PageStart[NewFixupPage];
502 Context->KextsFixupChains->PageStart[NewFixupPage] = NewFixupPageOffset;
506 }
else if (NewFixupPageOffset < IterFixupPageOffset) {
510 NewFixup.
Next = IterFixupPageOffset - NewFixupPageOffset;
511 Context->KextsFixupChains->PageStart[NewFixupPage] = NewFixupPageOffset;
519 NextIterFixupPageOffset = IterFixupPageOffset;
521 IterFixupPageOffset = NextIterFixupPageOffset;
522 IterFixupData = SegmentPageData + IterFixupPageOffset;
524 CopyMem (&IterFixup, IterFixupData,
sizeof (IterFixup));
525 NextIterFixupPageOffset = (UINT16)(IterFixupPageOffset + IterFixup.
Next);
526 }
while (NextIterFixupPageOffset < NewFixupPageOffset && IterFixup.
Next != 0);
528 FixupDelta = NewFixupPageOffset - IterFixupPageOffset;
533 if (IterFixup.
Next != 0) {
535 NewFixup.
Next = IterFixup.
Next - FixupDelta;
543 IterFixup.
Next = FixupDelta;
544 CopyMem (IterFixupData, &IterFixup,
sizeof (IterFixup));
547 CopyMem (RelocDest, &NewFixup,
sizeof (NewFixup));
572 ASSERT (MachContext != NULL);
597 if (DySymtab == NULL) {
606 ASSERT (DySymtab != NULL);
607 ASSERT (FirstSegment != NULL);
611 ASSERT (FirstSegment->VirtualAddress >= Context->KextsVmAddress);
616 ASSERT (DySymtab->NumExternalRelocations == 0);
622 (UINTN)FileData + DySymtab->LocalRelocationsOffset
627 "OCAK: Local relocs %u on %LX\n",
628 DySymtab->NumOfLocalRelocations,
629 FirstSegment->VirtualAddress
632 for (RelocIndex = 0; RelocIndex < DySymtab->NumOfLocalRelocations; ++RelocIndex) {
636 &Relocations[RelocIndex],
637 FirstSegment->VirtualAddress
645 IN UINT64 SourceAddress
651 ASSERT (Context->IsKernelCollection);
675 return (UINT32)(Context->LinkEditSegment->Segment64.VirtualAddress
676 - SourceAddress + Context->LinkEditSegment->Segment64.Size);
698 ASSERT (PrelinkedContext != NULL);
703 ASSERT (KextHeader != NULL);
711 (UINTN)
Command < TopOfCommands;
715 switch (
Command->CommandType) {
718 return EFI_UNSUPPORTED;
725 for (SectIndex = 0; SectIndex < Segment->
NumSections; ++SectIndex) {
742 return EFI_UNSUPPORTED;
761 return EFI_UNSUPPORTED;
793 Context->FileData = PrelinkedContext->Prelinked;
794 Context->FileSize = PrelinkedContext->PrelinkedSize;
802 IN CONST CHAR8 *Name OPTIONAL
825 || (Rebase->
Key != 0)
828 DEBUG ((DEBUG_INFO,
"OCAK: Invalid fixup %Lx for %a\n", Value, Name != NULL ? Name :
"<none>"));
#define MACH_LOAD_COMMAND_SEGMENT_64
#define MACH_LOAD_COMMAND_DYLD_CHAINED_FIXUPS
#define MACH_LOAD_COMMAND_FILESET_ENTRY
#define NEXT_MACH_LOAD_COMMAND(Command)
#define MACH_LOAD_COMMAND_DYSYMTAB
#define MACH_SEGMENT_VM_PROT_READ
#define MACH_LOAD_COMMAND_SYMTAB
#define MACH_SEGMENT_VM_PROT_EXECUTE
@ MACH_DYLD_CHAINED_PTR_START_NONE
used in page_start[] to denote a page with no fixups
@ MachX8664RelocUnsigned
for absolute addresses
@ MACH_DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE
stride 1, x86_64 kernel caches
#define MACH_HEADER_FLAG_DYLIB_IN_CACHE
#define MACH_SEGMENT_VM_PROT_WRITE
UINT8 Command[7]
Actual command for the Command Page.
EFI_STATUS KcRebuildMachHeader(IN OUT PRELINKED_CONTEXT *Context)
UINT32 KcGetKextSize(IN PRELINKED_CONTEXT *Context, IN UINT64 SourceAddress)
STATIC VOID InternalKcConvertRelocToFixup(IN OUT PRELINKED_CONTEXT *Context, IN OC_MACHO_CONTEXT *MachContext, IN CONST MACH_RELOCATION_INFO *RelocInfo, IN UINT64 RelocBase)
VOID KcKextIndexFixups(IN OUT PRELINKED_CONTEXT *Context, IN OC_MACHO_CONTEXT *MachContext)
STATIC VOID InternalKcWriteCommandHeaders(IN OUT PRELINKED_CONTEXT *Context, IN OUT MACH_HEADER_64 *MachHeader)
EFI_STATUS KcInitKextFixupChains(IN OUT PRELINKED_CONTEXT *Context, IN UINT32 SegChainSize, IN UINT32 ReservedSize)
EFI_STATUS KcKextApplyFileDelta(IN PRELINKED_CONTEXT *PrelinkedContext, IN OUT OC_MACHO_CONTEXT *Context, IN UINT32 Delta)
UINT64 KcFixupValue(IN UINT64 Value, IN CONST CHAR8 *Name OPTIONAL)
UINT32 KcGetSegmentFixupChainsSize(IN UINT32 SegmentSize)
STATIC UINTN InternalKcGetKextFilesetSize(IN OUT PRELINKED_CONTEXT *Context)
DMG_SIZE_DEVICE_PATH Size
#define PRELINKED_KEXTS_MAX_SIZE
#define KC_REGION_SEGMENT_PREFIX
#define KC_MOSCOW_SEGMENT
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
MACH_SEGMENT_COMMAND_64 * MachoGetNextSegment64(IN OUT OC_MACHO_CONTEXT *Context, IN CONST MACH_SEGMENT_COMMAND_64 *Segment OPTIONAL)
MACH_HEADER_64 * MachoGetMachHeader64(IN OUT OC_MACHO_CONTEXT *Context)
UINT64 MachoGetLastAddress(IN OUT OC_MACHO_CONTEXT *Context)
VOID * MachoGetFileData(IN OUT OC_MACHO_CONTEXT *Context)
MACH_SEGMENT_COMMAND_64 * MachoGetSegmentByName64(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *SegmentName)
MACH_LOAD_COMMAND * MachoGetNextCommand(IN OUT OC_MACHO_CONTEXT *Context, IN MACH_LOAD_COMMAND_TYPE LoadCommandType, IN CONST MACH_LOAD_COMMAND *LoadCommand OPTIONAL)
BOOLEAN MachoMergeSegments(IN OUT OC_MACHO_CONTEXT *Context, IN CONST CHAR8 *Prefix)
#define KERNEL_ADDRESS_MASK
#define KERNEL_ADDRESS_BASE
#define GET_INJECTED_KEXT_FROM_LINK(This)
#define KERNEL_ADDRESS_KEXT
#define KERNEL_FIXUP_OFFSET
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
UINT64 EFIAPI ReadUnaligned64(IN CONST UINT64 *Buffer)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 CacheLevel
what level of cache to bind to (indexes a mach_header array)
UINT64 Target
basePointers[cacheLevel] + target
UINT64 IsAuth
0 -> not authenticated. 1 -> authenticated
UINT64 Next
1 or 4-byte stide
UINT32 NumOfLocalRelocations
number of local relocation entries
UINT32 IndirectSymbolsOffset
UINT32 LocalRelocationsOffset
offset to local relocation entries
UINT32 CommandsSize
the size of all load commands
MACH_HEADER_FLAGS Flags
flags
MACH_LOAD_COMMAND Commands[]
UINT32 Offset
file offset of this section
UINT32 NumSections
number of sections in segment
UINT64 FileOffset
file offset of this segment
UINT64 Size
memory size of this segment
MACH_SECTION_64 Sections[]
UINT64 FileSize
amount to map from the file
UINT64 VirtualAddress
memory address of this segment
MACH_LOAD_COMMAND_HDR_ UINT32 SymbolsOffset
symbol table offset
UINT32 StringsOffset
string table offset
OC_MACHO_CONTEXT MachContext