OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
MkextContext.c
Go to the documentation of this file.
1
16#include <Uefi.h>
17
18#include <Library/BaseLib.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/BaseOverflowLib.h>
21#include <Library/DebugLib.h>
22#include <Library/MemoryAllocationLib.h>
25#include <Library/OcStringLib.h>
26
27#include "MkextInternal.h"
28#include "PrelinkedInternal.h"
29
30//
31// Alignment to 8 bytes.
32//
33#define MKEXT_ALIGN(a) (ALIGN_VALUE (a, sizeof (UINT64)))
34
35BOOLEAN
37 IN OUT UINT8 **Buffer,
38 IN OUT UINT32 *BufferSize,
39 IN BOOLEAN Is32Bit
40 )
41{
42 EFI_STATUS Status;
43 MACH_HEADER_ANY *MachHeader;
44
45 Status = FatFilterArchitectureByType (Buffer, BufferSize, Is32Bit ? MachCpuTypeI386 : MachCpuTypeX8664);
46 if (EFI_ERROR (Status)) {
47 return FALSE;
48 }
49
50 //
51 // Size/alignment checked by FatFilterArchitectureByType.
52 //
53 MachHeader = (MACH_HEADER_ANY *)*Buffer;
54
55 if ( (!Is32Bit && (MachHeader->Signature == MACH_HEADER_64_SIGNATURE))
56 || (Is32Bit && (MachHeader->Signature == MACH_HEADER_SIGNATURE)))
57 {
58 return TRUE;
59 }
60
61 return FALSE;
62}
63
64STATIC
65VOID
67 IN MKEXT_HEADER_ANY *Mkext,
68 IN UINT32 Length
69 )
70{
71 Mkext->Common.Length = SwapBytes32 (Length);
72 Mkext->Common.Adler32 = SwapBytes32 (
73 Adler32 (
74 (UINT8 *)&Mkext->Common.Version,
75 Length - OFFSET_OF (MKEXT_CORE_HEADER, Version)
76 )
77 );
78}
79
80STATIC
81BOOLEAN
83 IN MKEXT_V2_HEADER *Mkext,
84 OUT UINT8 **Plist,
85 OUT UINT32 *PlistSize,
86 OUT XML_DOCUMENT **PlistDoc,
87 OUT XML_NODE **PlistBundles
88 )
89{
90 UINT8 *MkextBuffer;
91 UINT32 MkextLength;
92 VOID *PlistBuffer;
93 XML_DOCUMENT *PlistXml;
94 UINT32 PlistOffset;
95 UINT32 PlistCompressedSize;
96 UINT32 PlistFullSize;
97 UINT32 PlistStoredSize;
98 UINT32 Tmp;
99
100 XML_NODE *MkextInfoRoot;
101 UINT32 MkextInfoRootIndex;
102 UINT32 MkextInfoRootCount;
103
104 XML_NODE *PlistBundleArray;
105 CONST CHAR8 *BundleArrayKey;
106
107 MkextBuffer = (UINT8 *)Mkext;
108 MkextLength = SwapBytes32 (Mkext->Header.Length);
109 PlistOffset = SwapBytes32 (Mkext->PlistOffset);
110 PlistCompressedSize = SwapBytes32 (Mkext->PlistCompressedSize);
111 PlistFullSize = SwapBytes32 (Mkext->PlistFullSize);
112
113 PlistStoredSize = PlistCompressedSize;
114 if (PlistStoredSize == 0) {
115 PlistStoredSize = PlistFullSize;
116 }
117
118 if (BaseOverflowAddU32 (PlistOffset, PlistStoredSize, &Tmp) || (Tmp > MkextLength)) {
119 return FALSE;
120 }
121
122 PlistBuffer = AllocatePool (PlistFullSize);
123 if (PlistBuffer == NULL) {
124 return FALSE;
125 }
126
127 //
128 // Copy/decompress plist.
129 //
130 if (PlistCompressedSize > 0) {
131 if (DecompressZLIB (
132 PlistBuffer,
133 PlistFullSize,
134 &MkextBuffer[PlistOffset],
135 PlistCompressedSize
136 ) != PlistFullSize)
137 {
138 FreePool (PlistBuffer);
139 return FALSE;
140 }
141 } else {
142 CopyMem (PlistBuffer, &MkextBuffer[PlistOffset], PlistFullSize);
143 }
144
145 PlistXml = XmlDocumentParse (PlistBuffer, PlistFullSize, FALSE);
146 if (PlistXml == NULL) {
147 FreePool (PlistBuffer);
148 return FALSE;
149 }
150
151 //
152 // Mkext v2 root element is a dictionary containing an array of bundles.
153 //
154 MkextInfoRoot = PlistNodeCast (XmlDocumentRoot (PlistXml), PLIST_NODE_TYPE_DICT);
155 if (MkextInfoRoot == NULL) {
156 XmlDocumentFree (PlistXml);
157 FreePool (PlistBuffer);
158 return FALSE;
159 }
160
161 //
162 // Get bundle array.
163 //
164 MkextInfoRootCount = PlistDictChildren (MkextInfoRoot);
165 for (MkextInfoRootIndex = 0; MkextInfoRootIndex < MkextInfoRootCount; MkextInfoRootIndex++) {
166 BundleArrayKey = PlistKeyValue (PlistDictChild (MkextInfoRoot, MkextInfoRootIndex, &PlistBundleArray));
167 if (BundleArrayKey == NULL) {
168 continue;
169 }
170
171 if (AsciiStrCmp (BundleArrayKey, MKEXT_INFO_DICTIONARIES_KEY) == 0) {
172 *Plist = PlistBuffer;
173 *PlistSize = PlistFullSize;
174 *PlistDoc = PlistXml;
175 *PlistBundles = PlistBundleArray;
176
177 return TRUE;
178 }
179 }
180
181 //
182 // No bundle array found.
183 //
184 XmlDocumentFree (PlistXml);
185 FreePool (PlistBuffer);
186 return FALSE;
187}
188
189STATIC
190UINT32
192 IN OUT MKEXT_V2_HEADER *Mkext,
193 IN UINT32 AllocatedSize,
194 IN XML_DOCUMENT *PlistDoc,
195 IN UINT32 Offset
196 )
197{
198 UINT8 *MkextBuffer;
199 CHAR8 *ExportedInfo;
200 UINT32 ExportedInfoSize;
201 UINT32 TmpSize;
202
203 //
204 // Export plist and include \0 terminator in size.
205 //
206 ExportedInfo = XmlDocumentExport (PlistDoc, &ExportedInfoSize, 0, FALSE);
207 if (ExportedInfo == NULL) {
208 return 0;
209 }
210
211 ExportedInfoSize++;
212
213 if ( BaseOverflowAddU32 (Offset, ExportedInfoSize, &TmpSize)
214 || (TmpSize > AllocatedSize))
215 {
216 FreePool (ExportedInfo);
217 return 0;
218 }
219
220 MkextBuffer = (UINT8 *)Mkext;
221 CopyMem (&MkextBuffer[Offset], ExportedInfo, ExportedInfoSize);
222 FreePool (ExportedInfo);
223
224 Mkext->PlistOffset = SwapBytes32 (Offset);
225 Mkext->PlistFullSize = SwapBytes32 (ExportedInfoSize);
226 Mkext->PlistCompressedSize = 0;
227 return ExportedInfoSize;
228}
229
230STATIC
233 IN OUT MKEXT_CONTEXT *Context,
234 IN CONST CHAR8 *Identifier,
235 IN UINT32 BinOffset,
236 IN UINT32 BinSize
237 )
238{
239 MKEXT_KEXT *MkextKext;
240
241 MkextKext = AllocateZeroPool (sizeof (*MkextKext));
242 if (MkextKext == NULL) {
243 return NULL;
244 }
245
246 MkextKext->Signature = MKEXT_KEXT_SIGNATURE;
247 MkextKext->BinaryOffset = BinOffset;
248 MkextKext->BinarySize = BinSize;
249 MkextKext->Identifier = AllocateCopyPool (AsciiStrSize (Identifier), Identifier);
250 if (MkextKext->Identifier == NULL) {
251 FreePool (MkextKext);
252 return NULL;
253 }
254
255 InsertTailList (&Context->CachedKexts, &MkextKext->Link);
256
257 DEBUG ((DEBUG_VERBOSE, "OCAK: Inserted %a into mkext cache\n", Identifier));
258
259 return MkextKext;
260}
261
262VOID
264 IN OUT MKEXT_CONTEXT *Context,
265 IN CONST CHAR8 *Identifier
266 )
267{
268 MKEXT_KEXT *MkextKext;
269 LIST_ENTRY *KextLink;
270
271 //
272 // Try to get cached kext.
273 //
274 MkextKext = NULL;
275 KextLink = GetFirstNode (&Context->CachedKexts);
276 while (!IsNull (&Context->CachedKexts, KextLink)) {
277 MkextKext = GET_MKEXT_KEXT_FROM_LINK (KextLink);
278
279 if (AsciiStrCmp (Identifier, MkextKext->Identifier) == 0) {
280 break;
281 }
282
283 KextLink = GetNextNode (&Context->CachedKexts, KextLink);
284 }
285
286 //
287 // Remove from cache linked list if found.
288 //
289 if (MkextKext != NULL) {
290 RemoveEntryList (&MkextKext->Link);
291 DEBUG ((DEBUG_VERBOSE, "OCAK: Removed %a from mkext cache\n", Identifier));
292 }
293}
294
295EFI_STATUS
297 IN OUT MKEXT_CONTEXT *Context,
298 IN CONST CHAR8 *Identifier,
299 OUT UINT32 *KextIndex,
300 OUT UINT32 *KextPlistOffset,
301 OUT UINT32 *KextPlistSize,
302 OUT UINT32 *KextBinOffset,
303 OUT UINT32 *KextBinSize
304 )
305{
306 MKEXT_HEADER_ANY *MkextHeader;
307
308 UINT32 Index;
309 UINT32 PlistOffsetSize;
310 UINT32 BinOffsetSize;
311 BOOLEAN IsKextMatch;
312
313 UINT32 PlistOffset;
314 UINT32 PlistSize;
315 CHAR8 *PlistBuffer;
316 XML_DOCUMENT *PlistXml;
317 XML_NODE *PlistRoot;
318
319 UINT32 PlistBundleIndex;
320 UINT32 PlistBundleCount;
321 CONST CHAR8 *PlistBundleKey;
322 XML_NODE *PlistBundleKeyValue;
323
324 CONST CHAR8 *KextIdentifier;
325 UINT32 BinOffset;
326 UINT32 BinSize;
327
328 ASSERT (Context->MkextVersion == MKEXT_VERSION_V1);
329
330 MkextHeader = Context->MkextHeader;
331 IsKextMatch = FALSE;
332 PlistOffset = 0;
333 PlistSize = 0;
334 BinOffset = 0;
335 BinSize = 0;
336
337 for (Index = 0; Index < Context->NumKexts; Index++) {
338 //
339 // Binaryless and compressed kexts are not supported.
340 //
341 if ( (MkextHeader->V1.Kexts[Index].Plist.CompressedSize != 0)
342 || (MkextHeader->V1.Kexts[Index].Binary.CompressedSize != 0)
343 || (MkextHeader->V1.Kexts[Index].Binary.Offset == 0))
344 {
345 continue;
346 }
347
348 PlistOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.Offset);
349 PlistSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.FullSize);
350 BinOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.Offset);
351 BinSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.FullSize);
352
353 //
354 // Verify plist and binary are within bounds.
355 //
356 if ( BaseOverflowAddU32 (PlistOffset, PlistSize, &PlistOffsetSize)
357 || (PlistOffsetSize > Context->MkextSize)
358 || BaseOverflowAddU32 (BinOffset, BinSize, &BinOffsetSize)
359 || (BinOffsetSize > Context->MkextSize))
360 {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 PlistBuffer = AllocateCopyPool (PlistSize, &Context->Mkext[PlistOffset]);
365 if (PlistBuffer == NULL) {
366 return EFI_OUT_OF_RESOURCES;
367 }
368
369 PlistXml = XmlDocumentParse (PlistBuffer, PlistSize, FALSE);
370 if (PlistXml == NULL) {
371 FreePool (PlistBuffer);
372 return EFI_OUT_OF_RESOURCES;
373 }
374
375 PlistRoot = PlistNodeCast (PlistDocumentRoot (PlistXml), PLIST_NODE_TYPE_DICT);
376 if (PlistRoot == NULL) {
377 XmlDocumentFree (PlistXml);
378 FreePool (PlistBuffer);
379 return EFI_OUT_OF_RESOURCES;
380 }
381
382 KextIdentifier = NULL;
383 PlistBundleCount = PlistDictChildren (PlistRoot);
384 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
385 PlistBundleKey = PlistKeyValue (PlistDictChild (PlistRoot, PlistBundleIndex, &PlistBundleKeyValue));
386 if ((PlistBundleKey == NULL) || (PlistBundleKeyValue == NULL)) {
387 continue;
388 }
389
390 if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
391 KextIdentifier = XmlNodeContent (PlistBundleKeyValue);
392 break;
393 }
394 }
395
396 IsKextMatch = KextIdentifier != NULL && AsciiStrCmp (KextIdentifier, Identifier) == 0;
397 XmlDocumentFree (PlistXml);
398 FreePool (PlistBuffer);
399
400 if (IsKextMatch && (BinOffset > 0) && (BinSize > 0)) {
401 break;
402 }
403 }
404
405 //
406 // Bundle was not found, or invalid.
407 //
408 if (!IsKextMatch) {
409 return EFI_NOT_FOUND;
410 }
411
412 *KextIndex = Index;
413 *KextPlistOffset = PlistOffset;
414 *KextPlistSize = PlistSize;
415 *KextBinOffset = BinOffset;
416 *KextBinSize = BinSize;
417
418 return EFI_SUCCESS;
419}
420
423 IN OUT MKEXT_CONTEXT *Context,
424 IN CONST CHAR8 *Identifier
425 )
426{
427 EFI_STATUS Status;
428 MKEXT_V2_FILE_ENTRY *MkextV2FileEntry;
429
430 MKEXT_KEXT *MkextKext;
431 LIST_ENTRY *KextLink;
432 UINT32 Index;
433 UINT32 BinOffsetSize;
434 BOOLEAN IsKextMatch;
435
436 UINT32 PlistOffset;
437 UINT32 PlistSize;
438
439 UINT32 PlistBundlesCount;
440 XML_NODE *PlistBundle;
441 UINT32 PlistBundleIndex;
442 UINT32 PlistBundleCount;
443 CONST CHAR8 *PlistBundleKey;
444 XML_NODE *PlistBundleKeyValue;
445
446 CONST CHAR8 *KextIdentifier;
447 UINT32 KextBinOffset;
448 UINT32 KextBinSize;
449
450 //
451 // Try to get cached kext.
452 //
453 KextLink = GetFirstNode (&Context->CachedKexts);
454 while (!IsNull (&Context->CachedKexts, KextLink)) {
455 MkextKext = GET_MKEXT_KEXT_FROM_LINK (KextLink);
456
457 if (AsciiStrCmp (Identifier, MkextKext->Identifier) == 0) {
458 return MkextKext;
459 }
460
461 KextLink = GetNextNode (&Context->CachedKexts, KextLink);
462 }
463
464 //
465 // Search mkext and add kext to cache.
466 //
467 IsKextMatch = FALSE;
468
469 //
470 // Mkext v1.
471 //
472 if (Context->MkextVersion == MKEXT_VERSION_V1) {
473 Status = InternalGetMkextV1KextOffsets (Context, Identifier, &Index, &PlistOffset, &PlistSize, &KextBinOffset, &KextBinSize);
474 if (Status != EFI_SUCCESS) {
475 return NULL;
476 }
477
478 //
479 // Mkext v2.
480 //
481 } else if (Context->MkextVersion == MKEXT_VERSION_V2) {
482 KextIdentifier = NULL;
483 KextBinOffset = 0;
484
485 //
486 // Enumerate bundle dicts.
487 //
488 PlistBundlesCount = XmlNodeChildren (Context->MkextKexts);
489 for (Index = 0; Index < PlistBundlesCount; Index++) {
490 PlistBundle = PlistNodeCast (XmlNodeChild (Context->MkextKexts, Index), PLIST_NODE_TYPE_DICT);
491 if (PlistBundle == NULL) {
492 return NULL;
493 }
494
495 PlistBundleCount = PlistDictChildren (PlistBundle);
496 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
497 PlistBundleKey = PlistKeyValue (PlistDictChild (PlistBundle, PlistBundleIndex, &PlistBundleKeyValue));
498 if ((PlistBundleKey == NULL) || (PlistBundleKeyValue == NULL)) {
499 continue;
500 }
501
502 if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
503 KextIdentifier = XmlNodeContent (PlistBundleKeyValue);
504 }
505
506 if (AsciiStrCmp (PlistBundleKey, MKEXT_EXECUTABLE_KEY) == 0) {
507 //
508 // Ensure binary offset is before plist offset.
509 //
510 if (!PlistIntegerValue (PlistBundleKeyValue, &KextBinOffset, sizeof (KextBinOffset), TRUE)) {
511 return NULL;
512 }
513 }
514 }
515
516 if ( (KextIdentifier != NULL)
517 && (AsciiStrCmp (KextIdentifier, Identifier) == 0)
518 && (KextBinOffset > 0)
519 && (KextBinOffset < Context->MkextSize - sizeof (MKEXT_V2_FILE_ENTRY)))
520 {
521 IsKextMatch = TRUE;
522 break;
523 }
524
525 KextIdentifier = NULL;
526 KextBinOffset = 0;
527 }
528
529 //
530 // Bundle was not found, or invalid.
531 //
532 if (!IsKextMatch) {
533 return NULL;
534 }
535
536 //
537 // Parse v2 binary header.
538 // We cannot support compressed binaries.
539 //
540 MkextV2FileEntry = (MKEXT_V2_FILE_ENTRY *)&Context->Mkext[KextBinOffset];
541 if (MkextV2FileEntry->CompressedSize != 0) {
542 return NULL;
543 }
544
545 KextBinOffset += OFFSET_OF (MKEXT_V2_FILE_ENTRY, Data);
546 KextBinSize = SwapBytes32 (MkextV2FileEntry->FullSize);
547
548 //
549 // Ensure binary is within mkext bounds.
550 //
551 if ( BaseOverflowAddU32 (KextBinOffset, KextBinSize, &BinOffsetSize)
552 || (BinOffsetSize > Context->MkextSize))
553 {
554 return NULL;
555 }
556
557 //
558 // Unsupported version.
559 //
560 } else {
561 return NULL;
562 }
563
564 return InsertCachedMkextKext (Context, Identifier, KextBinOffset, KextBinSize);
565}
566
567EFI_STATUS
569 IN CONST UINT8 *Buffer,
570 IN UINT32 BufferSize,
571 IN UINT32 NumReservedKexts,
572 IN OUT UINT8 *OutBuffer OPTIONAL,
573 IN UINT32 OutBufferSize OPTIONAL,
574 IN OUT UINT32 *OutMkextSize
575 )
576{
577 BOOLEAN Decompress;
578
579 MKEXT_HEADER_ANY *MkextHeader;
580 MKEXT_HEADER_ANY *MkextHeaderOut;
581 UINT32 MkextSize;
582 UINT32 MkextVersion;
583 UINT32 NumKexts;
584 UINT32 NumMaxKexts;
585
586 UINT32 Tmp;
587 UINT32 Index;
588 UINT32 CurrentOffset;
589 UINT32 NewOffset;
590 UINT32 PlistOffset;
591 UINT32 PlistCompSize;
592 UINT32 PlistFullSize;
593 UINT32 PlistFullSizeAligned;
594 UINT32 BinOffset;
595 UINT32 BinCompSize;
596 UINT32 BinFullSize;
597 UINT32 BinFullSizeAligned;
598
599 UINT8 *PlistBuffer;
600 XML_DOCUMENT *PlistXml;
601 XML_NODE *PlistBundles;
602 UINT32 PlistBundlesCount;
603 XML_NODE *PlistBundle;
604 UINT32 PlistBundleIndex;
605 UINT32 PlistBundleCount;
606 CONST CHAR8 *PlistBundleKey;
607 XML_NODE *BundleExecutable;
608
609 MKEXT_V2_FILE_ENTRY *MkextExecutableEntry;
610 MKEXT_V2_FILE_ENTRY *MkextOutExecutableEntry;
611 CHAR8 *BinaryOffsetStrings;
612 UINT32 BinaryOffsetStringsSize;
613
614 ASSERT (Buffer != NULL);
615 ASSERT (BufferSize > 0);
616
617 Decompress = OutBufferSize > 0;
618 if (Decompress) {
619 ASSERT (OutBuffer != NULL);
620 ASSERT (OutMkextSize != NULL);
621 }
622
623 if ( (BufferSize < sizeof (MKEXT_CORE_HEADER))
624 || !BASE_TYPE_ALIGNED (MKEXT_CORE_HEADER, Buffer))
625 {
626 return EFI_INVALID_PARAMETER;
627 }
628
629 MkextHeader = (MKEXT_HEADER_ANY *)Buffer;
630 MkextSize = SwapBytes32 (MkextHeader->Common.Length);
631 MkextVersion = SwapBytes32 (MkextHeader->Common.Version);
632 NumKexts = SwapBytes32 (MkextHeader->Common.NumKexts);
633
634 if ( (MkextHeader->Common.Magic != MKEXT_INVERT_MAGIC)
635 || (MkextHeader->Common.Signature != MKEXT_INVERT_SIGNATURE)
636 || (BufferSize != MkextSize)
637 || BaseOverflowAddU32 (NumKexts, NumReservedKexts, &NumMaxKexts))
638 {
639 return EFI_INVALID_PARAMETER;
640 }
641
642 MkextHeaderOut = NULL;
643
644 //
645 // Mkext v1.
646 //
647 if (MkextVersion == MKEXT_VERSION_V1) {
648 //
649 // Validate header and array size.
650 // We need to start our offset after the header including reserved kext slots.
651 //
652 if ( BaseOverflowMulAddU32 (sizeof (MKEXT_V1_KEXT), NumKexts, sizeof (MKEXT_V1_HEADER), &Tmp)
653 || (Tmp > MkextSize)
654 || BaseOverflowMulAddU32 (sizeof (MKEXT_V1_KEXT), NumMaxKexts, sizeof (MKEXT_V1_HEADER), &CurrentOffset)
655 || (MKEXT_ALIGN (CurrentOffset) < CurrentOffset))
656 {
657 return EFI_INVALID_PARAMETER;
658 }
659
660 CurrentOffset = MKEXT_ALIGN (CurrentOffset);
661
662 if (Decompress) {
663 //
664 // When decompressing, CurrentOffset needs to be within bounds of OutBufferSize.
665 // If not decompressing, this is unnecessary as we are calculating decompressed size only.
666 //
667 if (CurrentOffset > OutBufferSize) {
668 return EFI_BUFFER_TOO_SMALL;
669 }
670
671 //
672 // Copy header.
673 //
674 CopyMem (OutBuffer, Buffer, sizeof (MKEXT_V1_HEADER));
675 MkextHeaderOut = (MKEXT_HEADER_ANY *)OutBuffer;
676 }
677
678 //
679 // Process plists and binaries if present, decompressing as needed.
680 //
681 for (Index = 0; Index < NumKexts; Index++) {
682 PlistFullSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.FullSize);
683 BinFullSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.FullSize);
684 PlistFullSizeAligned = MKEXT_ALIGN (PlistFullSize);
685 BinFullSizeAligned = MKEXT_ALIGN (BinFullSize);
686
687 if ( (PlistFullSizeAligned < PlistFullSize)
688 || (BinFullSizeAligned < BinFullSize))
689 {
690 return EFI_INVALID_PARAMETER;
691 }
692
693 if (Decompress) {
694 //
695 // Decompress entry.
696 //
697 PlistOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.Offset);
698 PlistCompSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.CompressedSize);
699 BinOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.Offset);
700 BinCompSize = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.CompressedSize);
701
702 if (BaseOverflowTriAddU32 (CurrentOffset, PlistFullSizeAligned, BinFullSizeAligned, &Tmp)) {
703 return EFI_INVALID_PARAMETER;
704 }
705
706 if (Tmp > OutBufferSize) {
707 return EFI_BUFFER_TOO_SMALL;
708 }
709
710 //
711 // Compressed size == 0 means no compression.
712 //
713 if (PlistCompSize > 0) {
714 if ( BaseOverflowAddU32 (PlistOffset, PlistCompSize, &Tmp)
715 || (Tmp > MkextSize)
716 || (DecompressLZSS (
717 &OutBuffer[CurrentOffset],
718 PlistFullSize,
719 &((UINT8 *)Buffer)[PlistOffset],
720 PlistCompSize
721 ) != PlistFullSize))
722 {
723 return EFI_INVALID_PARAMETER;
724 }
725 } else {
726 if ( BaseOverflowAddU32 (PlistOffset, PlistFullSize, &Tmp)
727 || (Tmp > MkextSize))
728 {
729 return EFI_INVALID_PARAMETER;
730 }
731
732 CopyMem (&OutBuffer[CurrentOffset], &Buffer[PlistOffset], PlistFullSize);
733 }
734
735 MkextHeaderOut->V1.Kexts[Index].Plist.Offset = SwapBytes32 (CurrentOffset);
736 MkextHeaderOut->V1.Kexts[Index].Plist.CompressedSize = 0;
737 MkextHeaderOut->V1.Kexts[Index].Plist.FullSize = SwapBytes32 (PlistFullSize);
738 MkextHeaderOut->V1.Kexts[Index].Plist.ModifiedSeconds = MkextHeader->V1.Kexts[Index].Plist.ModifiedSeconds;
739 CurrentOffset += PlistFullSizeAligned;
740
741 if (BinFullSize > 0) {
742 //
743 // Compressed size == 0 means no compression.
744 //
745 if (BinCompSize > 0) {
746 if ( BaseOverflowAddU32 (BinOffset, BinCompSize, &Tmp)
747 || (Tmp > MkextSize)
748 || (DecompressLZSS (
749 &OutBuffer[CurrentOffset],
750 BinFullSize,
751 &((UINT8 *)Buffer)[BinOffset],
752 BinCompSize
753 ) != BinFullSize))
754 {
755 return EFI_INVALID_PARAMETER;
756 }
757 } else {
758 if ( BaseOverflowAddU32 (BinOffset, BinFullSize, &Tmp)
759 || (Tmp > MkextSize))
760 {
761 return EFI_INVALID_PARAMETER;
762 }
763
764 CopyMem (&OutBuffer[CurrentOffset], &Buffer[BinOffset], BinFullSize);
765 }
766
767 MkextHeaderOut->V1.Kexts[Index].Binary.Offset = SwapBytes32 (CurrentOffset);
768 MkextHeaderOut->V1.Kexts[Index].Binary.CompressedSize = 0;
769 MkextHeaderOut->V1.Kexts[Index].Binary.FullSize = SwapBytes32 (BinFullSize);
770 MkextHeaderOut->V1.Kexts[Index].Binary.ModifiedSeconds = MkextHeader->V1.Kexts[Index].Binary.ModifiedSeconds;
771 CurrentOffset += BinFullSizeAligned;
772 } else {
773 ZeroMem (&MkextHeaderOut->V1.Kexts[Index].Binary, sizeof (MKEXT_V1_KEXT_FILE));
774 }
775 } else {
776 //
777 // Calculate size only.
778 //
779 if (BaseOverflowTriAddU32 (
780 CurrentOffset,
781 PlistFullSizeAligned,
782 BinFullSizeAligned,
783 &CurrentOffset
784 ))
785 {
786 return EFI_INVALID_PARAMETER;
787 }
788 }
789 }
790
791 *OutMkextSize = CurrentOffset;
792
793 //
794 // Mkext v2.
795 //
796 } else if (MkextVersion == MKEXT_VERSION_V2) {
797 if (MkextSize < sizeof (MKEXT_V2_HEADER)) {
798 return EFI_INVALID_PARAMETER;
799 }
800
801 CurrentOffset = MKEXT_ALIGN (sizeof (MKEXT_V2_HEADER));
802
803 if (Decompress) {
804 //
805 // When decompressing, CurrentOffset needs to be within bounds of OutBufferSize.
806 // If not decompressing, this is unnecessary as we are calculating decompressed size only.
807 //
808 if (CurrentOffset > OutBufferSize) {
809 return EFI_BUFFER_TOO_SMALL;
810 }
811
812 //
813 // Copy header.
814 //
815 CopyMem (OutBuffer, Buffer, sizeof (MKEXT_V2_HEADER));
816 MkextHeaderOut = (MKEXT_HEADER_ANY *)OutBuffer;
817 }
818
819 if (!ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistFullSize, &PlistXml, &PlistBundles)) {
820 return EFI_INVALID_PARAMETER;
821 }
822
823 //
824 // All offset strings are kept in array until the plist is regenerated.
825 //
826 PlistBundlesCount = XmlNodeChildren (PlistBundles);
827 BinaryOffsetStrings = NULL;
828
829 if (Decompress) {
830 if (BaseOverflowTriMulU32 (PlistBundlesCount, KEXT_OFFSET_STR_LEN, sizeof (CHAR8), &BinaryOffsetStringsSize)) {
831 XmlDocumentFree (PlistXml);
832 FreePool (PlistBuffer);
833 return EFI_INVALID_PARAMETER;
834 }
835
836 BinaryOffsetStrings = AllocateZeroPool (BinaryOffsetStringsSize);
837 if (BinaryOffsetStrings == NULL) {
838 XmlDocumentFree (PlistXml);
839 FreePool (PlistBuffer);
840 return EFI_OUT_OF_RESOURCES;
841 }
842 }
843
844 //
845 // Enumerate bundles.
846 //
847 for (Index = 0; Index < PlistBundlesCount; Index++) {
848 PlistBundle = PlistNodeCast (XmlNodeChild (PlistBundles, Index), PLIST_NODE_TYPE_DICT);
849 if (PlistBundle == NULL) {
850 XmlDocumentFree (PlistXml);
851 FreePool (PlistBuffer);
852 if (Decompress) {
853 FreePool (BinaryOffsetStrings);
854 }
855
856 return EFI_INVALID_PARAMETER;
857 }
858
859 //
860 // Get executable information, if present.
861 //
862 PlistBundleCount = PlistDictChildren (PlistBundle);
863 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
864 PlistBundleKey = PlistKeyValue (PlistDictChild (PlistBundle, PlistBundleIndex, &BundleExecutable));
865 if (PlistBundleKey == NULL) {
866 continue;
867 }
868
869 if (AsciiStrCmp (PlistBundleKey, MKEXT_EXECUTABLE_KEY) == 0) {
870 if ( !PlistIntegerValue (BundleExecutable, &BinOffset, sizeof (BinOffset), TRUE)
871 || (BinOffset == 0)
872 || (BinOffset > MkextSize - sizeof (MKEXT_V2_FILE_ENTRY)))
873 {
874 XmlDocumentFree (PlistXml);
875 FreePool (PlistBuffer);
876 if (Decompress) {
877 FreePool (BinaryOffsetStrings);
878 }
879
880 return EFI_INVALID_PARAMETER;
881 }
882
883 MkextExecutableEntry = (MKEXT_V2_FILE_ENTRY *)&Buffer[BinOffset];
884 BinCompSize = SwapBytes32 (MkextExecutableEntry->CompressedSize);
885 BinFullSize = SwapBytes32 (MkextExecutableEntry->FullSize);
886 BinFullSizeAligned = MKEXT_ALIGN (BinFullSize);
887
888 if (BaseOverflowTriAddU32 (CurrentOffset, sizeof (MKEXT_V2_FILE_ENTRY), BinFullSizeAligned, &NewOffset)) {
889 XmlDocumentFree (PlistXml);
890 FreePool (PlistBuffer);
891 if (Decompress) {
892 FreePool (BinaryOffsetStrings);
893 }
894
895 return EFI_INVALID_PARAMETER;
896 }
897
898 if (Decompress) {
899 if (NewOffset > OutBufferSize) {
900 XmlDocumentFree (PlistXml);
901 FreePool (PlistBuffer);
902 FreePool (BinaryOffsetStrings);
903 return EFI_BUFFER_TOO_SMALL;
904 }
905
906 MkextOutExecutableEntry = (MKEXT_V2_FILE_ENTRY *)&OutBuffer[CurrentOffset];
907 MkextOutExecutableEntry->CompressedSize = 0;
908 MkextOutExecutableEntry->FullSize = SwapBytes32 (BinFullSize);
909
910 //
911 // Compressed size == 0 means no compression.
912 //
913 if (BinCompSize > 0) {
914 if ( BaseOverflowAddU32 (BinOffset, BinCompSize, &Tmp)
915 || (Tmp > MkextSize - sizeof (MKEXT_V2_FILE_ENTRY))
916 || (DecompressZLIB (
917 MkextOutExecutableEntry->Data,
918 BinFullSize,
919 MkextExecutableEntry->Data,
920 BinCompSize
921 ) != BinFullSize))
922 {
923 XmlDocumentFree (PlistXml);
924 FreePool (PlistBuffer);
925 FreePool (BinaryOffsetStrings);
926 return EFI_INVALID_PARAMETER;
927 }
928 } else {
929 if ( BaseOverflowAddU32 (BinOffset, BinFullSize, &Tmp)
930 || (Tmp > MkextSize - sizeof (MKEXT_V2_FILE_ENTRY)))
931 {
932 XmlDocumentFree (PlistXml);
933 FreePool (PlistBuffer);
934 FreePool (BinaryOffsetStrings);
935 return EFI_INVALID_PARAMETER;
936 }
937
938 CopyMem (MkextOutExecutableEntry->Data, MkextExecutableEntry->Data, BinFullSize);
939 }
940
942 &BinaryOffsetStrings[Index * KEXT_OFFSET_STR_LEN],
944 CurrentOffset
945 ))
946 {
947 XmlDocumentFree (PlistXml);
948 FreePool (PlistBuffer);
949 FreePool (BinaryOffsetStrings);
950 return EFI_INVALID_PARAMETER;
951 }
952
953 XmlNodeChangeContent (BundleExecutable, &BinaryOffsetStrings[Index * KEXT_OFFSET_STR_LEN]);
954 }
955
956 //
957 // Move to next bundle.
958 //
959 CurrentOffset = NewOffset;
960 break;
961 }
962 }
963 }
964
965 if (Decompress) {
966 PlistFullSize = UpdateMkextV2Plist (&MkextHeaderOut->V2, OutBufferSize, PlistXml, CurrentOffset);
967 }
968
969 XmlDocumentFree (PlistXml);
970 FreePool (PlistBuffer);
971 if (Decompress) {
972 FreePool (BinaryOffsetStrings);
973
974 if ( (PlistFullSize == 0)
975 || BaseOverflowAddU32 (CurrentOffset, PlistFullSize, OutMkextSize))
976 {
977 return EFI_INVALID_PARAMETER;
978 }
979 } else {
980 //
981 // Account for plist, future plist expansion for each bundle,
982 // and additional headers for future kext injection.
983 //
984 PlistFullSize = SwapBytes32 (MkextHeader->V2.PlistFullSize);
985 if ( BaseOverflowAddU32 (CurrentOffset, PlistFullSize, &CurrentOffset)
986 || BaseOverflowMulAddU32 (PlistBundlesCount, PLIST_EXPANSION_SIZE, CurrentOffset, &CurrentOffset)
987 || BaseOverflowMulAddU32 (NumReservedKexts, sizeof (MKEXT_V2_FILE_ENTRY), CurrentOffset, OutMkextSize))
988 {
989 return EFI_INVALID_PARAMETER;
990 }
991 }
992
993 //
994 // Unsupported version.
995 //
996 } else {
997 return EFI_UNSUPPORTED;
998 }
999
1000 if (Decompress) {
1001 UpdateMkextLengthChecksum (MkextHeaderOut, *OutMkextSize);
1002 }
1003
1004 return EFI_SUCCESS;
1005}
1006
1007BOOLEAN
1009 IN UINT8 *Mkext,
1010 IN UINT32 MkextSize,
1011 IN MACH_CPU_TYPE CpuType
1012 )
1013{
1014 MKEXT_HEADER_ANY *MkextHeader;
1015 MACH_CPU_TYPE MkextCpuType;
1016
1017 ASSERT (Mkext != NULL);
1018 ASSERT (MkextSize > 0);
1019
1020 if ( (MkextSize < sizeof (MKEXT_CORE_HEADER))
1021 || !BASE_TYPE_ALIGNED (MKEXT_CORE_HEADER, Mkext))
1022 {
1023 return FALSE;
1024 }
1025
1026 MkextHeader = (MKEXT_HEADER_ANY *)Mkext;
1027 MkextCpuType = SwapBytes32 (MkextHeader->Common.CpuType);
1028
1029 if ( (MkextHeader->Common.Magic != MKEXT_INVERT_MAGIC)
1030 || (MkextHeader->Common.Signature != MKEXT_INVERT_SIGNATURE)
1031 || (MkextSize != SwapBytes32 (MkextHeader->Common.Length)))
1032 {
1033 return FALSE;
1034 }
1035
1036 return MkextCpuType == CpuType;
1037}
1038
1039EFI_STATUS
1041 IN OUT MKEXT_CONTEXT *Context,
1042 IN OUT UINT8 *Mkext,
1043 IN UINT32 MkextSize,
1044 IN UINT32 MkextAllocSize
1045 )
1046{
1047 MKEXT_HEADER_ANY *MkextHeader;
1048 UINT32 MkextVersion;
1049 UINT32 MkextHeaderSize;
1050 MACH_CPU_TYPE CpuType;
1051 BOOLEAN Is32Bit;
1052 UINT32 NumKexts;
1053 UINT32 NumMaxKexts;
1054
1055 UINT32 Tmp;
1056 UINT32 Index;
1057 UINT32 StartingOffset;
1058 UINT32 CurrentOffset;
1059
1060 UINT8 *PlistBuffer;
1061 XML_DOCUMENT *PlistXml;
1062 UINT32 PlistOffset;
1063 UINT32 PlistFullSize;
1064 XML_NODE *PlistBundles;
1065
1066 //
1067 // Assumptions:
1068 // Kexts are aligned to 8 bytes.
1069 // Patching or blocking requires kexts to be decompressed.
1070 // Plist (for v2) is at end of mkext.
1071 // Mkext is big-endian per XNU requirements.
1072 //
1073
1074 ASSERT (Context != NULL);
1075 ASSERT (Mkext != NULL);
1076 ASSERT (MkextSize > 0);
1077 ASSERT (MkextAllocSize >= MkextSize);
1078
1079 if ( (MkextSize < sizeof (MKEXT_CORE_HEADER))
1080 || !BASE_TYPE_ALIGNED (MKEXT_CORE_HEADER, Mkext))
1081 {
1082 return EFI_INVALID_PARAMETER;
1083 }
1084
1085 MkextHeader = (MKEXT_HEADER_ANY *)Mkext;
1086 MkextVersion = SwapBytes32 (MkextHeader->Common.Version);
1087 NumKexts = SwapBytes32 (MkextHeader->Common.NumKexts);
1088 CpuType = SwapBytes32 (MkextHeader->Common.CpuType);
1089
1090 if ( (MkextHeader->Common.Magic != MKEXT_INVERT_MAGIC)
1091 || (MkextHeader->Common.Signature != MKEXT_INVERT_SIGNATURE)
1092 || (MkextSize != SwapBytes32 (MkextHeader->Common.Length)))
1093 {
1094 return EFI_INVALID_PARAMETER;
1095 }
1096
1097 if (CpuType == MachCpuTypeI386) {
1098 Is32Bit = TRUE;
1099 } else if (CpuType == MachCpuTypeX8664) {
1100 Is32Bit = FALSE;
1101 } else {
1102 return EFI_UNSUPPORTED;
1103 }
1104
1105 //
1106 // Mkext v1.
1107 //
1108 if (MkextVersion == MKEXT_VERSION_V1) {
1109 //
1110 // Validate header and array size.
1111 //
1112 if ( BaseOverflowMulAddU32 (sizeof (MKEXT_V1_KEXT), NumKexts, sizeof (MKEXT_V1_HEADER), &MkextHeaderSize)
1113 || (MkextHeaderSize > MkextSize))
1114 {
1115 return EFI_INVALID_PARAMETER;
1116 }
1117
1118 //
1119 // Calculate available kext slots. This value is assumed to be under the UINT32 max later on.
1120 //
1121 // Below finds the lowest offset to a plist or a binary, which is used to locate
1122 // the end of the usable space allocated for kext slots.
1123 //
1124 StartingOffset = 0;
1125 for (Index = 0; Index < NumKexts; Index++) {
1126 CurrentOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Plist.Offset);
1127 if ((StartingOffset == 0) || (CurrentOffset < StartingOffset)) {
1128 StartingOffset = CurrentOffset;
1129 }
1130
1131 //
1132 // A binary entry of zero size indicates no binary is present.
1133 //
1134 if (MkextHeader->V1.Kexts[Index].Binary.FullSize > 0) {
1135 CurrentOffset = SwapBytes32 (MkextHeader->V1.Kexts[Index].Binary.Offset);
1136 if (CurrentOffset < StartingOffset) {
1137 StartingOffset = CurrentOffset;
1138 }
1139 }
1140 }
1141
1142 if ( (StartingOffset < MkextHeaderSize)
1143 || (StartingOffset > MkextSize))
1144 {
1145 return EFI_INVALID_PARAMETER;
1146 }
1147
1148 Tmp = (StartingOffset - MkextHeaderSize) / sizeof (MKEXT_V1_KEXT);
1149 if ( BaseOverflowAddU32 (Tmp, NumKexts, &NumMaxKexts)
1150 || (NumMaxKexts == MAX_UINT32))
1151 {
1152 return EFI_INVALID_PARAMETER;
1153 }
1154
1155 //
1156 // Mkext v2.
1157 //
1158 } else if (MkextVersion == MKEXT_VERSION_V2) {
1159 if ( (MkextSize < sizeof (MKEXT_V2_HEADER))
1160 || !ParseMkextV2Plist (&MkextHeader->V2, &PlistBuffer, &PlistFullSize, &PlistXml, &PlistBundles))
1161 {
1162 return EFI_INVALID_PARAMETER;
1163 }
1164
1165 PlistOffset = SwapBytes32 (MkextHeader->V2.PlistOffset);
1166
1167 if ( BaseOverflowAddU32 (PlistOffset, PlistFullSize, &Tmp)
1168 || (Tmp != MkextSize))
1169 {
1170 return EFI_INVALID_PARAMETER;
1171 }
1172
1173 //
1174 // Unsupported version.
1175 //
1176 } else {
1177 return EFI_UNSUPPORTED;
1178 }
1179
1180 ZeroMem (Context, sizeof (*Context));
1181 Context->Mkext = Mkext;
1182 Context->MkextSize = MkextSize;
1183 Context->MkextHeader = MkextHeader;
1184 Context->MkextAllocSize = MkextAllocSize;
1185 Context->MkextVersion = MkextVersion;
1186 Context->Is32Bit = Is32Bit;
1187 Context->NumKexts = NumKexts;
1188 InitializeListHead (&Context->CachedKexts);
1189
1190 if (MkextVersion == MKEXT_VERSION_V1) {
1191 Context->NumMaxKexts = NumMaxKexts;
1192 } else if (MkextVersion == MKEXT_VERSION_V2) {
1193 Context->MkextInfoOffset = PlistOffset;
1194 Context->MkextInfo = PlistBuffer;
1195 Context->MkextInfoDocument = PlistXml;
1196 Context->MkextKexts = PlistBundles;
1197 }
1198
1199 return EFI_SUCCESS;
1200}
1201
1202VOID
1204 IN OUT MKEXT_CONTEXT *Context
1205 )
1206{
1207 MKEXT_KEXT *MkextKext;
1208 LIST_ENTRY *KextLink;
1209
1210 ASSERT (Context != NULL);
1211
1212 while (!IsListEmpty (&Context->CachedKexts)) {
1213 KextLink = GetFirstNode (&Context->CachedKexts);
1214 MkextKext = GET_MKEXT_KEXT_FROM_LINK (KextLink);
1215 RemoveEntryList (KextLink);
1216
1217 FreePool (MkextKext->Identifier);
1218 FreePool (MkextKext);
1219 }
1220
1221 if (Context->MkextInfoDocument != NULL) {
1222 XmlDocumentFree (Context->MkextInfoDocument);
1223 }
1224
1225 if (Context->MkextInfo != NULL) {
1226 FreePool (Context->MkextInfo);
1227 }
1228
1229 ZeroMem (Context, sizeof (*Context));
1230}
1231
1232EFI_STATUS
1234 IN OUT UINT32 *ReservedInfoSize,
1235 IN OUT UINT32 *ReservedExeSize,
1236 IN UINT32 InfoPlistSize,
1237 IN UINT8 *Executable OPTIONAL,
1238 IN UINT32 ExecutableSize OPTIONAL,
1239 IN BOOLEAN Is32Bit
1240 )
1241{
1242 OC_MACHO_CONTEXT Context;
1243
1244 ASSERT (ReservedInfoSize != NULL);
1245 ASSERT (ReservedExeSize != NULL);
1246
1247 InfoPlistSize = MACHO_ALIGN (InfoPlistSize);
1248
1249 if (Executable != NULL) {
1250 ASSERT (ExecutableSize > 0);
1251 if (!MachoInitializeContext (&Context, Executable, ExecutableSize, 0, ExecutableSize, Is32Bit)) {
1252 return EFI_INVALID_PARAMETER;
1253 }
1254
1255 ExecutableSize = MachoGetVmSize (&Context);
1256 if (ExecutableSize == 0) {
1257 return EFI_INVALID_PARAMETER;
1258 }
1259 }
1260
1261 if ( BaseOverflowAddU32 (*ReservedInfoSize, InfoPlistSize, &InfoPlistSize)
1262 || BaseOverflowAddU32 (*ReservedExeSize, ExecutableSize, &ExecutableSize))
1263 {
1264 return EFI_INVALID_PARAMETER;
1265 }
1266
1267 *ReservedInfoSize = InfoPlistSize;
1268 *ReservedExeSize = ExecutableSize;
1269
1270 return EFI_SUCCESS;
1271}
1272
1273EFI_STATUS
1275 IN OUT MKEXT_CONTEXT *Context,
1276 IN CONST CHAR8 *Identifier OPTIONAL,
1277 IN CONST CHAR8 *BundlePath,
1278 IN CONST CHAR8 *InfoPlist,
1279 IN UINT32 InfoPlistSize,
1280 IN UINT8 *Executable OPTIONAL,
1281 IN UINT32 ExecutableSize OPTIONAL,
1282 OUT CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE] OPTIONAL
1283 )
1284{
1285 UINT32 MkextNewSize;
1286 UINT32 PlistOffset;
1287 UINT32 BinOffset;
1288 UINT32 InfoPlistSizeAligned;
1289 UINT32 ExecutableSizeAligned;
1290
1291 CHAR8 *PlistBuffer;
1292 CHAR8 *PlistExported;
1293 UINT32 PlistExportedSize;
1294 XML_DOCUMENT *PlistXml;
1295 XML_NODE *PlistRoot;
1296 XML_NODE *KextPlistValue;
1297 BOOLEAN PlistFailed;
1298 UINT32 PlistBundleIndex;
1299 UINT32 PlistBundleCount;
1300 CONST CHAR8 *PlistBundleKey;
1301 XML_NODE *PlistBundleKeyValue;
1302 CONST CHAR8 *BundleVerStr;
1303
1304 CONST CHAR8 *TmpKeyValue;
1305 UINT32 FieldCount;
1306 UINT32 FieldIndex;
1307
1308 CHAR8 ExecutableSourceAddrStr[24];
1309 MKEXT_V2_FILE_ENTRY *MkextExecutableEntry;
1310
1311 ASSERT (Context != NULL);
1312 ASSERT (BundlePath != NULL);
1313 ASSERT (InfoPlist != NULL);
1314 ASSERT (InfoPlistSize > 0);
1315
1316 BinOffset = 0;
1317
1318 //
1319 // If an identifier was passed, ensure it does not already exist.
1320 //
1321 if (Identifier != NULL) {
1322 if (InternalCachedMkextKext (Context, Identifier) != NULL) {
1323 DEBUG ((DEBUG_INFO, "OCAK: Bundle %a is already present in mkext\n", Identifier));
1324 return EFI_ALREADY_STARTED;
1325 }
1326 }
1327
1328 PlistBuffer = AllocateCopyPool (InfoPlistSize, InfoPlist);
1329 if (PlistBuffer == NULL) {
1330 return EFI_OUT_OF_RESOURCES;
1331 }
1332
1333 PlistXml = XmlDocumentParse (PlistBuffer, InfoPlistSize, FALSE);
1334 if (PlistXml == NULL) {
1335 FreePool (PlistBuffer);
1336 return EFI_INVALID_PARAMETER;
1337 }
1338
1339 PlistRoot = PlistNodeCast (PlistDocumentRoot (PlistXml), PLIST_NODE_TYPE_DICT);
1340 if (PlistRoot == NULL) {
1341 XmlDocumentFree (PlistXml);
1342 FreePool (PlistBuffer);
1343 return EFI_INVALID_PARAMETER;
1344 }
1345
1346 //
1347 // We are not supposed to check for this, it is XNU responsibility, which reliably panics.
1348 // However, to avoid certain users making this kind of mistake, we still provide some
1349 // code in debug mode to diagnose it.
1350 //
1351 DEBUG_CODE_BEGIN ();
1352 FieldCount = PlistDictChildren (PlistRoot);
1353
1354 if (BundleVersion != NULL) {
1355 for (FieldIndex = 0; FieldIndex < FieldCount; ++FieldIndex) {
1356 TmpKeyValue = PlistKeyValue (PlistDictChild (PlistRoot, FieldIndex, &KextPlistValue));
1357 if (TmpKeyValue == NULL) {
1358 continue;
1359 }
1360
1361 //
1362 // Match CFBundleVersion.
1363 //
1364 if (AsciiStrCmp (TmpKeyValue, INFO_BUNDLE_VERSION_KEY) == 0) {
1365 if (PlistNodeCast (KextPlistValue, PLIST_NODE_TYPE_STRING) == NULL) {
1366 break;
1367 }
1368
1369 BundleVerStr = XmlNodeContent (KextPlistValue);
1370 AsciiStrCpyS (BundleVersion, MAX_INFO_BUNDLE_VERSION_KEY_SIZE, BundleVerStr);
1371 break;
1372 }
1373 }
1374 }
1375
1376 if (Executable == NULL) {
1377 for (FieldIndex = 0; FieldIndex < FieldCount; ++FieldIndex) {
1378 TmpKeyValue = PlistKeyValue (PlistDictChild (PlistRoot, FieldIndex, NULL));
1379 if (TmpKeyValue == NULL) {
1380 continue;
1381 }
1382
1383 if (AsciiStrCmp (TmpKeyValue, INFO_BUNDLE_EXECUTABLE_KEY) == 0) {
1384 DEBUG ((DEBUG_ERROR, "OCK: Plist-only kext has %a key\n", INFO_BUNDLE_EXECUTABLE_KEY));
1385 ASSERT (FALSE);
1386 CpuDeadLoop ();
1387 }
1388 }
1389 }
1390
1391 DEBUG_CODE_END ();
1392
1393 Identifier = NULL;
1394 PlistBundleCount = PlistDictChildren (PlistRoot);
1395 for (PlistBundleIndex = 0; PlistBundleIndex < PlistBundleCount; PlistBundleIndex++) {
1396 PlistBundleKey = PlistKeyValue (PlistDictChild (PlistRoot, PlistBundleIndex, &PlistBundleKeyValue));
1397 if ((PlistBundleKey == NULL) || (PlistBundleKeyValue == NULL)) {
1398 continue;
1399 }
1400
1401 if (AsciiStrCmp (PlistBundleKey, INFO_BUNDLE_IDENTIFIER_KEY) == 0) {
1402 Identifier = XmlNodeContent (PlistBundleKeyValue);
1403 break;
1404 }
1405 }
1406
1407 if (Identifier == NULL) {
1408 XmlDocumentFree (PlistXml);
1409 FreePool (PlistBuffer);
1410 return EFI_INVALID_PARAMETER;
1411 }
1412
1413 //
1414 // Mkext v1.
1415 //
1416 if (Context->MkextVersion == MKEXT_VERSION_V1) {
1417 XmlDocumentFree (PlistXml);
1418 FreePool (PlistBuffer);
1419
1420 if (Context->NumKexts >= Context->NumMaxKexts) {
1421 return EFI_BUFFER_TOO_SMALL;
1422 }
1423
1424 InfoPlistSizeAligned = MKEXT_ALIGN (InfoPlistSize);
1425 if (InfoPlistSizeAligned < InfoPlistSize) {
1426 return EFI_INVALID_PARAMETER;
1427 }
1428
1429 //
1430 // Plist will be placed at end of mkext.
1431 //
1432 PlistOffset = Context->MkextSize;
1433 if (BaseOverflowAddU32 (PlistOffset, InfoPlistSizeAligned, &MkextNewSize)) {
1434 return EFI_INVALID_PARAMETER;
1435 }
1436
1437 if (MkextNewSize > Context->MkextAllocSize) {
1438 return EFI_BUFFER_TOO_SMALL;
1439 }
1440
1441 //
1442 // Executable, if present, will be placed right after plist.
1443 //
1444 if (Executable != NULL) {
1445 ASSERT (ExecutableSize > 0);
1446
1447 BinOffset = MkextNewSize;
1448 if (!InternalParseKextBinary (&Executable, &ExecutableSize, Context->Is32Bit)) {
1449 return EFI_INVALID_PARAMETER;
1450 }
1451
1452 ExecutableSizeAligned = MKEXT_ALIGN (ExecutableSize);
1453 if ( (ExecutableSizeAligned < ExecutableSize)
1454 || BaseOverflowAddU32 (BinOffset, ExecutableSizeAligned, &MkextNewSize))
1455 {
1456 return EFI_INVALID_PARAMETER;
1457 }
1458
1459 if (MkextNewSize > Context->MkextAllocSize) {
1460 return EFI_BUFFER_TOO_SMALL;
1461 }
1462
1463 CopyMem (&Context->Mkext[BinOffset], Executable, ExecutableSize);
1464 Context->MkextHeader->V1.Kexts[Context->NumKexts].Binary.Offset = SwapBytes32 (BinOffset);
1465 Context->MkextHeader->V1.Kexts[Context->NumKexts].Binary.CompressedSize = 0;
1466 Context->MkextHeader->V1.Kexts[Context->NumKexts].Binary.FullSize = SwapBytes32 (ExecutableSize);
1467 Context->MkextHeader->V1.Kexts[Context->NumKexts].Binary.ModifiedSeconds = 0;
1468 }
1469
1470 CopyMem (&Context->Mkext[PlistOffset], InfoPlist, InfoPlistSize);
1471 Context->MkextHeader->V1.Kexts[Context->NumKexts].Plist.Offset = SwapBytes32 (PlistOffset);
1472 Context->MkextHeader->V1.Kexts[Context->NumKexts].Plist.CompressedSize = 0;
1473 Context->MkextHeader->V1.Kexts[Context->NumKexts].Plist.FullSize = SwapBytes32 (InfoPlistSize);
1474 Context->MkextHeader->V1.Kexts[Context->NumKexts].Plist.ModifiedSeconds = 0;
1475
1476 //
1477 // Assumption:
1478 // NumKexts is checked to be under MaxNumKexts, which is assumed to be under
1479 // the max value of UINT32 during context creation. This operation thus cannot overflow.
1480 //
1481 Context->MkextSize = MkextNewSize;
1482 Context->NumKexts++;
1483
1484 //
1485 // Mkext v2.
1486 //
1487 } else if (Context->MkextVersion == MKEXT_VERSION_V2) {
1488 //
1489 // Executable, if present, will be placed at end of mkext and plist will be moved further out.
1490 //
1491 PlistOffset = Context->MkextInfoOffset;
1492 PlistFailed = FALSE;
1493 if (Executable != NULL) {
1494 ASSERT (ExecutableSize > 0);
1495
1496 BinOffset = PlistOffset;
1497 if (!InternalParseKextBinary (&Executable, &ExecutableSize, Context->Is32Bit)) {
1498 XmlDocumentFree (PlistXml);
1499 FreePool (PlistBuffer);
1500 return EFI_INVALID_PARAMETER;
1501 }
1502
1503 ExecutableSizeAligned = MKEXT_ALIGN (ExecutableSize);
1504 if ( (ExecutableSizeAligned < ExecutableSize)
1505 || BaseOverflowTriAddU32 (BinOffset, sizeof (MKEXT_V2_FILE_ENTRY), ExecutableSizeAligned, &PlistOffset))
1506 {
1507 XmlDocumentFree (PlistXml);
1508 FreePool (PlistBuffer);
1509 return EFI_INVALID_PARAMETER;
1510 }
1511
1512 if (PlistOffset >= Context->MkextAllocSize) {
1513 XmlDocumentFree (PlistXml);
1514 FreePool (PlistBuffer);
1515 return EFI_BUFFER_TOO_SMALL;
1516 }
1517
1518 PlistFailed |= !AsciiUint64ToLowerHex (ExecutableSourceAddrStr, sizeof (ExecutableSourceAddrStr), BinOffset);
1519 PlistFailed |= XmlNodeAppend (PlistRoot, "key", NULL, MKEXT_EXECUTABLE_KEY) == NULL;
1520 PlistFailed |= XmlNodeAppend (PlistRoot, "integer", MKEXT_INFO_INTEGER_ATTRIBUTES, ExecutableSourceAddrStr) == NULL;
1521 }
1522
1523 //
1524 // Add bundle path.
1525 //
1526 PlistFailed |= XmlNodeAppend (PlistRoot, "key", NULL, MKEXT_BUNDLE_PATH_KEY) == NULL;
1527 PlistFailed |= XmlNodeAppend (PlistRoot, "string", NULL, BundlePath) == NULL;
1528 if (PlistFailed) {
1529 XmlDocumentFree (PlistXml);
1530 FreePool (PlistBuffer);
1531 return EFI_OUT_OF_RESOURCES;
1532 }
1533
1534 //
1535 // Strip down Info.plist for appending to primary plist.
1536 //
1537 PlistExported = XmlDocumentExport (PlistXml, &PlistExportedSize, 2, FALSE);
1538 XmlDocumentFree (PlistXml);
1539 FreePool (PlistBuffer);
1540
1541 if (XmlNodeAppend (Context->MkextKexts, "dict", NULL, PlistExported) == NULL) {
1542 return EFI_OUT_OF_RESOURCES;
1543 }
1544
1545 Context->MkextInfoOffset = PlistOffset;
1546
1547 if (Executable != NULL) {
1548 MkextExecutableEntry = (MKEXT_V2_FILE_ENTRY *)&Context->Mkext[BinOffset];
1549 MkextExecutableEntry->CompressedSize = 0;
1550 MkextExecutableEntry->FullSize = SwapBytes32 (ExecutableSize);
1551 CopyMem (MkextExecutableEntry->Data, Executable, ExecutableSize);
1552
1553 BinOffset += OFFSET_OF (MKEXT_V2_FILE_ENTRY, Data);
1554 }
1555
1556 //
1557 // Unsupported version.
1558 //
1559 } else {
1560 XmlDocumentFree (PlistXml);
1561 FreePool (PlistBuffer);
1562 return EFI_UNSUPPORTED;
1563 }
1564
1565 //
1566 // Add kext to cache.
1567 //
1568 InsertCachedMkextKext (Context, Identifier, BinOffset, ExecutableSize);
1569
1570 return EFI_SUCCESS;
1571}
1572
1573EFI_STATUS
1575 IN OUT MKEXT_CONTEXT *Context,
1576 IN CONST CHAR8 *Identifier,
1577 IN PATCHER_GENERIC_PATCH *Patch
1578 )
1579{
1580 EFI_STATUS Status;
1581 PATCHER_CONTEXT Patcher;
1582
1583 ASSERT (Context != NULL);
1584 ASSERT (Identifier != NULL);
1585 ASSERT (Patch != NULL);
1586
1587 Status = PatcherInitContextFromMkext (&Patcher, Context, Identifier);
1588 if (EFI_ERROR (Status)) {
1589 DEBUG ((DEBUG_INFO, "OCAK: Failed to mkext find %a - %r\n", Identifier, Status));
1590 return Status;
1591 }
1592
1593 return PatcherApplyGenericPatch (&Patcher, Patch);
1594}
1595
1596EFI_STATUS
1598 IN OUT MKEXT_CONTEXT *Context,
1599 IN KERNEL_QUIRK_NAME Quirk,
1600 IN UINT32 KernelVersion
1601 )
1602{
1603 EFI_STATUS Status;
1604 KERNEL_QUIRK *KernelQuirk;
1605 PATCHER_CONTEXT Patcher;
1606
1607 ASSERT (Context != NULL);
1608
1609 KernelQuirk = &gKernelQuirks[Quirk];
1610 ASSERT (KernelQuirk->Identifier != NULL);
1611
1612 Status = PatcherInitContextFromMkext (&Patcher, Context, KernelQuirk->Identifier);
1613 if (!EFI_ERROR (Status)) {
1614 return KernelQuirk->PatchFunction (&Patcher, KernelVersion);
1615 }
1616
1617 //
1618 // It is up to the function to decide whether this is critical or not.
1619 //
1620 DEBUG ((DEBUG_INFO, "OCAK: Failed to mkext find %a - %r\n", KernelQuirk->Identifier, Status));
1621 return KernelQuirk->PatchFunction (NULL, KernelVersion);
1622}
1623
1624EFI_STATUS
1626 IN OUT MKEXT_CONTEXT *Context,
1627 IN CONST CHAR8 *Identifier,
1628 IN BOOLEAN Exclude
1629 )
1630{
1631 EFI_STATUS Status;
1632 PATCHER_CONTEXT Patcher;
1633
1634 ASSERT (Context != NULL);
1635 ASSERT (Identifier != NULL);
1636
1637 if (Exclude) {
1638 Status = PatcherExcludeMkextKext (Context, Identifier);
1639 } else {
1640 Status = PatcherInitContextFromMkext (&Patcher, Context, Identifier);
1641 if (EFI_ERROR (Status)) {
1642 DEBUG ((DEBUG_INFO, "OCAK: Failed to mkext find %a - %r\n", Identifier, Status));
1643 return Status;
1644 }
1645
1646 Status = PatcherBlockKext (&Patcher);
1647 }
1648
1649 return Status;
1650}
1651
1652EFI_STATUS
1654 IN OUT MKEXT_CONTEXT *Context
1655 )
1656{
1657 UINT32 MkextPlistSize;
1658
1659 ASSERT (Context != NULL);
1660
1661 //
1662 // Mkext v1.
1663 //
1664 if (Context->MkextVersion == MKEXT_VERSION_V1) {
1665 Context->MkextHeader->Common.NumKexts = SwapBytes32 (Context->NumKexts);
1666
1667 //
1668 // Mkext v2.
1669 //
1670 } else if (Context->MkextVersion == MKEXT_VERSION_V2) {
1671 MkextPlistSize = UpdateMkextV2Plist (
1672 &Context->MkextHeader->V2,
1673 Context->MkextAllocSize,
1674 Context->MkextInfoDocument,
1675 Context->MkextInfoOffset
1676 );
1677 Context->MkextSize = Context->MkextInfoOffset + MkextPlistSize;
1678
1679 //
1680 // Unsupported version.
1681 //
1682 } else {
1683 return EFI_UNSUPPORTED;
1684 }
1685
1686 UpdateMkextLengthChecksum (Context->MkextHeader, Context->MkextSize);
1687 return EFI_SUCCESS;
1688}
@ MachCpuTypeI386
@ MachCpuTypeX8664
INT32 MACH_CPU_TYPE
#define MACH_HEADER_SIGNATURE
the mach magic number
#define MACH_HEADER_64_SIGNATURE
the 64-bit mach magic number
#define MKEXT_INVERT_SIGNATURE
Definition AppleMkext.h:37
#define MKEXT_VERSION_V2
Definition AppleMkext.h:45
#define MKEXT_VERSION_V1
Definition AppleMkext.h:41
#define MKEXT_INVERT_MAGIC
Definition AppleMkext.h:29
UINT32 Version
UINT64 Length
KERNEL_QUIRK gKernelQuirks[]
EFI_STATUS Decompress(IN RUNLIST *Runlist, IN UINT64 Offset, IN UINTN Length, OUT UINT8 *Dest)
STATIC UINT32 KernelVersion
Definition KextInject.c:28
EFI_STATUS MkextContextApplyQuirk(IN OUT MKEXT_CONTEXT *Context, IN KERNEL_QUIRK_NAME Quirk, IN UINT32 KernelVersion)
#define MKEXT_ALIGN(a)
MKEXT_KEXT * InternalCachedMkextKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier)
EFI_STATUS MkextContextBlock(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier, IN BOOLEAN Exclude)
EFI_STATUS MkextInjectPatchComplete(IN OUT MKEXT_CONTEXT *Context)
STATIC UINT32 UpdateMkextV2Plist(IN OUT MKEXT_V2_HEADER *Mkext, IN UINT32 AllocatedSize, IN XML_DOCUMENT *PlistDoc, IN UINT32 Offset)
EFI_STATUS MkextReserveKextSize(IN OUT UINT32 *ReservedInfoSize, IN OUT UINT32 *ReservedExeSize, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, IN BOOLEAN Is32Bit)
BOOLEAN MkextCheckCpuType(IN UINT8 *Mkext, IN UINT32 MkextSize, IN MACH_CPU_TYPE CpuType)
STATIC BOOLEAN ParseMkextV2Plist(IN MKEXT_V2_HEADER *Mkext, OUT UINT8 **Plist, OUT UINT32 *PlistSize, OUT XML_DOCUMENT **PlistDoc, OUT XML_NODE **PlistBundles)
VOID InternalDropCachedMkextKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier)
EFI_STATUS MkextContextApplyPatch(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier, IN PATCHER_GENERIC_PATCH *Patch)
VOID MkextContextFree(IN OUT MKEXT_CONTEXT *Context)
STATIC MKEXT_KEXT * InsertCachedMkextKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier, IN UINT32 BinOffset, IN UINT32 BinSize)
EFI_STATUS InternalGetMkextV1KextOffsets(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier, OUT UINT32 *KextIndex, OUT UINT32 *KextPlistOffset, OUT UINT32 *KextPlistSize, OUT UINT32 *KextBinOffset, OUT UINT32 *KextBinSize)
EFI_STATUS MkextContextInit(IN OUT MKEXT_CONTEXT *Context, IN OUT UINT8 *Mkext, IN UINT32 MkextSize, IN UINT32 MkextAllocSize)
BOOLEAN InternalParseKextBinary(IN OUT UINT8 **Buffer, IN OUT UINT32 *BufferSize, IN BOOLEAN Is32Bit)
EFI_STATUS MkextInjectKext(IN OUT MKEXT_CONTEXT *Context, IN CONST CHAR8 *Identifier OPTIONAL, IN CONST CHAR8 *BundlePath, IN CONST CHAR8 *InfoPlist, IN UINT32 InfoPlistSize, IN UINT8 *Executable OPTIONAL, IN UINT32 ExecutableSize OPTIONAL, OUT CHAR8 BundleVersion[MAX_INFO_BUNDLE_VERSION_KEY_SIZE] OPTIONAL)
EFI_STATUS MkextDecompress(IN CONST UINT8 *Buffer, IN UINT32 BufferSize, IN UINT32 NumReservedKexts, IN OUT UINT8 *OutBuffer OPTIONAL, IN UINT32 OutBufferSize OPTIONAL, IN OUT UINT32 *OutMkextSize)
STATIC VOID UpdateMkextLengthChecksum(IN MKEXT_HEADER_ANY *Mkext, IN UINT32 Length)
#define MKEXT_KEXT_SIGNATURE
#define GET_MKEXT_KEXT_FROM_LINK(This)
#define MKEXT_EXECUTABLE_KEY
EFI_STATUS PatcherBlockKext(IN OUT PATCHER_CONTEXT *Context)
EFI_STATUS PatcherInitContextFromMkext(IN OUT PATCHER_CONTEXT *Context, IN OUT MKEXT_CONTEXT *Mkext, IN CONST CHAR8 *Name)
EFI_STATUS PatcherExcludeMkextKext(IN OUT MKEXT_CONTEXT *MkextContext, IN CONST CHAR8 *Identifier)
#define MKEXT_INFO_INTEGER_ATTRIBUTES
#define MAX_INFO_BUNDLE_VERSION_KEY_SIZE
#define MKEXT_BUNDLE_PATH_KEY
#define MKEXT_INFO_DICTIONARIES_KEY
#define INFO_BUNDLE_EXECUTABLE_KEY
EFI_STATUS PatcherApplyGenericPatch(IN OUT PATCHER_CONTEXT *Context, IN PATCHER_GENERIC_PATCH *Patch)
#define PLIST_EXPANSION_SIZE
#define INFO_BUNDLE_VERSION_KEY
KERNEL_QUIRK_NAME
#define INFO_BUNDLE_IDENTIFIER_KEY
UINTN DecompressZLIB(OUT UINT8 *Dst, IN UINTN DstLen, IN CONST UINT8 *Src, IN UINTN SrcLen)
Definition zlib_uefi.c:59
UINT32 Adler32(IN CONST UINT8 *Buffer, IN UINT32 BufferLen)
Definition zlib_uefi.c:80
UINT32 DecompressLZSS(OUT UINT8 *Dst, IN UINT32 DstLen, IN UINT8 *Src, IN UINT32 SrcLen)
EFI_STATUS FatFilterArchitectureByType(IN OUT UINT8 **FileData, IN OUT UINT32 *FileSize, IN MACH_CPU_TYPE CpuType)
Definition MachoFat.c:116
BOOLEAN MachoInitializeContext(OUT OC_MACHO_CONTEXT *Context, IN VOID *FileData, IN UINT32 FileSize, IN UINT32 HeaderOffset, IN UINT32 InnerSize, IN BOOLEAN Is32Bit)
Definition Header.c:29
UINT32 MachoGetVmSize(IN OUT OC_MACHO_CONTEXT *Context)
Definition Header.c:88
#define MACHO_ALIGN(x)
Definition OcMachoLib.h:28
BOOLEAN AsciiUint64ToLowerHex(OUT CHAR8 *Buffer, IN UINT32 BufferSize, IN UINT64 Value)
Definition OcAsciiLib.c:150
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
XML_NODE * XmlDocumentRoot(IN CONST XML_DOCUMENT *Document)
Definition OcXmlLib.c:1447
@ PLIST_NODE_TYPE_DICT
Definition OcXmlLib.h:91
@ PLIST_NODE_TYPE_STRING
Definition OcXmlLib.h:93
XML_DOCUMENT * XmlDocumentParse(IN OUT CHAR8 *Buffer, IN UINT32 Length, IN BOOLEAN WithRefs)
Definition OcXmlLib.c:1308
CONST CHAR8 * PlistKeyValue(IN XML_NODE *Node OPTIONAL)
Definition OcXmlLib.c:1841
UINT32 XmlNodeChildren(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1493
CHAR8 * XmlDocumentExport(IN CONST XML_DOCUMENT *Document, OUT UINT32 *Length OPTIONAL, IN UINT32 Skip, IN BOOLEAN PrependPlistInfo)
Definition OcXmlLib.c:1367
CONST CHAR8 * XmlNodeContent(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1467
UINT32 PlistDictChildren(IN CONST XML_NODE *Node)
Definition OcXmlLib.c:1813
BOOLEAN PlistIntegerValue(IN XML_NODE *Node OPTIONAL, OUT VOID *Value, IN UINT32 Size, IN BOOLEAN Hex)
Definition OcXmlLib.c:1943
XML_NODE * PlistNodeCast(IN XML_NODE *Node OPTIONAL, IN PLIST_NODE_TYPE Type)
Definition OcXmlLib.c:1760
XML_NODE * XmlNodeAppend(IN OUT XML_NODE *Node, IN CONST CHAR8 *Name, IN CONST CHAR8 *Attributes OPTIONAL, IN CONST CHAR8 *Content OPTIONAL)
Definition OcXmlLib.c:1581
XML_NODE * PlistDocumentRoot(IN CONST XML_DOCUMENT *Document)
Definition OcXmlLib.c:1736
XML_NODE * XmlNodeChild(IN CONST XML_NODE *Node, IN UINT32 Child)
Definition OcXmlLib.c:1503
VOID XmlDocumentFree(IN OUT XML_DOCUMENT *Document)
Definition OcXmlLib.c:1435
VOID XmlNodeChangeContent(IN OUT XML_NODE *Node, IN CONST CHAR8 *Content)
Definition OcXmlLib.c:1477
XML_NODE * PlistDictChild(IN CONST XML_NODE *Node, IN UINT32 Child, OUT XML_NODE **Value OPTIONAL)
Definition OcXmlLib.c:1823
#define KEXT_OFFSET_STR_LEN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55
KERNEL_QUIRK_PATCH_FUNCTION * PatchFunction
CONST CHAR8 * Identifier
MACH_CPU_TYPE CpuType
Definition AppleMkext.h:78
CHAR8 * Identifier
UINT32 Signature
UINT32 BinarySize
UINT32 BinaryOffset
LIST_ENTRY Link
MKEXT_V1_KEXT Kexts[]
Definition AppleMkext.h:144
MKEXT_V1_KEXT_FILE Plist
Definition AppleMkext.h:126
MKEXT_V1_KEXT_FILE Binary
Definition AppleMkext.h:130
UINT32 PlistFullSize
Definition AppleMkext.h:196
MKEXT_V1_HEADER V1
Definition AppleMkext.h:204
MKEXT_CORE_HEADER Common
Definition AppleMkext.h:203
MKEXT_V2_HEADER V2
Definition AppleMkext.h:205