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