2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
31 * support for mandatory and extensible security protections. This notice
32 * is included in support of clause 2.2 (b) of the Apple Public License,
36 #include <libkern/c++/OSContainers.h>
37 #include <IOKit/IOCatalogue.h>
38 #include <IOKit/IOLib.h>
39 #include <libsa/kext.h>
40 #include <libsa/catalogue.h>
43 #include <mach-o/kld.h>
44 #include <libsa/vers_rsrc.h>
45 #include <libsa/stdlib.h>
46 #include <mach/kmod.h>
47 #include <vm/vm_kern.h>
48 #include <mach/kern_return.h>
49 #include <mach-o/fat.h>
50 #include <mach_loader.h>
52 #include "kld_patch.h"
65 kmod_destroy_internal(kmod_t id
);
72 mach_msg_type_number_t
*dataCount
);
74 extern kern_return_t
kmod_retain(kmod_t id
);
75 extern kern_return_t
kmod_release(kmod_t id
);
77 extern Boolean
kmod_load_request(const char * moduleName
, Boolean make_request
);
81 get_module_data(OSDictionary
* kextPlist
, mach_msg_type_number_t
* datalen
);
83 extern struct mac_module_data
*osdict_encode(OSDictionary
*dict
);
87 #define LOG_DELAY(x) IODelay((x) * 1000000)
88 #define VTYELLOW "\033[33m"
89 #define VTRESET "\033[0m"
97 #define KERNEL_PREFIX "com.apple.kernel"
98 #define KPI_PREFIX "com.apple.kpi"
101 /*********************************************************************
103 *********************************************************************/
106 const char * bundleid
,
107 OSDictionary
** plist
,
108 unsigned char ** code
,
109 unsigned long * code_size
,
110 bool * caller_owns_code
)
113 OSDictionary
* extensionsDict
; // don't release
114 OSDictionary
* extDict
; // don't release
115 OSDictionary
* extPlist
; // don't release
116 unsigned long code_size_local
;
118 /* Get the dictionary of startup extensions.
119 * This is keyed by module name.
121 extensionsDict
= getStartupExtensions();
122 if (!extensionsDict
) {
123 IOLog("startup extensions dictionary is missing\n");
128 /* Get the requested extension's dictionary entry and its property
129 * list, containing module dependencies.
131 extDict
= OSDynamicCast(OSDictionary
,
132 extensionsDict
->getObject(bundleid
));
135 IOLog("extension \"%s\" cannot be found\n",
142 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
144 IOLog("extension \"%s\" has no info dictionary\n",
154 /* If asking for code, the caller must provide a return buffer
157 if (!caller_owns_code
) {
158 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
167 *caller_owns_code
= false;
169 *code
= (unsigned char *)kld_file_getaddr(bundleid
,
170 (unsigned long *)&code_size_local
);
173 *code_size
= code_size_local
;
176 OSData
* driverCode
= 0; // release only if uncompressing!
178 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
180 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
182 *code_size
= driverCode
->getLength();
184 } else { // Look for compressed code and uncompress it
185 OSData
* compressedCode
= 0;
186 compressedCode
= OSDynamicCast(OSData
,
187 extDict
->getObject("compressedCode"));
188 if (compressedCode
) {
189 if (!uncompressModule(compressedCode
, &driverCode
)) {
190 IOLog("extension \"%s\": couldn't uncompress code\n",
195 *caller_owns_code
= true;
196 *code
= (unsigned char *)driverCode
->getBytesNoCopy();
198 *code_size
= driverCode
->getLength();
200 driverCode
->release();
212 /*********************************************************************
214 *********************************************************************/
216 bool verifyCompatibility(OSString
* extName
, OSString
* requiredVersion
)
218 OSDictionary
* extPlist
; // don't release
219 OSString
* extVersion
; // don't release
220 OSString
* extCompatVersion
; // don't release
221 VERS_version ext_version
;
222 VERS_version ext_compat_version
;
223 VERS_version required_version
;
225 if (!getKext(extName
->getCStringNoCopy(), &extPlist
, NULL
, NULL
, NULL
)) {
229 extVersion
= OSDynamicCast(OSString
,
230 extPlist
->getObject("CFBundleVersion"));
232 IOLog("verifyCompatibility(): "
233 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
234 extName
->getCStringNoCopy());
238 extCompatVersion
= OSDynamicCast(OSString
,
239 extPlist
->getObject("OSBundleCompatibleVersion"));
240 if (!extCompatVersion
) {
241 IOLog("verifyCompatibility(): "
242 "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n",
243 extName
->getCStringNoCopy());
247 required_version
= VERS_parse_string(requiredVersion
->getCStringNoCopy());
248 if (required_version
< 0) {
249 IOLog("verifyCompatibility(): "
250 "Can't parse required version \"%s\" of dependency %s.\n",
251 requiredVersion
->getCStringNoCopy(),
252 extName
->getCStringNoCopy());
255 ext_version
= VERS_parse_string(extVersion
->getCStringNoCopy());
256 if (ext_version
< 0) {
257 IOLog("verifyCompatibility(): "
258 "Can't parse version \"%s\" of dependency %s.\n",
259 extVersion
->getCStringNoCopy(),
260 extName
->getCStringNoCopy());
263 ext_compat_version
= VERS_parse_string(extCompatVersion
->getCStringNoCopy());
264 if (ext_compat_version
< 0) {
265 IOLog("verifyCompatibility(): "
266 "Can't parse compatible version \"%s\" of dependency %s.\n",
267 extCompatVersion
->getCStringNoCopy(),
268 extName
->getCStringNoCopy());
272 if (required_version
> ext_version
|| required_version
< ext_compat_version
) {
279 /*********************************************************************
280 *********************************************************************/
282 bool kextIsDependency(const char * kext_name
, char * is_kernel
) {
284 OSDictionary
* extensionsDict
= 0; // don't release
285 OSDictionary
* extDict
= 0; // don't release
286 OSDictionary
* extPlist
= 0; // don't release
287 OSBoolean
* isKernelResourceObj
= 0; // don't release
288 OSData
* driverCode
= 0; // don't release
289 OSData
* compressedCode
= 0; // don't release
295 /* Get the dictionary of startup extensions.
296 * This is keyed by module name.
298 extensionsDict
= getStartupExtensions();
299 if (!extensionsDict
) {
300 IOLog("startup extensions dictionary is missing\n");
305 /* Get the requested extension's dictionary entry and its property
306 * list, containing module dependencies.
308 extDict
= OSDynamicCast(OSDictionary
,
309 extensionsDict
->getObject(kext_name
));
312 IOLog("extension \"%s\" cannot be found\n",
318 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
320 IOLog("extension \"%s\" has no info dictionary\n",
326 /* A kext that is a kernel component is still a dependency, as there
327 * are fake kmod entries for them.
329 isKernelResourceObj
= OSDynamicCast(OSBoolean
,
330 extPlist
->getObject("OSKernelResource"));
331 if (isKernelResourceObj
&& isKernelResourceObj
->isTrue()) {
337 driverCode
= OSDynamicCast(OSData
, extDict
->getObject("code"));
338 compressedCode
= OSDynamicCast(OSData
,
339 extDict
->getObject("compressedCode"));
341 /* A kernel component that has code represents a KPI.
343 if ((driverCode
|| compressedCode
) && is_kernel
&& *is_kernel
) {
347 if (!driverCode
&& !compressedCode
&& !isKernelResourceObj
) {
357 /*********************************************************************
358 *********************************************************************/
360 addDependenciesForKext(OSDictionary
* kextPlist
,
361 OSArray
* dependencyList
,
362 OSString
* trueParent
,
363 Boolean skipKernelDependencies
)
366 bool hasDirectKernelDependency
= false;
367 bool hasKernelStyleDependency
= false;
368 bool hasKPIStyleDependency
= false;
369 OSString
* kextName
= 0; // don't release
370 OSDictionary
* libraries
= 0; // don't release
371 OSCollectionIterator
* keyIterator
= 0; // must release
372 OSString
* libraryName
= 0; // don't release
373 OSString
* dependentName
= 0; // don't release
375 kextName
= OSDynamicCast(OSString
,
376 kextPlist
->getObject("CFBundleIdentifier"));
378 // XXX: Add log message
383 libraries
= OSDynamicCast(OSDictionary
,
384 kextPlist
->getObject("OSBundleLibraries"));
390 keyIterator
= OSCollectionIterator::withCollection(libraries
);
392 // XXX: Add log message
397 dependentName
= trueParent
? trueParent
: kextName
;
399 while ( (libraryName
= OSDynamicCast(OSString
,
400 keyIterator
->getNextObject())) ) {
402 OSString
* libraryVersion
= OSDynamicCast(OSString
,
403 libraries
->getObject(libraryName
));
404 if (!libraryVersion
) {
405 // XXX: Add log message
409 if (!verifyCompatibility(libraryName
, libraryVersion
)) {
413 char is_kernel_component
;
415 if (!kextIsDependency(libraryName
->getCStringNoCopy(),
416 &is_kernel_component
)) {
418 is_kernel_component
= 0;
421 if (!skipKernelDependencies
|| !is_kernel_component
) {
422 dependencyList
->setObject(dependentName
);
423 dependencyList
->setObject(libraryName
);
425 if (!hasDirectKernelDependency
&& is_kernel_component
) {
426 hasDirectKernelDependency
= true;
429 /* We already know from the kextIsDependency() call whether
430 * the dependency *itself* is kernel- or KPI-style, but since
431 * the declaration semantic is by bundle ID, we check that here
434 if (strncmp(libraryName
->getCStringNoCopy(),
435 KERNEL_PREFIX
, strlen(KERNEL_PREFIX
)) == 0) {
437 hasKernelStyleDependency
= true;
439 } else if (strncmp(libraryName
->getCStringNoCopy(),
440 KPI_PREFIX
, strlen(KPI_PREFIX
)) == 0) {
442 hasKPIStyleDependency
= true;
447 if (!hasDirectKernelDependency
) {
448 const OSSymbol
* kernelName
= 0;
450 /* a kext without any kernel dependency is assumed dependent on 6.0 */
451 dependencyList
->setObject(dependentName
);
453 kernelName
= OSSymbol::withCString("com.apple.kernel.libkern");
455 // XXX: Add log message
459 dependencyList
->setObject(kernelName
);
460 kernelName
->release();
462 IOLog("Extension \"%s\" has no explicit kernel dependency; using version 6.0.\n",
463 kextName
->getCStringNoCopy());
465 } else if (hasKernelStyleDependency
&& hasKPIStyleDependency
) {
466 IOLog("Extension \"%s\" has immediate dependencies "
467 "on both com.apple.kernel and com.apple.kpi components; use only one style.\n",
468 kextName
->getCStringNoCopy());
472 if (keyIterator
) keyIterator
->release();
476 /*********************************************************************
477 *********************************************************************/
479 bool getVersionForKext(OSDictionary
* kextPlist
, char ** version
)
481 OSString
* kextName
= 0; // don't release
482 OSString
* kextVersion
; // don't release
484 kextName
= OSDynamicCast(OSString
,
485 kextPlist
->getObject("CFBundleIdentifier"));
487 // XXX: Add log message
491 kextVersion
= OSDynamicCast(OSString
,
492 kextPlist
->getObject("CFBundleVersion"));
494 IOLog("getVersionForKext(): "
495 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
496 kextName
->getCStringNoCopy());
501 *version
= (char *)kextVersion
->getCStringNoCopy();
507 /*********************************************************************
508 *********************************************************************/
510 bool add_dependencies_for_kmod(const char * kmod_name
, dgraph_t
* dgraph
)
513 OSDictionary
* kextPlist
= 0; // don't release
514 unsigned int index
= 0;
515 OSArray
* dependencyList
= 0; // must release
516 unsigned char * code
= 0;
517 unsigned long code_length
= 0;
518 bool code_is_kmem
= false;
519 char * kmod_vers
= 0; // from plist, don't free
520 char is_kernel_component
= 0;
521 dgraph_entry_t
* dgraph_entry
= 0; // don't free
522 dgraph_entry_t
* dgraph_dependency
= 0; // don't free
523 bool kext_is_dependency
= true;
526 kmod_args_t user_data
= 0;
527 mach_msg_type_number_t user_data_length
;
531 * Set up the root kmod.
533 if (!getKext(kmod_name
, &kextPlist
, &code
, &code_length
,
535 IOLog("can't find extension %s\n", kmod_name
);
540 if (!kextIsDependency(kmod_name
, &is_kernel_component
)) {
541 IOLog("extension %s is not loadable\n", kmod_name
);
546 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
547 IOLog("can't get version for extension %s\n", kmod_name
);
553 // check kext for module data in the plist
554 user_data
= get_module_data(kextPlist
, &user_data_length
);
557 dgraph_entry
= dgraph_add_dependent(dgraph
, kmod_name
,
558 code
, code_length
, code_is_kmem
,
560 user_data
, user_data_length
,
562 kmod_name
, kmod_vers
,
563 0 /* load_address not yet known */, is_kernel_component
);
565 IOLog("can't record %s in dependency graph\n", kmod_name
);
567 // kmem_alloc()ed code is freed in finish: block.
571 // pass ownership of code to kld patcher
573 if (kload_map_entry(dgraph_entry
) != kload_error_none
) {
574 IOLog("can't map %s in preparation for loading\n", kmod_name
);
576 // kmem_alloc()ed code is freed in finish: block.
580 // clear local record of code
583 code_is_kmem
= false;
586 * Now handle all the dependencies.
588 dependencyList
= OSArray::withCapacity(5);
589 if (!dependencyList
) {
590 IOLog("memory allocation failure\n");
596 if (!addDependenciesForKext(kextPlist
, dependencyList
, NULL
, false)) {
597 IOLog("can't determine immediate dependencies for extension %s\n",
603 /* IMPORTANT: loop condition gets list count every time through, as the
604 * array CAN change each iteration.
606 for (index
= 0; index
< dependencyList
->getCount(); index
+= 2) {
607 OSString
* dependentName
= 0;
608 OSString
* libraryName
= 0;
609 const char * dependent_name
= 0;
610 const char * library_name
= 0;
612 /* 255 is an arbitrary limit. Multiplied by 2 because the dependency
613 * list is stocked with pairs (dependent -> dependency).
615 if (index
> (2 * 255)) {
616 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
621 dependentName
= OSDynamicCast(OSString
,
622 dependencyList
->getObject(index
));
623 libraryName
= OSDynamicCast(OSString
,
624 dependencyList
->getObject(index
+ 1));
626 if (!dependentName
|| !libraryName
) {
627 IOLog("malformed dependency list\n");
632 dependent_name
= dependentName
->getCStringNoCopy();
633 library_name
= libraryName
->getCStringNoCopy();
635 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
637 IOLog("can't find extension %s\n", library_name
);
642 OSString
* string
= OSDynamicCast(OSString
,
643 kextPlist
->getObject("OSBundleSharedExecutableIdentifier"));
645 library_name
= string
->getCStringNoCopy();
646 if (!getKext(library_name
, &kextPlist
, NULL
, NULL
, NULL
)) {
647 IOLog("can't find extension %s\n", library_name
);
653 kext_is_dependency
= kextIsDependency(library_name
,
654 &is_kernel_component
);
656 if (kext_is_dependency
) {
657 dgraph_entry
= dgraph_find_dependent(dgraph
, dependent_name
);
659 IOLog("internal error with dependency graph\n");
665 if (!getVersionForKext(kextPlist
, &kmod_vers
)) {
666 IOLog("can't get version for extension %s\n", library_name
);
671 /* It's okay for code to be zero, as for a pseudokext
672 * representing a kernel component.
674 if (!getKext(library_name
, NULL
/* already got it */,
675 &code
, &code_length
, &code_is_kmem
)) {
676 IOLog("can't find extension %s\n", library_name
);
682 // check kext for module data in the plist
683 // XXX - is this really needed?
684 user_data
= get_module_data(kextPlist
, &user_data_length
);
686 dgraph_dependency
= dgraph_add_dependency(dgraph
, dgraph_entry
,
687 library_name
, code
, code_length
, code_is_kmem
,
689 user_data
, user_data_length
,
691 library_name
, kmod_vers
,
692 0 /* load_address not yet known */, is_kernel_component
);
694 if (!dgraph_dependency
) {
695 IOLog("can't record dependency %s -> %s\n", dependent_name
,
698 // kmem_alloc()ed code is freed in finish: block.
702 // pass ownership of code to kld patcher
704 if (kload_map_entry(dgraph_dependency
) != kload_error_none
) {
705 IOLog("can't map %s in preparation for loading\n", library_name
);
707 // kmem_alloc()ed code is freed in finish: block.
711 // clear local record of code
714 code_is_kmem
= false;
717 /* Now put the library's dependencies onto the pending set.
719 if (!addDependenciesForKext(kextPlist
, dependencyList
,
720 kext_is_dependency
? NULL
: dependentName
, !kext_is_dependency
)) {
722 IOLog("can't determine immediate dependencies for extension %s\n",
730 if (code
&& code_is_kmem
) {
731 kmem_free(kernel_map
, (unsigned int)code
, code_length
);
733 if (dependencyList
) dependencyList
->release();
736 if (user_data
&& !result
) {
737 vm_map_copy_discard((vm_map_copy_t
)user_data
);
744 /*********************************************************************
745 * This is the function that IOCatalogue calls in order to load a kmod.
746 * It first checks whether the kmod is already loaded. If the kmod
747 * isn't loaded, this function builds a dependency list and calls
748 * load_kmod() repeatedly to guarantee that each dependency is in fact
750 *********************************************************************/
752 kern_return_t
load_kernel_extension(char * kmod_name
)
754 kern_return_t result
= KERN_SUCCESS
;
755 kload_error load_result
= kload_error_none
;
757 bool free_dgraph
= false;
758 kmod_info_t
* kmod_info
;
760 // Put this in for lots of messages about kext loading.
762 kload_set_log_level(kload_log_level_load_details
);
765 /* See if the kmod is already loaded.
767 if ((kmod_info
= kmod_lookupbyname_locked(kmod_name
))) {
768 kfree(kmod_info
, sizeof(kmod_info_t
));
772 if (dgraph_init(&dgraph
) != dgraph_valid
) {
773 IOLog("Can't initialize dependency graph to load %s.\n",
775 result
= KERN_FAILURE
;
780 if (!add_dependencies_for_kmod(kmod_name
, &dgraph
)) {
781 IOLog("Can't determine dependencies for %s.\n",
783 result
= KERN_FAILURE
;
787 dgraph
.root
= dgraph_find_root(&dgraph
);
790 IOLog("Dependency graph to load %s has no root.\n",
792 result
= KERN_FAILURE
;
796 /* A kernel component is built in and need not be loaded.
798 if (dgraph
.root
->is_kernel_component
) {
799 result
= KERN_SUCCESS
;
803 dgraph_establish_load_order(&dgraph
);
805 load_result
= kload_load_dgraph(&dgraph
);
806 if (load_result
!= kload_error_none
&&
807 load_result
!= kload_error_already_loaded
) {
809 IOLog(VTYELLOW
"Failed to load extension %s.\n" VTRESET
, kmod_name
);
811 result
= KERN_FAILURE
;
818 dgraph_free(&dgraph
, 0 /* don't free dgraph itself */);
823 #define COM_APPLE "com.apple."
825 __private_extern__
void
826 load_security_extensions (void)
828 OSDictionary
* extensionsDict
= NULL
; // don't release
829 OSCollectionIterator
* keyIterator
= NULL
; // must release
830 OSString
* key
= NULL
; // don't release
831 OSDictionary
* extDict
; // don't release
832 OSDictionary
* extPlist
; // don't release
833 OSBoolean
* isSec
= 0; // don't release
836 extensionsDict
= getStartupExtensions();
837 if (!extensionsDict
) {
838 IOLog("startup extensions dictionary is missing\n");
843 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
845 IOLog("Error: Failed to allocate iterator for extensions.\n");
850 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
852 const char * bundle_id
= key
->getCStringNoCopy();
854 /* Skip extensions whose bundle IDs don't start with "com.apple.".
856 if (!bundle_id
|| (strncmp(bundle_id
, COM_APPLE
, strlen(COM_APPLE
)) != 0)) {
860 extDict
= OSDynamicCast(OSDictionary
, extensionsDict
->getObject(key
));
862 IOLog("extension \"%s\" cannot be found\n",
863 key
->getCStringNoCopy());
867 extPlist
= OSDynamicCast(OSDictionary
, extDict
->getObject("plist"));
869 IOLog("extension \"%s\" has no info dictionary\n",
870 key
->getCStringNoCopy());
874 isSec
= OSDynamicCast(OSBoolean
,
875 extPlist
->getObject("AppleSecurityExtension"));
876 if (isSec
&& isSec
->isTrue()) {
877 printf("Loading security extension %s\n", key
->getCStringNoCopy());
878 ret
= kmod_load_request(key
->getCStringNoCopy(), false);
880 load_kernel_extension((char *)key
->getCStringNoCopy());
886 keyIterator
->release();