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 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
readBooterExtensions(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
loadSecurityExtensions(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
loadKernelComponentKexts(void)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
loadKernelExternalComponents(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
readBuiltinPersonalities(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
bootstrapRecordStartupExtensions(void)772 bootstrapRecordStartupExtensions(void)
773 {
774 sBootstrapObject.readStartupExtensions();
775 return;
776 }
777
778 static void
bootstrapLoadSecurityExtensions(void)779 bootstrapLoadSecurityExtensions(void)
780 {
781 sBootstrapObject.loadSecurityExtensions();
782 return;
783 }
784
785