xref: /xnu-11215/libsa/bootstrap.cpp (revision 5c2921b0)
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 *********************************************************************/
KLDBootstrap(void)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 *********************************************************************/
~KLDBootstrap(void)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
readStartupExtensions(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
readPrelinkedExtensions(kernel_mach_header_t * mh,kc_kind_t type)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 
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 
369 typedef struct _DeviceTreeBuffer {
370 	uint32_t paddr;
371 	uint32_t length;
372 } _DeviceTreeBuffer;
373 
374 void
readBooterExtensions(void)375 KLDBootstrap::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 	    "Reading startup extensions from booter memory.");
391 
392 	booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
393 
394 	if (!booterMemoryMap) {
395 		OSKextLog(/* kext */ NULL,
396 		    kOSKextLogErrorLevel |
397 		    kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
398 		    "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 		    "Can't get property dictionary from memory map.");
408 		goto finish;
409 	}
410 
411 	keyIterator = OSCollectionIterator::withCollection(propertyDict.get());
412 	if (!keyIterator) {
413 		OSKextLog(/* kext */ NULL,
414 		    kOSKextLogErrorLevel |
415 		    kOSKextLogGeneralFlag,
416 		    "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(propertyDict.get(), 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(devTreeNameCString,
441 		    BOOTER_KEXT_PREFIX,
442 		    CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
443 			continue;
444 		}
445 
446 		deviceTreeBuffer = (const _DeviceTreeBuffer *)
447 		    deviceTreeEntry->getBytesNoCopy(0, 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 			    "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 			    "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(booterDataPtr,
476 		    deviceTreeBuffer->length);
477 		if (!booterData) {
478 			OSKextLog(/* kext */ NULL,
479 			    kOSKextLogErrorLevel |
480 			    kOSKextLogGeneralFlag,
481 			    "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.get());
492 
493 		booterMemoryMap->removeProperty(deviceTreeName);
494 	} /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
495 
496 finish:
497 	return;
498 }
499 
500 /*********************************************************************
501 *********************************************************************/
502 #define COM_APPLE  "com.apple."
503 
504 void
loadSecurityExtensions(void)505 KLDBootstrap::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 	    "Loading security extensions.");
516 
517 	extensionsDict = OSKext::copyKexts();
518 	if (!extensionsDict) {
519 		return;
520 	}
521 
522 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
523 	if (!keyIterator) {
524 		OSKextLog(/* kext */ NULL,
525 		    kOSKextLogErrorLevel |
526 		    kOSKextLogGeneralFlag,
527 		    "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(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 			    "Loading security extension %s.", bundleID->getCStringNoCopy());
551 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
552 			    /* allowDefer */ false);
553 		}
554 	}
555 
556 finish:
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 *********************************************************************/
571 OSReturn
loadKernelComponentKexts(void)572 KLDBootstrap::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(*kextIDPtr);
580 
581 		if (theKext) {
582 			if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
583 				    *kextIDPtr, /* allowDefer */ false)) {
584 				// xxx - check KextBookkeeping, might be redundant
585 				OSKextLog(/* kext */ NULL,
586 				    kOSKextLogErrorLevel |
587 				    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
588 				    "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 
607 void
loadKernelExternalComponents(void)608 KLDBootstrap::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 	    "Loading Kernel External Components.");
620 
621 	extensionsDict = OSKext::copyKexts();
622 	if (!extensionsDict) {
623 		return;
624 	}
625 
626 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
627 	if (!keyIterator) {
628 		OSKextLog(/* kext */ NULL,
629 		    kOSKextLogErrorLevel |
630 		    kOSKextLogGeneralFlag,
631 		    "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(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 			    "Loading kernel external component %s.", bundleID->getCStringNoCopy());
657 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
658 			    /* allowDefer */ false);
659 		}
660 	}
661 
662 finish:
663 	return;
664 }
665 
666 /*********************************************************************
667 *********************************************************************/
668 void
readBuiltinPersonalities(void)669 KLDBootstrap::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 	    "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("__BUILTIN", "__info");
692 	if (!infosect) {
693 		// this isn't fatal
694 		goto finish;
695 	}
696 
697 	parsedXML = OSUnserializeXML((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 		    "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(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 		    "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(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 			    "Adding built-in driver personality %s.",
765 			    personalityName->getCStringNoCopy());
766 
767 			if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
768 				personality->setObject(kCFBundleIdentifierKey, moduleName);
769 			}
770 			allPersonalities->setObject(personality);
771 		}
772 	}
773 
774 	gIOCatalogue->addDrivers(allPersonalities.get(), false);
775 
776 finish:
777 	return;
778 }
779 
780 #if PRAGMA_MARK
781 #pragma mark Bootstrap Functions
782 #endif
783 /*********************************************************************
784 * Bootstrap Functions
785 *********************************************************************/
786 static void
bootstrapRecordStartupExtensions(void)787 bootstrapRecordStartupExtensions(void)
788 {
789 	sBootstrapObject.readStartupExtensions();
790 	return;
791 }
792 
793 static void
bootstrapLoadSecurityExtensions(void)794 bootstrapLoadSecurityExtensions(void)
795 {
796 	sBootstrapObject.loadSecurityExtensions();
797 	return;
798 }
799 
800