forked from acidanthera/OpenCorePkg
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PrelinkedInternal.h
420 lines (361 loc) · 11.3 KB
/
PrelinkedInternal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
/** @file
Library handling KEXT prelinking.
Currently limited to Intel 64 architectures.
Copyright (c) 2018, Download-Fritz. All rights reserved.<BR>
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 PRELINKED_INTERNAL_H
#define PRELINKED_INTERNAL_H
#include <IndustryStandard/AppleMachoImage.h>
#include <Library/OcAppleKernelLib.h>
#include <Library/OcMachoLib.h>
#include <Library/OcXmlLib.h>
//
// Some sane maximum value.
//
#define MAX_KEXT_DEPEDENCIES 16
typedef struct PRELINKED_KEXT_ PRELINKED_KEXT;
typedef struct {
//
// Value is declared first as it has shown to improve comparison performance.
//
UINT64 Value; ///< value of this symbol (or stab offset)
CONST CHAR8 *Name; ///< name of this symbol
UINT32 Length;
} PRELINKED_KEXT_SYMBOL;
typedef struct {
CONST CHAR8 *Name; ///< The symbol's name.
UINT64 Address; ///< The symbol's address.
} PRELINKED_VTABLE_ENTRY;
#define GET_NEXT_PRELINKED_VTABLE(This) \
(PRELINKED_VTABLE *)( \
(UINTN)((This) + 1) + ((This)->NumEntries * sizeof (*(This)->Entries)) \
)
typedef struct {
CONST CHAR8 *Name; ///< The VTable's name.
UINT32 NumEntries; ///< The number of VTable entries.
PRELINKED_VTABLE_ENTRY Entries[]; ///< The VTable entries.
} PRELINKED_VTABLE;
struct PRELINKED_KEXT_ {
//
// These data are used to construct linked lists of dependency information
// for each KEXT. It is declared hear for every dependency will
// eventually be part of a list and to save separate allocations per KEXT.
//
UINT32 Signature;
//
// Link for global list (PRELINKED_CONTEXT -> PrelinkedKexts).
//
LIST_ENTRY Link;
//
// Link for local list (PRELINKED_CONTEXT -> InjectedKexts).
//
LIST_ENTRY InjectedLink;
//
// Kext CFBundleIdentifier.
//
CONST CHAR8 *Identifier;
//
// Patcher context containing useful data.
//
PATCHER_CONTEXT Context;
//
// Dependencies dictionary (OSBundleLibraries).
// May be NULL for KPI kexts or after Dependencies are set.
//
XML_NODE *BundleLibraries;
//
// Compatible version, may be NULL.
//
CONST CHAR8 *CompatibleVersion;
//
// Scanned dependencies (PRELINKED_KEXT) from BundleLibraries.
// Not resolved by default. See InternalScanPrelinkedKext for fields below.
//
PRELINKED_KEXT *Dependencies[MAX_KEXT_DEPEDENCIES];
//
// Linkedit segment reference.
//
MACH_SEGMENT_COMMAND_64 *LinkEditSegment;
//
// The String Table associated with this symbol table.
//
CONST CHAR8 *StringTable;
//
// Symbol table.
//
CONST MACH_NLIST_64 *SymbolTable;
//
// Symbol table size.
//
UINT32 NumberOfSymbols;
//
// Number of C++ symbols. They are put at the end of LinkedSymbolTable.
// Calculated at LinkedSymbolTable construction.
//
UINT32 NumberOfCxxSymbols;
//
// Sorted symbol table used only for dependencies.
//
PRELINKED_KEXT_SYMBOL *LinkedSymbolTable;
//
// A flag set during dependency walk BFS to avoid going through the same path.
//
BOOLEAN Processed;
//
// Number of vtables in this kext.
//
UINT32 NumberOfVtables;
//
// Scanned vtable buffer. Iterated with GET_NEXT_PRELINKED_VTABLE.
//
PRELINKED_VTABLE *LinkedVtables;
};
//
// PRELINKED_KEXT signature for list identification.
//
#define PRELINKED_KEXT_SIGNATURE SIGNATURE_32 ('P', 'K', 'X', 'T')
/**
Gets the next element in PrelinkedKexts list of PRELINKED_KEXT.
@param[in] This The current ListEntry.
**/
#define GET_PRELINKED_KEXT_FROM_LINK(This) \
(CR ( \
(This), \
PRELINKED_KEXT, \
Link, \
PRELINKED_KEXT_SIGNATURE \
))
/**
Gets the next element in InjectedKexts list of PRELINKED_KEXT.
@param[in] This The current ListEntry.
**/
#define GET_INJECTED_KEXT_FROM_LINK(This) \
(CR ( \
(This), \
PRELINKED_KEXT, \
InjectedLink, \
PRELINKED_KEXT_SIGNATURE \
))
/**
Creates new PRELINKED_KEXT from OC_MACHO_CONTEXT.
**/
PRELINKED_KEXT *
InternalNewPrelinkedKext (
IN OC_MACHO_CONTEXT *Context,
IN XML_NODE *KextPlist
);
/**
Frees PRELINKED_KEXT.
**/
VOID
InternalFreePrelinkedKext (
IN PRELINKED_KEXT *Kext
);
/**
Gets cached PRELINKED_KEXT from PRELINKED_CONTEXT.
**/
PRELINKED_KEXT *
InternalCachedPrelinkedKext (
IN OUT PRELINKED_CONTEXT *Prelinked,
IN CONST CHAR8 *Identifier
);
/**
Gets cached kernel PRELINKED_KEXT from PRELINKED_CONTEXT.
**/
PRELINKED_KEXT *
InternalCachedPrelinkedKernel (
IN OUT PRELINKED_CONTEXT *Prelinked
);
/**
Scan PRELINKED_KEXT for dependencies.
**/
EFI_STATUS
InternalScanPrelinkedKext (
IN OUT PRELINKED_KEXT *Kext,
IN OUT PRELINKED_CONTEXT *Context,
IN BOOLEAN Dependency
);
/**
Unlock all context dependency kexts by unsetting Processed flag.
@param[in] Context Prelinked context.
**/
VOID
InternalUnlockContextKexts (
IN PRELINKED_CONTEXT *Context
);
/**
Link executable within current prelink context.
@param[in,out] Context Prelinked context.
@param[in,out] Executable Kext executable copied to prelinked.
@param[in] PlistRoot Current kext info.plist.
@param[in] LoadAddress Kext load address.
@param[in] KmodAddress Kext kmod address.
@return prelinked kext to be inserted into PRELINKED_CONTEXT.
**/
PRELINKED_KEXT *
InternalLinkPrelinkedKext (
IN OUT PRELINKED_CONTEXT *Context,
IN OUT OC_MACHO_CONTEXT *Executable,
IN XML_NODE *PlistRoot,
IN UINT64 LoadAddress,
IN UINT64 KmodAddress
);
EFI_STATUS
InternalConnectExternalSymtab (
IN OUT OC_MACHO_CONTEXT *Context,
OUT OC_MACHO_CONTEXT *InnerContext,
IN UINT8 *Buffer,
IN UINT32 BufferSize,
OUT BOOLEAN *KernelCollection OPTIONAL
);
#define KXLD_WEAK_TEST_SYMBOL "_gOSKextUnresolved"
#define OS_METACLASS_VTABLE_NAME "__ZTV11OSMetaClass"
#define X86_64_RIP_RELATIVE_LIMIT 0x80000000ULL
#define SYM_MAX_NAME_LEN 256U
#define VTABLE_ENTRY_SIZE_64 8U
#define VTABLE_HEADER_LEN_64 2U
#define VTABLE_HEADER_SIZE_64 (VTABLE_HEADER_LEN_64 * VTABLE_ENTRY_SIZE_64)
#define KERNEL_ADDRESS_MASK 0xFFFFFFFF00000000ULL
#define KERNEL_ADDRESS_BASE 0xFFFFFF8000000000ULL
#define KERNEL_FIXUP_OFFSET BASE_1MB
typedef union {
struct {
UINT32 Major : 14;
UINT32 Minor : 7;
UINT32 Revision : 7;
UINT32 Stage : 4;
UINT32 StageLevel : 8;
} Bits;
UINT64 Value;
} OC_KEXT_VERSION;
typedef enum {
OcKextVersionStageDevelopment = 1,
OcKextVersionStageAlpha = 3,
OcKextVersionStageBeta = 5,
OcKextVersionStageCandidate = 7,
OcKextVersionStageRelease = 9
} OC_KEXT_VERSION_STAGE;
#define GET_NEXT_OC_VTABLE_PATCH_ENTRY(Entry) \
(OC_VTABLE_PATCH_ENTRY *)( \
(UINTN)((Entry) + 1) \
+ ((Entry)->NumSolveSymbols * sizeof (*(Entry)->SolveSymbols)) \
)
typedef struct {
CONST CHAR8 *Name;
union {
UINT64 Value;
CONST UINT64 *Data;
} Vtable;
} OC_PRELINKED_VTABLE_LOOKUP_ENTRY;
STATIC_ASSERT (
(sizeof (OC_PRELINKED_VTABLE_LOOKUP_ENTRY) <= sizeof (MACH_NLIST_64)),
"Prelinked VTable lookup data might not safely fit LinkBuffer"
);
typedef struct {
CONST MACH_NLIST_64 *Smcp;
CONST MACH_NLIST_64 *Vtable;
UINT64 *VtableData;
CONST MACH_NLIST_64 *MetaVtable;
UINT64 *MetaVtableData;
UINT32 NumSolveSymbols;
UINT32 MetaSymsIndex;
MACH_NLIST_64 *SolveSymbols[];
} OC_VTABLE_PATCH_ENTRY;
//
// This ASSERT is very dirty, but it is unlikely to trigger nevertheless.
// One symbol pointer, for which LinkBuffer is guaranteed to be able to fit one
// NLIST, has either 1 pointer or 2 UINT32s following in the struct.
// Due to the location logic, the three symbols pointers will not be equal.
//
STATIC_ASSERT (
((sizeof (MACH_NLIST_64 *) + MAX ((2 * sizeof (UINT32)), sizeof (UINT64 *))) <= sizeof (MACH_NLIST_64)),
"VTable Patch data might not safely fit LinkBuffer"
);
//
// VTables
//
BOOLEAN
InternalGetVtableEntries64 (
IN CONST UINT64 *VtableData,
IN UINT32 MaxSize,
OUT UINT32 *NumEntries
);
BOOLEAN
InternalPatchByVtables64 (
IN PRELINKED_CONTEXT *Context,
IN OUT PRELINKED_KEXT *Kext
);
BOOLEAN
InternalPrepareCreateVtablesPrelinked64 (
IN PRELINKED_KEXT *Kext,
IN UINT32 MaxSize,
OUT UINT32 *NumVtables,
OUT OC_PRELINKED_VTABLE_LOOKUP_ENTRY *Vtables
);
VOID
InternalCreateVtablesPrelinked64 (
IN PRELINKED_CONTEXT *Context,
IN OUT PRELINKED_KEXT *Kext,
IN UINT32 NumVtables,
IN CONST OC_PRELINKED_VTABLE_LOOKUP_ENTRY *VtableLookups,
OUT PRELINKED_VTABLE *VtableBuffer
);
CONST PRELINKED_VTABLE *
InternalGetOcVtableByName (
IN PRELINKED_CONTEXT *Context,
IN PRELINKED_KEXT *Kext,
IN CONST CHAR8 *Name
);
//
// Prelink
//
typedef enum {
OcGetSymbolByName,
OcGetSymbolByValue
} OC_GET_SYMBOL_TYPE;
typedef enum {
OcGetSymbolAnyLevel,
OcGetSymbolFirstLevel,
OcGetSymbolOnlyCxx
} OC_GET_SYMBOL_LEVEL;
CONST PRELINKED_KEXT_SYMBOL *
InternalOcGetSymbolName (
IN PRELINKED_CONTEXT *Context,
IN PRELINKED_KEXT *Kext,
IN CONST CHAR8 *LookupValue,
IN OC_GET_SYMBOL_LEVEL SymbolLevel
);
CONST PRELINKED_KEXT_SYMBOL *
InternalOcGetSymbolValue (
IN PRELINKED_CONTEXT *Context,
IN PRELINKED_KEXT *Kext,
IN UINT64 LookupValue,
IN OC_GET_SYMBOL_LEVEL SymbolLevel
);
VOID
InternalSolveSymbolValue64 (
IN UINT64 Value,
OUT MACH_NLIST_64 *Symbol
);
/**
Prelinks the specified KEXT against the specified LoadAddress and the data
of its dependencies.
@param[in,out] Context Prelinking context.
@param[in] Kext KEXT prelinking context.
@param[in] LoadAddress The address this KEXT shall be linked against.
@retval Returned is whether the prelinking process has been successful.
The state of the KEXT is undefined in case this routine fails.
**/
EFI_STATUS
InternalPrelinkKext64 (
IN OUT PRELINKED_CONTEXT *Context,
IN PRELINKED_KEXT *Kext,
IN UINT64 LoadAddress
);
#endif // PRELINKED_INTERNAL_H