]> git.saurik.com Git - apple/xnu.git/blob - libsa/kext.cpp
7adbcf55fc1fca82d0eedae54d27f0845e139282
[apple/xnu.git] / libsa / kext.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <libkern/c++/OSContainers.h>
24 #include <IOKit/IOCatalogue.h>
25 #include <IOKit/IOLib.h>
26 #include <libsa/kext.h>
27 #include <libsa/catalogue.h>
28
29 extern "C" {
30 #include <mach-o/kld.h>
31 #include <libsa/vers_rsrc.h>
32 #include <libsa/stdlib.h>
33 #include <mach/kmod.h>
34 #include <vm/vm_kern.h>
35 #include <mach/kern_return.h>
36 #include <mach-o/fat.h>
37 #include <mach_loader.h>
38
39 #include "kld_patch.h"
40 #include "dgraph.h"
41 #include "load.h"
42 };
43
44
45 extern "C" {
46 extern kern_return_t
47 kmod_create_internal(
48 kmod_info_t *info,
49 kmod_t *id);
50
51 extern kern_return_t
52 kmod_destroy_internal(kmod_t id);
53
54 extern kern_return_t
55 kmod_start_or_stop(
56 kmod_t id,
57 int start,
58 kmod_args_t *data,
59 mach_msg_type_number_t *dataCount);
60
61 extern kern_return_t kmod_retain(kmod_t id);
62 extern kern_return_t kmod_release(kmod_t id);
63
64 extern void flush_dcache(vm_offset_t addr, unsigned cnt, int phys);
65 extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
66 };
67
68 #define DEBUG
69 #ifdef DEBUG
70 #define LOG_DELAY(x) IODelay((x) * 1000000)
71 #define VTYELLOW "\033[33m"
72 #define VTRESET "\033[0m"
73 #else
74 #define LOG_DELAY(x)
75 #define VTYELLOW
76 #define VTRESET
77 #endif /* DEBUG */
78
79 /*********************************************************************
80 *
81 *********************************************************************/
82 static
83 bool getKext(
84 const char * bundleid,
85 OSDictionary ** plist,
86 unsigned char ** code,
87 unsigned long * code_size,
88 bool * caller_owns_code)
89 {
90 bool result = true;
91 OSDictionary * extensionsDict; // don't release
92 OSDictionary * extDict; // don't release
93 OSDictionary * extPlist; // don't release
94 unsigned long code_size_local;
95
96 /* Get the dictionary of startup extensions.
97 * This is keyed by module name.
98 */
99 extensionsDict = getStartupExtensions();
100 if (!extensionsDict) {
101 IOLog("startup extensions dictionary is missing\n");
102 result = false;
103 goto finish;
104 }
105
106 /* Get the requested extension's dictionary entry and its property
107 * list, containing module dependencies.
108 */
109 extDict = OSDynamicCast(OSDictionary,
110 extensionsDict->getObject(bundleid));
111
112 if (!extDict) {
113 IOLog("extension \"%s\" cannot be found\n",
114 bundleid);
115 result = false;
116 goto finish;
117 }
118
119 if (plist) {
120 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
121 if (!extPlist) {
122 IOLog("extension \"%s\" has no info dictionary\n",
123 bundleid);
124 result = false;
125 goto finish;
126 }
127 *plist = extPlist;
128 }
129
130 if (code) {
131
132 /* If asking for code, the caller must provide a return buffer
133 * for ownership!
134 */
135 if (!caller_owns_code) {
136 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
137 result = false;
138 goto finish;
139 }
140
141 *code = 0;
142 if (code_size) {
143 *code_size = 0;
144 }
145 *caller_owns_code = false;
146
147 *code = (unsigned char *)kld_file_getaddr(bundleid,
148 (long *)&code_size_local);
149 if (*code) {
150 if (code_size) {
151 *code_size = code_size_local;
152 }
153 } else {
154 OSData * driverCode = 0; // release only if uncompressing!
155
156 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
157 if (driverCode) {
158 *code = (unsigned char *)driverCode->getBytesNoCopy();
159 if (code_size) {
160 *code_size = driverCode->getLength();
161 }
162 } else { // Look for compressed code and uncompress it
163 OSData * compressedCode = 0;
164 compressedCode = OSDynamicCast(OSData,
165 extDict->getObject("compressedCode"));
166 if (compressedCode) {
167 if (!uncompressModule(compressedCode, &driverCode)) {
168 IOLog("extension \"%s\": couldn't uncompress code\n",
169 bundleid);
170 LOG_DELAY(1);
171 result = false;
172 goto finish;
173 }
174 *caller_owns_code = true;
175 *code = (unsigned char *)driverCode->getBytesNoCopy();
176 if (code_size) {
177 *code_size = driverCode->getLength();
178 }
179 driverCode->release();
180 }
181 }
182 }
183 }
184
185 finish:
186
187 return result;
188 }
189
190
191 /*********************************************************************
192 *
193 *********************************************************************/
194 static
195 bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
196 {
197 OSDictionary * extPlist; // don't release
198 OSString * extVersion; // don't release
199 OSString * extCompatVersion; // don't release
200 VERS_version ext_version;
201 VERS_version ext_compat_version;
202 VERS_version required_version;
203
204 if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) {
205 return false;
206 }
207
208 extVersion = OSDynamicCast(OSString,
209 extPlist->getObject("CFBundleVersion"));
210 if (!extVersion) {
211 IOLog("verifyCompatibility(): "
212 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
213 extName->getCStringNoCopy());
214 return false;
215 }
216
217 extCompatVersion = OSDynamicCast(OSString,
218 extPlist->getObject("OSBundleCompatibleVersion"));
219 if (!extCompatVersion) {
220 IOLog("verifyCompatibility(): "
221 "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
222 extName->getCStringNoCopy());
223 return false;
224 }
225
226 required_version = VERS_parse_string(requiredVersion->getCStringNoCopy());
227 if (required_version < 0) {
228 IOLog("verifyCompatibility(): "
229 "Can't parse required version \"%s\" of dependency %s.\n",
230 requiredVersion->getCStringNoCopy(),
231 extName->getCStringNoCopy());
232 return false;
233 }
234 ext_version = VERS_parse_string(extVersion->getCStringNoCopy());
235 if (ext_version < 0) {
236 IOLog("verifyCompatibility(): "
237 "Can't parse version \"%s\" of dependency %s.\n",
238 extVersion->getCStringNoCopy(),
239 extName->getCStringNoCopy());
240 return false;
241 }
242 ext_compat_version = VERS_parse_string(extCompatVersion->getCStringNoCopy());
243 if (ext_compat_version < 0) {
244 IOLog("verifyCompatibility(): "
245 "Can't parse compatible version \"%s\" of dependency %s.\n",
246 extCompatVersion->getCStringNoCopy(),
247 extName->getCStringNoCopy());
248 return false;
249 }
250
251 if (required_version > ext_version || required_version < ext_compat_version) {
252 return false;
253 }
254
255 return true;
256 }
257
258 /*********************************************************************
259 *********************************************************************/
260 static
261 bool kextIsDependency(const char * kext_name, char * is_kernel) {
262 bool result = true;
263 OSDictionary * extensionsDict = 0; // don't release
264 OSDictionary * extDict = 0; // don't release
265 OSDictionary * extPlist = 0; // don't release
266 OSBoolean * isKernelResourceObj = 0; // don't release
267 OSData * driverCode = 0; // don't release
268 OSData * compressedCode = 0; // don't release
269
270 if (is_kernel) {
271 *is_kernel = false;
272 }
273
274 /* Get the dictionary of startup extensions.
275 * This is keyed by module name.
276 */
277 extensionsDict = getStartupExtensions();
278 if (!extensionsDict) {
279 IOLog("startup extensions dictionary is missing\n");
280 result = false;
281 goto finish;
282 }
283
284 /* Get the requested extension's dictionary entry and its property
285 * list, containing module dependencies.
286 */
287 extDict = OSDynamicCast(OSDictionary,
288 extensionsDict->getObject(kext_name));
289
290 if (!extDict) {
291 IOLog("extension \"%s\" cannot be found\n",
292 kext_name);
293 result = false;
294 goto finish;
295 }
296
297 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
298 if (!extPlist) {
299 IOLog("extension \"%s\" has no info dictionary\n",
300 kext_name);
301 result = false;
302 goto finish;
303 }
304
305 /* A kext that is a kernel component is still a dependency, as there
306 * are fake kmod entries for them.
307 */
308 isKernelResourceObj = OSDynamicCast(OSBoolean,
309 extPlist->getObject("OSKernelResource"));
310 if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
311 if (is_kernel) {
312 *is_kernel = true;
313 }
314 }
315
316 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
317 compressedCode = OSDynamicCast(OSData,
318 extDict->getObject("compressedCode"));
319
320 if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
321 *is_kernel = 2;
322 }
323
324 if (!driverCode && !compressedCode && !isKernelResourceObj) {
325 result = false;
326 goto finish;
327 }
328
329 finish:
330
331 return result;
332 }
333
334 /*********************************************************************
335 *********************************************************************/
336 static bool
337 figureDependenciesForKext(OSDictionary * kextPlist,
338 OSDictionary * dependencies,
339 OSString * trueParent,
340 Boolean skipKernelDependencies)
341 {
342 bool result = true;
343 bool hasDirectKernelDependency = false;
344 OSString * kextName = 0; // don't release
345 OSDictionary * libraries = 0; // don't release
346 OSCollectionIterator * keyIterator = 0; // must release
347 OSString * libraryName = 0; // don't release
348
349 kextName = OSDynamicCast(OSString,
350 kextPlist->getObject("CFBundleIdentifier"));
351 if (!kextName) {
352 // XXX: Add log message
353 result = false;
354 goto finish;
355 }
356
357 libraries = OSDynamicCast(OSDictionary,
358 kextPlist->getObject("OSBundleLibraries"));
359 if (!libraries) {
360 result = true;
361 goto finish;
362 }
363
364 keyIterator = OSCollectionIterator::withCollection(libraries);
365 if (!keyIterator) {
366 // XXX: Add log message
367 result = false;
368 goto finish;
369 }
370
371 while ( (libraryName = OSDynamicCast(OSString,
372 keyIterator->getNextObject())) ) {
373
374 OSString * libraryVersion = OSDynamicCast(OSString,
375 libraries->getObject(libraryName));
376 if (!libraryVersion) {
377 // XXX: Add log message
378 result = false;
379 goto finish;
380 }
381 if (!verifyCompatibility(libraryName, libraryVersion)) {
382 result = false;
383 goto finish;
384 } else {
385 char is_kernel_component;
386
387 if (!kextIsDependency(libraryName->getCStringNoCopy(), &is_kernel_component))
388 is_kernel_component = false;
389
390 if (!skipKernelDependencies || !is_kernel_component) {
391 dependencies->setObject(libraryName,
392 trueParent ? trueParent : kextName);
393 }
394 if (!hasDirectKernelDependency && is_kernel_component) {
395 hasDirectKernelDependency = true;
396 }
397 }
398 }
399 if (!hasDirectKernelDependency) {
400 /* a kext without any kernel dependency is assumed dependent on 6.0 */
401 dependencies->setObject("com.apple.kernel.libkern",
402 trueParent ? trueParent : kextName);
403 IOLog("Extension \"%s\" has no kernel dependency.\n",
404 kextName->getCStringNoCopy());
405 }
406
407 finish:
408 if (keyIterator) keyIterator->release();
409 return result;
410 }
411
412 /*********************************************************************
413 *********************************************************************/
414 static
415 bool getVersionForKext(OSDictionary * kextPlist, char ** version)
416 {
417 OSString * kextName = 0; // don't release
418 OSString * kextVersion; // don't release
419
420 kextName = OSDynamicCast(OSString,
421 kextPlist->getObject("CFBundleIdentifier"));
422 if (!kextName) {
423 // XXX: Add log message
424 return false;
425 }
426
427 kextVersion = OSDynamicCast(OSString,
428 kextPlist->getObject("CFBundleVersion"));
429 if (!kextVersion) {
430 IOLog("getVersionForKext(): "
431 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
432 kextName->getCStringNoCopy());
433 return false;
434 }
435
436 if (version) {
437 *version = (char *)kextVersion->getCStringNoCopy();
438 }
439
440 return true;
441 }
442
443 /*********************************************************************
444 *********************************************************************/
445 static
446 bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
447 {
448 bool result = true;
449 OSDictionary * kextPlist = 0; // don't release
450 OSDictionary * workingDependencies = 0; // must release
451 OSDictionary * pendingDependencies = 0; // must release
452 OSDictionary * swapDict = 0; // don't release
453 OSString * dependentName = 0; // don't release
454 const char * dependent_name = 0; // don't free
455 OSString * libraryName = 0; // don't release
456 const char * library_name = 0; // don't free
457 OSCollectionIterator * dependencyIterator = 0; // must release
458 unsigned char * code = 0;
459 unsigned long code_length = 0;
460 bool code_is_kmem = false;
461 char * kmod_vers = 0; // from plist, don't free
462 char is_kernel_component = false;
463 dgraph_entry_t * dgraph_entry = 0; // don't free
464 dgraph_entry_t * dgraph_dependency = 0; // don't free
465 unsigned int graph_depth = 0;
466 bool kext_is_dependency = true;
467
468 if (!getKext(kmod_name, &kextPlist, &code, &code_length,
469 &code_is_kmem)) {
470 IOLog("can't find extension %s\n", kmod_name);
471 result = false;
472 goto finish;
473 }
474
475 if (!kextIsDependency(kmod_name, &is_kernel_component)) {
476 IOLog("extension %s is not loadable\n", kmod_name);
477 result = false;
478 goto finish;
479 }
480
481 if (!getVersionForKext(kextPlist, &kmod_vers)) {
482 IOLog("can't get version for extension %s\n", kmod_name);
483 result = false;
484 goto finish;
485 }
486
487 dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
488 code, code_length, code_is_kmem,
489 kmod_name, kmod_vers,
490 0 /* load_address not yet known */, is_kernel_component);
491 if (!dgraph_entry) {
492 IOLog("can't record %s in dependency graph\n", kmod_name);
493 result = false;
494 // kmem_alloc()ed code is freed in finish: block.
495 goto finish;
496 }
497
498 // pass ownership of code to kld patcher
499 if (code)
500 {
501 if (kload_map_entry(dgraph_entry) != kload_error_none) {
502 IOLog("can't map %s in preparation for loading\n", kmod_name);
503 result = false;
504 // kmem_alloc()ed code is freed in finish: block.
505 goto finish;
506 }
507 }
508 // clear local record of code
509 code = 0;
510 code_length = 0;
511 code_is_kmem = false;
512
513 workingDependencies = OSDictionary::withCapacity(5);
514 if (!workingDependencies) {
515 IOLog("memory allocation failure\n");
516 result = false;
517 goto finish;
518 }
519
520 pendingDependencies = OSDictionary::withCapacity(5);
521 if (!pendingDependencies) {
522 IOLog("memory allocation failure\n");
523 result = false;
524 goto finish;
525 }
526
527 if (!figureDependenciesForKext(kextPlist, workingDependencies, NULL, false)) {
528 IOLog("can't determine immediate dependencies for extension %s\n",
529 kmod_name);
530 result = false;
531 goto finish;
532 }
533
534 graph_depth = 0;
535 while (workingDependencies->getCount()) {
536 if (graph_depth > 255) {
537 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
538 result = false;
539 goto finish;
540 }
541
542 if (dependencyIterator) {
543 dependencyIterator->release();
544 dependencyIterator = 0;
545 }
546
547 dependencyIterator = OSCollectionIterator::withCollection(
548 workingDependencies);
549 if (!dependencyIterator) {
550 IOLog("memory allocation failure\n");
551 result = false;
552 goto finish;
553 }
554
555 while ( (libraryName =
556 OSDynamicCast(OSString, dependencyIterator->getNextObject())) ) {
557
558 library_name = libraryName->getCStringNoCopy();
559
560 dependentName = OSDynamicCast(OSString,
561 workingDependencies->getObject(libraryName));
562
563 dependent_name = dependentName->getCStringNoCopy();
564
565 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
566 IOLog("can't find extension %s\n", library_name);
567 result = false;
568 goto finish;
569 }
570
571 OSString * string;
572 if ((string = OSDynamicCast(OSString,
573 kextPlist->getObject("OSBundleSharedExecutableIdentifier"))))
574 {
575 library_name = string->getCStringNoCopy();
576 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
577 IOLog("can't find extension %s\n", library_name);
578 result = false;
579 goto finish;
580 }
581 }
582
583 kext_is_dependency = kextIsDependency(library_name,
584 &is_kernel_component);
585
586 if (!kext_is_dependency) {
587
588 /* For binaryless kexts, add a new pending dependency from the
589 * original dependent onto the dependencies of the current,
590 * binaryless, dependency.
591 */
592 if (!figureDependenciesForKext(kextPlist, pendingDependencies,
593 dependentName, true)) {
594
595 IOLog("can't determine immediate dependencies for extension %s\n",
596 library_name);
597 result = false;
598 goto finish;
599 }
600 continue;
601 } else {
602 dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
603 if (!dgraph_entry) {
604 IOLog("internal error with dependency graph\n");
605 LOG_DELAY(1);
606 result = false;
607 goto finish;
608 }
609
610 if (!getVersionForKext(kextPlist, &kmod_vers)) {
611 IOLog("can't get version for extension %s\n", library_name);
612 result = false;
613 goto finish;
614 }
615
616 /* It's okay for code to be zero, as for a pseudokext
617 * representing a kernel component.
618 */
619 if (!getKext(library_name, NULL /* already got it */,
620 &code, &code_length, &code_is_kmem)) {
621 IOLog("can't find extension %s\n", library_name);
622 result = false;
623 goto finish;
624 }
625
626 dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
627 library_name, code, code_length, code_is_kmem,
628 library_name, kmod_vers,
629 0 /* load_address not yet known */, is_kernel_component);
630
631 if (!dgraph_dependency) {
632 IOLog("can't record dependency %s -> %s\n", dependent_name,
633 library_name);
634 result = false;
635 // kmem_alloc()ed code is freed in finish: block.
636 goto finish;
637 }
638
639 // pass ownership of code to kld patcher
640 if (code) {
641 if (kload_map_entry(dgraph_dependency) != kload_error_none) {
642 IOLog("can't map %s in preparation for loading\n", library_name);
643 result = false;
644 // kmem_alloc()ed code is freed in finish: block.
645 goto finish;
646 }
647 }
648 // clear local record of code
649 code = 0;
650 code_length = 0;
651 code_is_kmem = false;
652 }
653
654 /* Now put the library's dependencies onto the pending set.
655 */
656 if (!figureDependenciesForKext(kextPlist, pendingDependencies,
657 NULL, false)) {
658
659 IOLog("can't determine immediate dependencies for extension %s\n",
660 library_name);
661 result = false;
662 goto finish;
663 }
664 }
665
666 dependencyIterator->release();
667 dependencyIterator = 0;
668
669 workingDependencies->flushCollection();
670 swapDict = workingDependencies;
671 workingDependencies = pendingDependencies;
672 pendingDependencies = swapDict;
673 graph_depth++;
674 }
675
676 finish:
677 if (code && code_is_kmem) {
678 kmem_free(kernel_map, (unsigned int)code, code_length);
679 }
680 if (workingDependencies) workingDependencies->release();
681 if (pendingDependencies) pendingDependencies->release();
682 if (dependencyIterator) dependencyIterator->release();
683 return result;
684 }
685
686 /*********************************************************************
687 * This is the function that IOCatalogue calls in order to load a kmod.
688 * It first checks whether the kmod is already loaded. If the kmod
689 * isn't loaded, this function builds a dependency list and calls
690 * load_kmod() repeatedly to guarantee that each dependency is in fact
691 * loaded.
692 *********************************************************************/
693 __private_extern__
694 kern_return_t load_kernel_extension(char * kmod_name)
695 {
696 kern_return_t result = KERN_SUCCESS;
697 kload_error load_result = kload_error_none;
698 dgraph_t dgraph;
699 bool free_dgraph = false;
700 kmod_info_t * kmod_info;
701
702 // Put this in for lots of messages about kext loading.
703 #if 0
704 kload_set_log_level(kload_log_level_load_details);
705 #endif
706
707 /* See if the kmod is already loaded.
708 */
709 if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
710 kfree((vm_offset_t) kmod_info, sizeof(kmod_info_t));
711 return KERN_SUCCESS;
712 }
713
714 if (dgraph_init(&dgraph) != dgraph_valid) {
715 IOLog("Can't initialize dependency graph to load %s.\n",
716 kmod_name);
717 result = KERN_FAILURE;
718 goto finish;
719 }
720
721 free_dgraph = true;
722 if (!add_dependencies_for_kmod(kmod_name, &dgraph)) {
723 IOLog("Can't determine dependencies for %s.\n",
724 kmod_name);
725 result = KERN_FAILURE;
726 goto finish;
727 }
728
729 dgraph.root = dgraph_find_root(&dgraph);
730
731 if (!dgraph.root) {
732 IOLog("Dependency graph to load %s has no root.\n",
733 kmod_name);
734 result = KERN_FAILURE;
735 goto finish;
736 }
737
738 /* A kernel component is built in and need not be loaded.
739 */
740 if (dgraph.root->is_kernel_component) {
741 result = KERN_SUCCESS;
742 goto finish;
743 }
744
745 dgraph_establish_load_order(&dgraph);
746
747 load_result = kload_load_dgraph(&dgraph);
748 if (load_result != kload_error_none &&
749 load_result != kload_error_already_loaded) {
750
751 IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name);
752
753 result = KERN_FAILURE;
754 goto finish;
755 }
756
757 finish:
758
759 if (free_dgraph) {
760 dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
761 }
762 return result;
763 }