]> git.saurik.com Git - apple/xnu.git/blob - libsa/bootstrap.cpp
02e5694d06241f4ddc42ad5f6f4dbd0f5bf9638f
[apple/xnu.git] / libsa / bootstrap.cpp
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 }
33
34 #include <libkern/version.h>
35 #include <libkern/c++/OSContainers.h>
36 #include <libkern/OSKextLibPrivate.h>
37 #include <libkern/c++/OSKext.h>
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IOService.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOCatalogue.h>
42
43 #if __x86_64__
44 #define KASLR_KEXT_DEBUG 0
45 #endif
46
47 #if PRAGMA_MARK
48 #pragma mark Bootstrap Declarations
49 #endif
50 /*********************************************************************
51 * Bootstrap Declarations
52 *
53 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
54 * code from other parts of the kernel, so function symbols are not
55 * exported; rather pointers to those functions are exported.
56 *
57 * xxx - need to think about locking for handling the 'weak' refs.
58 * xxx - do export a non-KLD function that says you've called a
59 * xxx - bootstrap function that has been removed.
60 *
61 * ALL call-ins to this segment of the kernel must be done through
62 * exported pointers. The symbols themselves are private and not to
63 * be linked against.
64 *********************************************************************/
65 extern "C" {
66 extern void (*record_startup_extensions_function)(void);
67 extern void (*load_security_extensions_function)(void);
68 };
69
70 static void bootstrapRecordStartupExtensions(void);
71 static void bootstrapLoadSecurityExtensions(void);
72
73
74 #if NO_KEXTD
75 extern "C" bool IORamDiskBSDRoot(void);
76 #endif
77
78 #if PRAGMA_MARK
79 #pragma mark Macros
80 #endif
81 /*********************************************************************
82 * Macros
83 *********************************************************************/
84 #define CONST_STRLEN(str) (sizeof(str) - 1)
85
86 #if PRAGMA_MARK
87 #pragma mark Kernel Component Kext Identifiers
88 #endif
89 /*********************************************************************
90 * Kernel Component Kext Identifiers
91 *
92 * We could have each kernel resource kext automatically "load" as
93 * it's created, but it's nicer to have them listed in kextstat in
94 * the order of this list. We'll walk through this after setting up
95 * all the boot kexts and have them load up.
96 *********************************************************************/
97 static const char * sKernelComponentNames[] = {
98 // The kexts for these IDs must have a version matching 'osrelease'.
99 "com.apple.kernel",
100 "com.apple.kpi.bsd",
101 "com.apple.kpi.dsep",
102 "com.apple.kpi.iokit",
103 "com.apple.kpi.libkern",
104 "com.apple.kpi.mach",
105 "com.apple.kpi.private",
106 "com.apple.kpi.unsupported",
107 "com.apple.iokit.IONVRAMFamily",
108 "com.apple.driver.AppleNMI",
109 "com.apple.iokit.IOSystemManagementFamily",
110 "com.apple.iokit.ApplePlatformFamily",
111 NULL
112 };
113
114 #if PRAGMA_MARK
115 #pragma mark KLDBootstrap Class
116 #endif
117 /*********************************************************************
118 * KLDBootstrap Class
119 *
120 * We use a C++ class here so that it can be a friend of OSKext and
121 * get at private stuff. We can't hide the class itself, but we can
122 * hide the instance through which we invoke the functions.
123 *********************************************************************/
124 class KLDBootstrap {
125 friend void bootstrapRecordStartupExtensions(void);
126 friend void bootstrapLoadSecurityExtensions(void);
127
128 private:
129 void readStartupExtensions(void);
130
131 void readPrelinkedExtensions(
132 kernel_section_t * prelinkInfoSect);
133 void readBooterExtensions(void);
134
135 OSReturn loadKernelComponentKexts(void);
136 void loadKernelExternalComponents(void);
137 void readBuiltinPersonalities(void);
138
139 void loadSecurityExtensions(void);
140
141 public:
142 KLDBootstrap(void);
143 ~KLDBootstrap(void);
144 };
145
146 static KLDBootstrap sBootstrapObject;
147
148 /*********************************************************************
149 * Set the function pointers for the entry points into the bootstrap
150 * segment upon C++ static constructor invocation.
151 *********************************************************************/
152 KLDBootstrap::KLDBootstrap(void)
153 {
154 if (this != &sBootstrapObject) {
155 panic("Attempt to access bootstrap segment.");
156 }
157 record_startup_extensions_function = &bootstrapRecordStartupExtensions;
158 load_security_extensions_function = &bootstrapLoadSecurityExtensions;
159 }
160
161 /*********************************************************************
162 * Clear the function pointers for the entry points into the bootstrap
163 * segment upon C++ static destructor invocation.
164 *********************************************************************/
165 KLDBootstrap::~KLDBootstrap(void)
166 {
167 if (this != &sBootstrapObject) {
168 panic("Attempt to access bootstrap segment.");
169 }
170
171
172 record_startup_extensions_function = 0;
173 load_security_extensions_function = 0;
174 }
175
176 /*********************************************************************
177 *********************************************************************/
178 void
179 KLDBootstrap::readStartupExtensions(void)
180 {
181 kernel_section_t * prelinkInfoSect = NULL; // do not free
182
183 OSKextLog(/* kext */ NULL,
184 kOSKextLogProgressLevel |
185 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
186 kOSKextLogKextBookkeepingFlag,
187 "Reading startup extensions.");
188
189 /* If the prelink info segment has a nonzero size, we are prelinked
190 * and won't have any individual kexts or mkexts to read.
191 * Otherwise, we need to read kexts or the mkext from what the booter
192 * has handed us.
193 */
194 prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection);
195 if (prelinkInfoSect->size) {
196 readPrelinkedExtensions(prelinkInfoSect);
197 } else {
198 readBooterExtensions();
199 }
200
201 loadKernelComponentKexts();
202 loadKernelExternalComponents();
203 readBuiltinPersonalities();
204 OSKext::sendAllKextPersonalitiesToCatalog();
205
206 return;
207 }
208
209 /*********************************************************************
210 *********************************************************************/
211 void
212 KLDBootstrap::readPrelinkedExtensions(
213 kernel_section_t * prelinkInfoSect)
214 {
215 OSArray * infoDictArray = NULL; // do not release
216 OSObject * parsedXML = NULL; // must release
217 OSDictionary * prelinkInfoDict = NULL; // do not release
218 OSString * errorString = NULL; // must release
219 OSKext * theKernel = NULL; // must release
220
221 kernel_segment_command_t * prelinkTextSegment = NULL; // see code
222 kernel_segment_command_t * prelinkInfoSegment = NULL; // see code
223
224 /* We make some copies of data, but if anything fails we're basically
225 * going to fail the boot, so these won't be cleaned up on error.
226 */
227 void * prelinkData = NULL; // see code
228 vm_size_t prelinkLength = 0;
229
230
231 OSDictionary * infoDict = NULL; // do not release
232
233 IORegistryEntry * registryRoot = NULL; // do not release
234 OSNumber * prelinkCountObj = NULL; // must release
235
236 u_int i = 0;
237 #if NO_KEXTD
238 bool ramDiskBoot;
239 bool developerDevice;
240 bool dontLoad;
241 #endif
242
243 OSKextLog(/* kext */ NULL,
244 kOSKextLogProgressLevel |
245 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
246 "Starting from prelinked kernel.");
247
248 prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
249 if (!prelinkTextSegment) {
250 OSKextLog(/* kext */ NULL,
251 kOSKextLogErrorLevel |
252 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
253 "Can't find prelinked kexts' text segment.");
254 goto finish;
255 }
256
257 #if KASLR_KEXT_DEBUG
258 unsigned long scratchSize;
259 vm_offset_t scratchAddr;
260
261 IOLog("kaslr: prelinked kernel address info: \n");
262
263 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
264 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
265 (unsigned long)scratchAddr,
266 (unsigned long)(scratchAddr + scratchSize),
267 scratchSize);
268
269 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
270 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
271 (unsigned long)scratchAddr,
272 (unsigned long)(scratchAddr + scratchSize),
273 scratchSize);
274
275 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
276 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
277 (unsigned long)scratchAddr,
278 (unsigned long)(scratchAddr + scratchSize),
279 scratchSize);
280
281 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
282 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
283 (unsigned long)scratchAddr,
284 (unsigned long)(scratchAddr + scratchSize),
285 scratchSize);
286
287 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
288 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
289 (unsigned long)scratchAddr,
290 (unsigned long)(scratchAddr + scratchSize),
291 scratchSize);
292
293 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
294 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
295 (unsigned long)scratchAddr,
296 (unsigned long)(scratchAddr + scratchSize),
297 scratchSize);
298 #endif
299
300 prelinkData = (void *) prelinkTextSegment->vmaddr;
301 prelinkLength = prelinkTextSegment->vmsize;
302
303
304 /* Unserialize the info dictionary from the prelink info section.
305 */
306 parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr,
307 &errorString);
308 if (parsedXML) {
309 prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML);
310 }
311 if (!prelinkInfoDict) {
312 const char * errorCString = "(unknown error)";
313
314 if (errorString && errorString->getCStringNoCopy()) {
315 errorCString = errorString->getCStringNoCopy();
316 } else if (parsedXML) {
317 errorCString = "not a dictionary";
318 }
319 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
320 "Error unserializing prelink plist: %s.", errorCString);
321 goto finish;
322 }
323
324 #if NO_KEXTD
325 /* Check if we should keep developer kexts around.
326 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
327 */
328 developerDevice = true;
329 PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));
330
331 ramDiskBoot = IORamDiskBSDRoot();
332 #endif /* NO_KEXTD */
333
334 infoDictArray = OSDynamicCast(OSArray,
335 prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
336 if (!infoDictArray) {
337 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
338 "The prelinked kernel has no kext info dictionaries");
339 goto finish;
340 }
341
342 /* Create dictionary of excluded kexts
343 */
344 OSKext::createExcludeListFromPrelinkInfo(infoDictArray);
345
346 /* Create OSKext objects for each info dictionary.
347 */
348 for (i = 0; i < infoDictArray->getCount(); ++i) {
349 infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i));
350 if (!infoDict) {
351 OSKextLog(/* kext */ NULL,
352 kOSKextLogErrorLevel |
353 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
354 "Can't find info dictionary for prelinked kext #%d.", i);
355 continue;
356 }
357
358 #if NO_KEXTD
359 dontLoad = false;
360
361 /* If we're not on a developer device, skip and free developer kexts.
362 */
363 if (developerDevice == false) {
364 OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
365 infoDict->getObject(kOSBundleDeveloperOnlyKey));
366 if (devOnlyBool == kOSBooleanTrue) {
367 dontLoad = true;
368 }
369 }
370
371 /* Skip and free kexts that are only needed when booted from a ram disk.
372 */
373 if (ramDiskBoot == false) {
374 OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean,
375 infoDict->getObject(kOSBundleRamDiskOnlyKey));
376 if (ramDiskOnlyBool == kOSBooleanTrue) {
377 dontLoad = true;
378 }
379 }
380
381 if (dontLoad == true) {
382 OSString *bundleID = OSDynamicCast(OSString,
383 infoDict->getObject(kCFBundleIdentifierKey));
384 if (bundleID) {
385 OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
386 "Kext %s not loading.", bundleID->getCStringNoCopy());
387 }
388
389 OSNumber *addressNum = OSDynamicCast(OSNumber,
390 infoDict->getObject(kPrelinkExecutableLoadKey));
391 OSNumber *lengthNum = OSDynamicCast(OSNumber,
392 infoDict->getObject(kPrelinkExecutableSizeKey));
393 if (addressNum && lengthNum) {
394 #error Pick the right way to free prelinked data on this arch
395 }
396
397 infoDictArray->removeObject(i--);
398 continue;
399 }
400 #endif /* NO_KEXTD */
401
402 /* Create the kext for the entry, then release it, because the
403 * kext system keeps them around until explicitly removed.
404 * Any creation/registration failures are already logged for us.
405 */
406 OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict);
407 OSSafeReleaseNULL(newKext);
408 }
409
410 /* Store the number of prelinked kexts in the registry so we can tell
411 * when the system has been started from a prelinked kernel.
412 */
413 registryRoot = IORegistryEntry::getRegistryRoot();
414 assert(registryRoot);
415
416 prelinkCountObj = OSNumber::withNumber(
417 (unsigned long long)infoDictArray->getCount(),
418 8 * sizeof(uint32_t));
419 assert(prelinkCountObj);
420 if (prelinkCountObj) {
421 registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj);
422 }
423
424 OSKextLog(/* kext */ NULL,
425 kOSKextLogProgressLevel |
426 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
427 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
428 "%u prelinked kexts",
429 infoDictArray->getCount());
430
431 #if CONFIG_KEXT_BASEMENT
432 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
433 * special VM region during OSKext init time, so we can free the whole
434 * segment now.
435 */
436 ml_static_mfree((vm_offset_t) prelinkData, prelinkLength);
437 #endif /* __x86_64__ */
438
439 /* Free the prelink info segment, we're done with it.
440 */
441 prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
442 if (prelinkInfoSegment) {
443 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
444 (vm_size_t)prelinkInfoSegment->vmsize);
445 }
446
447 finish:
448 OSSafeRelease(errorString);
449 OSSafeRelease(parsedXML);
450 OSSafeRelease(theKernel);
451 OSSafeRelease(prelinkCountObj);
452 return;
453 }
454
455 /*********************************************************************
456 *********************************************************************/
457 #define BOOTER_KEXT_PREFIX "Driver-"
458
459 typedef struct _DeviceTreeBuffer {
460 uint32_t paddr;
461 uint32_t length;
462 } _DeviceTreeBuffer;
463
464 void
465 KLDBootstrap::readBooterExtensions(void)
466 {
467 IORegistryEntry * booterMemoryMap = NULL; // must release
468 OSDictionary * propertyDict = NULL; // must release
469 OSCollectionIterator * keyIterator = NULL; // must release
470 OSString * deviceTreeName = NULL; // do not release
471
472 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not free
473 char * booterDataPtr = NULL; // do not free
474 OSData * booterData = NULL; // must release
475
476 OSKext * aKext = NULL; // must release
477
478 OSKextLog(/* kext */ NULL,
479 kOSKextLogProgressLevel |
480 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
481 "Reading startup extensions from booter memory.");
482
483 booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
484
485 if (!booterMemoryMap) {
486 OSKextLog(/* kext */ NULL,
487 kOSKextLogErrorLevel |
488 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
489 "Can't read booter memory map.");
490 goto finish;
491 }
492
493 propertyDict = booterMemoryMap->dictionaryWithProperties();
494 if (!propertyDict) {
495 OSKextLog(/* kext */ NULL,
496 kOSKextLogErrorLevel |
497 kOSKextLogDirectoryScanFlag,
498 "Can't get property dictionary from memory map.");
499 goto finish;
500 }
501
502 keyIterator = OSCollectionIterator::withCollection(propertyDict);
503 if (!keyIterator) {
504 OSKextLog(/* kext */ NULL,
505 kOSKextLogErrorLevel |
506 kOSKextLogGeneralFlag,
507 "Can't allocate iterator for driver images.");
508 goto finish;
509 }
510
511 /* Create dictionary of excluded kexts
512 */
513 OSKext::createExcludeListFromBooterData(propertyDict, keyIterator);
514 keyIterator->reset();
515
516 while ( ( deviceTreeName =
517 OSDynamicCast(OSString, keyIterator->getNextObject() ))) {
518
519 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
520 OSData * deviceTreeEntry = OSDynamicCast(OSData,
521 propertyDict->getObject(deviceTreeName));
522
523 /* Clear out the booterData from the prior iteration.
524 */
525 OSSafeReleaseNULL(booterData);
526
527 /* If there is no entry for the name, we can't do much with it. */
528 if (!deviceTreeEntry) {
529 continue;
530 }
531
532 /* Make sure it is a kext */
533 if (strncmp(devTreeNameCString,
534 BOOTER_KEXT_PREFIX,
535 CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
536 continue;
537 }
538
539 deviceTreeBuffer = (const _DeviceTreeBuffer *)
540 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
541 if (!deviceTreeBuffer) {
542 /* We can't get to the data, so we can't do anything,
543 * not even free it from physical memory (if it's there).
544 */
545 OSKextLog(/* kext */ NULL,
546 kOSKextLogErrorLevel |
547 kOSKextLogDirectoryScanFlag,
548 "Device tree entry %s has NULL pointer.",
549 devTreeNameCString);
550 goto finish; // xxx - continue, panic?
551 }
552
553 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
554 if (!booterDataPtr) {
555 OSKextLog(/* kext */ NULL,
556 kOSKextLogErrorLevel |
557 kOSKextLogDirectoryScanFlag,
558 "Can't get virtual address for device tree entry %s.",
559 devTreeNameCString);
560 goto finish;
561 }
562
563 /* Wrap the booter data buffer in an OSData and set a dealloc function
564 * so it will take care of the physical memory when freed. Kexts will
565 * retain the booterData for as long as they need it. Remove the entry
566 * from the booter memory map after this is done.
567 */
568 booterData = OSData::withBytesNoCopy(booterDataPtr,
569 deviceTreeBuffer->length);
570 if (!booterData) {
571 OSKextLog(/* kext */ NULL,
572 kOSKextLogErrorLevel |
573 kOSKextLogGeneralFlag,
574 "Error - Can't allocate OSData wrapper for device tree entry %s.",
575 devTreeNameCString);
576 goto finish;
577 }
578 booterData->setDeallocFunction(osdata_phys_free);
579
580 /* Create the kext for the entry, then release it, because the
581 * kext system keeps them around until explicitly removed.
582 * Any creation/registration failures are already logged for us.
583 */
584 OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData);
585 OSSafeRelease(newKext);
586
587 booterMemoryMap->removeProperty(deviceTreeName);
588
589 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
590
591 finish:
592
593 OSSafeRelease(booterMemoryMap);
594 OSSafeRelease(propertyDict);
595 OSSafeRelease(keyIterator);
596 OSSafeRelease(booterData);
597 OSSafeRelease(aKext);
598 return;
599 }
600
601 /*********************************************************************
602 *********************************************************************/
603 #define COM_APPLE "com.apple."
604
605 void
606 KLDBootstrap::loadSecurityExtensions(void)
607 {
608 OSDictionary * extensionsDict = NULL; // must release
609 OSCollectionIterator * keyIterator = NULL; // must release
610 OSString * bundleID = NULL; // don't release
611 OSKext * theKext = NULL; // don't release
612 OSBoolean * isSecurityKext = NULL; // don't release
613
614 OSKextLog(/* kext */ NULL,
615 kOSKextLogStepLevel |
616 kOSKextLogLoadFlag,
617 "Loading security extensions.");
618
619 extensionsDict = OSKext::copyKexts();
620 if (!extensionsDict) {
621 return;
622 }
623
624 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
625 if (!keyIterator) {
626 OSKextLog(/* kext */ NULL,
627 kOSKextLogErrorLevel |
628 kOSKextLogGeneralFlag,
629 "Failed to allocate iterator for security extensions.");
630 goto finish;
631 }
632
633 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
634
635 const char * bundle_id = bundleID->getCStringNoCopy();
636
637 /* Skip extensions whose bundle IDs don't start with "com.apple.".
638 */
639 if (!bundle_id ||
640 (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
641
642 continue;
643 }
644
645 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
646 if (!theKext) {
647 continue;
648 }
649
650 isSecurityKext = OSDynamicCast(OSBoolean,
651 theKext->getPropertyForHostArch(kAppleSecurityExtensionKey));
652 if (isSecurityKext && isSecurityKext->isTrue()) {
653 OSKextLog(/* kext */ NULL,
654 kOSKextLogStepLevel |
655 kOSKextLogLoadFlag,
656 "Loading security extension %s.", bundleID->getCStringNoCopy());
657 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
658 /* allowDefer */ false);
659 }
660 }
661
662 finish:
663 OSSafeRelease(keyIterator);
664 OSSafeRelease(extensionsDict);
665
666 return;
667 }
668
669 /*********************************************************************
670 * We used to require that all listed kernel components load, but
671 * nowadays we can get them from userland so we only try to load the
672 * ones we have. If an error occurs later, such is life.
673 *
674 * Note that we look the kexts up first, so we can avoid spurious
675 * (in this context, anyhow) log messages about kexts not being found.
676 *
677 * xxx - do we even need to do this any more? Check if the kernel
678 * xxx - compoonents just load in the regular paths
679 *********************************************************************/
680 OSReturn
681 KLDBootstrap::loadKernelComponentKexts(void)
682 {
683 OSReturn result = kOSReturnSuccess; // optimistic
684 OSKext * theKext = NULL; // must release
685 const char ** kextIDPtr = NULL; // do not release
686
687 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
688
689 OSSafeReleaseNULL(theKext);
690 theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);
691
692 if (theKext) {
693 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
694 *kextIDPtr, /* allowDefer */ false)) {
695
696 // xxx - check KextBookkeeping, might be redundant
697 OSKextLog(/* kext */ NULL,
698 kOSKextLogErrorLevel |
699 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
700 "Failed to initialize kernel component %s.", *kextIDPtr);
701 result = kOSReturnError;
702 }
703 }
704 }
705
706 OSSafeRelease(theKext);
707 return result;
708 }
709
710 /*********************************************************************
711 * Ensure that Kernel External Components are loaded early in boot,
712 * before other kext personalities get sent to the IOCatalogue. These
713 * kexts are treated specially because they may provide the implementation
714 * for kernel-vended KPI, so they must register themselves before
715 * general purpose IOKit probing begins.
716 *********************************************************************/
717
718 #define COM_APPLE_KEC "com.apple.kec."
719
720 void
721 KLDBootstrap::loadKernelExternalComponents(void)
722 {
723 OSDictionary * extensionsDict = NULL; // must release
724 OSCollectionIterator * keyIterator = NULL; // must release
725 OSString * bundleID = NULL; // don't release
726 OSKext * theKext = NULL; // don't release
727 OSBoolean * isKernelExternalComponent = NULL; // don't release
728
729 OSKextLog(/* kext */ NULL,
730 kOSKextLogStepLevel |
731 kOSKextLogLoadFlag,
732 "Loading Kernel External Components.");
733
734 extensionsDict = OSKext::copyKexts();
735 if (!extensionsDict) {
736 return;
737 }
738
739 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
740 if (!keyIterator) {
741 OSKextLog(/* kext */ NULL,
742 kOSKextLogErrorLevel |
743 kOSKextLogGeneralFlag,
744 "Failed to allocate iterator for Kernel External Components.");
745 goto finish;
746 }
747
748 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
749
750 const char * bundle_id = bundleID->getCStringNoCopy();
751
752 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
753 */
754 if (!bundle_id ||
755 (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
756
757 continue;
758 }
759
760 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
761 if (!theKext) {
762 continue;
763 }
764
765 isKernelExternalComponent = OSDynamicCast(OSBoolean,
766 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
767 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
768 OSKextLog(/* kext */ NULL,
769 kOSKextLogStepLevel |
770 kOSKextLogLoadFlag,
771 "Loading kernel external component %s.", bundleID->getCStringNoCopy());
772 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
773 /* allowDefer */ false);
774 }
775 }
776
777 finish:
778 OSSafeRelease(keyIterator);
779 OSSafeRelease(extensionsDict);
780
781 return;
782 }
783
784 /*********************************************************************
785 *********************************************************************/
786 void
787 KLDBootstrap::readBuiltinPersonalities(void)
788 {
789 OSObject * parsedXML = NULL; // must release
790 OSArray * builtinExtensions = NULL; // do not release
791 OSArray * allPersonalities = NULL; // must release
792 OSString * errorString = NULL; // must release
793 kernel_section_t * infosect = NULL; // do not free
794 OSCollectionIterator * personalitiesIterator = NULL; // must release
795 unsigned int count, i;
796
797 OSKextLog(/* kext */ NULL,
798 kOSKextLogStepLevel |
799 kOSKextLogLoadFlag,
800 "Reading built-in kernel personalities for I/O Kit drivers.");
801
802 /* Look in the __BUILTIN __info segment for an array of Info.plist
803 * entries. For each one, extract the personalities dictionary, add
804 * it to our array, then push them all (without matching) to
805 * the IOCatalogue. This can be used to augment the personalities
806 * in gIOKernelConfigTables, especially when linking entire kexts into
807 * the mach_kernel image.
808 */
809 infosect = getsectbyname("__BUILTIN", "__info");
810 if (!infosect) {
811 // this isn't fatal
812 goto finish;
813 }
814
815 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
816 &errorString);
817 if (parsedXML) {
818 builtinExtensions = OSDynamicCast(OSArray, parsedXML);
819 }
820 if (!builtinExtensions) {
821 const char * errorCString = "(unknown error)";
822
823 if (errorString && errorString->getCStringNoCopy()) {
824 errorCString = errorString->getCStringNoCopy();
825 } else if (parsedXML) {
826 errorCString = "not an array";
827 }
828 OSKextLog(/* kext */ NULL,
829 kOSKextLogErrorLevel |
830 kOSKextLogLoadFlag,
831 "Error unserializing built-in personalities: %s.", errorCString);
832 goto finish;
833 }
834
835 // estimate 3 personalities per Info.plist/kext
836 count = builtinExtensions->getCount();
837 allPersonalities = OSArray::withCapacity(count * 3);
838
839 for (i = 0; i < count; i++) {
840 OSDictionary * infoDict = NULL; // do not release
841 OSString * moduleName = NULL; // do not release
842 OSDictionary * personalities; // do not release
843 OSString * personalityName; // do not release
844
845 OSSafeReleaseNULL(personalitiesIterator);
846
847 infoDict = OSDynamicCast(OSDictionary,
848 builtinExtensions->getObject(i));
849 if (!infoDict) {
850 continue;
851 }
852
853 moduleName = OSDynamicCast(OSString,
854 infoDict->getObject(kCFBundleIdentifierKey));
855 if (!moduleName) {
856 continue;
857 }
858
859 OSKextLog(/* kext */ NULL,
860 kOSKextLogStepLevel |
861 kOSKextLogLoadFlag,
862 "Adding personalities for built-in driver %s:",
863 moduleName->getCStringNoCopy());
864
865 personalities = OSDynamicCast(OSDictionary,
866 infoDict->getObject("IOKitPersonalities"));
867 if (!personalities) {
868 continue;
869 }
870
871 personalitiesIterator = OSCollectionIterator::withCollection(personalities);
872 if (!personalitiesIterator) {
873 continue; // xxx - well really, what can we do? should we panic?
874 }
875
876 while ((personalityName = OSDynamicCast(OSString,
877 personalitiesIterator->getNextObject()))) {
878
879 OSDictionary * personality = OSDynamicCast(OSDictionary,
880 personalities->getObject(personalityName));
881
882 OSKextLog(/* kext */ NULL,
883 kOSKextLogDetailLevel |
884 kOSKextLogLoadFlag,
885 "Adding built-in driver personality %s.",
886 personalityName->getCStringNoCopy());
887
888 if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
889 personality->setObject(kCFBundleIdentifierKey, moduleName);
890 }
891 allPersonalities->setObject(personality);
892 }
893 }
894
895 gIOCatalogue->addDrivers(allPersonalities, false);
896
897 finish:
898 OSSafeRelease(parsedXML);
899 OSSafeRelease(allPersonalities);
900 OSSafeRelease(errorString);
901 OSSafeRelease(personalitiesIterator);
902 return;
903 }
904
905 #if PRAGMA_MARK
906 #pragma mark Bootstrap Functions
907 #endif
908 /*********************************************************************
909 * Bootstrap Functions
910 *********************************************************************/
911 static void bootstrapRecordStartupExtensions(void)
912 {
913 sBootstrapObject.readStartupExtensions();
914 return;
915 }
916
917 static void bootstrapLoadSecurityExtensions(void)
918 {
919 sBootstrapObject.loadSecurityExtensions();
920 return;
921 }
922