]> git.saurik.com Git - apple/xnu.git/blob - libsa/catalogue.cpp
ab7ce249aba877d95fa0bf7f2f1772ed90382553
[apple/xnu.git] / libsa / catalogue.cpp
1 /*
2 * Copyright (c) 2000-2007 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 #include <libkern/c++/OSContainers.h>
29 #include <IOKit/IODeviceTreeSupport.h>
30 #include <IOKit/IORegistryEntry.h>
31 #include <IOKit/IOCatalogue.h>
32 #include <IOKit/IOKitKeysPrivate.h>
33 #include <libkern/c++/OSUnserialize.h>
34 #include <libkern/OSByteOrder.h>
35 #include <libsa/catalogue.h>
36
37 extern "C" {
38 #include <machine/machine_routines.h>
39 #include <mach/host_info.h>
40 #include <mach/kmod.h>
41 #include <libsa/mkext.h>
42 #include <libsa/vers_rsrc.h>
43 #include <mach-o/loader.h>
44 };
45
46 #include <IOKit/IOLib.h>
47
48 #include <IOKit/assert.h>
49
50 extern "C" {
51 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
52 // extern kern_return_t host_info(host_t host,
53 // host_flavor_t flavor,
54 // host_info_t info,
55 // mach_msg_type_number_t *count);
56 extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
57 // Return the address of the named Mach-O segment from the currently
58 // executing 32 bit kernel, or NULL.
59 extern struct segment_command *getsegbyname(char *seg_name);
60 // Return the address of the named section from the named Mach-O segment
61 // from the currently executing 32 bit kernel, or NULL.
62 extern struct section *getsectbyname(const char *segname, const char *sectname);
63 };
64
65 #define LOG_DELAY()
66
67 #if 0
68 #define VTYELLOW "\033[33m"
69 #define VTRESET "\033[0m"
70 #else
71 #define VTYELLOW ""
72 #define VTRESET ""
73 #endif
74
75 /*********************************************************************
76 *********************************************************************/
77 static OSDictionary * gStartupExtensions = 0;
78 static OSArray * gBootLoaderObjects = 0;
79 extern OSArray * gIOPrelinkedModules;
80
81 OSDictionary * getStartupExtensions(void) {
82 if (gStartupExtensions) {
83 return gStartupExtensions;
84 }
85 gStartupExtensions = OSDictionary::withCapacity(1);
86 assert (gStartupExtensions);
87
88 return gStartupExtensions;
89 }
90
91 /* This array holds objects that are needed to be held around during
92 * boot before kextd starts up. Currently it contains OSData objects
93 * copied from OF entries for mkext archives in device ROMs. Because
94 * the Device Tree support code dumps these after initially handing
95 * them to us, we have to be able to clean them up later.
96 */
97 OSArray * getBootLoaderObjects(void) {
98 if (gBootLoaderObjects) {
99 return gBootLoaderObjects;
100 }
101 gBootLoaderObjects = OSArray::withCapacity(1);
102 assert (gBootLoaderObjects);
103
104 return gBootLoaderObjects;
105 }
106
107 /*********************************************************************
108 * This function checks that a driver dict has all the required
109 * entries and does a little bit of value checking too.
110 *
111 * index is nonnegative if the index of an entry from an mkext
112 * archive.
113 *********************************************************************/
114 bool validateExtensionDict(OSDictionary * extension, int index) {
115
116 bool result = true;
117 bool not_a_dict = false;
118 bool id_missing = false;
119 bool is_kernel_resource = false;
120 bool has_executable = false;
121 bool ineligible_for_safe_boot = false;
122 OSString * bundleIdentifier = NULL; // do not release
123 OSObject * rawValue = NULL; // do not release
124 OSString * stringValue = NULL; // do not release
125 OSBoolean * booleanValue = NULL; // do not release
126 OSDictionary * personalities = NULL; // do not release
127 OSDictionary * libraries = NULL; // do not release
128 OSCollectionIterator * keyIterator = NULL; // must release
129 OSString * key = NULL; // do not release
130 VERS_version vers;
131 VERS_version compatible_vers;
132 char namep[16]; // unused but needed for PE_parse_boot_arg()
133
134 // Info dict is a dictionary
135 if (!OSDynamicCast(OSDictionary, extension)) {
136 not_a_dict = true;
137 result = false;
138 goto finish;
139 }
140
141 // CFBundleIdentifier is a string - REQUIRED
142 bundleIdentifier = OSDynamicCast(OSString,
143 extension->getObject("CFBundleIdentifier"));
144 if (!bundleIdentifier) {
145 id_missing = true;
146 result = false;
147 goto finish;
148 }
149
150 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
151 if (bundleIdentifier->getLength() >= KMOD_MAX_NAME) {
152 result = false;
153 goto finish;
154 }
155
156 // CFBundlePackageType is "KEXT" - REQUIRED
157 stringValue = OSDynamicCast(OSString,
158 extension->getObject("CFBundlePackageType"));
159 if (!stringValue) {
160 result = false;
161 goto finish;
162 }
163 if (!stringValue->isEqualTo("KEXT")) {
164 result = false;
165 goto finish;
166 }
167
168 // CFBundleVersion is a string - REQUIRED
169 stringValue = OSDynamicCast(OSString,
170 extension->getObject("CFBundleVersion"));
171 if (!stringValue) {
172 result = false;
173 goto finish;
174 }
175 // CFBundleVersion is of valid form
176 vers = VERS_parse_string(stringValue->getCStringNoCopy());
177 if (vers < 0) {
178 result = false;
179 goto finish;
180 }
181
182 // OSBundleCompatibleVersion is a string - OPTIONAL
183 rawValue = extension->getObject("OSBundleCompatibleVersion");
184 if (rawValue) {
185 stringValue = OSDynamicCast(OSString, rawValue);
186 if (!stringValue) {
187 result = false;
188 goto finish;
189 }
190
191 // OSBundleCompatibleVersion is of valid form
192 compatible_vers = VERS_parse_string(stringValue->getCStringNoCopy());
193 if (compatible_vers < 0) {
194 result = false;
195 goto finish;
196 }
197
198 // OSBundleCompatibleVersion <= CFBundleVersion
199 if (compatible_vers > vers) {
200 result = false;
201 goto finish;
202 }
203 }
204
205 // CFBundleExecutable is a string - OPTIONAL
206 rawValue = extension->getObject("CFBundleExecutable");
207 if (rawValue) {
208 stringValue = OSDynamicCast(OSString, rawValue);
209 if (!stringValue || stringValue->getLength() == 0) {
210 result = false;
211 goto finish;
212 }
213 has_executable = true;
214 }
215
216 // OSKernelResource is a boolean value - OPTIONAL
217 rawValue = extension->getObject("OSKernelResource");
218 if (rawValue) {
219 booleanValue = OSDynamicCast(OSBoolean, rawValue);
220 if (!booleanValue) {
221 result = false;
222 goto finish;
223 }
224 is_kernel_resource = booleanValue->isTrue();
225 }
226
227 // IOKitPersonalities is a dictionary - OPTIONAL
228 rawValue = extension->getObject("IOKitPersonalities");
229 if (rawValue) {
230 personalities = OSDynamicCast(OSDictionary, rawValue);
231 if (!personalities) {
232 result = false;
233 goto finish;
234 }
235
236 keyIterator = OSCollectionIterator::withCollection(personalities);
237 if (!keyIterator) {
238 IOLog("Error: Failed to allocate iterator for personalities.\n");
239 LOG_DELAY();
240 result = false;
241 goto finish;
242 }
243
244 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
245 OSDictionary * personality = NULL; // do not release
246
247 // Each personality is a dictionary
248 personality = OSDynamicCast(OSDictionary,
249 personalities->getObject(key));
250 if (!personality) {
251 result = false;
252 goto finish;
253 }
254
255 // IOClass exists as a string - REQUIRED
256 if (!OSDynamicCast(OSString, personality->getObject("IOClass"))) {
257 result = false;
258 goto finish;
259 }
260
261 // IOProviderClass exists as a string - REQUIRED
262 if (!OSDynamicCast(OSString,
263 personality->getObject("IOProviderClass"))) {
264
265 result = false;
266 goto finish;
267 }
268
269 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
270 rawValue = personality->getObject("CFBundleIdentifier");
271 if (!rawValue) {
272 personality->setObject("CFBundleIdentifier", bundleIdentifier);
273 } else {
274 OSString * personalityID = NULL; // do not release
275 personalityID = OSDynamicCast(OSString, rawValue);
276 if (!personalityID) {
277 result = false;
278 goto finish;
279 } else {
280 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
281 if (personalityID->getLength() >= KMOD_MAX_NAME) {
282 result = false;
283 goto finish;
284 }
285 }
286 }
287
288 // IOKitDebug is a number - OPTIONAL
289 rawValue = personality->getObject("IOKitDebug");
290 if (rawValue && !OSDynamicCast(OSNumber, rawValue)) {
291 result = false;
292 goto finish;
293 }
294 }
295
296 keyIterator->release();
297 keyIterator = NULL;
298 }
299
300
301 // OSBundleLibraries is a dictionary - REQUIRED if
302 // not kernel resource & has executable
303 //
304 rawValue = extension->getObject("OSBundleLibraries");
305 if (!rawValue && !is_kernel_resource && has_executable) {
306 result = false;
307 goto finish;
308 }
309
310 if (rawValue) {
311 libraries = OSDynamicCast(OSDictionary, rawValue);
312 if (!libraries) {
313 result = false;
314 goto finish;
315 }
316
317 keyIterator = OSCollectionIterator::withCollection(libraries);
318 if (!keyIterator) {
319 IOLog("Error: Failed to allocate iterator for libraries.\n");
320 LOG_DELAY();
321 result = false;
322 goto finish;
323 }
324
325 while ((key = OSDynamicCast(OSString,
326 keyIterator->getNextObject()))) {
327
328 OSString * libraryVersion = NULL; // do not release
329
330 // Each key's length is not >= KMOD_MAX_NAME
331 if (key->getLength() >= KMOD_MAX_NAME) {
332 result = false;
333 goto finish;
334 }
335
336 libraryVersion = OSDynamicCast(OSString,
337 libraries->getObject(key));
338 if (!libraryVersion) {
339 result = false;
340 goto finish;
341 }
342
343 // Each value is a valid version string
344 vers = VERS_parse_string(libraryVersion->getCStringNoCopy());
345 if (vers < 0) {
346 result = false;
347 goto finish;
348 }
349 }
350
351 keyIterator->release();
352 keyIterator = NULL;
353 }
354
355 // OSBundleRequired, if present, must have a legal value.
356 // If it is not present and if we are safe-booting,
357 // then the kext is not eligible.
358 //
359 rawValue = extension->getObject("OSBundleRequired");
360 if (rawValue) {
361 stringValue = OSDynamicCast(OSString, rawValue);
362 if (!stringValue) {
363 result = false;
364 goto finish;
365 }
366 if (!stringValue->isEqualTo("Root") &&
367 !stringValue->isEqualTo("Local-Root") &&
368 !stringValue->isEqualTo("Network-Root") &&
369 !stringValue->isEqualTo("Safe Boot") &&
370 !stringValue->isEqualTo("Console")) {
371
372 result = false;
373 goto finish;
374 }
375
376 } else if (PE_parse_boot_argn("-x", namep, sizeof (namep))) { /* safe boot */
377 ineligible_for_safe_boot = true;
378 result = false;
379 goto finish;
380 }
381
382
383 finish:
384 if (keyIterator) keyIterator->release();
385
386 if (!result) {
387 if (ineligible_for_safe_boot) {
388 IOLog(VTYELLOW "Skipping extension \"%s\" during safe boot "
389 "(no OSBundleRequired property)\n"
390 VTRESET,
391 bundleIdentifier->getCStringNoCopy());
392 } else if (not_a_dict) {
393 if (index > -1) {
394 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
395 } else {
396 IOLog(VTYELLOW "kernel extension " VTRESET);
397 }
398 IOLog(VTYELLOW "info dictionary isn't a dictionary\n"
399 VTRESET);
400 } else if (id_missing) {
401 if (index > -1) {
402 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
403 } else {
404 IOLog(VTYELLOW "kernel extension " VTRESET);
405 }
406 IOLog(VTYELLOW "\"CFBundleIdentifier\" property is "
407 "missing or not a string\n"
408 VTRESET);
409 } else {
410 IOLog(VTYELLOW "kernel extension \"%s\": info dictionary is invalid\n"
411 VTRESET, bundleIdentifier->getCStringNoCopy());
412 }
413 LOG_DELAY();
414 }
415
416 return result;
417 }
418
419
420 /*********************************************************************
421 *********************************************************************/
422 OSDictionary * compareExtensionVersions(
423 OSDictionary * incumbent,
424 OSDictionary * candidate) {
425
426 OSDictionary * winner = NULL;
427
428 OSDictionary * incumbentPlist = NULL;
429 OSDictionary * candidatePlist = NULL;
430 OSString * incumbentName = NULL;
431 OSString * candidateName = NULL;
432 OSString * incumbentVersionString = NULL;
433 OSString * candidateVersionString = NULL;
434 VERS_version incumbent_vers = 0;
435 VERS_version candidate_vers = 0;
436
437 incumbentPlist = OSDynamicCast(OSDictionary,
438 incumbent->getObject("plist"));
439 candidatePlist = OSDynamicCast(OSDictionary,
440 candidate->getObject("plist"));
441
442 if (!incumbentPlist || !candidatePlist) {
443 IOLog("compareExtensionVersions() called with invalid "
444 "extension dictionaries.\n");
445 LOG_DELAY();
446 winner = NULL;
447 goto finish;
448 }
449
450 incumbentName = OSDynamicCast(OSString,
451 incumbentPlist->getObject("CFBundleIdentifier"));
452 candidateName = OSDynamicCast(OSString,
453 candidatePlist->getObject("CFBundleIdentifier"));
454 incumbentVersionString = OSDynamicCast(OSString,
455 incumbentPlist->getObject("CFBundleVersion"));
456 candidateVersionString = OSDynamicCast(OSString,
457 candidatePlist->getObject("CFBundleVersion"));
458
459 if (!incumbentName || !candidateName ||
460 !incumbentVersionString || !candidateVersionString) {
461
462 IOLog("compareExtensionVersions() called with invalid "
463 "extension dictionaries.\n");
464 LOG_DELAY();
465 winner = NULL;
466 goto finish;
467 }
468
469 if (strcmp(incumbentName->getCStringNoCopy(),
470 candidateName->getCStringNoCopy())) {
471
472 IOLog("compareExtensionVersions() called with different "
473 "extension names (%s and %s).\n",
474 incumbentName->getCStringNoCopy(),
475 candidateName->getCStringNoCopy());
476 LOG_DELAY();
477 winner = NULL;
478 goto finish;
479 }
480
481 incumbent_vers = VERS_parse_string(incumbentVersionString->getCStringNoCopy());
482 if (incumbent_vers < 0) {
483
484 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
485 VTRESET,
486 incumbentName->getCStringNoCopy(),
487 incumbentVersionString->getCStringNoCopy());
488 LOG_DELAY();
489 winner = NULL;
490 goto finish;
491 }
492
493 candidate_vers = VERS_parse_string(candidateVersionString->getCStringNoCopy());
494 if (candidate_vers < 0) {
495
496 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
497 VTRESET,
498 candidateName->getCStringNoCopy(),
499 candidateVersionString->getCStringNoCopy());
500 LOG_DELAY();
501 winner = NULL;
502 goto finish;
503 }
504
505 if (0 == strcmp("com.apple.driver.AppleIntelCPUPowerManagement",
506 incumbentName->getCStringNoCopy())) {
507 /* Special rules. Always favor version 51.0.0 exactly at the
508 * expense of all other versions newer or older.
509 */
510 if(0 == strcmp(incumbentVersionString->getCStringNoCopy(), "51.0.0")) {
511 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with "
512 " version (%s -> %s).\n" VTRESET,
513 candidateName->getCStringNoCopy(),
514 candidateVersionString->getCStringNoCopy(),
515 incumbentVersionString->getCStringNoCopy());
516 winner = incumbent;
517 goto finish;
518 } else if (0 == strcmp(candidateVersionString->getCStringNoCopy(), "51.0.0")) {
519 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with "
520 " version (%s -> %s).\n" VTRESET,
521 candidateName->getCStringNoCopy(),
522 incumbentVersionString->getCStringNoCopy(),
523 candidateVersionString->getCStringNoCopy());
524 winner = candidate;
525 goto finish;
526 }
527 }
528
529 if (candidate_vers > incumbent_vers) {
530 IOLog(VTYELLOW "Replacing extension \"%s\" with newer version "
531 "(%s -> %s).\n" VTRESET,
532 incumbentName->getCStringNoCopy(),
533 incumbentVersionString->getCStringNoCopy(),
534 candidateVersionString->getCStringNoCopy());
535 LOG_DELAY();
536 winner = candidate;
537 goto finish;
538 } else {
539 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with older/same "
540 " version (%s -> %s).\n" VTRESET,
541 candidateName->getCStringNoCopy(),
542 candidateVersionString->getCStringNoCopy(),
543 incumbentVersionString->getCStringNoCopy());
544 LOG_DELAY();
545 winner = incumbent;
546 goto finish;
547 }
548
549 finish:
550
551 // no cleanup, how nice
552 return winner;
553 }
554
555
556 /*********************************************************************
557 * This function merges entries in the mergeFrom dictionary into the
558 * mergeInto dictionary. If it returns false, the two dictionaries are
559 * not altered. If it returns true, then mergeInto may have new
560 * entries; any keys that were already present in mergeInto are
561 * removed from mergeFrom, so that the caller can see what was
562 * actually merged.
563 *********************************************************************/
564 bool mergeExtensionDictionaries(OSDictionary * mergeInto,
565 OSDictionary * mergeFrom) {
566
567 bool result = true;
568 OSDictionary * mergeIntoCopy = NULL; // must release
569 OSDictionary * mergeFromCopy = NULL; // must release
570 OSCollectionIterator * keyIterator = NULL; // must release
571 OSString * key; // don't release
572
573 /* Add 1 to count to guarantee copy can grow (grr).
574 */
575 mergeIntoCopy = OSDictionary::withDictionary(mergeInto,
576 mergeInto->getCount() + 1);
577 if (!mergeIntoCopy) {
578 IOLog("Error: Failed to copy 'into' extensions dictionary "
579 "for merge.\n");
580 LOG_DELAY();
581 result = false;
582 goto finish;
583 }
584
585 /* Add 1 to count to guarantee copy can grow (grr).
586 */
587 mergeFromCopy = OSDictionary::withDictionary(mergeFrom,
588 mergeFrom->getCount() + 1);
589 if (!mergeFromCopy) {
590 IOLog("Error: Failed to copy 'from' extensions dictionary "
591 "for merge.\n");
592 LOG_DELAY();
593 result = false;
594 goto finish;
595 }
596
597 keyIterator = OSCollectionIterator::withCollection(mergeFrom);
598 if (!keyIterator) {
599 IOLog("Error: Failed to allocate iterator for extensions.\n");
600 LOG_DELAY();
601 result = false;
602 goto finish;
603 }
604
605
606 /*****
607 * Loop through "from" dictionary, checking if the identifier already
608 * exists in the "into" dictionary and checking versions if it does.
609 */
610 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
611 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
612 mergeIntoCopy->getObject(key));
613 OSDictionary * candidateExt = OSDynamicCast(OSDictionary,
614 mergeFrom->getObject(key));
615
616 if (!incumbentExt) {
617 if (!mergeIntoCopy->setObject(key, candidateExt)) {
618
619 /* This is a fatal error, so bail.
620 */
621 IOLog("mergeExtensionDictionaries(): Failed to add "
622 "identifier %s\n",
623 key->getCStringNoCopy());
624 LOG_DELAY();
625 result = false;
626 goto finish;
627 }
628 } else {
629 OSDictionary * mostRecentExtension =
630 compareExtensionVersions(incumbentExt, candidateExt);
631
632 if (mostRecentExtension == incumbentExt) {
633 mergeFromCopy->removeObject(key);
634 } else if (mostRecentExtension == candidateExt) {
635
636 if (!mergeIntoCopy->setObject(key, candidateExt)) {
637
638 /* This is a fatal error, so bail.
639 */
640 IOLog("mergeExtensionDictionaries(): Failed to add "
641 "identifier %s\n",
642 key->getCStringNoCopy());
643 LOG_DELAY();
644 result = false;
645 goto finish;
646 }
647 } else /* should be NULL */ {
648
649 /* This is a nonfatal error, so continue doing others.
650 */
651 IOLog("mergeExtensionDictionaries(): Error comparing "
652 "versions of duplicate extensions %s.\n",
653 key->getCStringNoCopy());
654 LOG_DELAY();
655 continue;
656 }
657 }
658 }
659
660 finish:
661
662 /* If successful, replace the contents of the original
663 * dictionaries with those of the modified copies.
664 */
665 if (result) {
666 mergeInto->flushCollection();
667 mergeInto->merge(mergeIntoCopy);
668 mergeFrom->flushCollection();
669 mergeFrom->merge(mergeFromCopy);
670 }
671
672 if (mergeIntoCopy) mergeIntoCopy->release();
673 if (mergeFromCopy) mergeFromCopy->release();
674 if (keyIterator) keyIterator->release();
675
676 return result;
677 }
678
679
680 /****
681 * These bits are used to parse data made available by bootx.
682 */
683 #define BOOTX_KEXT_PREFIX "Driver-"
684 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
685
686 typedef struct MemoryMapFileInfo {
687 UInt32 paddr;
688 UInt32 length;
689 } MemoryMapFileInfo;
690
691 typedef struct BootxDriverInfo {
692 char *plistAddr;
693 long plistLength;
694 void *moduleAddr;
695 long moduleLength;
696 } BootxDriverInfo;
697
698 typedef struct MkextEntryInfo {
699 vm_address_t base_address;
700 mkext_file * fileinfo;
701 } MkextEntryInfo;
702
703
704 /*********************************************************************
705 * This private function reads the data for a single extension from
706 * the bootx memory-map's propery dict, returning a dictionary with
707 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
708 * and "code" for the extension's executable code as an OSData.
709 *********************************************************************/
710 OSDictionary * readExtension(OSDictionary * propertyDict,
711 const char * memory_map_name) {
712
713 int error = 0;
714 OSData * bootxDriverDataObject = NULL;
715 OSDictionary * driverPlist = NULL;
716 OSString * driverName = NULL;
717 OSData * driverCode = NULL;
718 OSString * errorString = NULL;
719 OSDictionary * driverDict = NULL;
720
721 const MemoryMapFileInfo * driverInfo = 0;
722 BootxDriverInfo * dataBuffer;
723
724 kmod_info_t * loaded_kmod = NULL;
725
726 bootxDriverDataObject = OSDynamicCast(OSData,
727 propertyDict->getObject(memory_map_name));
728 // don't release bootxDriverDataObject
729
730 if (!bootxDriverDataObject) {
731 IOLog("Error: No driver data object "
732 "for device tree entry \"%s\".\n",
733 memory_map_name);
734 LOG_DELAY();
735 error = 1;
736 goto finish;
737 }
738
739 driverDict = OSDictionary::withCapacity(2);
740 if (!driverDict) {
741 IOLog("Error: Couldn't allocate dictionary "
742 "for device tree entry \"%s\".\n", memory_map_name);
743 LOG_DELAY();
744 error = 1;
745 goto finish;
746 }
747
748 driverInfo = (const MemoryMapFileInfo *)
749 bootxDriverDataObject->getBytesNoCopy(0,
750 sizeof(MemoryMapFileInfo));
751 #if defined (__ppc__) || defined (__arm__)
752 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(driverInfo->paddr);
753 #elif defined (__i386__)
754 dataBuffer = (BootxDriverInfo *)ml_boot_ptovirt(driverInfo->paddr);
755 dataBuffer->plistAddr = (char *)ml_boot_ptovirt((vm_address_t)dataBuffer->plistAddr);
756 if (dataBuffer->moduleAddr)
757 dataBuffer->moduleAddr = (void *)ml_boot_ptovirt((vm_address_t)dataBuffer->moduleAddr);
758 #else
759 #error unsupported architecture
760 #endif
761 if (!dataBuffer) {
762 IOLog("Error: No data buffer "
763 "for device tree entry \"%s\".\n", memory_map_name);
764 LOG_DELAY();
765 error = 1;
766 goto finish;
767 }
768
769 driverPlist = OSDynamicCast(OSDictionary,
770 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
771 if (!driverPlist) {
772 IOLog("Error: Couldn't read XML property list "
773 "for device tree entry \"%s\".\n", memory_map_name);
774 LOG_DELAY();
775 if (errorString) {
776 IOLog("XML parse error: %s.\n",
777 errorString->getCStringNoCopy());
778 LOG_DELAY();
779 }
780 error = 1;
781 goto finish;
782 }
783
784
785 driverName = OSDynamicCast(OSString,
786 driverPlist->getObject("CFBundleIdentifier")); // do not release
787 if (!driverName) {
788 IOLog("Error: Device tree entry \"%s\" has "
789 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
790 LOG_DELAY();
791 error = 1;
792 goto finish;
793 }
794
795 /* Check if kmod is already loaded and is a real loadable one (has
796 * an address).
797 */
798 loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy());
799 if (loaded_kmod && loaded_kmod->address) {
800 IOLog("Skipping new extension \"%s\"; an extension named "
801 "\"%s\" is already loaded.\n",
802 driverName->getCStringNoCopy(),
803 loaded_kmod->name);
804 LOG_DELAY();
805 error = 1;
806 goto finish;
807 }
808
809 if (!validateExtensionDict(driverPlist, -1)) {
810 // validateExtensionsDict() logs an error
811 error = 1;
812 goto finish;
813 }
814
815 driverDict->setObject("plist", driverPlist);
816
817 /* It's perfectly okay for a KEXT to have no executable.
818 * Check that moduleAddr is nonzero before attempting to
819 * get one.
820 *
821 * NOTE: The driverCode object is created "no-copy", so
822 * it doesn't own that memory. The memory must be freed
823 * separately from the OSData object (see
824 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
825 */
826 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
827 driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
828 dataBuffer->moduleLength);
829 if (!driverCode) {
830 IOLog("Error: Couldn't allocate data object "
831 "to hold code for device tree entry \"%s\".\n",
832 memory_map_name);
833 LOG_DELAY();
834 error = 1;
835 goto finish;
836 }
837
838 if (driverCode) {
839 driverDict->setObject("code", driverCode);
840 }
841 }
842
843 finish:
844
845 if (loaded_kmod) {
846 kfree(loaded_kmod, sizeof(kmod_info_t));
847 }
848
849 // do not release bootxDriverDataObject
850 // do not release driverName
851
852 if (driverPlist) {
853 driverPlist->release();
854 }
855 if (errorString) {
856 errorString->release();
857 }
858 if (driverCode) {
859 driverCode->release();
860 }
861 if (error) {
862 if (driverDict) {
863 driverDict->release();
864 driverDict = NULL;
865 }
866 }
867 return driverDict;
868 }
869
870
871 /*********************************************************************
872 * Used to uncompress a single file entry in an mkext archive.
873 *
874 * The OSData returned does not own its memory! You must deallocate
875 * that memory using kmem_free() before releasing the OSData().
876 *********************************************************************/
877 static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
878 /* out */ OSData ** file) {
879
880 bool result = true;
881 kern_return_t kern_result;
882 u_int8_t * uncompressed_file = 0; // kmem_free() on error
883 OSData * uncompressedFile = 0; // returned
884 size_t uncompressed_size = 0;
885
886 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
887 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
888 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
889 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
890
891 *file = 0;
892
893 /* If these four fields are zero there's no file, but that isn't
894 * an error.
895 */
896 if (offset == 0 && compsize == 0 &&
897 realsize == 0 && modifiedsecs == 0) {
898 goto finish;
899 }
900
901 // Add 1 for '\0' to terminate XML string!
902 kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
903 realsize + 1);
904 if (kern_result != KERN_SUCCESS) {
905 IOLog("Error: Couldn't allocate data buffer "
906 "to uncompress file.\n");
907 LOG_DELAY();
908 result = false;
909 goto finish;
910 }
911
912 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
913 realsize + 1);
914 if (!uncompressedFile) {
915 IOLog("Error: Couldn't allocate data object "
916 "to uncompress file.\n");
917 LOG_DELAY();
918 result = false;
919 goto finish;
920 }
921
922 if (compsize != 0) {
923 uncompressed_size = decompress_lzss(uncompressed_file,
924 base_address + offset,
925 compsize);
926 if (uncompressed_size != realsize) {
927 IOLog("Error: Uncompressed file is not the length "
928 "recorded.\n");
929 LOG_DELAY();
930 result = false;
931 goto finish;
932 }
933 uncompressed_file[uncompressed_size] = '\0';
934 } else {
935 bcopy(base_address + offset, uncompressed_file,
936 realsize);
937 uncompressed_file[realsize] = '\0';
938 }
939
940 *file = uncompressedFile;
941
942 finish:
943 if (!result) {
944 if (uncompressed_file) {
945 kmem_free(kernel_map, (vm_address_t)uncompressed_file,
946 realsize + 1);
947 }
948 if (uncompressedFile) {
949 uncompressedFile->release();
950 *file = 0;
951 }
952 }
953 return result;
954 }
955
956 bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
957
958 const MkextEntryInfo *info = (const MkextEntryInfo *) compData->getBytesNoCopy();
959
960 return uncompressFile((u_int8_t *) info->base_address,
961 info->fileinfo, file);
962 }
963
964
965 /*********************************************************************
966 * Does the work of pulling extensions out of an mkext archive located
967 * in memory.
968 *********************************************************************/
969 bool extractExtensionsFromArchive(const MemoryMapFileInfo * mkext_file_info,
970 bool vaddr,
971 OSDictionary * extensions) {
972
973 bool result = true;
974
975 u_int8_t * crc_address = 0;
976 u_int32_t checksum;
977 mkext_header * mkext_data = 0; // don't free
978 mkext_kext * onekext_data = 0; // don't free
979 mkext_file * plist_file = 0; // don't free
980 mkext_file * module_file = 0; // don't free
981 kmod_info_t * loaded_kmod = 0; // must free
982
983 OSData * driverPlistDataObject = 0; // must release
984 OSDictionary * driverPlist = 0; // must release
985 OSData * driverCode = 0; // must release
986 OSDictionary * driverDict = 0; // must release
987 OSString * moduleName = 0; // don't release
988 OSString * errorString = NULL; // must release
989
990 OSData * moduleInfo = 0; // must release
991 MkextEntryInfo module_info;
992
993 IORegistryEntry * root;
994 OSData * checksumObj;
995
996 if (vaddr) {
997 // addExtensionsFromArchive passes a kernel virtual address
998 mkext_data = (mkext_header *)mkext_file_info->paddr;
999 } else {
1000 #if defined (__ppc__) || defined (__arm__)
1001 mkext_data = (mkext_header *)ml_static_ptovirt(mkext_file_info->paddr);
1002 #elif defined (__i386__)
1003 mkext_data = (mkext_header *)ml_boot_ptovirt(mkext_file_info->paddr);
1004 #else
1005 #error unsupported architecture
1006 #endif
1007 }
1008
1009 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
1010 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
1011 IOLog("Error: Extension archive has invalid magic or signature.\n");
1012 LOG_DELAY();
1013 result = false;
1014 goto finish;
1015 }
1016
1017 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
1018 IOLog("Error: Mismatch between extension archive & "
1019 "recorded length.\n");
1020 LOG_DELAY();
1021 result = false;
1022 goto finish;
1023 }
1024
1025 crc_address = (u_int8_t *)&mkext_data->version;
1026 checksum = adler32(crc_address,
1027 (unsigned int)mkext_data +
1028 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
1029
1030 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
1031 IOLog("Error: Extension archive has a bad checksum.\n");
1032 LOG_DELAY();
1033 result = false;
1034 goto finish;
1035 }
1036
1037 root = IORegistryEntry::getRegistryRoot();
1038 assert(root);
1039 checksumObj = OSData::withBytes((void *)&checksum,
1040 sizeof(checksum));
1041 assert(checksumObj);
1042 if (checksumObj) {
1043 root->setProperty(kIOStartupMkextCRC, checksumObj);
1044 checksumObj->release();
1045 }
1046
1047 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
1048 * match that of the running kernel.
1049 */
1050 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
1051 kern_return_t kresult = KERN_FAILURE;
1052 host_basic_info_data_t hostinfo;
1053 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
1054 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
1055
1056 kresult = host_info((host_t)1, HOST_BASIC_INFO,
1057 hostinfo_ptr, &count);
1058 if (kresult != KERN_SUCCESS) {
1059 IOLog("Error: Couldn't get current host info.\n");
1060 LOG_DELAY();
1061 result = false;
1062 goto finish;
1063 }
1064 if ((UInt32)hostinfo.cpu_type !=
1065 OSSwapBigToHostInt32(mkext_data->cputype)) {
1066
1067 IOLog("Error: Extension archive doesn't contain software "
1068 "for this computer's CPU type.\n");
1069 LOG_DELAY();
1070 result = false;
1071 goto finish;
1072 }
1073 if (!grade_binary(OSSwapBigToHostInt32(mkext_data->cputype),
1074 OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
1075 IOLog("Error: Extension archive doesn't contain software "
1076 "for this computer's CPU subtype.\n");
1077 LOG_DELAY();
1078 result = false;
1079 goto finish;
1080 }
1081 }
1082
1083 for (unsigned int i = 0;
1084 i < OSSwapBigToHostInt32(mkext_data->numkexts);
1085 i++) {
1086
1087 if (loaded_kmod) {
1088 kfree(loaded_kmod, sizeof(kmod_info_t));
1089 loaded_kmod = 0;
1090 }
1091
1092 if (driverPlistDataObject) {
1093 kmem_free(kernel_map,
1094 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1095 driverPlistDataObject->getLength());
1096
1097 driverPlistDataObject->release();
1098 driverPlistDataObject = NULL;
1099 }
1100 if (driverPlist) {
1101 driverPlist->release();
1102 driverPlist = NULL;
1103 }
1104 if (driverCode) {
1105 driverCode->release();
1106 driverCode = NULL;
1107 }
1108 if (driverDict) {
1109 driverDict->release();
1110 driverDict = NULL;
1111 }
1112 if (errorString) {
1113 errorString->release();
1114 errorString = NULL;
1115 }
1116
1117 onekext_data = &mkext_data->kext[i];
1118 plist_file = &onekext_data->plist;
1119 module_file = &onekext_data->module;
1120
1121 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
1122 &driverPlistDataObject)) {
1123
1124 IOLog("Error: couldn't uncompress plist file "
1125 "from multikext archive entry %d.\n", i);
1126 LOG_DELAY();
1127 continue;
1128 }
1129
1130 if (!driverPlistDataObject) {
1131 IOLog("Error: No property list present "
1132 "for multikext archive entry %d.\n", i);
1133 LOG_DELAY();
1134 continue;
1135 } else {
1136 driverPlist = OSDynamicCast(OSDictionary,
1137 OSUnserializeXML(
1138 (const char *)driverPlistDataObject->getBytesNoCopy(),
1139 &errorString));
1140 if (!driverPlist) {
1141 IOLog("Error: Couldn't read XML property list "
1142 "for multikext archive entry %d.\n", i);
1143 LOG_DELAY();
1144 if (errorString) {
1145 IOLog("XML parse error: %s.\n",
1146 errorString->getCStringNoCopy());
1147 LOG_DELAY();
1148 }
1149 continue;
1150 }
1151
1152 if (!validateExtensionDict(driverPlist, i)) {
1153 // validateExtensionsDict() logs an error
1154 continue;
1155 }
1156
1157 }
1158
1159 /* Get the extension's module name. This is used to record
1160 * the extension.
1161 */
1162 moduleName = OSDynamicCast(OSString,
1163 driverPlist->getObject("CFBundleIdentifier")); // do not release
1164 if (!moduleName) {
1165 IOLog("Error: Multikext archive entry %d has "
1166 "no \"CFBundleIdentifier\" property.\n", i);
1167 LOG_DELAY();
1168 continue; // assume a kext config error & continue
1169 }
1170
1171 /* Check if kmod is already loaded and is a real loadable one (has
1172 * an address).
1173 */
1174 loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy());
1175 if (loaded_kmod && loaded_kmod->address) {
1176 IOLog("Skipping new extension \"%s\"; an extension named "
1177 "\"%s\" is already loaded.\n",
1178 moduleName->getCStringNoCopy(),
1179 loaded_kmod->name);
1180 continue;
1181 }
1182
1183
1184 driverDict = OSDictionary::withCapacity(2);
1185 if (!driverDict) {
1186 IOLog("Error: Couldn't allocate dictionary "
1187 "for multikext archive entry %d.\n", i);
1188 LOG_DELAY();
1189 result = false;
1190 goto finish;
1191 }
1192
1193 driverDict->setObject("plist", driverPlist);
1194
1195 /*****
1196 * Prepare an entry to hold the mkext entry info for the
1197 * compressed binary module, if there is one. If all four fields
1198 * of the module entry are zero, there isn't one.
1199 */
1200 if (!(loaded_kmod && loaded_kmod->address) && (OSSwapBigToHostInt32(module_file->offset) ||
1201 OSSwapBigToHostInt32(module_file->compsize) ||
1202 OSSwapBigToHostInt32(module_file->realsize) ||
1203 OSSwapBigToHostInt32(module_file->modifiedsecs))) {
1204
1205 moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
1206 if (!moduleInfo) {
1207 IOLog("Error: Couldn't allocate data object "
1208 "for multikext archive entry %d.\n", i);
1209 LOG_DELAY();
1210 result = false;
1211 goto finish;
1212 }
1213
1214 module_info.base_address = (vm_address_t)mkext_data;
1215 module_info.fileinfo = module_file;
1216
1217 if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
1218 IOLog("Error: Couldn't record info "
1219 "for multikext archive entry %d.\n", i);
1220 LOG_DELAY();
1221 result = false;
1222 goto finish;
1223 }
1224
1225 driverDict->setObject("compressedCode", moduleInfo);
1226 }
1227
1228 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1229 extensions->getObject(moduleName));
1230
1231 if (!incumbentExt) {
1232 extensions->setObject(moduleName, driverDict);
1233 } else {
1234 OSDictionary * mostRecentExtension =
1235 compareExtensionVersions(incumbentExt, driverDict);
1236
1237 if (mostRecentExtension == incumbentExt) {
1238 /* Do nothing, we've got the most recent. */
1239 } else if (mostRecentExtension == driverDict) {
1240 if (!extensions->setObject(moduleName, driverDict)) {
1241
1242 /* This is a fatal error, so bail.
1243 */
1244 IOLog("extractExtensionsFromArchive(): Failed to add "
1245 "identifier %s\n",
1246 moduleName->getCStringNoCopy());
1247 LOG_DELAY();
1248 result = false;
1249 goto finish;
1250 }
1251 } else /* should be NULL */ {
1252
1253 /* This is a nonfatal error, so continue.
1254 */
1255 IOLog("extractExtensionsFromArchive(): Error comparing "
1256 "versions of duplicate extensions %s.\n",
1257 moduleName->getCStringNoCopy());
1258 LOG_DELAY();
1259 continue;
1260 }
1261 }
1262 }
1263
1264 finish:
1265
1266 if (loaded_kmod) kfree(loaded_kmod, sizeof(kmod_info_t));
1267 if (driverPlistDataObject) {
1268 kmem_free(kernel_map,
1269 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1270 driverPlistDataObject->getLength());
1271 driverPlistDataObject->release();
1272 }
1273 if (driverPlist) driverPlist->release();
1274 if (driverCode) driverCode->release();
1275 if (moduleInfo) moduleInfo->release();
1276 if (driverDict) driverDict->release();
1277 if (errorString) errorString->release();
1278
1279 return result;
1280 }
1281
1282 /*********************************************************************
1283 *
1284 *********************************************************************/
1285 bool readExtensions(OSDictionary * propertyDict,
1286 const char * memory_map_name,
1287 OSDictionary * extensions) {
1288
1289 bool result = true;
1290 OSData * mkextDataObject = 0; // don't release
1291 const MemoryMapFileInfo * mkext_file_info = 0; // don't free
1292
1293 mkextDataObject = OSDynamicCast(OSData,
1294 propertyDict->getObject(memory_map_name));
1295 // don't release mkextDataObject
1296
1297 if (!mkextDataObject) {
1298 IOLog("Error: No mkext data object "
1299 "for device tree entry \"%s\".\n",
1300 memory_map_name);
1301 LOG_DELAY();
1302 result = false;
1303 goto finish;
1304 }
1305
1306 mkext_file_info = (const MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
1307 if (!mkext_file_info) {
1308 result = false;
1309 goto finish;
1310 }
1311
1312 result = extractExtensionsFromArchive(mkext_file_info, false /*physical*/, extensions);
1313
1314 finish:
1315
1316 if (!result && extensions) {
1317 extensions->flushCollection();
1318 }
1319
1320 return result;
1321 }
1322
1323
1324 /*********************************************************************
1325 * Adds the personalities for an extensions dictionary to the global
1326 * IOCatalogue.
1327 *********************************************************************/
1328 bool addPersonalities(OSDictionary * extensions) {
1329 bool result = true;
1330 OSCollectionIterator * keyIterator = NULL; // must release
1331 OSString * key; // don't release
1332 OSDictionary * driverDict = NULL; // don't release
1333 OSDictionary * driverPlist = NULL; // don't release
1334 OSDictionary * thisDriverPersonalities = NULL; // don't release
1335 OSArray * allDriverPersonalities = NULL; // must release
1336
1337 allDriverPersonalities = OSArray::withCapacity(1);
1338 if (!allDriverPersonalities) {
1339 IOLog("Error: Couldn't allocate personality dictionary.\n");
1340 LOG_DELAY();
1341 result = false;
1342 goto finish;
1343 }
1344
1345 /* Record all personalities found so that they can be
1346 * added to the catalogue.
1347 * Note: Not all extensions have personalities.
1348 */
1349
1350 keyIterator = OSCollectionIterator::withCollection(extensions);
1351 if (!keyIterator) {
1352 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1353 LOG_DELAY();
1354 result = false;
1355 goto finish;
1356 }
1357
1358 while ( ( key = OSDynamicCast(OSString,
1359 keyIterator->getNextObject() ))) {
1360
1361 driverDict = OSDynamicCast(OSDictionary,
1362 extensions->getObject(key));
1363 driverPlist = OSDynamicCast(OSDictionary,
1364 driverDict->getObject("plist"));
1365 thisDriverPersonalities = OSDynamicCast(OSDictionary,
1366 driverPlist->getObject("IOKitPersonalities"));
1367
1368 if (thisDriverPersonalities) {
1369 OSCollectionIterator * pIterator;
1370 OSString * locakKey;
1371 pIterator = OSCollectionIterator::withCollection(
1372 thisDriverPersonalities);
1373 if (!pIterator) {
1374 IOLog("Error: Couldn't allocate iterator "
1375 "to record extension personalities.\n");
1376 LOG_DELAY();
1377 continue;
1378 }
1379 while ( (locakKey = OSDynamicCast(OSString,
1380 pIterator->getNextObject())) ) {
1381
1382 OSDictionary * personality = OSDynamicCast(
1383 OSDictionary,
1384 thisDriverPersonalities->getObject(locakKey));
1385 if (personality) {
1386 allDriverPersonalities->setObject(personality);
1387 }
1388 }
1389 pIterator->release();
1390 }
1391 } /* extract personalities */
1392
1393
1394 /* Add all personalities found to the IOCatalogue,
1395 * but don't start matching.
1396 */
1397 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1398
1399 finish:
1400
1401 if (allDriverPersonalities) allDriverPersonalities->release();
1402 if (keyIterator) keyIterator->release();
1403
1404 return result;
1405 }
1406
1407
1408 /*********************************************************************
1409 * Called from IOCatalogue to add extensions from an mkext archive.
1410 * This function makes a copy of the mkext object passed in because
1411 * the device tree support code dumps it after calling us (indirectly
1412 * through the IOCatalogue).
1413 *********************************************************************/
1414 bool addExtensionsFromArchive(OSData * mkextDataObject) {
1415 bool result = true;
1416
1417 OSDictionary * startupExtensions = NULL; // don't release
1418 OSArray * bootLoaderObjects = NULL; // don't release
1419 OSDictionary * extensions = NULL; // must release
1420 MemoryMapFileInfo mkext_file_info;
1421 OSCollectionIterator * keyIterator = NULL; // must release
1422 OSString * key = NULL; // don't release
1423
1424 startupExtensions = getStartupExtensions();
1425 if (!startupExtensions) {
1426 IOLog("Can't record extension archive; there is no"
1427 " extensions dictionary.\n");
1428 LOG_DELAY();
1429 result = false;
1430 goto finish;
1431 }
1432
1433 bootLoaderObjects = getBootLoaderObjects();
1434 if (! bootLoaderObjects) {
1435 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1436 LOG_DELAY();
1437 result = false;
1438 goto finish;
1439 }
1440
1441 extensions = OSDictionary::withCapacity(2);
1442 if (!extensions) {
1443 IOLog("Error: Couldn't allocate dictionary to unpack "
1444 "extension archive.\n");
1445 LOG_DELAY();
1446 result = false;
1447 goto finish;
1448 }
1449
1450 mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
1451 mkext_file_info.length = mkextDataObject->getLength();
1452
1453 /* Save the local mkext data object so that we can deallocate it later.
1454 */
1455 bootLoaderObjects->setObject(mkextDataObject);
1456
1457 result = extractExtensionsFromArchive(&mkext_file_info, true /*virtual*/, extensions);
1458 if (!result) {
1459 IOLog("Error: Failed to extract extensions from archive.\n");
1460 LOG_DELAY();
1461 result = false;
1462 goto finish;
1463 }
1464
1465 result = mergeExtensionDictionaries(startupExtensions, extensions);
1466 if (!result) {
1467 IOLog("Error: Failed to merge new extensions into existing set.\n");
1468 LOG_DELAY();
1469 goto finish;
1470 }
1471
1472 result = addPersonalities(extensions);
1473 if (!result) {
1474 IOLog("Error: Failed to add personalities for extensions extracted "
1475 "from archive.\n");
1476 LOG_DELAY();
1477 result = false;
1478 goto finish;
1479 }
1480
1481 finish:
1482
1483 if (!result) {
1484 IOLog("Error: Failed to record extensions from archive.\n");
1485 LOG_DELAY();
1486 } else {
1487 keyIterator = OSCollectionIterator::withCollection(
1488 extensions);
1489
1490 if (keyIterator) {
1491 while ( (key = OSDynamicCast(OSString,
1492 keyIterator->getNextObject())) ) {
1493
1494 IOLog("Added extension \"%s\" from archive.\n",
1495 key->getCStringNoCopy());
1496 LOG_DELAY();
1497 }
1498 keyIterator->release();
1499 }
1500 }
1501
1502 if (extensions) extensions->release();
1503
1504 return result;
1505 }
1506
1507
1508 /*********************************************************************
1509 * This function builds dictionaries for the startup extensions
1510 * put into memory by bootx, recording each in the startup extensions
1511 * dictionary. The dictionary format is this:
1512 *
1513 * {
1514 * "plist" = (the extension's Info.plist as an OSDictionary)
1515 * "code" = (an OSData containing the executable file)
1516 * }
1517 *
1518 * This function returns true if any extensions were found and
1519 * recorded successfully, or if there are no start extensions,
1520 * and false if an unrecoverable error occurred. An error reading
1521 * a single extension is not considered fatal, and this function
1522 * will simply skip the problematic extension to try the next one.
1523 *********************************************************************/
1524
1525 bool recordStartupExtensions(void) {
1526 bool result = true;
1527 OSDictionary * startupExtensions = NULL; // must release
1528 OSDictionary * existingExtensions = NULL; // don't release
1529 OSDictionary * mkextExtensions = NULL; // must release
1530 IORegistryEntry * bootxMemoryMap = NULL; // must release
1531 OSDictionary * propertyDict = NULL; // must release
1532 OSCollectionIterator * keyIterator = NULL; // must release
1533 OSString * key = NULL; // don't release
1534
1535 OSDictionary * newDriverDict = NULL; // must release
1536 OSDictionary * driverPlist = NULL; // don't release
1537
1538 struct section * infosect;
1539 struct section * symsect;
1540 unsigned int prelinkedCount = 0;
1541
1542 existingExtensions = getStartupExtensions();
1543 if (!existingExtensions) {
1544 IOLog("Error: There is no dictionary for startup extensions.\n");
1545 LOG_DELAY();
1546 result = false;
1547 goto finish;
1548 }
1549
1550 startupExtensions = OSDictionary::withCapacity(1);
1551 if (!startupExtensions) {
1552 IOLog("Error: Couldn't allocate dictionary "
1553 "to record startup extensions.\n");
1554 LOG_DELAY();
1555 result = false;
1556 goto finish;
1557 }
1558
1559 // --
1560 // add any prelinked modules as startup extensions
1561
1562 infosect = getsectbyname("__PRELINK", "__info");
1563 symsect = getsectbyname("__PRELINK", "__symtab");
1564 if (infosect && infosect->addr && infosect->size
1565 && symsect && symsect->addr && symsect->size) do
1566 {
1567 gIOPrelinkedModules = OSDynamicCast(OSArray,
1568 OSUnserializeXML((const char *) infosect->addr, NULL));
1569
1570 if (!gIOPrelinkedModules)
1571 break;
1572 for( unsigned int idx = 0;
1573 (propertyDict = OSDynamicCast(OSDictionary, gIOPrelinkedModules->getObject(idx)));
1574 idx++)
1575 {
1576 enum { kPrelinkReservedCount = 4 };
1577
1578 /* Get the extension's module name. This is used to record
1579 * the extension. Do *not* release the moduleName.
1580 */
1581 OSString * moduleName = OSDynamicCast(OSString,
1582 propertyDict->getObject("CFBundleIdentifier"));
1583 if (!moduleName) {
1584 IOLog("Error: Prelinked module entry has "
1585 "no \"CFBundleIdentifier\" property.\n");
1586 LOG_DELAY();
1587 continue;
1588 }
1589
1590 /* Add the kext, & its plist.
1591 */
1592 newDriverDict = OSDictionary::withCapacity(4);
1593 assert(newDriverDict);
1594 newDriverDict->setObject("plist", propertyDict);
1595 startupExtensions->setObject(moduleName, newDriverDict);
1596 newDriverDict->release();
1597
1598 /* Add the code if present.
1599 */
1600 OSData * data = OSDynamicCast(OSData, propertyDict->getObject("OSBundlePrelink"));
1601 if (data) {
1602 if (data->getLength() < (kPrelinkReservedCount * sizeof(UInt32))) {
1603 IOLog("Error: Prelinked module entry has "
1604 "invalid \"OSBundlePrelink\" property.\n");
1605 LOG_DELAY();
1606 continue;
1607 }
1608 const UInt32 * prelink;
1609 prelink = (const UInt32 *) data->getBytesNoCopy();
1610 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
1611 // end of "file" is end of symbol sect
1612 data = OSData::withBytesNoCopy((void *) kmod_info->address,
1613 symsect->addr + symsect->size - kmod_info->address);
1614 newDriverDict->setObject("code", data);
1615 data->release();
1616 prelinkedCount++;
1617 continue;
1618 }
1619 /* Add the symbols if present.
1620 */
1621 OSNumber * num = OSDynamicCast(OSNumber, propertyDict->getObject("OSBundlePrelinkSymbols"));
1622 if (num) {
1623 UInt32 offset = num->unsigned32BitValue();
1624 data = OSData::withBytesNoCopy((void *) (symsect->addr + offset), symsect->size - offset);
1625 newDriverDict->setObject("code", data);
1626 data->release();
1627 prelinkedCount++;
1628 continue;
1629 }
1630 }
1631 if (gIOPrelinkedModules)
1632 IOLog("%d prelinked modules\n", prelinkedCount);
1633
1634 // free __info
1635 vm_offset_t
1636 virt = ml_static_ptovirt(infosect->addr);
1637 if( virt) {
1638 ml_static_mfree(virt, infosect->size);
1639 }
1640 newDriverDict = NULL;
1641 }
1642 while (false);
1643 // --
1644
1645 bootxMemoryMap =
1646 IORegistryEntry::fromPath(
1647 "/chosen/memory-map", // path
1648 gIODTPlane // plane
1649 );
1650 // return value is retained so be sure to release it
1651
1652 if (!bootxMemoryMap) {
1653 IOLog("Error: Couldn't read booter memory map.\n");
1654 LOG_DELAY();
1655 result = false;
1656 goto finish;
1657 }
1658
1659 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1660 if (!propertyDict) {
1661 IOLog("Error: Couldn't get property dictionary "
1662 "from memory map.\n");
1663 LOG_DELAY();
1664 result = false;
1665 goto finish;
1666 }
1667
1668 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1669 if (!keyIterator) {
1670 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1671 LOG_DELAY();
1672 result = false;
1673 goto finish;
1674 }
1675
1676 while ( (key = OSDynamicCast(OSString,
1677 keyIterator->getNextObject())) ) {
1678 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1679 * handling both successful and unsuccessful iterations.
1680 */
1681 if (newDriverDict) {
1682 newDriverDict->release();
1683 newDriverDict = NULL;
1684 }
1685 if (mkextExtensions) {
1686 mkextExtensions->release();
1687 mkextExtensions = NULL;
1688 }
1689
1690 const char * keyValue = key->getCStringNoCopy();
1691
1692 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1693 strlen(BOOTX_KEXT_PREFIX)) ) {
1694
1695 /* Read the extension from the bootx-supplied memory.
1696 */
1697 newDriverDict = readExtension(propertyDict, keyValue);
1698 if (!newDriverDict) {
1699 IOLog("Error: Couldn't read data "
1700 "for device tree entry \"%s\".\n", keyValue);
1701 LOG_DELAY();
1702 continue;
1703 }
1704
1705
1706 /* Preprare to record the extension by getting its info plist.
1707 */
1708 driverPlist = OSDynamicCast(OSDictionary,
1709 newDriverDict->getObject("plist"));
1710 if (!driverPlist) {
1711 IOLog("Error: Extension in device tree entry \"%s\" "
1712 "has no property list.\n", keyValue);
1713 LOG_DELAY();
1714 continue;
1715 }
1716
1717
1718 /* Get the extension's module name. This is used to record
1719 * the extension. Do *not* release the moduleName.
1720 */
1721 OSString * moduleName = OSDynamicCast(OSString,
1722 driverPlist->getObject("CFBundleIdentifier"));
1723 if (!moduleName) {
1724 IOLog("Error: Device tree entry \"%s\" has "
1725 "no \"CFBundleIdentifier\" property.\n", keyValue);
1726 LOG_DELAY();
1727 continue;
1728 }
1729
1730
1731 /* All has gone well so far, so record the extension under
1732 * its module name, checking for an existing duplicate.
1733 *
1734 * Do not release moduleName, as it's part of the extension's
1735 * plist.
1736 */
1737 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1738 startupExtensions->getObject(moduleName));
1739
1740 if (!incumbentExt) {
1741 startupExtensions->setObject(moduleName, newDriverDict);
1742 } else {
1743 OSDictionary * mostRecentExtension =
1744 compareExtensionVersions(incumbentExt, newDriverDict);
1745
1746 if (mostRecentExtension == incumbentExt) {
1747 /* Do nothing, we've got the most recent. */
1748 } else if (mostRecentExtension == newDriverDict) {
1749 if (!startupExtensions->setObject(moduleName,
1750 newDriverDict)) {
1751
1752 /* This is a fatal error, so bail.
1753 */
1754 IOLog("recordStartupExtensions(): Failed to add "
1755 "identifier %s\n",
1756 moduleName->getCStringNoCopy());
1757 LOG_DELAY();
1758 result = false;
1759 goto finish;
1760 }
1761 } else /* should be NULL */ {
1762
1763 /* This is a nonfatal error, so continue.
1764 */
1765 IOLog("recordStartupExtensions(): Error comparing "
1766 "versions of duplicate extensions %s.\n",
1767 moduleName->getCStringNoCopy());
1768 LOG_DELAY();
1769 continue;
1770 }
1771 }
1772
1773
1774 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1775 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1776
1777 mkextExtensions = OSDictionary::withCapacity(10);
1778 if (!mkextExtensions) {
1779 IOLog("Error: Couldn't allocate dictionary to unpack "
1780 "multi-extension archive.\n");
1781 LOG_DELAY();
1782 result = false;
1783 goto finish; // allocation failure is fatal for this routine
1784 }
1785 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1786 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1787 LOG_DELAY();
1788 continue;
1789 } else {
1790 if (!mergeExtensionDictionaries(startupExtensions,
1791 mkextExtensions)) {
1792
1793 IOLog("Error: Failed to merge new extensions into "
1794 "existing set.\n");
1795 LOG_DELAY();
1796 result = false;
1797 goto finish; // merge error is fatal for this routine
1798 }
1799 }
1800 }
1801
1802 // Do not release key.
1803
1804 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1805
1806 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1807 IOLog("Error: Failed to merge new extensions into existing set.\n");
1808 LOG_DELAY();
1809 result = false;
1810 goto finish;
1811 }
1812
1813 result = addPersonalities(startupExtensions);
1814 if (!result) {
1815 IOLog("Error: Failed to add personalities for extensions extracted "
1816 "from archive.\n");
1817 LOG_DELAY();
1818 result = false;
1819 goto finish;
1820 }
1821
1822 finish:
1823
1824 // reused so clear first!
1825 if (keyIterator) {
1826 keyIterator->release();
1827 keyIterator = 0;
1828 }
1829
1830 if (!result) {
1831 IOLog("Error: Failed to record startup extensions.\n");
1832 LOG_DELAY();
1833 } else {
1834 #if DEBUG
1835 keyIterator = OSCollectionIterator::withCollection(
1836 startupExtensions);
1837
1838 if (keyIterator) {
1839 while ( (key = OSDynamicCast(OSString,
1840 keyIterator->getNextObject())) ) {
1841
1842 IOLog("Found extension \"%s\".\n",
1843 key->getCStringNoCopy());
1844 LOG_DELAY();
1845 }
1846 keyIterator->release();
1847 keyIterator = 0;
1848 }
1849 #endif /* DEBUG */
1850 }
1851
1852 if (newDriverDict) newDriverDict->release();
1853 if (propertyDict) propertyDict->release();
1854 if (bootxMemoryMap) bootxMemoryMap->release();
1855 if (mkextExtensions) mkextExtensions->release();
1856 if (startupExtensions) startupExtensions->release();
1857
1858 return result;
1859 }
1860
1861
1862 /*********************************************************************
1863 * This function removes an entry from the dictionary of startup
1864 * extensions. It's used when an extension can't be loaded, for
1865 * whatever reason. For drivers, this allows another matching driver
1866 * to be loaded, so that, for example, a driver for the root device
1867 * can be found.
1868 *********************************************************************/
1869 void removeStartupExtension(const char * extensionName) {
1870 OSDictionary * startupExtensions = NULL; // don't release
1871 OSDictionary * extensionDict = NULL; // don't release
1872 OSDictionary * extensionPlist = NULL; // don't release
1873 OSDictionary * extensionPersonalities = NULL; // don't release
1874 OSDictionary * personality = NULL; // don't release
1875 OSCollectionIterator * keyIterator = NULL; // must release
1876 OSString * key = NULL; // don't release
1877
1878 startupExtensions = getStartupExtensions();
1879 if (!startupExtensions) goto finish;
1880
1881
1882 /* Find the extension's entry in the dictionary of
1883 * startup extensions.
1884 */
1885 extensionDict = OSDynamicCast(OSDictionary,
1886 startupExtensions->getObject(extensionName));
1887 if (!extensionDict) goto finish;
1888
1889 extensionPlist = OSDynamicCast(OSDictionary,
1890 extensionDict->getObject("plist"));
1891 if (!extensionPlist) goto finish;
1892
1893 extensionPersonalities = OSDynamicCast(OSDictionary,
1894 extensionPlist->getObject("IOKitPersonalities"));
1895 if (!extensionPersonalities) goto finish;
1896
1897 /* If it was there, remove it from the catalogue proper
1898 * by calling removeDrivers(). Pass true for the second
1899 * argument to trigger a new round of matching, and
1900 * then remove the extension from the dictionary of startup
1901 * extensions.
1902 */
1903 keyIterator = OSCollectionIterator::withCollection(
1904 extensionPersonalities);
1905 if (!keyIterator) {
1906 IOLog("Error: Couldn't allocate iterator to scan"
1907 " personalities for %s.\n", extensionName);
1908 LOG_DELAY();
1909 }
1910
1911 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1912 personality = OSDynamicCast(OSDictionary,
1913 extensionPersonalities->getObject(key));
1914
1915
1916 if (personality) {
1917 gIOCatalogue->removeDrivers(personality, true);
1918 }
1919 }
1920
1921 startupExtensions->removeObject(extensionName);
1922
1923 finish:
1924
1925 if (keyIterator) keyIterator->release();
1926 return;
1927 }
1928
1929 /*********************************************************************
1930 * FIXME: This function invalidates the globals gStartupExtensions and
1931 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1932 * FIXME: ...the code itself is immediately unloaded, there may not be
1933 * FIXME: ...any reason to worry about that!
1934 *********************************************************************/
1935 void clearStartupExtensionsAndLoaderInfo(void)
1936 {
1937 OSDictionary * startupExtensions = NULL; // must release
1938 OSArray * bootLoaderObjects = NULL; // must release
1939
1940 IORegistryEntry * bootxMemoryMap = NULL; // must release
1941 OSDictionary * propertyDict = NULL; // must release
1942 OSCollectionIterator * keyIterator = NULL; // must release
1943 OSString * key = NULL; // don't release
1944
1945 /*****
1946 * Drop any temporarily held data objects.
1947 */
1948 bootLoaderObjects = getBootLoaderObjects();
1949 if (bootLoaderObjects) {
1950 bootLoaderObjects->release();
1951 }
1952
1953 /****
1954 * If any "code" entries in driver dictionaries are accompanied
1955 * by "compressedCode" entries, then those data objects were
1956 * created based of of kmem_alloc()'ed memory, which must be
1957 * freed specially.
1958 */
1959 startupExtensions = getStartupExtensions();
1960 if (startupExtensions) {
1961 keyIterator =
1962 OSCollectionIterator::withCollection(startupExtensions);
1963 if (!keyIterator) {
1964 IOLog("Error: Couldn't allocate iterator for startup "
1965 "extensions.\n");
1966 LOG_DELAY();
1967 goto memory_map; // bail to the memory_map label
1968 }
1969
1970 while ( (key = OSDynamicCast(OSString,
1971 keyIterator->getNextObject())) ) {
1972
1973 OSDictionary * driverDict = 0;
1974 OSData * codeData = 0;
1975
1976 driverDict = OSDynamicCast(OSDictionary,
1977 startupExtensions->getObject(key));
1978 if (driverDict) {
1979 codeData = OSDynamicCast(OSData,
1980 driverDict->getObject("code"));
1981
1982 if (codeData &&
1983 driverDict->getObject("compressedCode")) {
1984
1985 kmem_free(kernel_map,
1986 (unsigned int)codeData->getBytesNoCopy(),
1987 codeData->getLength());
1988 }
1989 }
1990 }
1991
1992 keyIterator->release();
1993 startupExtensions->release();
1994 }
1995
1996 memory_map:
1997
1998 /****
1999 * Go through the device tree's memory map and remove any driver
2000 * data entries.
2001 */
2002 bootxMemoryMap =
2003 IORegistryEntry::fromPath(
2004 "/chosen/memory-map", // path
2005 gIODTPlane // plane
2006 );
2007 // return value is retained so be sure to release it
2008
2009 if (!bootxMemoryMap) {
2010 IOLog("Error: Couldn't read booter memory map.\n");
2011 LOG_DELAY();
2012 goto finish;
2013 }
2014
2015 propertyDict = bootxMemoryMap->dictionaryWithProperties();
2016 if (!propertyDict) {
2017 IOLog("Error: Couldn't get property dictionary "
2018 "from memory map.\n");
2019 LOG_DELAY();
2020 goto finish;
2021 }
2022
2023 keyIterator = OSCollectionIterator::withCollection(propertyDict);
2024 if (!keyIterator) {
2025 IOLog("Error: Couldn't allocate iterator for driver images.\n");
2026 LOG_DELAY();
2027 goto finish;
2028 }
2029
2030 while ( (key = OSDynamicCast(OSString,
2031 keyIterator->getNextObject())) ) {
2032
2033 const char * keyValue = key->getCStringNoCopy();
2034
2035 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
2036 strlen(BOOTX_KEXT_PREFIX)) ||
2037 !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
2038 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
2039
2040 OSData * bootxDriverDataObject = NULL;
2041 const MemoryMapFileInfo * driverInfo = 0;
2042
2043 bootxDriverDataObject = OSDynamicCast(OSData,
2044 propertyDict->getObject(keyValue));
2045 // don't release bootxDriverDataObject
2046
2047 if (!bootxDriverDataObject) {
2048 continue;
2049 }
2050 driverInfo = (const MemoryMapFileInfo *)
2051 bootxDriverDataObject->getBytesNoCopy(0,
2052 sizeof(MemoryMapFileInfo));
2053 IODTFreeLoaderInfo((char *)keyValue,
2054 (void *)driverInfo->paddr,
2055 (int)driverInfo->length);
2056 }
2057 }
2058
2059 finish:
2060 if (bootxMemoryMap) bootxMemoryMap->release();
2061 if (propertyDict) propertyDict->release();
2062 if (keyIterator) keyIterator->release();
2063
2064 return;
2065 }