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