]> git.saurik.com Git - apple/xnu.git/blob - libsa/catalogue.cpp
1528cc634caa1dc14fb0f2c83d46580de6e8a6db
[apple/xnu.git] / libsa / catalogue.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <libkern/c++/OSContainers.h>
23 #include <IOKit/IODeviceTreeSupport.h>
24 #include <IOKit/IORegistryEntry.h>
25 #include <IOKit/IOCatalogue.h>
26 #include <libkern/c++/OSUnserialize.h>
27 #include <libkern/OSByteOrder.h>
28 #include <libsa/catalogue.h>
29
30 extern "C" {
31 #include <machine/machine_routines.h>
32 #include <mach/host_info.h>
33 #include <mach/kmod.h>
34 #include <libsa/mkext.h>
35 #include <libsa/vers_rsrc.h>
36 };
37
38 #include <IOKit/IOLib.h>
39
40 #include <IOKit/assert.h>
41
42
43 extern "C" {
44 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
45 extern kern_return_t host_info(host_t host,
46 host_flavor_t flavor,
47 host_info_t info,
48 mach_msg_type_number_t *count);
49 extern int check_cpu_subtype(cpu_subtype_t cpu_subtype);
50
51 extern IOLock * kld_lock;
52 };
53
54
55 #define LOG_DELAY()
56
57 #define VTYELLOW "\033[33m"
58 #define VTRESET "\033[0m"
59
60
61 /*********************************************************************
62 *********************************************************************/
63 static OSDictionary * gStartupExtensions = 0;
64
65 OSDictionary * getStartupExtensions(void) {
66 if (gStartupExtensions) {
67 return gStartupExtensions;
68 }
69 gStartupExtensions = OSDictionary::withCapacity(1);
70 if (!gStartupExtensions) {
71 IOLog("Error: Couldn't allocate "
72 "startup extensions dictionary.\n");
73 LOG_DELAY();
74 }
75 return gStartupExtensions;
76 }
77
78
79 /*********************************************************************
80 * This function checks that a driver dict has all the required
81 * entries and does a little bit of value checking too.
82 *********************************************************************/
83 bool validateExtensionDict(OSDictionary * extension) {
84
85 bool result = true;
86 OSString * name; // do not release
87 OSString * stringValue; // do not release
88 UInt32 vers;
89
90 name = OSDynamicCast(OSString,
91 extension->getObject("CFBundleIdentifier"));
92 if (!name) {
93 IOLog(VTYELLOW "Extension has no \"CFBundleIdentifier\" property.\n"
94 VTRESET);
95 LOG_DELAY();
96 result = false;
97 goto finish;
98 }
99
100 stringValue = OSDynamicCast(OSString,
101 extension->getObject("CFBundleVersion"));
102 if (!stringValue) {
103 IOLog(VTYELLOW "Extension \"%s\" has no \"CFBundleVersion\" "
104 "property.\n" VTRESET,
105 name->getCStringNoCopy());
106 LOG_DELAY();
107 result = false;
108 goto finish;
109 }
110 if (!VERS_parse_string(stringValue->getCStringNoCopy(),
111 &vers)) {
112 IOLog(VTYELLOW "Extension \"%s\" has an invalid "
113 "\"CFBundleVersion\" property.\n" VTRESET,
114 name->getCStringNoCopy());
115 LOG_DELAY();
116 result = false;
117 goto finish;
118 }
119
120
121 finish:
122 // FIXME: Make return real result after kext conversion
123 return true;
124
125 return result;
126 }
127
128
129 /*********************************************************************
130 *********************************************************************/
131 OSDictionary * compareExtensionVersions(
132 OSDictionary * incumbent,
133 OSDictionary * candidate) {
134
135 OSDictionary * winner = NULL;
136
137 OSDictionary * incumbentPlist = NULL;
138 OSDictionary * candidatePlist = NULL;
139 OSString * incumbentName = NULL;
140 OSString * candidateName = NULL;
141 OSString * incumbentVersionString = NULL;
142 OSString * candidateVersionString = NULL;
143 UInt32 incumbent_vers = 0;
144 UInt32 candidate_vers = 0;
145
146 incumbentPlist = OSDynamicCast(OSDictionary,
147 incumbent->getObject("plist"));
148 candidatePlist = OSDynamicCast(OSDictionary,
149 candidate->getObject("plist"));
150
151 if (!incumbentPlist || !candidatePlist) {
152 IOLog("compareExtensionVersions() called with invalid "
153 "extension dictionaries.\n");
154 LOG_DELAY();
155 winner = NULL;
156 goto finish;
157 }
158
159 incumbentName = OSDynamicCast(OSString,
160 incumbentPlist->getObject("CFBundleIdentifier"));
161 candidateName = OSDynamicCast(OSString,
162 candidatePlist->getObject("CFBundleIdentifier"));
163 incumbentVersionString = OSDynamicCast(OSString,
164 incumbentPlist->getObject("CFBundleVersion"));
165 candidateVersionString = OSDynamicCast(OSString,
166 candidatePlist->getObject("CFBundleVersion"));
167
168 if (!incumbentName || !candidateName ||
169 !incumbentVersionString || !candidateVersionString) {
170
171 IOLog("compareExtensionVersions() called with invalid "
172 "extension dictionaries.\n");
173 LOG_DELAY();
174 winner = NULL;
175 goto finish;
176 }
177
178 if (strcmp(incumbentName->getCStringNoCopy(),
179 candidateName->getCStringNoCopy())) {
180
181 IOLog("compareExtensionVersions() called with different "
182 "extension names (%s and %s).\n",
183 incumbentName->getCStringNoCopy(),
184 candidateName->getCStringNoCopy());
185 LOG_DELAY();
186 winner = NULL;
187 goto finish;
188 }
189
190 if (!VERS_parse_string(incumbentVersionString->getCStringNoCopy(),
191 &incumbent_vers)) {
192
193 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
194 VTRESET,
195 incumbentName->getCStringNoCopy(),
196 incumbentVersionString->getCStringNoCopy());
197 LOG_DELAY();
198 winner = NULL;
199 goto finish;
200 }
201
202 if (!VERS_parse_string(candidateVersionString->getCStringNoCopy(),
203 &candidate_vers)) {
204
205 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
206 VTRESET,
207 candidateName->getCStringNoCopy(),
208 candidateVersionString->getCStringNoCopy());
209 LOG_DELAY();
210 winner = NULL;
211 goto finish;
212 }
213
214 if (candidate_vers > incumbent_vers) {
215 IOLog(VTYELLOW "Replacing extension \"%s\" with newer version "
216 "(%s -> %s).\n" VTRESET,
217 incumbentName->getCStringNoCopy(),
218 incumbentVersionString->getCStringNoCopy(),
219 candidateVersionString->getCStringNoCopy());
220 LOG_DELAY();
221 winner = candidate;
222 goto finish;
223 } else {
224 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with older/same "
225 " version (%s -> %s).\n" VTRESET,
226 candidateName->getCStringNoCopy(),
227 candidateVersionString->getCStringNoCopy(),
228 incumbentVersionString->getCStringNoCopy());
229 LOG_DELAY();
230 winner = incumbent;
231 goto finish;
232 }
233
234 finish:
235
236 // no cleanup, how nice
237 return winner;
238 }
239
240
241 /*********************************************************************
242 * This function merges entries in the mergeFrom dictionary into the
243 * mergeInto dictionary. If it returns false, the two dictionaries are
244 * not altered. If it returns true, then mergeInto may have new
245 * entries; any keys that were already present in mergeInto are
246 * removed from mergeFrom, so that the caller can see what was
247 * actually merged.
248 *********************************************************************/
249 bool mergeExtensionDictionaries(OSDictionary * mergeInto,
250 OSDictionary * mergeFrom) {
251
252 bool result = true;
253 OSDictionary * mergeIntoCopy = NULL; // must release
254 OSDictionary * mergeFromCopy = NULL; // must release
255 OSCollectionIterator * keyIterator = NULL; // must release
256 OSString * key; // don't release
257
258 /* Add 1 to count to guarantee copy can grow (grr).
259 */
260 mergeIntoCopy = OSDictionary::withDictionary(mergeInto,
261 mergeInto->getCount() + 1);
262 if (!mergeIntoCopy) {
263 IOLog("Error: Failed to copy 'into' extensions dictionary "
264 "for merge.\n");
265 LOG_DELAY();
266 result = false;
267 goto finish;
268 }
269
270 /* Add 1 to count to guarantee copy can grow (grr).
271 */
272 mergeFromCopy = OSDictionary::withDictionary(mergeFrom,
273 mergeFrom->getCount() + 1);
274 if (!mergeFromCopy) {
275 IOLog("Error: Failed to copy 'from' extensions dictionary "
276 "for merge.\n");
277 LOG_DELAY();
278 result = false;
279 goto finish;
280 }
281
282 keyIterator = OSCollectionIterator::withCollection(mergeFrom);
283 if (!keyIterator) {
284 IOLog("Error: Failed to allocate iterator for extensions.\n");
285 LOG_DELAY();
286 result = false;
287 goto finish;
288 }
289
290
291 /*****
292 * Loop through "from" dictionary, checking if the identifier already
293 * exists in the "into" dictionary and checking versions if it does.
294 */
295 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
296 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
297 mergeIntoCopy->getObject(key));
298 OSDictionary * candidateExt = OSDynamicCast(OSDictionary,
299 mergeFrom->getObject(key));
300
301 if (!incumbentExt) {
302 if (!mergeIntoCopy->setObject(key, candidateExt)) {
303
304 /* This is a fatal error, so bail.
305 */
306 IOLog("mergeExtensionDictionaries(): Failed to add "
307 "identifier %s\n",
308 key->getCStringNoCopy());
309 LOG_DELAY();
310 result = false;
311 goto finish;
312 }
313 } else {
314 OSDictionary * mostRecentExtension =
315 compareExtensionVersions(incumbentExt, candidateExt);
316
317 if (mostRecentExtension == incumbentExt) {
318 mergeFromCopy->removeObject(key);
319 } else if (mostRecentExtension == candidateExt) {
320
321 if (!mergeIntoCopy->setObject(key, candidateExt)) {
322
323 /* This is a fatal error, so bail.
324 */
325 IOLog("mergeExtensionDictionaries(): Failed to add "
326 "identifier %s\n",
327 key->getCStringNoCopy());
328 LOG_DELAY();
329 result = false;
330 goto finish;
331 }
332 } else /* should be NULL */ {
333
334 /* This is a nonfatal error, so continue doing others.
335 */
336 IOLog("mergeExtensionDictionaries(): Error comparing "
337 "versions of duplicate extensions %s.\n",
338 key->getCStringNoCopy());
339 LOG_DELAY();
340 continue;
341 }
342 }
343 }
344
345 finish:
346
347 /* If successful, replace the contents of the original
348 * dictionaries with those of the modified copies.
349 */
350 if (result) {
351 mergeInto->flushCollection();
352 mergeInto->merge(mergeIntoCopy);
353 mergeFrom->flushCollection();
354 mergeFrom->merge(mergeFromCopy);
355 }
356
357 if (mergeIntoCopy) mergeIntoCopy->release();
358 if (mergeFromCopy) mergeFromCopy->release();
359 if (keyIterator) keyIterator->release();
360
361 return result;
362 }
363
364
365 /****
366 * These bits are used to parse data made available by bootx.
367 */
368 #define BOOTX_KEXT_PREFIX "Driver-"
369 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
370
371 typedef struct MemoryMapFileInfo {
372 UInt32 paddr;
373 UInt32 length;
374 } MemoryMapFileInfo;
375
376 typedef struct BootxDriverInfo {
377 char *plistAddr;
378 long plistLength;
379 void *moduleAddr;
380 long moduleLength;
381 } BootxDriverInfo;
382
383
384 /*********************************************************************
385 * This private function reads the data for a single extension from
386 * the bootx memory-map's propery dict, returning a dictionary with
387 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
388 * and "code" for the extension's executable code as an OSData.
389 *********************************************************************/
390 OSDictionary * readExtension(OSDictionary * propertyDict,
391 const char * memory_map_name) {
392
393 int error = 0;
394 OSData * bootxDriverDataObject = NULL;
395 OSDictionary * driverPlist = NULL;
396 OSString * driverName = NULL;
397 OSData * driverCode = NULL;
398 OSString * errorString = NULL;
399 OSDictionary * driverDict = NULL;
400
401 MemoryMapFileInfo * driverInfo = 0;
402 BootxDriverInfo * dataBuffer;
403
404 kmod_info_t * loaded_kmod = NULL;
405
406
407 bootxDriverDataObject = OSDynamicCast(OSData,
408 propertyDict->getObject(memory_map_name));
409 // don't release bootxDriverDataObject
410
411 if (!bootxDriverDataObject) {
412 IOLog("Error: No driver data object "
413 "for device tree entry \"%s\".\n",
414 memory_map_name);
415 LOG_DELAY();
416 error = 1;
417 goto finish;
418 }
419
420 driverDict = OSDictionary::withCapacity(2);
421 if (!driverDict) {
422 IOLog("Error: Couldn't allocate dictionary "
423 "for device tree entry \"%s\".\n", memory_map_name);
424 LOG_DELAY();
425 error = 1;
426 goto finish;
427 }
428
429 driverInfo = (MemoryMapFileInfo *)
430 bootxDriverDataObject->getBytesNoCopy(0,
431 sizeof(MemoryMapFileInfo));
432 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(
433 driverInfo->paddr);
434 if (!dataBuffer) {
435 IOLog("Error: No data buffer "
436 "for device tree entry \"%s\".\n", memory_map_name);
437 LOG_DELAY();
438 error = 1;
439 goto finish;
440 }
441
442 driverPlist = OSDynamicCast(OSDictionary,
443 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
444 if (!driverPlist) {
445 IOLog("Error: Couldn't read XML property list "
446 "for device tree entry \"%s\".\n", memory_map_name);
447 LOG_DELAY();
448 if (errorString) {
449 IOLog("XML parse error: %s.\n",
450 errorString->getCStringNoCopy());
451 LOG_DELAY();
452 }
453 error = 1;
454 goto finish;
455 }
456
457
458 driverName = OSDynamicCast(OSString,
459 driverPlist->getObject("CFBundleIdentifier")); // do not release
460 if (!driverName) {
461 IOLog("Error: Device tree entry \"%s\" has "
462 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
463 LOG_DELAY();
464 error = 1;
465 goto finish;
466 }
467
468 /* Check if kmod is already loaded and is a real loadable one (has
469 * an address).
470 */
471 loaded_kmod = kmod_lookupbyname(driverName->getCStringNoCopy());
472 if (loaded_kmod && loaded_kmod->address) {
473 IOLog("Skipping new extension \"%s\"; an extension named "
474 "\"%s\" is already loaded.\n",
475 driverName->getCStringNoCopy(),
476 loaded_kmod->name);
477 LOG_DELAY();
478 error = 1;
479 goto finish;
480 }
481
482 if (!validateExtensionDict(driverPlist)) {
483 IOLog("Error: Failed to validate property list "
484 "for device tree entry \"%s\".\n", memory_map_name);
485 LOG_DELAY();
486 error = 1;
487 goto finish;
488 }
489
490 driverDict->setObject("plist", driverPlist);
491
492 /* It's perfectly okay for a KEXT to have no executable.
493 * Check that moduleAddr is nonzero before attempting to
494 * get one.
495 */
496 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
497 driverCode = OSData::withBytes(dataBuffer->moduleAddr,
498 dataBuffer->moduleLength);
499 if (!driverCode) {
500 IOLog("Error: Couldn't allocate data object "
501 "to hold code for device tree entry \"%s\".\n",
502 memory_map_name);
503 LOG_DELAY();
504 error = 1;
505 goto finish;
506 }
507
508 if (driverCode) {
509 driverDict->setObject("code", driverCode);
510 }
511 }
512
513 finish:
514
515 /* Free the memory for this extension that was set up
516 * by bootx.
517 */
518 IODTFreeLoaderInfo(memory_map_name, (void *)driverInfo->paddr,
519 (int)driverInfo->length);
520
521 // do not release bootxDriverDataObject
522 // do not release driverName
523
524 if (driverPlist) {
525 driverPlist->release();
526 }
527 if (errorString) {
528 errorString->release();
529 }
530 if (driverCode) {
531 driverCode->release();
532 }
533 if (error) {
534 if (driverDict) {
535 driverDict->release();
536 driverDict = NULL;
537 }
538 }
539 return driverDict;
540 }
541
542
543 /*********************************************************************
544 * Used to uncompress a single file entry in an mkext archive.
545 *********************************************************************/
546 int uncompressFile(u_int8_t * base_address,
547 mkext_file * fileinfo,
548 /* out */ OSData ** file) {
549
550 int result = 1;
551 u_int8_t * uncompressed_file = 0; // don't free; owned by OSData obj
552 OSData * uncompressedFile = 0; // don't release
553 size_t uncompressed_size = 0;
554
555 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
556 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
557 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
558 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
559
560 *file = 0;
561
562 /* If these four fields are zero there's no file, but that isn't
563 * an error.
564 */
565 if (offset == 0 && compsize == 0 &&
566 realsize == 0 && modifiedsecs == 0) {
567 goto finish;
568 }
569
570 // Add 1 for '\0' to terminate XML string!
571 uncompressed_file = (u_int8_t *)kalloc(realsize + 1);
572 if (!uncompressed_file) {
573 IOLog("Error: Couldn't allocate data buffer "
574 "to uncompress file.\n");
575 LOG_DELAY();
576 result = 0;
577 goto finish;
578 }
579
580 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
581 realsize + 1);
582 if (!uncompressedFile) {
583 IOLog("Error: Couldn't allocate data object "
584 "to uncompress file.\n");
585 LOG_DELAY();
586 result = 0;
587 goto finish;
588 }
589
590 if (compsize != 0) {
591 uncompressed_size = decompress_lzss(uncompressed_file,
592 base_address + offset,
593 compsize);
594 if (uncompressed_size != realsize) {
595 IOLog("Error: Uncompressed file is not the length "
596 "recorded.\n");
597 LOG_DELAY();
598 result = 0;
599 goto finish;
600 }
601 } else {
602 bcopy(base_address + offset, uncompressed_file,
603 compsize);
604 }
605 uncompressed_file[uncompressed_size] = '\0';
606
607 *file = uncompressedFile;
608
609 finish:
610 if (!result) {
611 if (uncompressedFile) {
612 uncompressedFile->release();
613 *file = 0;
614 }
615 }
616 return result;
617 }
618
619
620 /*********************************************************************
621 * Does the work of pulling extensions out of an mkext archive located
622 * in memory.
623 *********************************************************************/
624 bool extractExtensionsFromArchive(MemoryMapFileInfo * mkext_file_info,
625 OSDictionary * extensions) {
626
627 bool result = true;
628
629 u_int8_t * crc_address = 0;
630 u_int32_t checksum;
631 mkext_header * mkext_data = 0; // don't free
632 mkext_kext * onekext_data = 0; // don't free
633 mkext_file * plist_file = 0; // don't free
634 mkext_file * module_file = 0; // don't free
635 OSData * driverPlistDataObject = 0; // must release
636 OSDictionary * driverPlist = 0; // must release
637 OSData * driverCode = 0; // must release
638 OSDictionary * driverDict = 0; // must release
639 OSString * moduleName = 0; // don't release
640 OSString * errorString = NULL; // must release
641
642 mkext_data = (mkext_header *)mkext_file_info->paddr;
643
644 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
645 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
646 IOLog("Error: Extension archive has invalid magic or signature.\n");
647 LOG_DELAY();
648 result = false;
649 goto finish;
650 }
651
652 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
653 IOLog("Error: Mismatch between extension archive & "
654 "recorded length.\n");
655 LOG_DELAY();
656 result = false;
657 goto finish;
658 }
659
660 crc_address = (u_int8_t *)&mkext_data->version;
661 checksum = adler32(crc_address,
662 (unsigned int)mkext_data +
663 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
664
665 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
666 IOLog("Error: Extension archive has a bad checksum.\n");
667 LOG_DELAY();
668 result = false;
669 goto finish;
670 }
671
672 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
673 * match that of the running kernel.
674 */
675 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
676 kern_return_t kresult = KERN_FAILURE;
677 host_basic_info_data_t hostinfo;
678 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
679 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
680
681 kresult = host_info((host_t)1, HOST_BASIC_INFO,
682 hostinfo_ptr, &count);
683 if (kresult != KERN_SUCCESS) {
684 IOLog("Error: Couldn't get current host info.\n");
685 LOG_DELAY();
686 result = false;
687 goto finish;
688 }
689 if ((UInt32)hostinfo.cpu_type !=
690 OSSwapBigToHostInt32(mkext_data->cputype)) {
691
692 IOLog("Error: Extension archive doesn't contain software "
693 "for this computer's CPU type.\n");
694 LOG_DELAY();
695 result = false;
696 goto finish;
697 }
698 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
699 IOLog("Error: Extension archive doesn't contain software "
700 "for this computer's CPU subtype.\n");
701 LOG_DELAY();
702 result = false;
703 goto finish;
704 }
705 }
706
707 for (unsigned int i = 0;
708 i < OSSwapBigToHostInt32(mkext_data->numkexts);
709 i++) {
710
711 kmod_info_t * loaded_kmod = 0;
712
713 if (driverPlistDataObject) {
714 driverPlistDataObject->release();
715 driverPlistDataObject = NULL;
716 }
717 if (driverPlist) {
718 driverPlist->release();
719 driverPlist = NULL;
720 }
721 if (driverCode) {
722 driverCode->release();
723 driverCode = NULL;
724 }
725 if (driverDict) {
726 driverDict->release();
727 driverDict = NULL;
728 }
729 if (errorString) {
730 errorString->release();
731 errorString = NULL;
732 }
733
734 onekext_data = &mkext_data->kext[i];
735 plist_file = &onekext_data->plist;
736 module_file = &onekext_data->module;
737
738 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
739 &driverPlistDataObject)) {
740
741 IOLog("Error: couldn't uncompress plist file "
742 "%d from multikext archive.\n", i);
743 LOG_DELAY();
744 result = false;
745 goto finish; // or just continue?
746 }
747
748 if (!driverPlistDataObject) {
749 IOLog("Error: No property list present "
750 "for multikext archive entry %d.\n", i);
751 LOG_DELAY();
752 result = false;
753 goto finish; // or just continue?
754 } else {
755 driverPlist = OSDynamicCast(OSDictionary,
756 OSUnserializeXML(
757 (char *)driverPlistDataObject->getBytesNoCopy(),
758 &errorString));
759 if (!driverPlist) {
760 IOLog("Error: Couldn't read XML property list "
761 "for multikext archive entry %d.\n", i);
762 LOG_DELAY();
763 if (errorString) {
764 IOLog("XML parse error: %s.\n",
765 errorString->getCStringNoCopy());
766 LOG_DELAY();
767 }
768 result = false;
769 goto finish; // or just continue?
770 }
771
772 if (!validateExtensionDict(driverPlist)) {
773 IOLog("Error: Failed to validate property list "
774 "for multikext archive entry %d.\n", i);
775 LOG_DELAY();
776 result = false;
777 goto finish;
778 }
779
780 }
781
782 /* Get the extension's module name. This is used to record
783 * the extension.
784 */
785 moduleName = OSDynamicCast(OSString,
786 driverPlist->getObject("CFBundleIdentifier")); // do not release
787 if (!moduleName) {
788 IOLog("Error: Multikext archive entry %d has "
789 "no \"CFBundleIdentifier\" property.\n", i);
790 LOG_DELAY();
791 continue; // assume a kext config error & continue
792 }
793
794 /* Check if kmod is already loaded and is a real loadable one (has
795 * an address).
796 */
797 loaded_kmod = kmod_lookupbyname(moduleName->getCStringNoCopy());
798 if (loaded_kmod && loaded_kmod->address) {
799 IOLog("Skipping new extension \"%s\"; an extension named "
800 "\"%s\" is already loaded.\n",
801 moduleName->getCStringNoCopy(),
802 loaded_kmod->name);
803 continue;
804 }
805
806
807 driverDict = OSDictionary::withCapacity(2);
808 if (!driverDict) {
809 IOLog("Error: Couldn't allocate dictionary "
810 "for multikext archive entry %d.\n", i);
811 LOG_DELAY();
812 result = false;
813 goto finish;
814 }
815
816 driverDict->setObject("plist", driverPlist);
817
818 if (!uncompressFile((u_int8_t *)mkext_data, module_file,
819 &driverCode)) {
820
821 IOLog("Error: couldn't uncompress module file "
822 "%d from multikext archive.\n", i);
823 LOG_DELAY();
824 result = false;
825 goto finish; // or just continue?
826 }
827
828 /* It's okay for there to be no module
829 */
830 if (driverCode) {
831 driverDict->setObject("code", driverCode);
832 }
833
834 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
835 extensions->getObject(moduleName));
836
837 if (!incumbentExt) {
838 extensions->setObject(moduleName, driverDict);
839 } else {
840 OSDictionary * mostRecentExtension =
841 compareExtensionVersions(incumbentExt, driverDict);
842
843 if (mostRecentExtension == incumbentExt) {
844 /* Do nothing, we've got the most recent. */
845 } else if (mostRecentExtension == driverDict) {
846 if (!extensions->setObject(moduleName, driverDict)) {
847
848 /* This is a fatal error, so bail.
849 */
850 IOLog("extractExtensionsFromArchive(): Failed to add "
851 "identifier %s\n",
852 moduleName->getCStringNoCopy());
853 LOG_DELAY();
854 result = false;
855 goto finish;
856 }
857 } else /* should be NULL */ {
858
859 /* This is a nonfatal error, so continue.
860 */
861 IOLog("extractExtensionsFromArchive(): Error comparing "
862 "versions of duplicate extensions %s.\n",
863 moduleName->getCStringNoCopy());
864 LOG_DELAY();
865 continue;
866 }
867 }
868 }
869
870 finish:
871
872 if (driverPlistDataObject) driverPlistDataObject->release();
873 if (driverPlist) driverPlist->release();
874 if (driverCode) driverCode->release();
875 if (driverDict) driverDict->release();
876 if (errorString) errorString->release();
877
878 return result;
879 }
880
881
882 /*********************************************************************
883 * Unlike with single KEXTs, a failure to read any member of a
884 * multi-KEXT archive is considered a failure for all. We want to
885 * take no chances unpacking a single, compressed archive of drivers.
886 *********************************************************************/
887 bool readExtensions(OSDictionary * propertyDict,
888 const char * memory_map_name,
889 OSDictionary * extensions) {
890
891 bool result = true;
892 OSData * mkextDataObject = 0; // don't release
893 MemoryMapFileInfo * mkext_file_info = 0; // don't free
894
895 mkextDataObject = OSDynamicCast(OSData,
896 propertyDict->getObject(memory_map_name));
897 // don't release mkextDataObject
898
899 if (!mkextDataObject) {
900 IOLog("Error: No mkext data object "
901 "for device tree entry \"%s\".\n",
902 memory_map_name);
903 LOG_DELAY();
904 result = false;
905 goto finish;
906 }
907
908 mkext_file_info = (MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
909 if (!mkext_file_info) {
910 result = false;
911 goto finish;
912 }
913
914 result = extractExtensionsFromArchive(mkext_file_info, extensions);
915
916 finish:
917
918 if (!result && extensions) {
919 extensions->flushCollection();
920 }
921
922 IODTFreeLoaderInfo(memory_map_name, (void *)mkext_file_info->paddr,
923 (int)mkext_file_info->length);
924
925 return result;
926 }
927
928
929 /*********************************************************************
930 * Adds the personalities for an extensions dictionary to the global
931 * IOCatalogue.
932 *********************************************************************/
933 bool addPersonalities(OSDictionary * extensions) {
934 bool result = true;
935 OSCollectionIterator * keyIterator = NULL; // must release
936 OSString * key; // don't release
937 OSDictionary * driverDict = NULL; // don't release
938 OSDictionary * driverPlist = NULL; // don't release
939 OSDictionary * thisDriverPersonalities = NULL; // don't release
940 OSArray * allDriverPersonalities = NULL; // must release
941
942 allDriverPersonalities = OSArray::withCapacity(1);
943 if (!allDriverPersonalities) {
944 IOLog("Error: Couldn't allocate personality dictionary.\n");
945 LOG_DELAY();
946 result = false;
947 goto finish;
948 }
949
950 /* Record all personalities found so that they can be
951 * added to the catalogue.
952 * Note: Not all extensions have personalities.
953 */
954
955 keyIterator = OSCollectionIterator::withCollection(extensions);
956 if (!keyIterator) {
957 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
958 LOG_DELAY();
959 result = false;
960 goto finish;
961 }
962
963 while ( ( key = OSDynamicCast(OSString,
964 keyIterator->getNextObject() ))) {
965
966 driverDict = OSDynamicCast(OSDictionary,
967 extensions->getObject(key));
968 driverPlist = OSDynamicCast(OSDictionary,
969 driverDict->getObject("plist"));
970 thisDriverPersonalities = OSDynamicCast(OSDictionary,
971 driverPlist->getObject("IOKitPersonalities"));
972
973 if (thisDriverPersonalities) {
974 OSCollectionIterator * pIterator;
975 OSString * key;
976 pIterator = OSCollectionIterator::withCollection(
977 thisDriverPersonalities);
978 if (!pIterator) {
979 IOLog("Error: Couldn't allocate iterator "
980 "to record extension personalities.\n");
981 LOG_DELAY();
982 continue;
983 }
984 while ( (key = OSDynamicCast(OSString,
985 pIterator->getNextObject())) ) {
986
987 OSDictionary * personality = OSDynamicCast(
988 OSDictionary,
989 thisDriverPersonalities->getObject(key));
990 if (personality) {
991 allDriverPersonalities->setObject(personality);
992 }
993 }
994 pIterator->release();
995 }
996 } /* extract personalities */
997
998
999 /* Add all personalities found to the IOCatalogue,
1000 * but don't start matching.
1001 */
1002 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1003
1004 finish:
1005
1006 if (allDriverPersonalities) allDriverPersonalities->release();
1007 if (keyIterator) keyIterator->release();
1008
1009 return result;
1010 }
1011
1012
1013 /*********************************************************************
1014 * Called from IOCatalogue to add extensions from an mkext archive.
1015 *********************************************************************/
1016 bool addExtensionsFromArchive(OSData * mkextDataObject) {
1017 bool result = true;
1018
1019 OSDictionary * startupExtensions = NULL; // don't release
1020 OSDictionary * extensions = NULL; // must release
1021 MemoryMapFileInfo mkext_file_info;
1022 OSCollectionIterator * keyIterator = NULL; // must release
1023 OSString * key = NULL; // don't release
1024
1025 IOLockLock(kld_lock);
1026
1027 startupExtensions = getStartupExtensions();
1028 if (!startupExtensions) {
1029 IOLog("Can't record extension archive; there is no
1030 extensions dictionary.\n");
1031 LOG_DELAY();
1032 result = false;
1033 goto finish;
1034 }
1035
1036 extensions = OSDictionary::withCapacity(2);
1037 if (!extensions) {
1038 IOLog("Error: Couldn't allocate dictionary to unpack "
1039 "extension archive.\n");
1040 LOG_DELAY();
1041 result = false;
1042 goto finish;
1043 }
1044
1045 mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
1046 mkext_file_info.length = mkextDataObject->getLength();
1047
1048 result = extractExtensionsFromArchive(&mkext_file_info, extensions);
1049 if (!result) {
1050 IOLog("Error: Failed to extract extensions from archive.\n");
1051 LOG_DELAY();
1052 result = false;
1053 goto finish;
1054 }
1055
1056 result = mergeExtensionDictionaries(startupExtensions, extensions);
1057 if (!result) {
1058 IOLog("Error: Failed to merge new extensions into existing set.\n");
1059 LOG_DELAY();
1060 goto finish;
1061 }
1062
1063 result = addPersonalities(extensions);
1064 if (!result) {
1065 IOLog("Error: Failed to add personalities for extensions extracted "
1066 "from archive.\n");
1067 LOG_DELAY();
1068 result = false;
1069 goto finish;
1070 }
1071
1072 finish:
1073
1074 if (!result) {
1075 IOLog("Error: Failed to record extensions from archive.\n");
1076 LOG_DELAY();
1077 } else {
1078 keyIterator = OSCollectionIterator::withCollection(
1079 extensions);
1080
1081 if (keyIterator) {
1082 while ( (key = OSDynamicCast(OSString,
1083 keyIterator->getNextObject())) ) {
1084
1085 IOLog("Added extension \"%s\" from archive.\n",
1086 key->getCStringNoCopy());
1087 LOG_DELAY();
1088 }
1089 keyIterator->release();
1090 }
1091 }
1092
1093 if (extensions) extensions->release();
1094
1095 IOLockUnlock(kld_lock);
1096
1097 return result;
1098 }
1099
1100
1101 /*********************************************************************
1102 * This function builds dictionaries for the startup extensions
1103 * put into memory by bootx, recording each in the startup extensions
1104 * dictionary. The dictionary format is this:
1105 *
1106 * {
1107 * "plist" = (the extension's Info.plist as an OSDictionary)
1108 * "code" = (an OSData containing the executable file)
1109 * }
1110 *
1111 * This function returns true if any extensions were found and
1112 * recorded successfully, or if there are no start extensions,
1113 * and false if an unrecoverable error occurred. An error reading
1114 * a single extension is not considered fatal, and this function
1115 * will simply skip the problematic extension to try the next one.
1116 *********************************************************************/
1117 bool recordStartupExtensions(void) {
1118 bool result = true;
1119 OSDictionary * startupExtensions = NULL; // must release
1120 OSDictionary * existingExtensions = NULL; // don't release
1121 OSDictionary * mkextExtensions = NULL; // must release
1122 IORegistryEntry * bootxMemoryMap = NULL; // must release
1123 OSDictionary * propertyDict = NULL; // must release
1124 OSCollectionIterator * keyIterator = NULL; // must release
1125 OSString * key = NULL; // don't release
1126
1127 OSDictionary * newDriverDict = NULL; // must release
1128 OSDictionary * driverPlist = NULL; // don't release
1129
1130 IOLockLock(kld_lock);
1131
1132 IOLog("Recording startup extensions.\n");
1133 LOG_DELAY();
1134
1135 existingExtensions = getStartupExtensions();
1136 if (!existingExtensions) {
1137 IOLog("Error: There is no dictionary for startup extensions.\n");
1138 LOG_DELAY();
1139 result = false;
1140 goto finish;
1141 }
1142
1143 startupExtensions = OSDictionary::withCapacity(1);
1144 if (!startupExtensions) {
1145 IOLog("Error: Couldn't allocate dictionary "
1146 "to record startup extensions.\n");
1147 LOG_DELAY();
1148 result = false;
1149 goto finish;
1150 }
1151
1152 bootxMemoryMap =
1153 IORegistryEntry::fromPath(
1154 "/chosen/memory-map", // path
1155 gIODTPlane // plane
1156 );
1157 // return value is retained so be sure to release it
1158
1159 if (!bootxMemoryMap) {
1160 IOLog("Error: Couldn't read booter memory map.\n");
1161 LOG_DELAY();
1162 result = false;
1163 goto finish;
1164 }
1165
1166 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1167 if (!propertyDict) {
1168 IOLog("Error: Couldn't get property dictionary "
1169 "from memory map.\n");
1170 LOG_DELAY();
1171 result = false;
1172 goto finish;
1173 }
1174
1175 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1176 if (!keyIterator) {
1177 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1178 LOG_DELAY();
1179 result = false;
1180 goto finish;
1181 }
1182
1183 while ( (key = OSDynamicCast(OSString,
1184 keyIterator->getNextObject())) ) {
1185
1186 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1187 * handling both successful and unsuccessful iterations.
1188 */
1189 if (newDriverDict) {
1190 newDriverDict->release();
1191 newDriverDict = NULL;
1192 }
1193 if (mkextExtensions) {
1194 mkextExtensions->release();
1195 mkextExtensions = NULL;
1196 }
1197
1198 const char * keyValue = key->getCStringNoCopy();
1199
1200 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1201 strlen(BOOTX_KEXT_PREFIX)) ) {
1202
1203 /* Read the extension from the bootx-supplied memory.
1204 */
1205 newDriverDict = readExtension(propertyDict, keyValue);
1206 if (!newDriverDict) {
1207 IOLog("Error: Couldn't read data "
1208 "for device tree entry \"%s\".\n", keyValue);
1209 LOG_DELAY();
1210 continue;
1211 }
1212
1213
1214 /* Preprare to record the extension by getting its info plist.
1215 */
1216 driverPlist = OSDynamicCast(OSDictionary,
1217 newDriverDict->getObject("plist"));
1218 if (!driverPlist) {
1219 IOLog("Error: Extension in device tree entry \"%s\" "
1220 "has no property list.\n", keyValue);
1221 LOG_DELAY();
1222 continue;
1223 }
1224
1225
1226 /* Get the extension's module name. This is used to record
1227 * the extension. Do *not* release the moduleName.
1228 */
1229 OSString * moduleName = OSDynamicCast(OSString,
1230 driverPlist->getObject("CFBundleIdentifier"));
1231 if (!moduleName) {
1232 IOLog("Error: Device tree entry \"%s\" has "
1233 "no \"CFBundleIdentifier\" property.\n", keyValue);
1234 LOG_DELAY();
1235 continue;
1236 }
1237
1238
1239 /* All has gone well so far, so record the extension under
1240 * its module name, checking for an existing duplicate.
1241 *
1242 * Do not release moduleName, as it's part of the extension's
1243 * plist.
1244 */
1245 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1246 startupExtensions->getObject(moduleName));
1247
1248 if (!incumbentExt) {
1249 startupExtensions->setObject(moduleName, newDriverDict);
1250 } else {
1251 OSDictionary * mostRecentExtension =
1252 compareExtensionVersions(incumbentExt, newDriverDict);
1253
1254 if (mostRecentExtension == incumbentExt) {
1255 /* Do nothing, we've got the most recent. */
1256 } else if (mostRecentExtension == newDriverDict) {
1257 if (!startupExtensions->setObject(moduleName,
1258 newDriverDict)) {
1259
1260 /* This is a fatal error, so bail.
1261 */
1262 IOLog("recordStartupExtensions(): Failed to add "
1263 "identifier %s\n",
1264 moduleName->getCStringNoCopy());
1265 LOG_DELAY();
1266 result = false;
1267 goto finish;
1268 }
1269 } else /* should be NULL */ {
1270
1271 /* This is a nonfatal error, so continue.
1272 */
1273 IOLog("recordStartupExtensions(): Error comparing "
1274 "versions of duplicate extensions %s.\n",
1275 moduleName->getCStringNoCopy());
1276 LOG_DELAY();
1277 continue;
1278 }
1279 }
1280
1281
1282 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1283 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1284
1285 mkextExtensions = OSDictionary::withCapacity(10);
1286 if (!mkextExtensions) {
1287 IOLog("Error: Couldn't allocate dictionary to unpack "
1288 "multi-extension archive.\n");
1289 LOG_DELAY();
1290 result = false;
1291 goto finish; // allocation failure is fatal for this routine
1292 }
1293 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1294 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1295 LOG_DELAY();
1296 continue;
1297 } else {
1298 if (!mergeExtensionDictionaries(startupExtensions,
1299 mkextExtensions)) {
1300
1301 IOLog("Error: Failed to merge new extensions into "
1302 "existing set.\n");
1303 LOG_DELAY();
1304 result = false;
1305 goto finish; // merge error is fatal for this routine
1306 }
1307 }
1308 }
1309
1310 // Do not release key.
1311
1312 } /* while ( (key = OSDynamicCast(OSString, ... */
1313
1314 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1315 IOLog("Error: Failed to merge new extensions into existing set.\n");
1316 LOG_DELAY();
1317 result = false;
1318 goto finish;
1319 }
1320
1321 result = addPersonalities(startupExtensions);
1322 if (!result) {
1323 IOLog("Error: Failed to add personalities for extensions extracted "
1324 "from archive.\n");
1325 LOG_DELAY();
1326 result = false;
1327 goto finish;
1328 }
1329
1330 finish:
1331
1332 // reused so clear first!
1333 if (keyIterator) {
1334 keyIterator->release();
1335 keyIterator = 0;
1336 }
1337
1338 if (!result) {
1339 IOLog("Error: Failed to record startup extensions.\n");
1340 LOG_DELAY();
1341 } else {
1342 keyIterator = OSCollectionIterator::withCollection(
1343 startupExtensions);
1344
1345 if (keyIterator) {
1346 while ( (key = OSDynamicCast(OSString,
1347 keyIterator->getNextObject())) ) {
1348
1349 IOLog("Found extension \"%s\".\n",
1350 key->getCStringNoCopy());
1351 LOG_DELAY();
1352 }
1353 keyIterator->release();
1354 keyIterator = 0;
1355 }
1356 }
1357
1358 if (newDriverDict) newDriverDict->release();
1359 if (propertyDict) propertyDict->release();
1360 if (bootxMemoryMap) bootxMemoryMap->release();
1361 if (mkextExtensions) mkextExtensions->release();
1362 if (startupExtensions) startupExtensions->release();
1363
1364 IOLockUnlock(kld_lock);
1365 return result;
1366 }
1367
1368
1369 /*********************************************************************
1370 * This function removes an entry from the dictionary of startup
1371 * extensions. It's used when an extension can't be loaded, for
1372 * whatever reason. For drivers, this allows another matching driver
1373 * to be loaded, so that, for example, a driver for the root device
1374 * can be found.
1375 *********************************************************************/
1376 void removeStartupExtension(const char * extensionName) {
1377 OSDictionary * startupExtensions = NULL; // don't release
1378 OSDictionary * extensionDict = NULL; // don't release
1379 OSDictionary * extensionPlist = NULL; // don't release
1380 OSDictionary * extensionPersonalities = NULL; // don't release
1381 OSDictionary * personality = NULL; // don't release
1382 OSCollectionIterator * keyIterator = NULL; // must release
1383 OSString * key = NULL; // don't release
1384
1385 IOLockLock(kld_lock);
1386
1387 startupExtensions = getStartupExtensions();
1388 if (!startupExtensions) goto finish;
1389
1390
1391 /* Find the extension's entry in the dictionary of
1392 * startup extensions.
1393 */
1394 extensionDict = OSDynamicCast(OSDictionary,
1395 startupExtensions->getObject(extensionName));
1396 if (!extensionDict) goto finish;
1397
1398 extensionPlist = OSDynamicCast(OSDictionary,
1399 extensionDict->getObject("plist"));
1400 if (!extensionPlist) goto finish;
1401
1402 extensionPersonalities = OSDynamicCast(OSDictionary,
1403 extensionPlist->getObject("IOKitPersonalities"));
1404 if (!extensionPersonalities) goto finish;
1405
1406 /* If it was there, remove it from the catalogue proper
1407 * by calling removeDrivers(). Pass true for the second
1408 * argument to trigger a new round of matching, and
1409 * then remove the extension from the dictionary of startup
1410 * extensions.
1411 */
1412 keyIterator = OSCollectionIterator::withCollection(
1413 extensionPersonalities);
1414 if (!keyIterator) {
1415 IOLog("Error: Couldn't allocate iterator to scan
1416 personalities for %s.\n", extensionName);
1417 LOG_DELAY();
1418 }
1419
1420 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1421 personality = OSDynamicCast(OSDictionary,
1422 extensionPersonalities->getObject(key));
1423
1424
1425 if (personality) {
1426 gIOCatalogue->removeDrivers(personality, true);
1427 }
1428 }
1429
1430 startupExtensions->removeObject(extensionName);
1431
1432 finish:
1433
1434 if (keyIterator) keyIterator->release();
1435
1436 IOLockUnlock(kld_lock);
1437 return;
1438 }