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