]> git.saurik.com Git - apple/xnu.git/blob - libsa/kmod.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / libsa / kmod.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <libsa/kmod.h>
23 #include <libkern/c++/OSContainers.h>
24 #include <IOKit/IOCatalogue.h>
25 #include <IOKit/IOLib.h>
26 #include <libsa/kmod.h>
27 #include <libsa/catalogue.h>
28
29 extern "C" {
30 #include <mach-o/kld.h>
31 #include <libsa/vers_rsrc.h>
32 #include <libsa/stdlib.h>
33 #include <mach/kmod.h>
34 #include <vm/vm_kern.h>
35 #include <mach/kern_return.h>
36 #include <mach-o/fat.h>
37 #include <mach_loader.h>
38 };
39
40
41 extern "C" {
42 extern load_return_t fatfile_getarch(
43 void * vp, // normally a (struct vnode *)
44 vm_offset_t data_ptr,
45 struct fat_arch * archret);
46
47 extern kern_return_t
48 kmod_create_internal(
49 kmod_info_t *info,
50 kmod_t *id);
51
52 extern kern_return_t
53 kmod_destroy_internal(kmod_t id);
54
55 extern kern_return_t
56 kmod_start_or_stop(
57 kmod_t id,
58 int start,
59 kmod_args_t *data,
60 mach_msg_type_number_t *dataCount);
61
62 extern kern_return_t kmod_retain(kmod_t id);
63 extern kern_return_t kmod_release(kmod_t id);
64
65 extern void flush_dcache(vm_offset_t addr, unsigned cnt, int phys);
66 extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
67 };
68
69
70 IOLock * kld_lock;
71
72
73 #define LOG_DELAY()
74
75 #define VTYELLOW "\033[33m"
76 #define VTRESET "\033[0m"
77
78
79 /*********************************************************************
80 * This function builds a uniqued, in-order list of modules that need
81 * to be loaded in order for kmod_name to be successfully loaded. This
82 * list ends with kmod_name itself.
83 *********************************************************************/
84 static
85 OSArray * getDependencyListForKmod(char * kmod_name) {
86
87 int error = 0;
88
89 OSDictionary * extensionsDict; // don't release
90 OSDictionary * extDict; // don't release
91 OSDictionary * extPlist; // don't release
92 OSString * extName; // don't release
93 OSArray * dependencyList = NULL; // return value, caller releases
94 unsigned int i;
95
96 /* These are used to remove duplicates from the dependency list.
97 */
98 OSArray * originalList = NULL; // must be released
99 OSDictionary * encounteredNames = NULL; // must be release
100
101
102 /* Get the dictionary of startup extensions.
103 * This is keyed by module name.
104 */
105 extensionsDict = getStartupExtensions();
106 if (!extensionsDict) {
107 IOLog("getDependencyListForKmod(): No extensions dictionary.\n");
108 LOG_DELAY();
109 error = 1;
110 goto finish;
111 }
112
113
114 /* Get the requested extension's dictionary entry and its property
115 * list, containing module dependencies.
116 */
117 extDict = OSDynamicCast(OSDictionary,
118 extensionsDict->getObject(kmod_name));
119
120 if (!extDict) {
121 IOLog("getDependencyListForKmod(): "
122 "Extension \"%s\" cannot be found.\n",
123 kmod_name);
124 LOG_DELAY();
125 error = 1;
126 goto finish;
127 }
128
129 extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist"));
130 if (!extPlist) {
131 IOLog("getDependencyListForKmod(): "
132 "Extension \"%s\" has no property list.\n",
133 kmod_name);
134 LOG_DELAY();
135 error = 1;
136 goto finish;
137 }
138
139
140 /* Verify that the retrieved entry's "CFBundleIdentifier" property exists.
141 * This will be added to the dependency list.
142 */
143 extName = OSDynamicCast(OSString,
144 extPlist->getObject("CFBundleIdentifier"));
145 if (!extName) {
146 IOLog("getDependencyListForKmod(): "
147 "Extension \"%s\" has no \"CFBundleIdentifier\" property.\n",
148 kmod_name);
149 LOG_DELAY();
150 error = 1;
151 goto finish;
152 }
153
154 dependencyList = OSArray::withCapacity(10);
155 if (!dependencyList) {
156 IOLog("getDependencyListForKmod(): "
157 "Couldn't allocate dependency array for extension \"%s\".\n",
158 kmod_name);
159 LOG_DELAY();
160 error = 1;
161 goto finish;
162 }
163
164 dependencyList->setObject(extName);
165
166
167 /* Here's a slightly tricky bit. This loop iterates through
168 * the dependency list until it runs off the end. Each time
169 * through, however, any number of dependencies can be added
170 * to the end of the list. Eventually some extensions won't
171 * have any more dependencies, no more names will be added
172 * to the list, and this loop will terminate.
173 */
174 for (i = 0; i < dependencyList->getCount(); i++) {
175
176 // None of these needs to be released, as they're all from plists.
177 OSString * curName;
178 OSDictionary * curExtDict;
179 OSDictionary * curExtDepDict;
180 OSDictionary * curExtPlist;
181 OSString * curDepName;
182
183
184 /* An arbitrary limit to prevent infinite loops.
185 */
186 if (i > 255) {
187 IOLog("getDependencyListForKmod(): "
188 "max dependency list length exceeded for "
189 "extension \"%s\".\n",
190 kmod_name);
191 LOG_DELAY();
192 error = 1;
193 goto finish;
194 }
195
196 curName = OSDynamicCast(OSString, dependencyList->getObject(i));
197
198 curExtDict = OSDynamicCast(OSDictionary,
199 extensionsDict->getObject(curName));
200 if (!curExtDict) {
201 IOLog("getDependencyListForKmod(): "
202 "Extension \"%s\", required for extension \"%s\", "
203 "is not available.\n",
204 curName->getCStringNoCopy(), kmod_name);
205 LOG_DELAY();
206 error = 1;
207 goto finish;
208 }
209
210 curExtPlist = OSDynamicCast(OSDictionary,
211 curExtDict->getObject("plist"));
212 if (!curExtPlist) {
213 IOLog("getDependencyListForKmod(): "
214 "Extension \"%s\", required for extension \"%s\", "
215 "has no property list.\n",
216 curName->getCStringNoCopy(), kmod_name);
217 LOG_DELAY();
218 error = 1;
219 goto finish;
220 }
221
222 curExtDepDict = OSDynamicCast(OSDictionary,
223 curExtPlist->getObject("OSBundleLibraries"));
224 if (curExtDepDict) {
225 OSCollectionIterator * keyIterator =
226 OSCollectionIterator::withCollection(curExtDepDict);
227
228 if (!keyIterator) {
229 IOLog("getDependencyListForKmod(): "
230 "Couldn't allocate iterator for extension "
231 "\"%s\".\n", kmod_name);
232 LOG_DELAY();
233 error = 1;
234 goto finish;
235 }
236 while ( (curDepName =
237 OSDynamicCast(OSString,
238 keyIterator->getNextObject())) ) {
239
240 dependencyList->setObject(curDepName);
241 }
242
243 keyIterator->release();
244 }
245 }
246
247
248 /*****
249 * The dependency list now exists in the reverse order of required loads,
250 * and may have duplicates. Now we turn the list around and remove
251 * duplicates.
252 */
253 originalList = dependencyList;
254 dependencyList = OSArray::withCapacity(originalList->getCount());
255 if (!dependencyList) {
256 IOLog("getDependenciesForKmod(): "
257 "Couldn't allocate reversal dependency list for extension "
258 "\"%s\".\n", kmod_name);
259 LOG_DELAY();
260 error = 1;
261 goto finish;
262 }
263 encounteredNames = OSDictionary::withCapacity(originalList->getCount());
264 if (!encounteredNames) {
265 IOLog("getDependenciesForKmod(): "
266 "Couldn't allocate list of encountered names for extension "
267 "\"%s\".\n", kmod_name);
268 LOG_DELAY();
269 error = 1;
270 goto finish;
271 }
272
273
274 /* Go backward through the original list, using the encounteredNames
275 * dictionary to check for duplicates. We put originalList in as the
276 * value because we need some non-NULL value.
277 */
278 i = originalList->getCount();
279
280 if (i > 0) {
281 do {
282 i--;
283
284 OSString * item = OSDynamicCast(OSString,
285 originalList->getObject(i));
286
287 if ( ! encounteredNames->getObject(item) ) {
288 encounteredNames->setObject(item, originalList);
289 dependencyList->setObject(item);
290 }
291 } while (i > 0);
292 }
293
294
295
296 finish:
297
298 if (originalList) {
299 originalList->release();
300 }
301 if (encounteredNames) {
302 encounteredNames->release();
303 }
304 if (error) {
305 if (dependencyList) {
306 dependencyList->release();
307 dependencyList = NULL;
308 }
309 }
310
311 return dependencyList;
312 }
313
314
315 /*********************************************************************
316 *********************************************************************/
317 static bool verifyCompatibleVersions(OSArray * dependencyList) {
318 bool result = true;
319
320 OSString * requestedModuleName = NULL;
321
322 OSDictionary * extensionsDict = NULL;
323 int count, i;
324 OSString * curName = NULL;
325 OSDictionary * curExt = NULL;
326 OSDictionary * curExtPlist = NULL;
327
328 OSBoolean * isKernelResource = NULL;
329
330 OSDictionary * dependencies = NULL;
331 OSCollectionIterator * dependencyIterator = NULL; // must release
332 OSString * dependencyName = NULL;
333 OSString * curExtDependencyVersion = NULL;
334 UInt32 cur_ext_required_dependency_vers;
335
336 OSDictionary * dependency = NULL;
337 OSDictionary * dependencyPlist = NULL;
338
339 OSString * dependencyVersion = NULL;
340 OSString * dependencyCompatibleVersion = NULL;
341 UInt32 dependency_vers;
342 UInt32 dependency_compat_vers;
343
344
345 /* Get the dictionary of startup extensions.
346 * This is keyed by module name.
347 */
348 extensionsDict = getStartupExtensions();
349 if (!extensionsDict) {
350 IOLog("verifyCompatibleVersions(): No extensions dictionary.\n");
351 LOG_DELAY();
352 result = false;
353 goto finish;
354 }
355
356
357 count = dependencyList->getCount();
358 if (!count) {
359 IOLog("verifyCompatibleVersions(): "
360 "Invoked with no dependency list.\n");
361 LOG_DELAY();
362 result = false;
363 goto finish;
364 }
365
366 requestedModuleName = OSDynamicCast(OSString,
367 dependencyList->getObject(count - 1));
368
369 for (i = count - 1; i >= 0; i--) {
370
371 if (dependencyIterator) {
372 dependencyIterator->release();
373 dependencyIterator = NULL;
374 }
375
376 curName = OSDynamicCast(OSString, dependencyList->getObject(i));
377 if (!curName) {
378 IOLog("verifyCompatibleVersions(): Internal error (1).\n");
379 LOG_DELAY();
380 result = false;
381 goto finish;
382 }
383
384 curExt = OSDynamicCast(OSDictionary,
385 extensionsDict->getObject(curName));
386 if (!curExt) {
387 IOLog("verifyCompatibleVersions(): Internal error (2).\n");
388 LOG_DELAY();
389 result = false;
390 goto finish;
391 }
392
393 curExtPlist = OSDynamicCast(OSDictionary,
394 curExt->getObject("plist"));
395 if (!curExtPlist) {
396 IOLog("verifyCompatibleVersions(): Internal error (3).\n");
397 LOG_DELAY();
398 result = false;
399 goto finish;
400 }
401
402
403 /* In-kernel extensions don't need to check dependencies.
404 */
405 isKernelResource = OSDynamicCast(OSBoolean,
406 curExtPlist->getObject("OSKernelResource"));
407 if (isKernelResource && isKernelResource->isTrue()) {
408 continue;
409 }
410
411 dependencies = OSDynamicCast(OSDictionary,
412 curExtPlist->getObject("OSBundleLibraries"));
413 if (!dependencies || dependencies->getCount() < 1) {
414 IOLog(VTYELLOW "verifyCompatibleVersions(): Extension \"%s\" "
415 "declares no dependencies.\n" VTRESET,
416 curName->getCStringNoCopy());
417 LOG_DELAY();
418 result = false;
419 goto finish;
420 }
421
422 dependencyIterator =
423 OSCollectionIterator::withCollection(dependencies);
424 if (!curExtPlist) {
425 IOLog("verifyCompatibleVersions(): Internal error (4).\n");
426 LOG_DELAY();
427 result = false;
428 goto finish;
429 }
430
431 while ((dependencyName = OSDynamicCast(OSString,
432 dependencyIterator->getNextObject()))) {
433
434 curExtDependencyVersion = OSDynamicCast(OSString,
435 dependencies->getObject(dependencyName));
436 if (!curExtDependencyVersion) {
437 IOLog("verifyCompatibleVersions(): Internal error (5).\n");
438 LOG_DELAY();
439 result = false;
440 goto finish;
441 }
442
443 dependency = OSDynamicCast(OSDictionary,
444 extensionsDict->getObject(dependencyName));
445 if (!dependency) {
446 IOLog("verifyCompatibleVersions(): Internal error (6).\n");
447 LOG_DELAY();
448 result = false;
449 goto finish;
450 }
451
452 dependencyPlist = OSDynamicCast(OSDictionary,
453 dependency->getObject("plist"));
454 if (!dependencyPlist) {
455 IOLog("verifyCompatibleVersions(): Internal error (7).\n");
456 LOG_DELAY();
457 result = false;
458 goto finish;
459 }
460
461 dependencyVersion = OSDynamicCast(OSString,
462 dependencyPlist->getObject("CFBundleVersion"));
463 if (!curExtDependencyVersion) {
464 IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
465 "version.\n" VTRESET,
466 dependencyName->getCStringNoCopy());
467 LOG_DELAY();
468 result = false;
469 goto finish;
470 }
471
472 dependencyCompatibleVersion = OSDynamicCast(OSString,
473 dependencyPlist->getObject("OSBundleCompatibleVersion"));
474 if (!dependencyCompatibleVersion) {
475 IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
476 "compatible version.\n" VTRESET,
477 dependencyName->getCStringNoCopy());
478 LOG_DELAY();
479 result = false;
480 goto finish;
481 }
482
483 IOLog("\033[33m %s (needs %s, compat-current is %s-%s).\n" VTRESET,
484 dependencyName->getCStringNoCopy(),
485 curExtDependencyVersion->getCStringNoCopy(),
486 dependencyCompatibleVersion->getCStringNoCopy(),
487 dependencyVersion->getCStringNoCopy());
488 LOG_DELAY();
489
490 if (!VERS_parse_string(curExtDependencyVersion->getCStringNoCopy(),
491 &cur_ext_required_dependency_vers)) {
492 }
493 if (!VERS_parse_string(dependencyVersion->getCStringNoCopy(),
494 &dependency_vers)) {
495 }
496 if (!VERS_parse_string(dependencyCompatibleVersion->getCStringNoCopy(),
497 &dependency_compat_vers)) {
498 }
499
500 if (cur_ext_required_dependency_vers > dependency_vers ||
501 cur_ext_required_dependency_vers < dependency_compat_vers) {
502
503 IOLog(VTYELLOW "Cannot load extension \"%s\": dependencies "
504 "\"%s\" and \"%s\" are not of compatible versions.\n" VTRESET,
505 requestedModuleName->getCStringNoCopy(),
506 curName->getCStringNoCopy(),
507 dependencyName->getCStringNoCopy());
508 LOG_DELAY();
509 result = false;
510 goto finish;
511 }
512 }
513 }
514
515 finish:
516 return result;
517 }
518
519
520 /* Used in address_for_loaded_kmod.
521 */
522 static kmod_info_t * g_current_kmod_info = NULL;
523 static const char * g_current_kmod_name = NULL;
524
525 /* Globals to pass link buffer info from
526 * address_for_loaded_kmod() and alloc_for_kmod()
527 * to load_kmod().
528 *
529 * link_load_address is the address used to lay
530 * down the linked code. It gets adjusted by the
531 * pad between the headers size and a full page
532 * multiple. If an error occurs this gets set to
533 * zero so that the kld client code can detect
534 * an address or allocation error even if kld
535 * returns success.
536 *
537 * link_load_size is the size of the image as
538 * created by kld_load_from_memory(). link_buffer_size
539 * is the size of the buffer allocated for the final
540 * laid-down image, and is adjusted by rounding the
541 * load size and header size up to full-page multiples.
542 *
543 * link_buffer_address is set only by alloc_for_kmod();
544 * its value is used as a check if kld_load_from_memory()
545 * fails so that the buffer can be deallocated.
546 */
547 static unsigned long link_load_address = 0;
548 static unsigned long link_load_size = 0;
549 static unsigned long link_buffer_size = 0;
550 static unsigned long link_header_size = 0;
551 static unsigned long link_buffer_address = 0;
552
553
554 /*********************************************************************
555 * This function is registered before kmod_load_from_memory() is
556 * invoked to build symbol table entries for an already-loaded
557 * kmod. This function just checks the g_current_kmod_info variable
558 * to gets its load address, and futzes it by the header offset (pad).
559 * See lower comments for more info on load address futzing.
560 *********************************************************************/
561 static
562 unsigned long address_for_loaded_kmod(
563 unsigned long size,
564 unsigned long headers_size) {
565
566 unsigned long round_headers_size;
567 unsigned long headers_pad;
568
569 if (!g_current_kmod_info) {
570 IOLog("address_for_loaded_kmod(): No current kmod.\n");
571 LOG_DELAY();
572 link_load_address = 0; // error sentinel for kld client
573 return 0;
574 }
575
576 round_headers_size = round_page(headers_size);
577 headers_pad = round_headers_size - headers_size;
578
579 link_load_address = (unsigned long)g_current_kmod_info->address +
580 headers_pad;
581
582 return link_load_address;
583 }
584
585
586 /*********************************************************************
587 * This function is registered before kmod_load_from_memory() is
588 * invoked to actually load a new kmod. It rounds up the header and
589 * total sizes and vm_allocates a buffer for the kmod. Now, KLD doesn't
590 * enforce any alignment of headers or segments, and we want to make
591 * sure that the executable code of the kmod lies on a page boundary.
592 * to do so, this function figures the pad between the actual header
593 * size and the page-rounded header size, and returns that offset into
594 * the allocated buffer. After kmod_load_from_memory() returns, its
595 * caller will move the mach_header struct back to the beginning of the
596 * allocated buffer so that the kmod_info_t structure contains the
597 * correct address.
598 *********************************************************************/
599 static
600 unsigned long alloc_for_kmod(
601 unsigned long size,
602 unsigned long headers_size) {
603
604 vm_address_t buffer = 0;
605 kern_return_t k_result;
606
607 unsigned long round_headers_size;
608 unsigned long round_segments_size;
609 unsigned long round_size;
610 unsigned long headers_pad;
611
612 round_headers_size = round_page(headers_size);
613 round_segments_size = round_page(size - headers_size);
614 round_size = round_headers_size + round_segments_size;
615 headers_pad = round_headers_size - headers_size;
616
617 k_result = vm_allocate(kernel_map, (vm_offset_t *)&buffer,
618 round_size, TRUE);
619 if (k_result != KERN_SUCCESS) {
620 IOLog("alloc_for_kmod(): Can't allocate memory.\n");
621 LOG_DELAY();
622 link_buffer_address = 0; // make sure it's clear
623 link_load_address = 0; // error sentinel for kld client
624 return 0;
625 }
626
627 link_load_size = size;
628
629 link_buffer_address = buffer;
630 link_buffer_size = round_size;
631 link_header_size = headers_size; // NOT rounded!
632
633 link_load_address = link_buffer_address + headers_pad;
634
635 return link_load_address;
636 }
637
638
639 /*********************************************************************
640 * This function reads the startup extensions dictionary to get the
641 * address and length of the executable data for the requested kmod.
642 *********************************************************************/
643 static
644 int get_text_info_for_kmod(const char * kmod_name,
645 char ** text_address,
646 unsigned long * text_size) {
647
648 // None of these needs to be released.
649 OSDictionary * extensionsDict;
650 OSDictionary * kmodDict;
651 OSData * driverCode;
652
653 vm_offset_t kmod_address;
654 typedef union {
655 struct mach_header mach_header;
656 struct fat_header fat_header;
657 } kmod_header_composite;
658 kmod_header_composite * kmod_headers;
659
660
661 /* Get the requested kmod's info dictionary from the global
662 * startup extensions dictionary.
663 */
664 extensionsDict = getStartupExtensions();
665 if (!extensionsDict) {
666 IOLog("text_address_for_kmod(): No extensions dictionary.\n");
667 LOG_DELAY();
668 return 0;
669 }
670
671 kmodDict = OSDynamicCast(OSDictionary,
672 extensionsDict->getObject(kmod_name));
673 if (!kmodDict) {
674 IOLog("text_address_for_kmod(): "
675 "Extension \"%s\" cannot be found.\n", kmod_name);
676 LOG_DELAY();
677 return 0;
678 }
679
680 driverCode = OSDynamicCast(OSData, kmodDict->getObject("code"));
681 if (!driverCode) {
682 IOLog("text_address_for_kmod(): "
683 "Extension \"%s\" has no \"code\" property.\n",
684 kmod_name);
685 LOG_DELAY();
686 return 0;
687 }
688
689 kmod_address = (vm_offset_t)driverCode->getBytesNoCopy();
690 kmod_headers = (kmod_header_composite *)kmod_address;
691
692 /* Now extract the appropriate code from the executable data.
693 */
694 if (kmod_headers->mach_header.magic == MH_MAGIC) {
695
696 *text_address = (char *)kmod_address;
697 *text_size = driverCode->getLength();
698 return 1;
699
700 } else if (kmod_headers->fat_header.magic == FAT_MAGIC ||
701 kmod_headers->fat_header.magic == FAT_CIGAM) {
702 // CIGAM is byte-swapped MAGIC
703
704 load_return_t load_return;
705 struct fat_arch fatinfo;
706
707 load_return = fatfile_getarch(NULL, kmod_address, &fatinfo);
708 if (load_return != LOAD_SUCCESS) {
709 IOLog("text_address_for_kmod(): Extension \"%s\" "
710 "doesn't contain code for this computer.\n", kmod_name);
711 LOG_DELAY();
712 return 0;
713 }
714
715 *text_address = (char *)(kmod_address + fatinfo.offset);
716 *text_size = fatinfo.size;
717 return 1;
718
719 } else {
720 IOLog("text_address_for_kmod(): Extension \"%s\" either "
721 "isn't code or doesn't contain code for this computer.\n",
722 kmod_name);
723 LOG_DELAY();
724 return 0;
725 }
726
727 return 1;
728 }
729
730
731 /*********************************************************************
732 *********************************************************************/
733 bool verify_kmod(const char * kmod_name, kmod_info_t * kmod_info) {
734 bool result = false;
735 OSDictionary * extensionsDict = NULL; // don't release
736 OSDictionary * kmodDict = NULL; // don't release
737 OSDictionary * plist = NULL; // don't release
738 OSString * versionString = NULL; // don't release
739 UInt32 plist_vers;
740 UInt32 kmod_vers;
741
742 if (strncmp(kmod_name, kmod_info->name, sizeof(kmod_info->name))) {
743 IOLog("verify_kmod(): kmod loaded as \"%s\" has different "
744 "identifier \"%s\".\n", kmod_name, kmod_info->name);
745 LOG_DELAY();
746 result = false;
747 goto finish;
748 }
749
750 if (!VERS_parse_string(kmod_info->version,
751 &kmod_vers)) {
752
753 IOLog(VTYELLOW "verify_kmod(): kmod \"%s\" has an invalid "
754 "version.\n" VTRESET, kmod_info->name);
755 LOG_DELAY();
756 result = false;
757 goto finish;
758 }
759
760
761 /* Get the dictionary of startup extensions.
762 * This is keyed by module name.
763 */
764 extensionsDict = getStartupExtensions();
765 if (!extensionsDict) {
766 IOLog("verify_kmod(): No extensions dictionary.\n");
767 LOG_DELAY();
768 result = false;
769 goto finish;
770 }
771
772 kmodDict = OSDynamicCast(OSDictionary,
773 extensionsDict->getObject(kmod_name));
774 if (!kmodDict) {
775 IOLog("verify_kmod(): Can't find record for kmod \"%s\".\n",
776 kmod_name);
777 LOG_DELAY();
778 result = false;
779 goto finish;
780 }
781
782 plist = OSDynamicCast(OSDictionary,
783 extensionsDict->getObject("plist"));
784 if (!kmodDict) {
785 IOLog("verify_kmod(): Kmod \"%s\" has no property list.\n",
786 kmod_name);
787 LOG_DELAY();
788 result = false;
789 goto finish;
790 }
791
792 versionString = OSDynamicCast(OSString,
793 extensionsDict->getObject("CFBundleVersion"));
794 if (!versionString) {
795 IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" "
796 "property.\n" VTRESET,
797 kmod_name);
798 LOG_DELAY();
799 result = false;
800 goto finish;
801 }
802
803 if (!VERS_parse_string(versionString->getCStringNoCopy(),
804 &plist_vers)) {
805
806 IOLog(VTYELLOW "verify_kmod(): Property list for kmod \"%s\" has "
807 "an invalid version.\n" VTRESET, kmod_info->name);
808 LOG_DELAY();
809 result = false;
810 goto finish;
811 }
812
813 if (kmod_vers != plist_vers) {
814 IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" and its property list "
815 "claim different versions (%s & %s).\n" VTRESET,
816 kmod_info->name,
817 kmod_info->version,
818 versionString->getCStringNoCopy());
819 LOG_DELAY();
820 result = false;
821 goto finish;
822 }
823
824
825 finish:
826
827 // FIXME: make this really return the result after conversion
828 return true;
829
830 return result;
831 }
832
833
834 /*********************************************************************
835 * This function takes a dependency list containing a series of
836 * already-loaded module names, followed by a single name for a module
837 * that hasn't yet been loaded. It invokes kld_load_from_memory() to
838 * build symbol info for the already-loaded modules, and then finally
839 * loads the actually requested module.
840 *********************************************************************/
841 static
842 kern_return_t load_kmod(OSArray * dependencyList) {
843 kern_return_t result = KERN_SUCCESS;
844
845 unsigned int num_dependencies = 0;
846 kmod_info_t ** kmod_dependencies = NULL;
847 unsigned int i;
848 OSString * requestedKmodName; // don't release
849 const char * requested_kmod_name;
850 OSString * currentKmodName; // don't release
851 char * kmod_address;
852 unsigned long kmod_size;
853 struct mach_header * kmod_header;
854 unsigned long kld_result;
855 int do_kld_unload = 0;
856 kmod_info_t * kmod_info;
857 kmod_t kmod_id;
858
859
860 /* Separate the requested kmod from its dependencies.
861 */
862 i = dependencyList->getCount();
863 if (i == 0) {
864 IOLog("load_kmod(): Called with empty list.\n");
865 LOG_DELAY();
866 result = KERN_FAILURE;
867 goto finish;
868 } else {
869 i--; // make i be the index of the last entry
870 }
871
872 requestedKmodName = OSDynamicCast(OSString, dependencyList->getObject(i));
873 if (!requestedKmodName) {
874 IOLog("load_kmod(): Called with invalid list of kmod names.\n");
875 LOG_DELAY();
876 result = KERN_FAILURE;
877 goto finish;
878 }
879 requested_kmod_name = requestedKmodName->getCStringNoCopy();
880 dependencyList->removeObject(i);
881
882 /* If the requested kmod is already loaded, there's no work to do.
883 */
884 kmod_info = kmod_lookupbyname(requested_kmod_name);
885 if (kmod_info) {
886 // FIXME: Need to check for version mismatch if already loaded.
887 result = KERN_SUCCESS;
888 goto finish;
889 }
890
891
892 /* Do the KLD loads for the already-loaded modules in order to get
893 * their symbols.
894 */
895 kld_address_func(&address_for_loaded_kmod);
896
897 num_dependencies = dependencyList->getCount();
898 kmod_dependencies = (kmod_info_t **)kalloc(num_dependencies *
899 sizeof(kmod_info_t *));
900 if (!kmod_dependencies) {
901 IOLog("load_kmod(): Failed to allocate memory for dependency array "
902 "during load of kmod \"%s\".\n", requested_kmod_name);
903 LOG_DELAY();
904 result = KERN_FAILURE;
905 goto finish;
906 }
907
908 for (i = 0; i < num_dependencies; i++) {
909
910 currentKmodName = OSDynamicCast(OSString,
911 dependencyList->getObject(i));
912
913 if (!currentKmodName) {
914 IOLog("load_kmod(): Invalid dependency name at index %d for "
915 "kmod \"%s\".\n", i, requested_kmod_name);
916 LOG_DELAY();
917 result = KERN_FAILURE;
918 goto finish;
919 }
920
921 const char * current_kmod_name = currentKmodName->getCStringNoCopy();
922
923 // These globals are needed by the kld_address functions
924 g_current_kmod_info = kmod_lookupbyname(current_kmod_name);
925 g_current_kmod_name = current_kmod_name;
926
927 if (!g_current_kmod_info) {
928 IOLog("load_kmod(): Missing dependency \"%s\".\n",
929 current_kmod_name);
930 LOG_DELAY();
931 result = KERN_FAILURE;
932 goto finish;
933 }
934
935 /* Record the current kmod as a dependency of the requested
936 * one. This will be used in building references after the
937 * load is complete.
938 */
939 kmod_dependencies[i] = g_current_kmod_info;
940
941 /* If the current kmod's size is zero it means that we have a
942 * fake in-kernel dependency. If so then don't have to arrange
943 * for its symbol table to be reloaded as it is
944 * part of the kernel's symbol table..
945 */
946 if (!g_current_kmod_info->size)
947 continue;
948
949 if (!get_text_info_for_kmod(current_kmod_name,
950 &kmod_address, &kmod_size)) {
951
952 IOLog("get_text_info_for_kmod() failed for dependency kmod "
953 "\"%s\".\n", current_kmod_name);
954 LOG_DELAY();
955 result = KERN_FAILURE;
956 goto finish;
957 }
958
959 kld_result = kld_load_from_memory(&kmod_header,
960 current_kmod_name,
961 (char *)kmod_address,
962 kmod_size);
963
964 if (kld_result) {
965 do_kld_unload = 1;
966 }
967
968 if (!kld_result || !link_load_address) {
969 IOLog("kld_load_from_memory() failed for dependency kmod "
970 "\"%s\".\n", current_kmod_name);
971 LOG_DELAY();
972 result = KERN_FAILURE;
973 goto finish;
974 }
975
976 kld_forget_symbol("_kmod_info");
977 }
978
979 /*****
980 * Now that we've done all the dependencies, which should have already
981 * been loaded, we do the last requested module, which should not have
982 * already been loaded.
983 */
984 kld_address_func(&alloc_for_kmod);
985
986 g_current_kmod_name = requested_kmod_name;
987 g_current_kmod_info = 0; // there is no kmod yet
988
989 if (!get_text_info_for_kmod(requested_kmod_name,
990 &kmod_address, &kmod_size)) {
991 IOLog("load_kmod: get_text_info_for_kmod() failed for "
992 "kmod \"%s\".\n", requested_kmod_name);
993 LOG_DELAY();
994 result = KERN_FAILURE;
995 goto finish;
996 }
997
998 kld_result = kld_load_from_memory(&kmod_header,
999 requested_kmod_name,
1000 (char *)kmod_address,
1001 kmod_size);
1002
1003 if (kld_result) {
1004 do_kld_unload = 1;
1005 }
1006
1007 if (!kld_result || !link_load_address) {
1008 IOLog("load_kmod(): kld_load_from_memory() failed for "
1009 "kmod \"%s\".\n", requested_kmod_name);
1010 LOG_DELAY();
1011 result = KERN_FAILURE;
1012 goto finish;
1013 }
1014
1015
1016 /* Copy the linked header and image into the vm_allocated buffer.
1017 * Move each onto the appropriate page-aligned boundary as given
1018 * by the global link_... variables.
1019 */
1020 bzero((char *)link_buffer_address, link_buffer_size);
1021 // bcopy() is (from, to, length)
1022 bcopy((char *)kmod_header, (char *)link_buffer_address, link_header_size);
1023 bcopy((char *)kmod_header + link_header_size,
1024 (char *)link_buffer_address + round_page(link_header_size),
1025 link_load_size - link_header_size);
1026
1027
1028 /* Get the kmod_info struct for the newly-loaded kmod.
1029 */
1030 if (!kld_lookup("_kmod_info", (unsigned long *)&kmod_info)) {
1031 IOLog("kld_lookup() of \"_kmod_info\" failed for "
1032 "kmod \"%s\".\n", requested_kmod_name);
1033 LOG_DELAY();
1034 result = KERN_FAILURE;
1035 goto finish;
1036 }
1037
1038
1039 if (!verify_kmod(requested_kmod_name, kmod_info)) {
1040 // verify_kmod() logs a meaningful message
1041 result = KERN_FAILURE;
1042 goto finish;
1043 }
1044
1045
1046 /* kld_lookup of _kmod_info yielded the actual linked address,
1047 * so now that we've copied the data into its real place,
1048 * we can set this stuff.
1049 */
1050 kmod_info->address = link_buffer_address;
1051 kmod_info->size = link_buffer_size;
1052 kmod_info->hdr_size = round_page(link_header_size);
1053
1054 /* We've written data and instructions, so *flush* the data cache
1055 * and *invalidate* the instruction cache.
1056 */
1057 flush_dcache(link_buffer_address, link_buffer_size, false);
1058 invalidate_icache(link_buffer_address, link_buffer_size, false);
1059
1060
1061 /* Register the new kmod with the kernel proper.
1062 */
1063 if (kmod_create_internal(kmod_info, &kmod_id) != KERN_SUCCESS) {
1064 IOLog("load_kmod(): kmod_create() failed for "
1065 "kmod \"%s\".\n", requested_kmod_name);
1066 LOG_DELAY();
1067 result = KERN_FAILURE;
1068 goto finish;
1069 }
1070
1071 IOLog("kmod id %d successfully created at 0x%lx, size %ld.\n",
1072 (unsigned int)kmod_id, link_buffer_address, link_buffer_size);
1073 LOG_DELAY();
1074
1075 /* Record dependencies for the newly-loaded kmod.
1076 */
1077 for (i = 0; i < num_dependencies; i++) {
1078 kmod_info_t * cur_dependency_info;
1079 kmod_t packed_id;
1080 cur_dependency_info = kmod_dependencies[i];
1081 packed_id = KMOD_PACK_IDS(kmod_id, cur_dependency_info->id);
1082 if (kmod_retain(packed_id) != KERN_SUCCESS) {
1083 IOLog("load_kmod(): kmod_retain() failed for "
1084 "kmod \"%s\".\n", requested_kmod_name);
1085 LOG_DELAY();
1086 kmod_destroy_internal(kmod_id);
1087 result = KERN_FAILURE;
1088 goto finish;
1089 }
1090 }
1091
1092 /* Start the kmod (which invokes constructors for I/O Kit
1093 * drivers.
1094 */
1095 // kmod_start_or_stop(id, start?, user data, datalen)
1096 if (kmod_start_or_stop(kmod_id, 1, 0, 0) != KERN_SUCCESS) {
1097 IOLog("load_kmod(): kmod_start_or_stop() failed for "
1098 "kmod \"%s\".\n", requested_kmod_name);
1099 LOG_DELAY();
1100 kmod_destroy_internal(kmod_id);
1101 result = KERN_FAILURE;
1102 goto finish;
1103 }
1104
1105 finish:
1106
1107 /* Only do a kld_unload_all() if at least one load happened.
1108 */
1109 if (do_kld_unload) {
1110 kld_unload_all(/* deallocate sets */ 1);
1111
1112 }
1113
1114 /* If the link failed, blow away the allocated link buffer.
1115 */
1116 if (result != KERN_SUCCESS && link_buffer_address) {
1117 vm_deallocate(kernel_map, link_buffer_address, link_buffer_size);
1118 }
1119
1120 if (kmod_dependencies) {
1121 kfree((unsigned int)kmod_dependencies,
1122 num_dependencies * sizeof(kmod_info_t *));
1123 }
1124
1125 /* Reset these static global variables for the next call.
1126 */
1127 g_current_kmod_name = NULL;
1128 g_current_kmod_info = NULL;
1129 link_buffer_address = 0;
1130 link_load_address = 0;
1131 link_load_size = 0;
1132 link_buffer_size = 0;
1133 link_header_size = 0;
1134
1135 return result;
1136 }
1137
1138
1139 /*********************************************************************
1140 * This is the function that IOCatalogue calls in order to load a kmod.
1141 * It first checks whether the kmod is already loaded. If the kmod
1142 * isn't loaded, this function builds a dependency list and calls
1143 * load_kmod() repeatedly to guarantee that each dependency is in fact
1144 * loaded.
1145 *********************************************************************/
1146 __private_extern__
1147 kern_return_t load_kernel_extension(char * kmod_name) {
1148 kern_return_t result = KERN_SUCCESS;
1149 kmod_info_t * kmod_info;
1150 OSArray * dependencyList = NULL; // must release
1151 OSArray * curDependencyList = NULL; // must release
1152
1153
1154 /* This must be the very first thing done by this function.
1155 */
1156 IOLockLock(kld_lock);
1157
1158
1159 /* See if the kmod is already loaded.
1160 */
1161 kmod_info = kmod_lookupbyname(kmod_name);
1162 if (kmod_info) { // NOT checked
1163 result = KERN_SUCCESS;
1164 goto finish;
1165 }
1166
1167 // FIXME: Need to check whether kmod is built into the kernel!
1168
1169 /* It isn't loaded; build a dependency list and
1170 * load those.
1171 */
1172 unsigned int count;
1173 unsigned int i;
1174 dependencyList = getDependencyListForKmod(kmod_name);
1175 if (!dependencyList) {
1176 IOLog("load_kernel_extension(): "
1177 "Can't get dependencies for kernel extension \"%s\".\n",
1178 kmod_name);
1179 LOG_DELAY();
1180 result = KERN_FAILURE;
1181 goto finish;
1182 }
1183
1184 if (!verifyCompatibleVersions(dependencyList)) {
1185 IOLog(VTYELLOW "load_kernel_extension(): "
1186 "Version mismatch for kernel extension \"%s\".\n" VTRESET,
1187 kmod_name);
1188 LOG_DELAY();
1189 #if 0
1190 // FIXME: This is currently a warning only; when kexts are updated
1191 // this will become an error.
1192 result = KERN_FAILURE;
1193 goto finish;
1194 #else
1195 IOLog(VTYELLOW "Loading anyway.\n" VTRESET);
1196 #endif 0
1197 }
1198
1199 count = dependencyList->getCount();
1200 for (i = 0; i < count; i++) {
1201 kern_return_t load_result;
1202 OSString * curKmodName; // don't release
1203 const char * cur_kmod_name;
1204
1205 curKmodName = OSDynamicCast(OSString,
1206 dependencyList->getObject(i));
1207 cur_kmod_name = curKmodName->getCStringNoCopy();
1208 curDependencyList = getDependencyListForKmod(cur_kmod_name);
1209
1210 load_result = load_kmod(curDependencyList);
1211 if (load_result != KERN_SUCCESS) {
1212 IOLog("load_kernel_extension(): "
1213 "load_kmod() failed for kmod \"%s\".\n",
1214 cur_kmod_name);
1215 LOG_DELAY();
1216 result = load_result;
1217 goto finish;
1218 }
1219 curDependencyList->release();
1220 curDependencyList = NULL;
1221 }
1222
1223
1224 finish:
1225
1226 if (dependencyList) {
1227 dependencyList->release();
1228 dependencyList = NULL;
1229 }
1230 if (curDependencyList) {
1231 curDependencyList->release();
1232 curDependencyList = NULL;
1233 }
1234
1235 /* This must be the very last thing done before returning.
1236 */
1237 IOLockUnlock(kld_lock);
1238
1239 return result;
1240 }