]> git.saurik.com Git - apple/xnu.git/blob - libsa/kext.cpp
xnu-1228.tar.gz
[apple/xnu.git] / libsa / kext.cpp
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. 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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
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,
33 * Version 2.0.
34 */
35
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>
41
42 extern "C" {
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>
51
52 #include "kld_patch.h"
53 #include "dgraph.h"
54 #include "load.h"
55 };
56
57
58 extern "C" {
59 extern kern_return_t
60 kmod_create_internal(
61 kmod_info_t *info,
62 kmod_t *id);
63
64 extern kern_return_t
65 kmod_destroy_internal(kmod_t id);
66
67 extern kern_return_t
68 kmod_start_or_stop(
69 kmod_t id,
70 int start,
71 kmod_args_t *data,
72 mach_msg_type_number_t *dataCount);
73
74 extern kern_return_t kmod_retain(kmod_t id);
75 extern kern_return_t kmod_release(kmod_t id);
76
77 extern Boolean kmod_load_request(const char * moduleName, Boolean make_request);
78 };
79
80 extern kmod_args_t
81 get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen);
82
83 extern struct mac_module_data *osdict_encode(OSDictionary *dict);
84
85 #define DEBUG
86 #ifdef DEBUG
87 #define LOG_DELAY(x) IODelay((x) * 1000000)
88 #define VTYELLOW "\033[33m"
89 #define VTRESET "\033[0m"
90 #else
91 #define LOG_DELAY(x)
92 #define VTYELLOW
93 #define VTRESET
94 #endif /* DEBUG */
95
96
97 #define KERNEL_PREFIX "com.apple.kernel"
98 #define KPI_PREFIX "com.apple.kpi"
99
100
101 /*********************************************************************
102 *
103 *********************************************************************/
104 static
105 bool getKext(
106 const char * bundleid,
107 OSDictionary ** plist,
108 unsigned char ** code,
109 unsigned long * code_size,
110 bool * caller_owns_code)
111 {
112 bool result = true;
113 OSDictionary * extensionsDict; // don't release
114 OSDictionary * extDict; // don't release
115 OSDictionary * extPlist; // don't release
116 unsigned long code_size_local;
117
118 /* Get the dictionary of startup extensions.
119 * This is keyed by module name.
120 */
121 extensionsDict = getStartupExtensions();
122 if (!extensionsDict) {
123 IOLog("startup extensions dictionary is missing\n");
124 result = false;
125 goto finish;
126 }
127
128 /* Get the requested extension's dictionary entry and its property
129 * list, containing module dependencies.
130 */
131 extDict = OSDynamicCast(OSDictionary,
132 extensionsDict->getObject(bundleid));
133
134 if (!extDict) {
135 IOLog("extension \"%s\" cannot be found\n",
136 bundleid);
137 result = false;
138 goto finish;
139 }
140
141 if (plist) {
142 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
143 if (!extPlist) {
144 IOLog("extension \"%s\" has no info dictionary\n",
145 bundleid);
146 result = false;
147 goto finish;
148 }
149 *plist = extPlist;
150 }
151
152 if (code) {
153
154 /* If asking for code, the caller must provide a return buffer
155 * for ownership!
156 */
157 if (!caller_owns_code) {
158 IOLog("getKext(): invalid usage (caller_owns_code not provided)\n");
159 result = false;
160 goto finish;
161 }
162
163 *code = 0;
164 if (code_size) {
165 *code_size = 0;
166 }
167 *caller_owns_code = false;
168
169 *code = (unsigned char *)kld_file_getaddr(bundleid,
170 (unsigned long *)&code_size_local);
171 if (*code) {
172 if (code_size) {
173 *code_size = code_size_local;
174 }
175 } else {
176 OSData * driverCode = 0; // release only if uncompressing!
177
178 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
179 if (driverCode) {
180 *code = (unsigned char *)driverCode->getBytesNoCopy();
181 if (code_size) {
182 *code_size = driverCode->getLength();
183 }
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",
191 bundleid);
192 result = false;
193 goto finish;
194 }
195 *caller_owns_code = true;
196 *code = (unsigned char *)driverCode->getBytesNoCopy();
197 if (code_size) {
198 *code_size = driverCode->getLength();
199 }
200 driverCode->release();
201 }
202 }
203 }
204 }
205
206 finish:
207
208 return result;
209 }
210
211
212 /*********************************************************************
213 *
214 *********************************************************************/
215 static
216 bool verifyCompatibility(OSString * extName, OSString * requiredVersion)
217 {
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;
224
225 if (!getKext(extName->getCStringNoCopy(), &extPlist, NULL, NULL, NULL)) {
226 return false;
227 }
228
229 extVersion = OSDynamicCast(OSString,
230 extPlist->getObject("CFBundleVersion"));
231 if (!extVersion) {
232 IOLog("verifyCompatibility(): "
233 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
234 extName->getCStringNoCopy());
235 return false;
236 }
237
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());
244 return false;
245 }
246
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());
253 return false;
254 }
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());
261 return false;
262 }
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());
269 return false;
270 }
271
272 if (required_version > ext_version || required_version < ext_compat_version) {
273 return false;
274 }
275
276 return true;
277 }
278
279 /*********************************************************************
280 *********************************************************************/
281 static
282 bool kextIsDependency(const char * kext_name, char * is_kernel) {
283 bool result = true;
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
290
291 if (is_kernel) {
292 *is_kernel = 0;
293 }
294
295 /* Get the dictionary of startup extensions.
296 * This is keyed by module name.
297 */
298 extensionsDict = getStartupExtensions();
299 if (!extensionsDict) {
300 IOLog("startup extensions dictionary is missing\n");
301 result = false;
302 goto finish;
303 }
304
305 /* Get the requested extension's dictionary entry and its property
306 * list, containing module dependencies.
307 */
308 extDict = OSDynamicCast(OSDictionary,
309 extensionsDict->getObject(kext_name));
310
311 if (!extDict) {
312 IOLog("extension \"%s\" cannot be found\n",
313 kext_name);
314 result = false;
315 goto finish;
316 }
317
318 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
319 if (!extPlist) {
320 IOLog("extension \"%s\" has no info dictionary\n",
321 kext_name);
322 result = false;
323 goto finish;
324 }
325
326 /* A kext that is a kernel component is still a dependency, as there
327 * are fake kmod entries for them.
328 */
329 isKernelResourceObj = OSDynamicCast(OSBoolean,
330 extPlist->getObject("OSKernelResource"));
331 if (isKernelResourceObj && isKernelResourceObj->isTrue()) {
332 if (is_kernel) {
333 *is_kernel = 1;
334 }
335 }
336
337 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
338 compressedCode = OSDynamicCast(OSData,
339 extDict->getObject("compressedCode"));
340
341 /* A kernel component that has code represents a KPI.
342 */
343 if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
344 *is_kernel = 2;
345 }
346
347 if (!driverCode && !compressedCode && !isKernelResourceObj) {
348 result = false;
349 goto finish;
350 }
351
352 finish:
353
354 return result;
355 }
356
357 /*********************************************************************
358 *********************************************************************/
359 static bool
360 addDependenciesForKext(OSDictionary * kextPlist,
361 OSArray * dependencyList,
362 OSString * trueParent,
363 Boolean skipKernelDependencies)
364 {
365 bool result = true;
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
374
375 kextName = OSDynamicCast(OSString,
376 kextPlist->getObject("CFBundleIdentifier"));
377 if (!kextName) {
378 // XXX: Add log message
379 result = false;
380 goto finish;
381 }
382
383 libraries = OSDynamicCast(OSDictionary,
384 kextPlist->getObject("OSBundleLibraries"));
385 if (!libraries) {
386 result = true;
387 goto finish;
388 }
389
390 keyIterator = OSCollectionIterator::withCollection(libraries);
391 if (!keyIterator) {
392 // XXX: Add log message
393 result = false;
394 goto finish;
395 }
396
397 dependentName = trueParent ? trueParent : kextName;
398
399 while ( (libraryName = OSDynamicCast(OSString,
400 keyIterator->getNextObject())) ) {
401
402 OSString * libraryVersion = OSDynamicCast(OSString,
403 libraries->getObject(libraryName));
404 if (!libraryVersion) {
405 // XXX: Add log message
406 result = false;
407 goto finish;
408 }
409 if (!verifyCompatibility(libraryName, libraryVersion)) {
410 result = false;
411 goto finish;
412 } else {
413 char is_kernel_component;
414
415 if (!kextIsDependency(libraryName->getCStringNoCopy(),
416 &is_kernel_component)) {
417
418 is_kernel_component = 0;
419 }
420
421 if (!skipKernelDependencies || !is_kernel_component) {
422 dependencyList->setObject(dependentName);
423 dependencyList->setObject(libraryName);
424 }
425 if (!hasDirectKernelDependency && is_kernel_component) {
426 hasDirectKernelDependency = true;
427 }
428
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
432 * instead.
433 */
434 if (strncmp(libraryName->getCStringNoCopy(),
435 KERNEL_PREFIX, strlen(KERNEL_PREFIX)) == 0) {
436
437 hasKernelStyleDependency = true;
438
439 } else if (strncmp(libraryName->getCStringNoCopy(),
440 KPI_PREFIX, strlen(KPI_PREFIX)) == 0) {
441
442 hasKPIStyleDependency = true;
443 }
444 }
445 }
446
447 if (!hasDirectKernelDependency) {
448 const OSSymbol * kernelName = 0;
449
450 /* a kext without any kernel dependency is assumed dependent on 6.0 */
451 dependencyList->setObject(dependentName);
452
453 kernelName = OSSymbol::withCString("com.apple.kernel.libkern");
454 if (!kernelName) {
455 // XXX: Add log message
456 result = false;
457 goto finish;
458 }
459 dependencyList->setObject(kernelName);
460 kernelName->release();
461
462 IOLog("Extension \"%s\" has no explicit kernel dependency; using version 6.0.\n",
463 kextName->getCStringNoCopy());
464
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());
469 }
470
471 finish:
472 if (keyIterator) keyIterator->release();
473 return result;
474 }
475
476 /*********************************************************************
477 *********************************************************************/
478 static
479 bool getVersionForKext(OSDictionary * kextPlist, char ** version)
480 {
481 OSString * kextName = 0; // don't release
482 OSString * kextVersion; // don't release
483
484 kextName = OSDynamicCast(OSString,
485 kextPlist->getObject("CFBundleIdentifier"));
486 if (!kextName) {
487 // XXX: Add log message
488 return false;
489 }
490
491 kextVersion = OSDynamicCast(OSString,
492 kextPlist->getObject("CFBundleVersion"));
493 if (!kextVersion) {
494 IOLog("getVersionForKext(): "
495 "Extension \"%s\" has no \"CFBundleVersion\" property.\n",
496 kextName->getCStringNoCopy());
497 return false;
498 }
499
500 if (version) {
501 *version = (char *)kextVersion->getCStringNoCopy();
502 }
503
504 return true;
505 }
506
507 /*********************************************************************
508 *********************************************************************/
509 static
510 bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
511 {
512 bool result = true;
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;
524
525 #if CONFIG_MACF_KEXT
526 kmod_args_t user_data = 0;
527 mach_msg_type_number_t user_data_length;
528 #endif
529
530 /*****
531 * Set up the root kmod.
532 */
533 if (!getKext(kmod_name, &kextPlist, &code, &code_length,
534 &code_is_kmem)) {
535 IOLog("can't find extension %s\n", kmod_name);
536 result = false;
537 goto finish;
538 }
539
540 if (!kextIsDependency(kmod_name, &is_kernel_component)) {
541 IOLog("extension %s is not loadable\n", kmod_name);
542 result = false;
543 goto finish;
544 }
545
546 if (!getVersionForKext(kextPlist, &kmod_vers)) {
547 IOLog("can't get version for extension %s\n", kmod_name);
548 result = false;
549 goto finish;
550 }
551
552 #if CONFIG_MACF_KEXT
553 // check kext for module data in the plist
554 user_data = get_module_data(kextPlist, &user_data_length);
555 #endif
556
557 dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
558 code, code_length, code_is_kmem,
559 #if CONFIG_MACF_KEXT
560 user_data, user_data_length,
561 #endif
562 kmod_name, kmod_vers,
563 0 /* load_address not yet known */, is_kernel_component);
564 if (!dgraph_entry) {
565 IOLog("can't record %s in dependency graph\n", kmod_name);
566 result = false;
567 // kmem_alloc()ed code is freed in finish: block.
568 goto finish;
569 }
570
571 // pass ownership of code to kld patcher
572 if (code) {
573 if (kload_map_entry(dgraph_entry) != kload_error_none) {
574 IOLog("can't map %s in preparation for loading\n", kmod_name);
575 result = false;
576 // kmem_alloc()ed code is freed in finish: block.
577 goto finish;
578 }
579 }
580 // clear local record of code
581 code = 0;
582 code_length = 0;
583 code_is_kmem = false;
584
585 /*****
586 * Now handle all the dependencies.
587 */
588 dependencyList = OSArray::withCapacity(5);
589 if (!dependencyList) {
590 IOLog("memory allocation failure\n");
591 result = false;
592 goto finish;
593 }
594
595 index = 0;
596 if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) {
597 IOLog("can't determine immediate dependencies for extension %s\n",
598 kmod_name);
599 result = false;
600 goto finish;
601 }
602
603 /* IMPORTANT: loop condition gets list count every time through, as the
604 * array CAN change each iteration.
605 */
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;
611
612 /* 255 is an arbitrary limit. Multiplied by 2 because the dependency
613 * list is stocked with pairs (dependent -> dependency).
614 */
615 if (index > (2 * 255)) {
616 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
617 result = false;
618 goto finish;
619 }
620
621 dependentName = OSDynamicCast(OSString,
622 dependencyList->getObject(index));
623 libraryName = OSDynamicCast(OSString,
624 dependencyList->getObject(index + 1));
625
626 if (!dependentName || !libraryName) {
627 IOLog("malformed dependency list\n");
628 result = false;
629 goto finish;
630 }
631
632 dependent_name = dependentName->getCStringNoCopy();
633 library_name = libraryName->getCStringNoCopy();
634
635 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
636
637 IOLog("can't find extension %s\n", library_name);
638 result = false;
639 goto finish;
640 }
641
642 OSString * string = OSDynamicCast(OSString,
643 kextPlist->getObject("OSBundleSharedExecutableIdentifier"));
644 if (string) {
645 library_name = string->getCStringNoCopy();
646 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
647 IOLog("can't find extension %s\n", library_name);
648 result = false;
649 goto finish;
650 }
651 }
652
653 kext_is_dependency = kextIsDependency(library_name,
654 &is_kernel_component);
655
656 if (kext_is_dependency) {
657 dgraph_entry = dgraph_find_dependent(dgraph, dependent_name);
658 if (!dgraph_entry) {
659 IOLog("internal error with dependency graph\n");
660 LOG_DELAY(1);
661 result = false;
662 goto finish;
663 }
664
665 if (!getVersionForKext(kextPlist, &kmod_vers)) {
666 IOLog("can't get version for extension %s\n", library_name);
667 result = false;
668 goto finish;
669 }
670
671 /* It's okay for code to be zero, as for a pseudokext
672 * representing a kernel component.
673 */
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);
677 result = false;
678 goto finish;
679 }
680
681 #if CONFIG_MACF_KEXT
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);
685 #endif
686 dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
687 library_name, code, code_length, code_is_kmem,
688 #if CONFIG_MACF_KEXT
689 user_data, user_data_length,
690 #endif
691 library_name, kmod_vers,
692 0 /* load_address not yet known */, is_kernel_component);
693
694 if (!dgraph_dependency) {
695 IOLog("can't record dependency %s -> %s\n", dependent_name,
696 library_name);
697 result = false;
698 // kmem_alloc()ed code is freed in finish: block.
699 goto finish;
700 }
701
702 // pass ownership of code to kld patcher
703 if (code) {
704 if (kload_map_entry(dgraph_dependency) != kload_error_none) {
705 IOLog("can't map %s in preparation for loading\n", library_name);
706 result = false;
707 // kmem_alloc()ed code is freed in finish: block.
708 goto finish;
709 }
710 }
711 // clear local record of code
712 code = 0;
713 code_length = 0;
714 code_is_kmem = false;
715 }
716
717 /* Now put the library's dependencies onto the pending set.
718 */
719 if (!addDependenciesForKext(kextPlist, dependencyList,
720 kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) {
721
722 IOLog("can't determine immediate dependencies for extension %s\n",
723 library_name);
724 result = false;
725 goto finish;
726 }
727 }
728
729 finish:
730 if (code && code_is_kmem) {
731 kmem_free(kernel_map, (unsigned int)code, code_length);
732 }
733 if (dependencyList) dependencyList->release();
734
735 #if CONFIG_MACF_KEXT
736 if (user_data && !result) {
737 vm_map_copy_discard((vm_map_copy_t)user_data);
738 }
739 #endif
740
741 return result;
742 }
743
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
749 * loaded.
750 *********************************************************************/
751 __private_extern__
752 kern_return_t load_kernel_extension(char * kmod_name)
753 {
754 kern_return_t result = KERN_SUCCESS;
755 kload_error load_result = kload_error_none;
756 dgraph_t dgraph;
757 bool free_dgraph = false;
758 kmod_info_t * kmod_info;
759
760 // Put this in for lots of messages about kext loading.
761 #if 0
762 kload_set_log_level(kload_log_level_load_details);
763 #endif
764
765 /* See if the kmod is already loaded.
766 */
767 if ((kmod_info = kmod_lookupbyname_locked(kmod_name))) {
768 kfree(kmod_info, sizeof(kmod_info_t));
769 return KERN_SUCCESS;
770 }
771
772 if (dgraph_init(&dgraph) != dgraph_valid) {
773 IOLog("Can't initialize dependency graph to load %s.\n",
774 kmod_name);
775 result = KERN_FAILURE;
776 goto finish;
777 }
778
779 free_dgraph = true;
780 if (!add_dependencies_for_kmod(kmod_name, &dgraph)) {
781 IOLog("Can't determine dependencies for %s.\n",
782 kmod_name);
783 result = KERN_FAILURE;
784 goto finish;
785 }
786
787 dgraph.root = dgraph_find_root(&dgraph);
788
789 if (!dgraph.root) {
790 IOLog("Dependency graph to load %s has no root.\n",
791 kmod_name);
792 result = KERN_FAILURE;
793 goto finish;
794 }
795
796 /* A kernel component is built in and need not be loaded.
797 */
798 if (dgraph.root->is_kernel_component) {
799 result = KERN_SUCCESS;
800 goto finish;
801 }
802
803 dgraph_establish_load_order(&dgraph);
804
805 load_result = kload_load_dgraph(&dgraph);
806 if (load_result != kload_error_none &&
807 load_result != kload_error_already_loaded) {
808
809 IOLog(VTYELLOW "Failed to load extension %s.\n" VTRESET, kmod_name);
810
811 result = KERN_FAILURE;
812 goto finish;
813 }
814
815 finish:
816
817 if (free_dgraph) {
818 dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
819 }
820 return result;
821 }
822
823 #define COM_APPLE "com.apple."
824
825 __private_extern__ void
826 load_security_extensions (void)
827 {
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
834 Boolean ret;
835
836 extensionsDict = getStartupExtensions();
837 if (!extensionsDict) {
838 IOLog("startup extensions dictionary is missing\n");
839 LOG_DELAY(1);
840 return;
841 }
842
843 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
844 if (!keyIterator) {
845 IOLog("Error: Failed to allocate iterator for extensions.\n");
846 LOG_DELAY(1);
847 return;
848 }
849
850 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
851
852 const char * bundle_id = key->getCStringNoCopy();
853
854 /* Skip extensions whose bundle IDs don't start with "com.apple.".
855 */
856 if (!bundle_id || (strncmp(bundle_id, COM_APPLE, strlen(COM_APPLE)) != 0)) {
857 continue;
858 }
859
860 extDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(key));
861 if (!extDict) {
862 IOLog("extension \"%s\" cannot be found\n",
863 key->getCStringNoCopy());
864 continue;
865 }
866
867 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
868 if (!extPlist) {
869 IOLog("extension \"%s\" has no info dictionary\n",
870 key->getCStringNoCopy());
871 continue;
872 }
873
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);
879 if (!ret) {
880 load_kernel_extension((char *)key->getCStringNoCopy());
881 }
882 }
883 }
884
885 if (keyIterator)
886 keyIterator->release();
887
888 return;
889 }