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