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