]> git.saurik.com Git - apple/xnu.git/blame - libsa/kext.cpp
xnu-1228.tar.gz
[apple/xnu.git] / libsa / kext.cpp
CommitLineData
55e303ae 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
55e303ae 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
55e303ae 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55
A
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.
55e303ae 34 */
2d21ac55 35
55e303ae
A
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
42extern "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
58extern "C" {
59extern kern_return_t
60kmod_create_internal(
61 kmod_info_t *info,
62 kmod_t *id);
63
64extern kern_return_t
65kmod_destroy_internal(kmod_t id);
66
67extern kern_return_t
68kmod_start_or_stop(
69 kmod_t id,
70 int start,
71 kmod_args_t *data,
72 mach_msg_type_number_t *dataCount);
73
74extern kern_return_t kmod_retain(kmod_t id);
75extern kern_return_t kmod_release(kmod_t id);
76
2d21ac55 77extern Boolean kmod_load_request(const char * moduleName, Boolean make_request);
55e303ae
A
78};
79
2d21ac55
A
80extern kmod_args_t
81get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen);
82
83extern struct mac_module_data *osdict_encode(OSDictionary *dict);
84
55e303ae
A
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
2d21ac55
A
96
97#define KERNEL_PREFIX "com.apple.kernel"
98#define KPI_PREFIX "com.apple.kpi"
99
100
55e303ae
A
101/*********************************************************************
102*
103*********************************************************************/
104static
105bool 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,
2d21ac55 170 (unsigned long *)&code_size_local);
55e303ae
A
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);
55e303ae
A
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
206finish:
207
208 return result;
209}
210
211
212/*********************************************************************
213*
214*********************************************************************/
215static
216bool 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*********************************************************************/
281static
282bool 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) {
2d21ac55 292 *is_kernel = 0;
55e303ae
A
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) {
2d21ac55 333 *is_kernel = 1;
55e303ae
A
334 }
335 }
336
337 driverCode = OSDynamicCast(OSData, extDict->getObject("code"));
338 compressedCode = OSDynamicCast(OSData,
339 extDict->getObject("compressedCode"));
340
2d21ac55
A
341 /* A kernel component that has code represents a KPI.
342 */
55e303ae 343 if ((driverCode || compressedCode) && is_kernel && *is_kernel) {
0c530ab8 344 *is_kernel = 2;
55e303ae
A
345 }
346
347 if (!driverCode && !compressedCode && !isKernelResourceObj) {
348 result = false;
349 goto finish;
350 }
351
352finish:
353
354 return result;
355}
356
357/*********************************************************************
358*********************************************************************/
359static bool
0c530ab8
A
360addDependenciesForKext(OSDictionary * kextPlist,
361 OSArray * dependencyList,
91447636
A
362 OSString * trueParent,
363 Boolean skipKernelDependencies)
55e303ae
A
364{
365 bool result = true;
91447636 366 bool hasDirectKernelDependency = false;
2d21ac55
A
367 bool hasKernelStyleDependency = false;
368 bool hasKPIStyleDependency = false;
55e303ae
A
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
0c530ab8 373 OSString * dependentName = 0; // don't release
55e303ae
A
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
0c530ab8
A
397 dependentName = trueParent ? trueParent : kextName;
398
55e303ae
A
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 {
91447636
A
413 char is_kernel_component;
414
0c530ab8
A
415 if (!kextIsDependency(libraryName->getCStringNoCopy(),
416 &is_kernel_component)) {
417
2d21ac55 418 is_kernel_component = 0;
0c530ab8 419 }
91447636
A
420
421 if (!skipKernelDependencies || !is_kernel_component) {
0c530ab8
A
422 dependencyList->setObject(dependentName);
423 dependencyList->setObject(libraryName);
91447636
A
424 }
425 if (!hasDirectKernelDependency && is_kernel_component) {
426 hasDirectKernelDependency = true;
427 }
2d21ac55
A
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 }
55e303ae
A
444 }
445 }
2d21ac55 446
91447636 447 if (!hasDirectKernelDependency) {
0c530ab8
A
448 const OSSymbol * kernelName = 0;
449
91447636 450 /* a kext without any kernel dependency is assumed dependent on 6.0 */
0c530ab8
A
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
2d21ac55
A
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",
0c530ab8 468 kextName->getCStringNoCopy());
91447636 469 }
55e303ae
A
470
471finish:
472 if (keyIterator) keyIterator->release();
473 return result;
474}
475
476/*********************************************************************
477*********************************************************************/
478static
479bool 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*********************************************************************/
509static
510bool add_dependencies_for_kmod(const char * kmod_name, dgraph_t * dgraph)
511{
512 bool result = true;
513 OSDictionary * kextPlist = 0; // don't release
0c530ab8
A
514 unsigned int index = 0;
515 OSArray * dependencyList = 0; // must release
55e303ae
A
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
2d21ac55 520 char is_kernel_component = 0;
55e303ae
A
521 dgraph_entry_t * dgraph_entry = 0; // don't free
522 dgraph_entry_t * dgraph_dependency = 0; // don't free
55e303ae
A
523 bool kext_is_dependency = true;
524
2d21ac55
A
525#if CONFIG_MACF_KEXT
526 kmod_args_t user_data = 0;
527 mach_msg_type_number_t user_data_length;
528#endif
529
0c530ab8
A
530 /*****
531 * Set up the root kmod.
532 */
55e303ae
A
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
2d21ac55
A
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
55e303ae
A
557 dgraph_entry = dgraph_add_dependent(dgraph, kmod_name,
558 code, code_length, code_is_kmem,
2d21ac55
A
559#if CONFIG_MACF_KEXT
560 user_data, user_data_length,
561#endif
55e303ae
A
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
0c530ab8 572 if (code) {
55e303ae
A
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
0c530ab8
A
585 /*****
586 * Now handle all the dependencies.
587 */
588 dependencyList = OSArray::withCapacity(5);
589 if (!dependencyList) {
21362eb3
A
590 IOLog("memory allocation failure\n");
591 result = false;
592 goto finish;
593 }
594
0c530ab8
A
595 index = 0;
596 if (!addDependenciesForKext(kextPlist, dependencyList, NULL, false)) {
55e303ae
A
597 IOLog("can't determine immediate dependencies for extension %s\n",
598 kmod_name);
599 result = false;
600 goto finish;
601 }
602
0c530ab8
A
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)) {
55e303ae
A
616 IOLog("extension dependency graph ridiculously long, indicating a loop\n");
617 result = false;
618 goto finish;
619 }
620
0c530ab8
A
621 dependentName = OSDynamicCast(OSString,
622 dependencyList->getObject(index));
623 libraryName = OSDynamicCast(OSString,
624 dependencyList->getObject(index + 1));
55e303ae 625
0c530ab8
A
626 if (!dependentName || !libraryName) {
627 IOLog("malformed dependency list\n");
55e303ae
A
628 result = false;
629 goto finish;
630 }
631
0c530ab8
A
632 dependent_name = dependentName->getCStringNoCopy();
633 library_name = libraryName->getCStringNoCopy();
55e303ae 634
0c530ab8 635 if (!getKext(library_name, &kextPlist, NULL, NULL, NULL)) {
55e303ae 636
0c530ab8
A
637 IOLog("can't find extension %s\n", library_name);
638 result = false;
639 goto finish;
640 }
55e303ae 641
0c530ab8
A
642 OSString * string = OSDynamicCast(OSString,
643 kextPlist->getObject("OSBundleSharedExecutableIdentifier"));
644 if (string) {
645 library_name = string->getCStringNoCopy();
55e303ae
A
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 }
0c530ab8 651 }
55e303ae 652
0c530ab8
A
653 kext_is_dependency = kextIsDependency(library_name,
654 &is_kernel_component);
55e303ae 655
0c530ab8 656 if (kext_is_dependency) {
55e303ae
A
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
2d21ac55
A
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
55e303ae
A
686 dgraph_dependency = dgraph_add_dependency(dgraph, dgraph_entry,
687 library_name, code, code_length, code_is_kmem,
2d21ac55
A
688#if CONFIG_MACF_KEXT
689 user_data, user_data_length,
690#endif
55e303ae
A
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 */
0c530ab8
A
719 if (!addDependenciesForKext(kextPlist, dependencyList,
720 kext_is_dependency ? NULL : dependentName, !kext_is_dependency)) {
55e303ae
A
721
722 IOLog("can't determine immediate dependencies for extension %s\n",
723 library_name);
724 result = false;
725 goto finish;
726 }
727 }
728
55e303ae
A
729finish:
730 if (code && code_is_kmem) {
731 kmem_free(kernel_map, (unsigned int)code, code_length);
732 }
0c530ab8
A
733 if (dependencyList) dependencyList->release();
734
2d21ac55
A
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
55e303ae
A
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__
752kern_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))) {
0c530ab8 768 kfree(kmod_info, sizeof(kmod_info_t));
55e303ae
A
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
815finish:
816
817 if (free_dgraph) {
818 dgraph_free(&dgraph, 0 /* don't free dgraph itself */);
819 }
820 return result;
821}
2d21ac55
A
822
823#define COM_APPLE "com.apple."
824
825__private_extern__ void
826load_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}