2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
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>
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>
46 #include "kld_patch.h"
59 kmod_destroy_internal(kmod_t id
);
66 mach_msg_type_number_t
*dataCount
);
68 extern kern_return_t
kmod_retain(kmod_t id
);
69 extern kern_return_t
kmod_release(kmod_t id
);
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
);
77 #define LOG_DELAY(x) IODelay((x) * 1000000)
78 #define VTYELLOW "\033[33m"
79 #define VTRESET "\033[0m"
86 /*********************************************************************
88 *********************************************************************/
91 const char * bundleid
,
92 OSDictionary
** plist
,
93 unsigned char ** code
,
94 unsigned long * code_size
,
95 bool * caller_owns_code
)
98 OSDictionary
* extensionsDict
; // don't release
99 OSDictionary
* extDict
; // don't release
100 OSDictionary
* extPlist
; // don't release
101 unsigned long code_size_local
;
103 /* Get the dictionary of startup extensions.
104 * This is keyed by module name.
106 extensionsDict
= getStartupExtensions();
107 if (!extensionsDict
) {
108 IOLog("startup extensions dictionary is missing\n");
113 /* Get the requested extension's dictionary entry and its property
114 * list, containing module dependencies.
116 extDict
= OSDynamicCast(OSDictionary
,
117 extensionsDict
->getObject(bundleid
));
120 IOLog("extension \"%s\" cannot be found\n",
127 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
129 IOLog("extension \"%s\" has no info dictionary\n",
139 /* If asking for code, the caller must provide a return buffer
142 if (!caller_owns_code
) {
143 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
152 *caller_owns_code
= false;
154 *code
= (unsigned char *)kld_file_getaddr(bundleid
,
155 (long *)&code_size_local
);
158 *code_size
= code_size_local
;
161 OSData
* driverCode
= 0; // release only if uncompressing!
163 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
165 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
167 *code_size
= driverCode
->getLength();
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",
180 *caller_owns_code
= true;
181 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
183 *code_size
= driverCode
->getLength();
185 driverCode
->release();
197 /*********************************************************************
199 *********************************************************************/
201 bool verifyCompatibility(OSString
* extName
, OSString
* requiredVersion
)
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
;
210 if (!getKext(extName
->getCStringNoCopy(), &extPlist
, NULL
, NULL
, NULL
)) {
214 extVersion
= OSDynamicCast(OSString
,
215 extPlist
->getObject("CFBundleVersion"));
217 IOLog("verifyCompatibility(): "
218 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
219 extName
->getCStringNoCopy());
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());
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());
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());
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());
257 if (required_version
> ext_version
|| required_version
< ext_compat_version
) {
264 /*********************************************************************
265 *********************************************************************/
267 bool kextIsDependency(const char * kext_name
, char * is_kernel
) {
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
280 /* Get the dictionary of startup extensions.
281 * This is keyed by module name.
283 extensionsDict
= getStartupExtensions();
284 if (!extensionsDict
) {
285 IOLog("startup extensions dictionary is missing\n");
290 /* Get the requested extension's dictionary entry and its property
291 * list, containing module dependencies.
293 extDict
= OSDynamicCast(OSDictionary
,
294 extensionsDict
->getObject(kext_name
));
297 IOLog("extension \"%s\" cannot be found\n",
303 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
305 IOLog("extension \"%s\" has no info dictionary\n",
311 /* A kext that is a kernel component is still a dependency, as there
312 * are fake kmod entries for them.
314 isKernelResourceObj
= OSDynamicCast(OSBoolean
,
315 extPlist
->getObject("OSKernelResource"));
316 if (isKernelResourceObj
&& isKernelResourceObj
->isTrue()) {
322 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
323 compressedCode
= OSDynamicCast(OSData
,
324 extDict
->getObject("compressedCode"));
326 if ((driverCode
|| compressedCode
) && is_kernel
&& *is_kernel
) {
330 if (!driverCode
&& !compressedCode
&& !isKernelResourceObj
) {
340 /*********************************************************************
341 *********************************************************************/
343 addDependenciesForKext(OSDictionary
* kextPlist
,
344 OSArray
* dependencyList
,
345 OSString
* trueParent
,
346 Boolean skipKernelDependencies
)
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
356 kextName
= OSDynamicCast(OSString
,
357 kextPlist
->getObject("CFBundleIdentifier"));
359 // XXX: Add log message
364 libraries
= OSDynamicCast(OSDictionary
,
365 kextPlist
->getObject("OSBundleLibraries"));
371 keyIterator
= OSCollectionIterator::withCollection(libraries
);
373 // XXX: Add log message
378 dependentName
= trueParent
? trueParent
: kextName
;
380 while ( (libraryName
= OSDynamicCast(OSString
,
381 keyIterator
->getNextObject())) ) {
383 OSString
* libraryVersion
= OSDynamicCast(OSString
,
384 libraries
->getObject(libraryName
));
385 if (!libraryVersion
) {
386 // XXX: Add log message
390 if (!verifyCompatibility(libraryName
, libraryVersion
)) {
394 char is_kernel_component
;
396 if (!kextIsDependency(libraryName
->getCStringNoCopy(),
397 &is_kernel_component
)) {
399 is_kernel_component
= false;
402 if (!skipKernelDependencies
|| !is_kernel_component
) {
403 dependencyList
->setObject(dependentName
);
404 dependencyList
->setObject(libraryName
);
406 if (!hasDirectKernelDependency
&& is_kernel_component
) {
407 hasDirectKernelDependency
= true;
411 if (!hasDirectKernelDependency
) {
412 const OSSymbol
* kernelName
= 0;
414 /* a kext without any kernel dependency is assumed dependent on 6.0 */
415 dependencyList
->setObject(dependentName
);
417 kernelName
= OSSymbol::withCString("com.apple.kernel.libkern");
419 // XXX: Add log message
423 dependencyList
->setObject(kernelName
);
424 kernelName
->release();
426 IOLog("Extension \"%s\" has no kernel dependency.\n",
427 kextName
->getCStringNoCopy());
431 if (keyIterator
) keyIterator
->release();
435 /*********************************************************************
436 *********************************************************************/
438 bool getVersionForKext(OSDictionary
* kextPlist
, char ** version
)
440 OSString
* kextName
= 0; // don't release
441 OSString
* kextVersion
; // don't release
443 kextName
= OSDynamicCast(OSString
,
444 kextPlist
->getObject("CFBundleIdentifier"));
446 // XXX: Add log message
450 kextVersion
= OSDynamicCast(OSString
,
451 kextPlist
->getObject("CFBundleVersion"));
453 IOLog("getVersionForKext(): "
454 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
455 kextName
->getCStringNoCopy());
460 *version
= (char *)kextVersion
->getCStringNoCopy();
466 /*********************************************************************
467 *********************************************************************/
469 bool add_dependencies_for_kmod(const char * kmod_name
, dgraph_t
* dgraph
)
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;
485 * Set up the root kmod.
487 if (!getKext(kmod_name
, &kextPlist
, &code
, &code_length
,
489 IOLog("can't find extension %s\n", kmod_name
);
494 if (!kextIsDependency(kmod_name
, &is_kernel_component
)) {
495 IOLog("extension %s is not loadable\n", kmod_name
);
500 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
501 IOLog("can't get version for extension %s\n", kmod_name
);
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
);
511 IOLog("can't record %s in dependency graph\n", kmod_name
);
513 // kmem_alloc()ed code is freed in finish: block.
517 // pass ownership of code to kld patcher
519 if (kload_map_entry(dgraph_entry
) != kload_error_none
) {
520 IOLog("can't map %s in preparation for loading\n", kmod_name
);
522 // kmem_alloc()ed code is freed in finish: block.
526 // clear local record of code
529 code_is_kmem
= false;
532 * Now handle all the dependencies.
534 dependencyList
= OSArray::withCapacity(5);
535 if (!dependencyList
) {
536 IOLog("memory allocation failure\n");
542 if (!addDependenciesForKext(kextPlist
, dependencyList
, NULL
, false)) {
543 IOLog("can't determine immediate dependencies for extension %s\n",
549 /* IMPORTANT: loop condition gets list count every time through, as the
550 * array CAN change each iteration.
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;
558 /* 255 is an arbitrary limit. Multiplied by 2 because the dependency
559 * list is stocked with pairs (dependent -> dependency).
561 if (index
> (2 * 255)) {
562 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
567 dependentName
= OSDynamicCast(OSString
,
568 dependencyList
->getObject(index
));
569 libraryName
= OSDynamicCast(OSString
,
570 dependencyList
->getObject(index
+ 1));
572 if (!dependentName
|| !libraryName
) {
573 IOLog("malformed dependency list\n");
578 dependent_name
= dependentName
->getCStringNoCopy();
579 library_name
= libraryName
->getCStringNoCopy();
581 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
583 IOLog("can't find extension %s\n", library_name
);
588 OSString
* string
= OSDynamicCast(OSString
,
589 kextPlist
->getObject("OSBundleSharedExecutableIdentifier"));
591 library_name
= string
->getCStringNoCopy();
592 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
593 IOLog("can't find extension %s\n", library_name
);
599 kext_is_dependency
= kextIsDependency(library_name
,
600 &is_kernel_component
);
602 if (kext_is_dependency
) {
603 dgraph_entry
= dgraph_find_dependent(dgraph
, dependent_name
);
605 IOLog("internal error with dependency graph\n");
611 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
612 IOLog("can't get version for extension %s\n", library_name
);
617 /* It's okay for code to be zero, as for a pseudokext
618 * representing a kernel component.
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
);
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
);
632 if (!dgraph_dependency
) {
633 IOLog("can't record dependency %s -> %s\n", dependent_name
,
636 // kmem_alloc()ed code is freed in finish: block.
640 // pass ownership of code to kld patcher
642 if (kload_map_entry(dgraph_dependency
) != kload_error_none
) {
643 IOLog("can't map %s in preparation for loading\n", library_name
);
645 // kmem_alloc()ed code is freed in finish: block.
649 // clear local record of code
652 code_is_kmem
= false;
655 /* Now put the library's dependencies onto the pending set.
657 if (!addDependenciesForKext(kextPlist
, dependencyList
,
658 kext_is_dependency
? NULL
: dependentName
, !kext_is_dependency
)) {
660 IOLog("can't determine immediate dependencies for extension %s\n",
668 if (code
&& code_is_kmem
) {
669 kmem_free(kernel_map
, (unsigned int)code
, code_length
);
671 if (dependencyList
) dependencyList
->release();
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
682 *********************************************************************/
684 kern_return_t
load_kernel_extension(char * kmod_name
)
686 kern_return_t result
= KERN_SUCCESS
;
687 kload_error load_result
= kload_error_none
;
689 bool free_dgraph
= false;
690 kmod_info_t
* kmod_info
;
692 // Put this in for lots of messages about kext loading.
694 kload_set_log_level(kload_log_level_load_details
);
697 /* See if the kmod is already loaded.
699 if ((kmod_info
= kmod_lookupbyname_locked(kmod_name
))) {
700 kfree(kmod_info
, sizeof(kmod_info_t
));
704 if (dgraph_init(&dgraph
) != dgraph_valid
) {
705 IOLog("Can't initialize dependency graph to load %s.\n",
707 result
= KERN_FAILURE
;
712 if (!add_dependencies_for_kmod(kmod_name
, &dgraph
)) {
713 IOLog("Can't determine dependencies for %s.\n",
715 result
= KERN_FAILURE
;
719 dgraph
.root
= dgraph_find_root(&dgraph
);
722 IOLog("Dependency graph to load %s has no root.\n",
724 result
= KERN_FAILURE
;
728 /* A kernel component is built in and need not be loaded.
730 if (dgraph
.root
->is_kernel_component
) {
731 result
= KERN_SUCCESS
;
735 dgraph_establish_load_order(&dgraph
);
737 load_result
= kload_load_dgraph(&dgraph
);
738 if (load_result
!= kload_error_none
&&
739 load_result
!= kload_error_already_loaded
) {
741 IOLog(VTYELLOW
"Failed to load extension %s.\n" VTRESET
, kmod_name
);
743 result
= KERN_FAILURE
;
750 dgraph_free(&dgraph
, 0 /* don't free dgraph itself */);