xref: /xnu-11215/libsa/bootstrap.cpp (revision e6231be0)
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  */
28 extern "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 *********************************************************************/
68 extern "C" {
69 extern void (*record_startup_extensions_function)(void);
70 extern void (*load_security_extensions_function)(void);
71 };
72 
73 static void bootstrapRecordStartupExtensions(void);
74 static void bootstrapLoadSecurityExtensions(void);
75 
76 
77 #if NO_KEXTD
78 extern "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 *********************************************************************/
100 static 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 *********************************************************************/
129 class KLDBootstrap {
130 	friend void bootstrapRecordStartupExtensions(void);
131 	friend void bootstrapLoadSecurityExtensions(void);
132 
133 private:
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 
145 public:
146 	KLDBootstrap(void);
147 	~KLDBootstrap(void);
148 };
149 
150 LIBKERN_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 *********************************************************************/
156 KLDBootstrap::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 *********************************************************************/
169 KLDBootstrap::~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 *********************************************************************/
182 void
183 KLDBootstrap::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 	    "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(&kc_format) && kc_format == KCFormatFileset) {
196 		mh = (kernel_mach_header_t *)PE_get_kc_header(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(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
205 	if (prelinkInfoSect->size) {
206 		readPrelinkedExtensions(mh, 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(KCKindAuxiliary);
213 	if (akc_mh) {
214 		readPrelinkedExtensions(akc_mh, KCKindAuxiliary);
215 	}
216 
217 	loadKernelComponentKexts();
218 	loadKernelExternalComponents();
219 	readBuiltinPersonalities();
220 	OSKext::sendAllKextPersonalitiesToCatalog(true);
221 
222 	return;
223 }
224 
225 /*********************************************************************
226 *********************************************************************/
227 void
228 KLDBootstrap::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 	    "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(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
249 	parsedXML = OSUnserializeXML((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 		    "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, KCKindAuxiliary) != 0) {
270 			OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
271 			    "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, KCKindAuxiliary)) {
281 			OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
282 			    "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, loaded_kcUUID, (mh->filetype == MH_FILESET) ? type : KCKindUnknown);
293 
294 	if (!ret) {
295 		OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
296 		    "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 		    "WARNING: did not find UUID in %s KC!", (type == KCKindAuxiliary) ? "Aux" : "Primary");
304 	} else if (type != KCKindAuxiliary) {
305 		kernelcache_uuid_valid = TRUE;
306 		memcpy((void *)&kernelcache_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
307 		uuid_unparse_upper(kernelcache_uuid, kernelcache_uuid_string);
308 	} else {
309 		auxkc_uuid_valid = TRUE;
310 		memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
311 		uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
312 	}
313 
314 skip_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 	kernel_segment_command_t *prelinkInfoSegment = NULL;
340 	prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
341 	if (prelinkInfoSegment) {
342 		ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
343 		    (vm_size_t)prelinkInfoSegment->vmsize);
344 	}
345 
346 	return;
347 }
348 
349 
350 /*********************************************************************
351 *********************************************************************/
352 #define BOOTER_KEXT_PREFIX   "Driver-"
353 
354 typedef struct _DeviceTreeBuffer {
355 	uint32_t paddr;
356 	uint32_t length;
357 } _DeviceTreeBuffer;
358 
359 void
360 KLDBootstrap::readBooterExtensions(void)
361 {
362 	OSSharedPtr<IORegistryEntry> booterMemoryMap;
363 	OSSharedPtr<OSDictionary>    propertyDict;
364 	OSSharedPtr<OSCollectionIterator>      keyIterator;
365 	OSString                  * deviceTreeName          = NULL;// do not release
366 
367 	const _DeviceTreeBuffer   * deviceTreeBuffer        = NULL;// do not free
368 	char                      * booterDataPtr           = NULL;// do not free
369 	OSSharedPtr<OSData>         booterData;
370 	OSSharedPtr<OSKext>         aKext;
371 
372 	OSKextLog(/* kext */ NULL,
373 	    kOSKextLogProgressLevel |
374 	    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
375 	    "Reading startup extensions from booter memory.");
376 
377 	booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
378 
379 	if (!booterMemoryMap) {
380 		OSKextLog(/* kext */ NULL,
381 		    kOSKextLogErrorLevel |
382 		    kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
383 		    "Can't read booter memory map.");
384 		goto finish;
385 	}
386 
387 	propertyDict = booterMemoryMap->dictionaryWithProperties();
388 	if (!propertyDict) {
389 		OSKextLog(/* kext */ NULL,
390 		    kOSKextLogErrorLevel |
391 		    kOSKextLogDirectoryScanFlag,
392 		    "Can't get property dictionary from memory map.");
393 		goto finish;
394 	}
395 
396 	keyIterator = OSCollectionIterator::withCollection(propertyDict.get());
397 	if (!keyIterator) {
398 		OSKextLog(/* kext */ NULL,
399 		    kOSKextLogErrorLevel |
400 		    kOSKextLogGeneralFlag,
401 		    "Can't allocate iterator for driver images.");
402 		goto finish;
403 	}
404 
405 	/* Create dictionary of excluded kexts
406 	 */
407 #ifndef CONFIG_EMBEDDED
408 	OSKext::createExcludeListFromBooterData(propertyDict.get(), keyIterator.get());
409 #endif
410 	// !! reset the iterator, not the pointer
411 	keyIterator->reset();
412 
413 	while ((deviceTreeName =
414 	    OSDynamicCast(OSString, keyIterator->getNextObject()))) {
415 		const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
416 		OSData * deviceTreeEntry = OSDynamicCast(OSData,
417 		    propertyDict->getObject(deviceTreeName));
418 
419 		/* If there is no entry for the name, we can't do much with it. */
420 		if (!deviceTreeEntry) {
421 			continue;
422 		}
423 
424 		/* Make sure it is a kext */
425 		if (strncmp(devTreeNameCString,
426 		    BOOTER_KEXT_PREFIX,
427 		    CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
428 			continue;
429 		}
430 
431 		deviceTreeBuffer = (const _DeviceTreeBuffer *)
432 		    deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
433 		if (!deviceTreeBuffer) {
434 			/* We can't get to the data, so we can't do anything,
435 			 * not even free it from physical memory (if it's there).
436 			 */
437 			OSKextLog(/* kext */ NULL,
438 			    kOSKextLogErrorLevel |
439 			    kOSKextLogDirectoryScanFlag,
440 			    "Device tree entry %s has NULL pointer.",
441 			    devTreeNameCString);
442 			goto finish; // xxx - continue, panic?
443 		}
444 
445 		booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
446 		if (!booterDataPtr) {
447 			OSKextLog(/* kext */ NULL,
448 			    kOSKextLogErrorLevel |
449 			    kOSKextLogDirectoryScanFlag,
450 			    "Can't get virtual address for device tree entry %s.",
451 			    devTreeNameCString);
452 			goto finish;
453 		}
454 
455 		/* Wrap the booter data buffer in an OSData and set a dealloc function
456 		 * so it will take care of the physical memory when freed. Kexts will
457 		 * retain the booterData for as long as they need it. Remove the entry
458 		 * from the booter memory map after this is done.
459 		 */
460 		booterData = OSData::withBytesNoCopy(booterDataPtr,
461 		    deviceTreeBuffer->length);
462 		if (!booterData) {
463 			OSKextLog(/* kext */ NULL,
464 			    kOSKextLogErrorLevel |
465 			    kOSKextLogGeneralFlag,
466 			    "Error - Can't allocate OSData wrapper for device tree entry %s.",
467 			    devTreeNameCString);
468 			goto finish;
469 		}
470 		booterData->setDeallocFunction(osdata_phys_free);
471 
472 		/* Create the kext for the entry, then release it, because the
473 		 * kext system keeps them around until explicitly removed.
474 		 * Any creation/registration failures are already logged for us.
475 		 */
476 		OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData.get());
477 
478 		booterMemoryMap->removeProperty(deviceTreeName);
479 	} /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
480 
481 finish:
482 	return;
483 }
484 
485 /*********************************************************************
486 *********************************************************************/
487 #define COM_APPLE  "com.apple."
488 
489 void
490 KLDBootstrap::loadSecurityExtensions(void)
491 {
492 	OSSharedPtr<OSDictionary>         extensionsDict;
493 	OSSharedPtr<OSCollectionIterator> keyIterator;
494 	OSString             * bundleID       = NULL;// don't release
495 	OSKext               * theKext        = NULL;// don't release
496 
497 	OSKextLog(/* kext */ NULL,
498 	    kOSKextLogStepLevel |
499 	    kOSKextLogLoadFlag,
500 	    "Loading security extensions.");
501 
502 	extensionsDict = OSKext::copyKexts();
503 	if (!extensionsDict) {
504 		return;
505 	}
506 
507 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
508 	if (!keyIterator) {
509 		OSKextLog(/* kext */ NULL,
510 		    kOSKextLogErrorLevel |
511 		    kOSKextLogGeneralFlag,
512 		    "Failed to allocate iterator for security extensions.");
513 		goto finish;
514 	}
515 
516 	while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
517 		const char * bundle_id = bundleID->getCStringNoCopy();
518 
519 		/* Skip extensions whose bundle IDs don't start with "com.apple.".
520 		 */
521 		if (!bundle_id ||
522 		    (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
523 			continue;
524 		}
525 
526 		theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
527 		if (!theKext) {
528 			continue;
529 		}
530 
531 		if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) {
532 			OSKextLog(/* kext */ NULL,
533 			    kOSKextLogStepLevel |
534 			    kOSKextLogLoadFlag,
535 			    "Loading security extension %s.", bundleID->getCStringNoCopy());
536 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
537 			    /* allowDefer */ false);
538 		}
539 	}
540 
541 finish:
542 	return;
543 }
544 
545 /*********************************************************************
546 * We used to require that all listed kernel components load, but
547 * nowadays we can get them from userland so we only try to load the
548 * ones we have. If an error occurs later, such is life.
549 *
550 * Note that we look the kexts up first, so we can avoid spurious
551 * (in this context, anyhow) log messages about kexts not being found.
552 *
553 * xxx - do we even need to do this any more? Check if the kernel
554 * xxx - compoonents just load in the regular paths
555 *********************************************************************/
556 OSReturn
557 KLDBootstrap::loadKernelComponentKexts(void)
558 {
559 	OSReturn            result      = kOSReturnSuccess;// optimistic
560 	OSSharedPtr<OSKext> theKext;
561 	const char       ** kextIDPtr   = NULL;          // do not release
562 
563 	for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
564 		theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);
565 
566 		if (theKext) {
567 			if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
568 				    *kextIDPtr, /* allowDefer */ false)) {
569 				// xxx - check KextBookkeeping, might be redundant
570 				OSKextLog(/* kext */ NULL,
571 				    kOSKextLogErrorLevel |
572 				    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
573 				    "Failed to initialize kernel component %s.", *kextIDPtr);
574 				result = kOSReturnError;
575 			}
576 		}
577 	}
578 
579 	return result;
580 }
581 
582 /*********************************************************************
583 * Ensure that Kernel External Components are loaded early in boot,
584 * before other kext personalities get sent to the IOCatalogue. These
585 * kexts are treated specially because they may provide the implementation
586 * for kernel-vended KPI, so they must register themselves before
587 * general purpose IOKit probing begins.
588 *********************************************************************/
589 
590 #define COM_APPLE_KEC  "com.apple.kec."
591 
592 void
593 KLDBootstrap::loadKernelExternalComponents(void)
594 {
595 	OSSharedPtr<OSDictionary>         extensionsDict;
596 	OSSharedPtr<OSCollectionIterator> keyIterator;
597 	OSString             * bundleID       = NULL;// don't release
598 	OSKext               * theKext        = NULL;// don't release
599 	OSBoolean            * isKernelExternalComponent = NULL;// don't release
600 
601 	OSKextLog(/* kext */ NULL,
602 	    kOSKextLogStepLevel |
603 	    kOSKextLogLoadFlag,
604 	    "Loading Kernel External Components.");
605 
606 	extensionsDict = OSKext::copyKexts();
607 	if (!extensionsDict) {
608 		return;
609 	}
610 
611 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
612 	if (!keyIterator) {
613 		OSKextLog(/* kext */ NULL,
614 		    kOSKextLogErrorLevel |
615 		    kOSKextLogGeneralFlag,
616 		    "Failed to allocate iterator for Kernel External Components.");
617 		goto finish;
618 	}
619 
620 	while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
621 		const char * bundle_id = bundleID->getCStringNoCopy();
622 
623 		/* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
624 		 */
625 		if (!bundle_id ||
626 		    (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
627 			continue;
628 		}
629 
630 		theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
631 		if (!theKext) {
632 			continue;
633 		}
634 
635 		isKernelExternalComponent = OSDynamicCast(OSBoolean,
636 		    theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
637 		if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
638 			OSKextLog(/* kext */ NULL,
639 			    kOSKextLogStepLevel |
640 			    kOSKextLogLoadFlag,
641 			    "Loading kernel external component %s.", bundleID->getCStringNoCopy());
642 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
643 			    /* allowDefer */ false);
644 		}
645 	}
646 
647 finish:
648 	return;
649 }
650 
651 /*********************************************************************
652 *********************************************************************/
653 void
654 KLDBootstrap::readBuiltinPersonalities(void)
655 {
656 	OSSharedPtr<OSObject>   parsedXML;
657 	OSArray               * builtinExtensions     = NULL;// do not release
658 	OSSharedPtr<OSArray>    allPersonalities;
659 	OSSharedPtr<OSString>   errorString;
660 	kernel_section_t      * infosect              = NULL;// do not free
661 	OSSharedPtr<OSCollectionIterator>  personalitiesIterator;
662 	unsigned int            count, i;
663 
664 	OSKextLog(/* kext */ NULL,
665 	    kOSKextLogStepLevel |
666 	    kOSKextLogLoadFlag,
667 	    "Reading built-in kernel personalities for I/O Kit drivers.");
668 
669 	/* Look in the __BUILTIN __info segment for an array of Info.plist
670 	 * entries. For each one, extract the personalities dictionary, add
671 	 * it to our array, then push them all (without matching) to
672 	 * the IOCatalogue. This can be used to augment the personalities
673 	 * in gIOKernelConfigTables, especially when linking entire kexts into
674 	 * the mach_kernel image.
675 	 */
676 	infosect   = getsectbyname("__BUILTIN", "__info");
677 	if (!infosect) {
678 		// this isn't fatal
679 		goto finish;
680 	}
681 
682 	parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
683 	    errorString);
684 	if (parsedXML) {
685 		builtinExtensions = OSDynamicCast(OSArray, parsedXML.get());
686 	}
687 	if (!builtinExtensions) {
688 		const char * errorCString = "(unknown error)";
689 
690 		if (errorString && errorString->getCStringNoCopy()) {
691 			errorCString = errorString->getCStringNoCopy();
692 		} else if (parsedXML) {
693 			errorCString = "not an array";
694 		}
695 		OSKextLog(/* kext */ NULL,
696 		    kOSKextLogErrorLevel |
697 		    kOSKextLogLoadFlag,
698 		    "Error unserializing built-in personalities: %s.", errorCString);
699 		goto finish;
700 	}
701 
702 	// estimate 3 personalities per Info.plist/kext
703 	count = builtinExtensions->getCount();
704 	allPersonalities = OSArray::withCapacity(count * 3);
705 
706 	for (i = 0; i < count; i++) {
707 		OSDictionary            * infoDict = NULL;// do not release
708 		OSString                * moduleName = NULL;// do not release
709 		OSDictionary            * personalities;// do not release
710 		OSString                * personalityName;// do not release
711 
712 		infoDict = OSDynamicCast(OSDictionary,
713 		    builtinExtensions->getObject(i));
714 		if (!infoDict) {
715 			continue;
716 		}
717 
718 		moduleName = OSDynamicCast(OSString,
719 		    infoDict->getObject(kCFBundleIdentifierKey));
720 		if (!moduleName) {
721 			continue;
722 		}
723 
724 		OSKextLog(/* kext */ NULL,
725 		    kOSKextLogStepLevel |
726 		    kOSKextLogLoadFlag,
727 		    "Adding personalities for built-in driver %s:",
728 		    moduleName->getCStringNoCopy());
729 
730 		personalities = OSDynamicCast(OSDictionary,
731 		    infoDict->getObject("IOKitPersonalities"));
732 		if (!personalities) {
733 			continue;
734 		}
735 
736 		personalitiesIterator = OSCollectionIterator::withCollection(personalities);
737 		if (!personalitiesIterator) {
738 			continue; // xxx - well really, what can we do? should we panic?
739 		}
740 
741 		while ((personalityName = OSDynamicCast(OSString,
742 		    personalitiesIterator->getNextObject()))) {
743 			OSDictionary * personality = OSDynamicCast(OSDictionary,
744 			    personalities->getObject(personalityName));
745 
746 			OSKextLog(/* kext */ NULL,
747 			    kOSKextLogDetailLevel |
748 			    kOSKextLogLoadFlag,
749 			    "Adding built-in driver personality %s.",
750 			    personalityName->getCStringNoCopy());
751 
752 			if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
753 				personality->setObject(kCFBundleIdentifierKey, moduleName);
754 			}
755 			allPersonalities->setObject(personality);
756 		}
757 	}
758 
759 	gIOCatalogue->addDrivers(allPersonalities.get(), false);
760 
761 finish:
762 	return;
763 }
764 
765 #if PRAGMA_MARK
766 #pragma mark Bootstrap Functions
767 #endif
768 /*********************************************************************
769 * Bootstrap Functions
770 *********************************************************************/
771 static void
772 bootstrapRecordStartupExtensions(void)
773 {
774 	sBootstrapObject.readStartupExtensions();
775 	return;
776 }
777 
778 static void
779 bootstrapLoadSecurityExtensions(void)
780 {
781 	sBootstrapObject.loadSecurityExtensions();
782 	return;
783 }
784 
785