1/*
2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28extern "C" {
29#include <mach/kmod.h>
30#include <libkern/kernel_mach_header.h>
31#include <libkern/prelink.h>
32#include <libkern/crypto/sha2.h>
33}
34
35#define IOKIT_ENABLE_SHARED_PTR
36
37#include <libkern/version.h>
38#include <libkern/c++/OSContainers.h>
39#include <libkern/OSKextLibPrivate.h>
40#include <libkern/c++/OSKext.h>
41#include <IOKit/IOLib.h>
42#include <IOKit/IOService.h>
43#include <IOKit/IODeviceTreeSupport.h>
44#include <IOKit/IOCatalogue.h>
45
46#if __x86_64__
47#define KASLR_KEXT_DEBUG 0
48#endif
49
50#if PRAGMA_MARK
51#pragma mark Bootstrap Declarations
52#endif
53/*********************************************************************
54* Bootstrap Declarations
55*
56* The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
57* code from other parts of the kernel, so function symbols are not
58* exported; rather pointers to those functions are exported.
59*
60* xxx - need to think about locking for handling the 'weak' refs.
61* xxx - do export a non-KLD function that says you've called a
62* xxx - bootstrap function that has been removed.
63*
64* ALL call-ins to this segment of the kernel must be done through
65* exported pointers. The symbols themselves are private and not to
66* be linked against.
67*********************************************************************/
68extern "C" {
69extern void (*record_startup_extensions_function)(void);
70extern void (*load_security_extensions_function)(void);
71};
72
73static void bootstrapRecordStartupExtensions(void);
74static void bootstrapLoadSecurityExtensions(void);
75
76
77#if NO_KEXTD
78extern "C" bool IORamDiskBSDRoot(void);
79#endif
80
81#if PRAGMA_MARK
82#pragma mark Macros
83#endif
84/*********************************************************************
85* Macros
86*********************************************************************/
87#define CONST_STRLEN(str) (sizeof(str) - 1)
88
89#if PRAGMA_MARK
90#pragma mark Kernel Component Kext Identifiers
91#endif
92/*********************************************************************
93* Kernel Component Kext Identifiers
94*
95* We could have each kernel resource kext automatically "load" as
96* it's created, but it's nicer to have them listed in kextstat in
97* the order of this list. We'll walk through this after setting up
98* all the boot kexts and have them load up.
99*********************************************************************/
100static const char * sKernelComponentNames[] = {
101 // The kexts for these IDs must have a version matching 'osrelease'.
102 "com.apple.kernel",
103 "com.apple.kpi.bsd",
104 "com.apple.kpi.dsep",
105 "com.apple.kpi.iokit",
106 "com.apple.kpi.kasan",
107 "com.apple.kpi.kcov",
108 "com.apple.kpi.libkern",
109 "com.apple.kpi.mach",
110 "com.apple.kpi.private",
111 "com.apple.kpi.unsupported",
112 "com.apple.iokit.IONVRAMFamily",
113 "com.apple.driver.AppleNMI",
114 "com.apple.iokit.IOSystemManagementFamily",
115 "com.apple.iokit.ApplePlatformFamily",
116 NULL
117};
118
119#if PRAGMA_MARK
120#pragma mark KLDBootstrap Class
121#endif
122/*********************************************************************
123* KLDBootstrap Class
124*
125* We use a C++ class here so that it can be a friend of OSKext and
126* get at private stuff. We can't hide the class itself, but we can
127* hide the instance through which we invoke the functions.
128*********************************************************************/
129class KLDBootstrap {
130 friend void bootstrapRecordStartupExtensions(void);
131 friend void bootstrapLoadSecurityExtensions(void);
132
133private:
134 void readStartupExtensions(void);
135
136 void readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type);
137 void readBooterExtensions(void);
138
139 OSReturn loadKernelComponentKexts(void);
140 void loadKernelExternalComponents(void);
141 void readBuiltinPersonalities(void);
142
143 void loadSecurityExtensions(void);
144
145public:
146 KLDBootstrap(void);
147 ~KLDBootstrap(void);
148};
149
150LIBKERN_ALWAYS_DESTROY static KLDBootstrap sBootstrapObject;
151
152/*********************************************************************
153* Set the function pointers for the entry points into the bootstrap
154* segment upon C++ static constructor invocation.
155*********************************************************************/
156KLDBootstrap::KLDBootstrap(void)
157{
158 if (this != &sBootstrapObject) {
159 panic("Attempt to access bootstrap segment.");
160 }
161 record_startup_extensions_function = &bootstrapRecordStartupExtensions;
162 load_security_extensions_function = &bootstrapLoadSecurityExtensions;
163}
164
165/*********************************************************************
166* Clear the function pointers for the entry points into the bootstrap
167* segment upon C++ static destructor invocation.
168*********************************************************************/
169KLDBootstrap::~KLDBootstrap(void)
170{
171 if (this != &sBootstrapObject) {
172 panic("Attempt to access bootstrap segment.");
173 }
174
175
176 record_startup_extensions_function = NULL;
177 load_security_extensions_function = NULL;
178}
179
180/*********************************************************************
181*********************************************************************/
182void
183KLDBootstrap::readStartupExtensions(void)
184{
185 kernel_section_t * prelinkInfoSect = NULL; // do not free
186
187 OSKextLog(/* kext */ NULL,
188 kOSKextLogProgressLevel |
189 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
190 kOSKextLogKextBookkeepingFlag,
191 format: "Reading startup extensions.");
192
193 kc_format_t kc_format;
194 kernel_mach_header_t *mh = &_mh_execute_header;
195 if (PE_get_primary_kc_format(type: &kc_format) && kc_format == KCFormatFileset) {
196 mh = (kernel_mach_header_t *)PE_get_kc_header(type: KCKindPrimary);
197 }
198
199 /* If the prelink info segment has a nonzero size, we are prelinked
200 * and won't have any individual kexts or mkexts to read.
201 * Otherwise, we need to read kexts or the mkext from what the booter
202 * has handed us.
203 */
204 prelinkInfoSect = getsectbynamefromheader(header: mh, kPrelinkInfoSegment, kPrelinkInfoSection);
205 if (prelinkInfoSect->size) {
206 readPrelinkedExtensions(mh, type: KCKindPrimary);
207 } else {
208 readBooterExtensions();
209 }
210
211 kernel_mach_header_t *akc_mh;
212 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(type: KCKindAuxiliary);
213 if (akc_mh) {
214 readPrelinkedExtensions(mh: akc_mh, type: KCKindAuxiliary);
215 }
216
217 loadKernelComponentKexts();
218 loadKernelExternalComponents();
219 readBuiltinPersonalities();
220 OSKext::sendAllKextPersonalitiesToCatalog(startMatching: true);
221
222 return;
223}
224
225/*********************************************************************
226*********************************************************************/
227void
228KLDBootstrap::readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type)
229{
230 bool ret;
231 OSSharedPtr<OSData> loaded_kcUUID;
232 OSSharedPtr<OSString> errorString;
233 OSSharedPtr<OSObject> parsedXML;
234 kernel_section_t *infoPlistSection = NULL;
235 OSDictionary *infoDict = NULL; // do not release
236
237 OSKextLog(/* kext */ NULL,
238 kOSKextLogProgressLevel |
239 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
240 format: "Starting from prelinked kernel.");
241
242 /*
243 * The 'infoPlistSection' should contains an XML dictionary that
244 * contains some meta data about the KC, and also describes each kext
245 * included in the kext collection. Unserialize this dictionary and
246 * then iterate over each kext.
247 */
248 infoPlistSection = getsectbynamefromheader(header: mh, kPrelinkInfoSegment, kPrelinkInfoSection);
249 parsedXML = OSUnserializeXML(buffer: (const char *)infoPlistSection->addr, errorString);
250 if (parsedXML) {
251 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
252 }
253
254 if (!infoDict) {
255 const char *errorCString = "(unknown error)";
256
257 if (errorString && errorString->getCStringNoCopy()) {
258 errorCString = errorString->getCStringNoCopy();
259 } else if (parsedXML) {
260 errorCString = "not a dictionary";
261 }
262 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
263 format: "Error unserializing kext info plist section: %s.", errorCString);
264 return;
265 }
266
267 /* Validate that the Kext Collection is prelinked to the loaded KC */
268 if (type == KCKindAuxiliary) {
269 if (OSKext::validateKCFileSetUUID(infoDict, type: KCKindAuxiliary) != 0) {
270 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
271 format: "Early boot AuxKC doesn't appear to be linked against the loaded BootKC.");
272 return;
273 }
274
275 /*
276 * Defer further processing of the AuxKC, but keep the
277 * processed info dictionary around so we can ml_static_free
278 * the segment.
279 */
280 if (!OSKext::registerDeferredKextCollection(mh, parsedXML, type: KCKindAuxiliary)) {
281 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
282 format: "Error deferring AuxKC kext processing: Kexts in this collection will be unusable.");
283 }
284 goto skip_adding_kexts;
285 }
286
287 /*
288 * this function does all the heavy lifting of adding OSKext objects
289 * and potentially sliding them if necessary
290 */
291 ret = OSKext::addKextsFromKextCollection(mh, infoDict,
292 kPrelinkTextSegment, kcUUID&: loaded_kcUUID, type: (mh->filetype == MH_FILESET) ? type : KCKindUnknown);
293
294 if (!ret) {
295 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
296 format: "Error loading kext info from prelinked primary KC");
297 return;
298 }
299
300 /* Copy in the kernelcache UUID */
301 if (!loaded_kcUUID) {
302 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
303 format: "WARNING: did not find UUID in %s KC!", (type == KCKindAuxiliary) ? "Aux" : "Primary");
304 } else if (type != KCKindAuxiliary) {
305 kernelcache_uuid_valid = TRUE;
306 memcpy(dst: (void *)&kernelcache_uuid, src: (const void *)loaded_kcUUID->getBytesNoCopy(), n: loaded_kcUUID->getLength());
307 uuid_unparse_upper(uu: kernelcache_uuid, out: kernelcache_uuid_string);
308 } else {
309 auxkc_uuid_valid = TRUE;
310 memcpy(dst: (void *)&auxkc_uuid, src: (const void *)loaded_kcUUID->getBytesNoCopy(), n: loaded_kcUUID->getLength());
311 uuid_unparse_upper(uu: auxkc_uuid, out: auxkc_uuid_string);
312 }
313
314skip_adding_kexts:
315#if CONFIG_KEXT_BASEMENT
316 if (mh->filetype != MH_FILESET) {
317 /*
318 * On CONFIG_KEXT_BASEMENT systems which do _not_ boot the new
319 * MH_FILESET kext collection, kexts are copied to their own
320 * special VM region during OSKext init time, so we can free
321 * the whole segment now.
322 */
323 kernel_segment_command_t *prelinkTextSegment = NULL;
324 prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
325 if (!prelinkTextSegment) {
326 OSKextLog(/* kext */ NULL,
327 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
328 "Can't find prelinked kexts' text segment.");
329 return;
330 }
331
332 ml_static_mfree((vm_offset_t)prelinkTextSegment->vmaddr, prelinkTextSegment->vmsize);
333 }
334#endif /* CONFIG_KEXT_BASEMENT */
335
336 /*
337 * Free the prelink info segment, we're done with it.
338 */
339
340#if !XNU_TARGET_OS_OSX
341 /*
342 * For now, we are limiting this freeing to embedded platforms.
343 * To enable freeing of prelink info segment on macOS, we need to
344 * fix rdar://88929016
345 */
346 bool freedPrelinkInfo = false;
347 kernel_segment_command_t *prelinkInfoSegment = NULL;
348 prelinkInfoSegment = getsegbynamefromheader(mh, kPrelinkInfoSegment);
349 if (prelinkInfoSegment) {
350 if (prelinkInfoSegment->vmsize != 0) {
351 freedPrelinkInfo = true;
352 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
353 (vm_size_t)prelinkInfoSegment->vmsize);
354 }
355 }
356
357 if (!freedPrelinkInfo) {
358 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "Failed to free prelink info.");
359 }
360#endif
361 return;
362}
363
364
365/*********************************************************************
366*********************************************************************/
367#define BOOTER_KEXT_PREFIX "Driver-"
368
369typedef struct _DeviceTreeBuffer {
370 uint32_t paddr;
371 uint32_t length;
372} _DeviceTreeBuffer;
373
374void
375KLDBootstrap::readBooterExtensions(void)
376{
377 OSSharedPtr<IORegistryEntry> booterMemoryMap;
378 OSSharedPtr<OSDictionary> propertyDict;
379 OSSharedPtr<OSCollectionIterator> keyIterator;
380 OSString * deviceTreeName = NULL;// do not release
381
382 const _DeviceTreeBuffer * deviceTreeBuffer = NULL;// do not free
383 char * booterDataPtr = NULL;// do not free
384 OSSharedPtr<OSData> booterData;
385 OSSharedPtr<OSKext> aKext;
386
387 OSKextLog(/* kext */ NULL,
388 kOSKextLogProgressLevel |
389 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
390 format: "Reading startup extensions from booter memory.");
391
392 booterMemoryMap = IORegistryEntry::fromPath( path: "/chosen/memory-map", plane: gIODTPlane);
393
394 if (!booterMemoryMap) {
395 OSKextLog(/* kext */ NULL,
396 kOSKextLogErrorLevel |
397 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
398 format: "Can't read booter memory map.");
399 goto finish;
400 }
401
402 propertyDict = booterMemoryMap->dictionaryWithProperties();
403 if (!propertyDict) {
404 OSKextLog(/* kext */ NULL,
405 kOSKextLogErrorLevel |
406 kOSKextLogDirectoryScanFlag,
407 format: "Can't get property dictionary from memory map.");
408 goto finish;
409 }
410
411 keyIterator = OSCollectionIterator::withCollection(inColl: propertyDict.get());
412 if (!keyIterator) {
413 OSKextLog(/* kext */ NULL,
414 kOSKextLogErrorLevel |
415 kOSKextLogGeneralFlag,
416 format: "Can't allocate iterator for driver images.");
417 goto finish;
418 }
419
420 /* Create dictionary of excluded kexts
421 */
422#ifndef CONFIG_EMBEDDED
423 OSKext::createExcludeListFromBooterData(theDictionary: propertyDict.get(), theIterator: keyIterator.get());
424#endif
425 // !! reset the iterator, not the pointer
426 keyIterator->reset();
427
428 while ((deviceTreeName =
429 OSDynamicCast(OSString, keyIterator->getNextObject()))) {
430 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
431 OSData * deviceTreeEntry = OSDynamicCast(OSData,
432 propertyDict->getObject(deviceTreeName));
433
434 /* If there is no entry for the name, we can't do much with it. */
435 if (!deviceTreeEntry) {
436 continue;
437 }
438
439 /* Make sure it is a kext */
440 if (strncmp(s1: devTreeNameCString,
441 BOOTER_KEXT_PREFIX,
442 CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
443 continue;
444 }
445
446 deviceTreeBuffer = (const _DeviceTreeBuffer *)
447 deviceTreeEntry->getBytesNoCopy(start: 0, numBytes: sizeof(deviceTreeBuffer));
448 if (!deviceTreeBuffer) {
449 /* We can't get to the data, so we can't do anything,
450 * not even free it from physical memory (if it's there).
451 */
452 OSKextLog(/* kext */ NULL,
453 kOSKextLogErrorLevel |
454 kOSKextLogDirectoryScanFlag,
455 format: "Device tree entry %s has NULL pointer.",
456 devTreeNameCString);
457 goto finish; // xxx - continue, panic?
458 }
459
460 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
461 if (!booterDataPtr) {
462 OSKextLog(/* kext */ NULL,
463 kOSKextLogErrorLevel |
464 kOSKextLogDirectoryScanFlag,
465 format: "Can't get virtual address for device tree entry %s.",
466 devTreeNameCString);
467 goto finish;
468 }
469
470 /* Wrap the booter data buffer in an OSData and set a dealloc function
471 * so it will take care of the physical memory when freed. Kexts will
472 * retain the booterData for as long as they need it. Remove the entry
473 * from the booter memory map after this is done.
474 */
475 booterData = OSData::withBytesNoCopy(bytes: booterDataPtr,
476 numBytes: deviceTreeBuffer->length);
477 if (!booterData) {
478 OSKextLog(/* kext */ NULL,
479 kOSKextLogErrorLevel |
480 kOSKextLogGeneralFlag,
481 format: "Error - Can't allocate OSData wrapper for device tree entry %s.",
482 devTreeNameCString);
483 goto finish;
484 }
485 booterData->setDeallocFunction(osdata_phys_free);
486
487 /* Create the kext for the entry, then release it, because the
488 * kext system keeps them around until explicitly removed.
489 * Any creation/registration failures are already logged for us.
490 */
491 OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData: booterData.get());
492
493 booterMemoryMap->removeProperty(aKey: deviceTreeName);
494 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
495
496finish:
497 return;
498}
499
500/*********************************************************************
501*********************************************************************/
502#define COM_APPLE "com.apple."
503
504void
505KLDBootstrap::loadSecurityExtensions(void)
506{
507 OSSharedPtr<OSDictionary> extensionsDict;
508 OSSharedPtr<OSCollectionIterator> keyIterator;
509 OSString * bundleID = NULL;// don't release
510 OSKext * theKext = NULL;// don't release
511
512 OSKextLog(/* kext */ NULL,
513 kOSKextLogStepLevel |
514 kOSKextLogLoadFlag,
515 format: "Loading security extensions.");
516
517 extensionsDict = OSKext::copyKexts();
518 if (!extensionsDict) {
519 return;
520 }
521
522 keyIterator = OSCollectionIterator::withCollection(inColl: extensionsDict.get());
523 if (!keyIterator) {
524 OSKextLog(/* kext */ NULL,
525 kOSKextLogErrorLevel |
526 kOSKextLogGeneralFlag,
527 format: "Failed to allocate iterator for security extensions.");
528 goto finish;
529 }
530
531 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
532 const char * bundle_id = bundleID->getCStringNoCopy();
533
534 /* Skip extensions whose bundle IDs don't start with "com.apple.".
535 */
536 if (!bundle_id ||
537 (strncmp(s1: bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
538 continue;
539 }
540
541 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
542 if (!theKext) {
543 continue;
544 }
545
546 if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) {
547 OSKextLog(/* kext */ NULL,
548 kOSKextLogStepLevel |
549 kOSKextLogLoadFlag,
550 format: "Loading security extension %s.", bundleID->getCStringNoCopy());
551 OSKext::loadKextWithIdentifier(kextIdentifier: bundleID->getCStringNoCopy(),
552 /* allowDefer */ allowDeferFlag: false);
553 }
554 }
555
556finish:
557 return;
558}
559
560/*********************************************************************
561* We used to require that all listed kernel components load, but
562* nowadays we can get them from userland so we only try to load the
563* ones we have. If an error occurs later, such is life.
564*
565* Note that we look the kexts up first, so we can avoid spurious
566* (in this context, anyhow) log messages about kexts not being found.
567*
568* xxx - do we even need to do this any more? Check if the kernel
569* xxx - compoonents just load in the regular paths
570*********************************************************************/
571OSReturn
572KLDBootstrap::loadKernelComponentKexts(void)
573{
574 OSReturn result = kOSReturnSuccess;// optimistic
575 OSSharedPtr<OSKext> theKext;
576 const char ** kextIDPtr = NULL; // do not release
577
578 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
579 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier: *kextIDPtr);
580
581 if (theKext) {
582 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
583 kextIdentifier: *kextIDPtr, /* allowDefer */ allowDeferFlag: false)) {
584 // xxx - check KextBookkeeping, might be redundant
585 OSKextLog(/* kext */ NULL,
586 kOSKextLogErrorLevel |
587 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
588 format: "Failed to initialize kernel component %s.", *kextIDPtr);
589 result = kOSReturnError;
590 }
591 }
592 }
593
594 return result;
595}
596
597/*********************************************************************
598* Ensure that Kernel External Components are loaded early in boot,
599* before other kext personalities get sent to the IOCatalogue. These
600* kexts are treated specially because they may provide the implementation
601* for kernel-vended KPI, so they must register themselves before
602* general purpose IOKit probing begins.
603*********************************************************************/
604
605#define COM_APPLE_KEC "com.apple.kec."
606
607void
608KLDBootstrap::loadKernelExternalComponents(void)
609{
610 OSSharedPtr<OSDictionary> extensionsDict;
611 OSSharedPtr<OSCollectionIterator> keyIterator;
612 OSString * bundleID = NULL;// don't release
613 OSKext * theKext = NULL;// don't release
614 OSBoolean * isKernelExternalComponent = NULL;// don't release
615
616 OSKextLog(/* kext */ NULL,
617 kOSKextLogStepLevel |
618 kOSKextLogLoadFlag,
619 format: "Loading Kernel External Components.");
620
621 extensionsDict = OSKext::copyKexts();
622 if (!extensionsDict) {
623 return;
624 }
625
626 keyIterator = OSCollectionIterator::withCollection(inColl: extensionsDict.get());
627 if (!keyIterator) {
628 OSKextLog(/* kext */ NULL,
629 kOSKextLogErrorLevel |
630 kOSKextLogGeneralFlag,
631 format: "Failed to allocate iterator for Kernel External Components.");
632 goto finish;
633 }
634
635 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
636 const char * bundle_id = bundleID->getCStringNoCopy();
637
638 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
639 */
640 if (!bundle_id ||
641 (strncmp(s1: bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
642 continue;
643 }
644
645 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
646 if (!theKext) {
647 continue;
648 }
649
650 isKernelExternalComponent = OSDynamicCast(OSBoolean,
651 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
652 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
653 OSKextLog(/* kext */ NULL,
654 kOSKextLogStepLevel |
655 kOSKextLogLoadFlag,
656 format: "Loading kernel external component %s.", bundleID->getCStringNoCopy());
657 OSKext::loadKextWithIdentifier(kextIdentifier: bundleID->getCStringNoCopy(),
658 /* allowDefer */ allowDeferFlag: false);
659 }
660 }
661
662finish:
663 return;
664}
665
666/*********************************************************************
667*********************************************************************/
668void
669KLDBootstrap::readBuiltinPersonalities(void)
670{
671 OSSharedPtr<OSObject> parsedXML;
672 OSArray * builtinExtensions = NULL;// do not release
673 OSSharedPtr<OSArray> allPersonalities;
674 OSSharedPtr<OSString> errorString;
675 kernel_section_t * infosect = NULL;// do not free
676 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
677 unsigned int count, i;
678
679 OSKextLog(/* kext */ NULL,
680 kOSKextLogStepLevel |
681 kOSKextLogLoadFlag,
682 format: "Reading built-in kernel personalities for I/O Kit drivers.");
683
684 /* Look in the __BUILTIN __info segment for an array of Info.plist
685 * entries. For each one, extract the personalities dictionary, add
686 * it to our array, then push them all (without matching) to
687 * the IOCatalogue. This can be used to augment the personalities
688 * in gIOKernelConfigTables, especially when linking entire kexts into
689 * the mach_kernel image.
690 */
691 infosect = getsectbyname(seg_name: "__BUILTIN", sect_name: "__info");
692 if (!infosect) {
693 // this isn't fatal
694 goto finish;
695 }
696
697 parsedXML = OSUnserializeXML(buffer: (const char *) (uintptr_t)infosect->addr,
698 errorString);
699 if (parsedXML) {
700 builtinExtensions = OSDynamicCast(OSArray, parsedXML.get());
701 }
702 if (!builtinExtensions) {
703 const char * errorCString = "(unknown error)";
704
705 if (errorString && errorString->getCStringNoCopy()) {
706 errorCString = errorString->getCStringNoCopy();
707 } else if (parsedXML) {
708 errorCString = "not an array";
709 }
710 OSKextLog(/* kext */ NULL,
711 kOSKextLogErrorLevel |
712 kOSKextLogLoadFlag,
713 format: "Error unserializing built-in personalities: %s.", errorCString);
714 goto finish;
715 }
716
717 // estimate 3 personalities per Info.plist/kext
718 count = builtinExtensions->getCount();
719 allPersonalities = OSArray::withCapacity(capacity: count * 3);
720
721 for (i = 0; i < count; i++) {
722 OSDictionary * infoDict = NULL;// do not release
723 OSString * moduleName = NULL;// do not release
724 OSDictionary * personalities;// do not release
725 OSString * personalityName;// do not release
726
727 infoDict = OSDynamicCast(OSDictionary,
728 builtinExtensions->getObject(i));
729 if (!infoDict) {
730 continue;
731 }
732
733 moduleName = OSDynamicCast(OSString,
734 infoDict->getObject(kCFBundleIdentifierKey));
735 if (!moduleName) {
736 continue;
737 }
738
739 OSKextLog(/* kext */ NULL,
740 kOSKextLogStepLevel |
741 kOSKextLogLoadFlag,
742 format: "Adding personalities for built-in driver %s:",
743 moduleName->getCStringNoCopy());
744
745 personalities = OSDynamicCast(OSDictionary,
746 infoDict->getObject("IOKitPersonalities"));
747 if (!personalities) {
748 continue;
749 }
750
751 personalitiesIterator = OSCollectionIterator::withCollection(inColl: personalities);
752 if (!personalitiesIterator) {
753 continue; // xxx - well really, what can we do? should we panic?
754 }
755
756 while ((personalityName = OSDynamicCast(OSString,
757 personalitiesIterator->getNextObject()))) {
758 OSDictionary * personality = OSDynamicCast(OSDictionary,
759 personalities->getObject(personalityName));
760
761 OSKextLog(/* kext */ NULL,
762 kOSKextLogDetailLevel |
763 kOSKextLogLoadFlag,
764 format: "Adding built-in driver personality %s.",
765 personalityName->getCStringNoCopy());
766
767 if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
768 personality->setObject(kCFBundleIdentifierKey, anObject: moduleName);
769 }
770 allPersonalities->setObject(personality);
771 }
772 }
773
774 gIOCatalogue->addDrivers(array: allPersonalities.get(), doNubMatching: false);
775
776finish:
777 return;
778}
779
780#if PRAGMA_MARK
781#pragma mark Bootstrap Functions
782#endif
783/*********************************************************************
784* Bootstrap Functions
785*********************************************************************/
786static void
787bootstrapRecordStartupExtensions(void)
788{
789 sBootstrapObject.readStartupExtensions();
790 return;
791}
792
793static void
794bootstrapLoadSecurityExtensions(void)
795{
796 sBootstrapObject.loadSecurityExtensions();
797 return;
798}
799
800