]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
xnu-1486.2.11.tar.gz
[apple/xnu.git] / libkern / c++ / OSKext.cpp
1 /*
2 * Copyright (c) 2008-2009 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 extern "C" {
30 #include <kern/clock.h>
31 #include <kern/host.h>
32 #include <kern/kext_alloc.h>
33 #include <kextd/kextd_mach.h>
34 #include <libkern/kernel_mach_header.h>
35 #include <libkern/kext_panic_report.h>
36 #include <libkern/kext_request_keys.h>
37 #include <libkern/mkext.h>
38 #include <libkern/prelink.h>
39 #include <libkern/version.h>
40 #include <libkern/zlib.h>
41 #include <mach/mach_vm.h>
42 #include <sys/sysctl.h>
43 };
44
45 #include <libkern/OSKextLibPrivate.h>
46 #include <libkern/c++/OSKext.h>
47 #include <libkern/c++/OSLib.h>
48
49 #include <IOKit/IOLib.h>
50 #include <IOKit/IOCatalogue.h>
51 #include <IOKit/IORegistryEntry.h>
52 #include <IOKit/IOService.h>
53
54 #if PRAGMA_MARK
55 #pragma mark External & Internal Function Protos
56 #endif
57 /*********************************************************************
58 *********************************************************************/
59 extern "C" {
60 // in libkern/OSKextLib.cpp, not in header for a reason.
61 extern kern_return_t OSKextPingKextd(void);
62
63 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
64 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
65 extern void OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment);
66 extern void OSRuntimeUnloadCPP(kmod_info_t * ki, void * data);
67
68 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
69 }
70
71 static OSReturn _OSKextCreateRequest(
72 const char * predicate,
73 OSDictionary ** requestP);
74 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
75 static OSObject * _OSKextGetRequestArgument(
76 OSDictionary * requestDict,
77 const char * argName);
78 static bool _OSKextSetRequestArgument(
79 OSDictionary * requestDict,
80 const char * argName,
81 OSObject * value);
82 static void * _OSKextExtractPointer(OSData * wrapper);
83 static OSReturn _OSDictionarySetCStringValue(
84 OSDictionary * dict,
85 const char * key,
86 const char * value);
87 #if CONFIG_MACF_KEXT
88 static void * MACFCopyModuleDataForKext(
89 OSKext * theKext,
90 mach_msg_type_number_t * datalen);
91 #endif /* CONFIG_MACF_KEXT */
92
93 #if PRAGMA_MARK
94 #pragma mark Constants & Macros
95 #endif
96 /*********************************************************************
97 * Constants & Macros
98 *********************************************************************/
99
100 /* A typical Snow Leopard system has a bit under 120 kexts loaded.
101 * Use this number to create containers.
102 */
103 #define kOSKextTypicalLoadCount (120)
104
105 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
106 * A loaded kext will no dependents or external retains will have 2 retains.
107 */
108 #define kOSKextMinRetainCount (1)
109 #define kOSKextMinLoadedRetainCount (2)
110
111 /**********
112 * Strings and substrings used in dependency resolution.
113 */
114 #define APPLE_KEXT_PREFIX "com.apple."
115 #define KERNEL_LIB "com.apple.kernel"
116
117 #define PRIVATE_KPI "com.apple.kpi.private"
118
119 /* Version for compatbility pseudokexts (com.apple.kernel.*),
120 * compatible back to v6.0.
121 */
122 #define KERNEL6_LIB "com.apple.kernel.6.0"
123 #define KERNEL6_VERSION "7.9.9"
124
125 #define KERNEL_LIB_PREFIX "com.apple.kernel."
126 #define KPI_LIB_PREFIX "com.apple.kpi."
127
128 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
129
130 /*********************************************************************
131 * infoDict keys for internally-stored data. Saves on ivar slots for
132 * objects we don't keep around past boot time or during active load.
133 *********************************************************************/
134
135 /* A usable, uncompressed file is stored under this key.
136 */
137 #define _kOSKextExecutableKey "_OSKextExecutable"
138
139 /* An indirect reference to the executable file from an mkext
140 * is stored under this key.
141 */
142 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
143
144 /* If the file is contained in a larger buffer laid down by the booter or
145 * sent from user space, the OSKext stores that OSData under this key so that
146 * references are properly tracked. This is always an mkext, right now.
147 */
148 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
149
150 #if PRAGMA_MARK
151 #pragma mark Typedefs
152 #endif
153 /*********************************************************************
154 * Typedefs
155 *********************************************************************/
156
157 /*********************************************************************
158 * MkextEntryRef describes the contents of an OSData object
159 * referencing a file entry from an mkext so that we can uncompress
160 * (if necessary) and extract it on demand.
161 *
162 * It contains the mkextVersion in case we ever wind up supporting
163 * multiple mkext formats. Mkext format 1 is officially retired as of
164 * Snow Leopard.
165 *********************************************************************/
166 typedef struct MkextEntryRef {
167 mkext_basic_header * mkext; // beginning of whole mkext file
168 void * fileinfo; // mkext2_file_entry or equiv; see mkext.h
169 } MkextEntryRef;
170
171 #if PRAGMA_MARK
172 #pragma mark Global and static Module Variables
173 #endif
174 /*********************************************************************
175 * Global & static variables, used to keep track of kexts.
176 *********************************************************************/
177
178 static bool sPrelinkBoot = false;
179 static bool sSafeBoot = false;
180
181 /******
182 * sKextLock is the principal lock for OSKext. Below, there is also an
183 * sKextInnerLock used to guard access to data accessed on in-calls from
184 * IOService. This 2nd lock is required to prevent a deadlock
185 * with IOService calling back into OSKext::considerUnloads()
186 * on a separate thread during a kext load operation.
187 */
188 static IORecursiveLock * sKextLock = NULL;
189
190 static OSDictionary * sKextsByID = NULL;
191 static OSArray * sLoadedKexts = NULL;
192
193 // Requests to kextd waiting to be picked up.
194 static OSArray * sKernelRequests = NULL;
195 // Identifier of kext load requests in sKernelRequests
196 static OSSet * sPostedKextLoadIdentifiers = NULL;
197 static OSArray * sRequestCallbackRecords = NULL;
198
199 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
200 static OSSet * sAllKextLoadIdentifiers = NULL;
201 static KXLDContext * sKxldContext = NULL;
202 static uint32_t sNextLoadTag = 0;
203 static uint32_t sNextRequestTag = 0;
204
205 static bool sUserLoadsActive = false;
206 static bool sKextdActive = false;
207 static bool sDeferredLoadSucceeded = false;
208 static bool sConsiderUnloadsExecuted = false;
209
210 static bool sKernelRequestsEnabled = true;
211 static bool sLoadEnabled = true;
212 static bool sUnloadEnabled = true;
213
214 /*********************************************************************
215 * Stuff for the OSKext representing the kernel itself.
216 **********/
217 static OSKext * sKernelKext = NULL;
218
219 /* Set up a fake kmod_info struct for the kernel.
220 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
221 * before OSKext is initialized; that call only needs the name
222 * and address to be set correctly.
223 *
224 * We don't do much else with the kerne's kmod_info; we never
225 * put it into the kmod list, never adjust the reference count,
226 * and never have kernel components reference it.
227 * For that matter, we don't do much with kmod_info structs
228 * at all anymore! We just keep them filled in for gdb and
229 * binary compability.
230 */
231 kmod_info_t g_kernel_kmod_info = {
232 /* next */ 0,
233 /* info_version */ KMOD_INFO_VERSION,
234 /* id */ 0, // loadTag: kernel is always 0
235 /* name */ kOSKextKernelIdentifier, // bundle identifier
236 /* version */ "0", // filled in in OSKext::initialize()
237 /* reference_count */ -1, // never adjusted; kernel never unloads
238 /* reference_list */ NULL,
239 /* address */ (vm_address_t)&_mh_execute_header,
240 /* size */ 0, // filled in in OSKext::initialize()
241 /* hdr_size */ 0,
242 /* start */ 0,
243 /* stop */ 0
244 };
245
246 extern "C" {
247 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
248 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
249 // misc_protos.h, db_low_trace.c, kgmacros
250 // 'kmod' is a holdover from the old kmod system, we can't rename it.
251 kmod_info_t * kmod = NULL;
252
253 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
254
255 static char * unloaded_kext_paniclist = NULL;
256 static uint32_t unloaded_kext_paniclist_size = 0;
257 static uint32_t unloaded_kext_paniclist_length = 0;
258 AbsoluteTime last_loaded_timestamp;
259
260 static char * loaded_kext_paniclist = NULL;
261 static uint32_t loaded_kext_paniclist_size = 0;
262 static uint32_t loaded_kext_paniclist_length = 0;
263 AbsoluteTime last_unloaded_timestamp;
264 static void * last_unloaded_address = NULL;
265 #if __LP64__
266 static uint64_t last_unloaded_size = 0;
267 #else
268 static uint32_t last_unloaded_size = 0;
269 #endif /* __LP64__ */
270
271 };
272
273 /*********************************************************************
274 * Because we can start IOService matching from OSKext (via IOCatalogue)
275 * and IOService can call into OSKext, there is potential for cross-lock
276 * contention, so OSKext needs two locks. The regular sKextLock above
277 * guards most OSKext class/static variables, and sKextInnerLock guards
278 * variables that can be accessed on in-calls from IOService, currently:
279 *
280 * * OSKext::considerUnloads()
281 *
282 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
283 *
284 * When both sKextLock and sKextInnerLock need to be taken,
285 * always lock sKextLock first and unlock it second. Never take both
286 * locks in an entry point to OSKext; if you need to do so, you must
287 * spawn an independent thread to avoid potential deadlocks for threads
288 * calling into OSKext.
289 *
290 * All static variables from here to the closing comment block fall
291 * under sKextInnerLock.
292 **********/
293 static IORecursiveLock * sKextInnerLock = NULL;
294
295 static bool sAutounloadEnabled = true;
296 static bool sConsiderUnloadsCalled = false;
297 static bool sConsiderUnloadsPending = false;
298
299 static unsigned int sConsiderUnloadDelay = 60; // seconds
300 static thread_call_t sUnloadCallout = 0;
301 static thread_call_t sDestroyLinkContextThread = 0; // one-shot, one-at-a-time thread
302 static bool sSystemSleep = false; // true when system going to sleep
303
304 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
305 kOSKextLogVerboseFlagsMask;
306 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
307 static bool sBootArgLogFilterFound = false;
308 SYSCTL_INT(_debug, OID_AUTO, kextlog, CTLFLAG_RW, &sKernelLogFilter,
309 sKernelLogFilter, "kernel kext logging");
310
311 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
312 static OSArray * sUserSpaceLogSpecArray = NULL;
313 static OSArray * sUserSpaceLogMessageArray = NULL;
314
315 /*********
316 * End scope for sKextInnerLock-protected variables.
317 *********************************************************************/
318
319 #if PRAGMA_MARK
320 #pragma mark OSData callbacks (need to move to OSData)
321 #endif
322 /*********************************************************************
323 * C functions used for callbacks.
324 *********************************************************************/
325 extern "C" {
326 void osdata_kmem_free(void * ptr, unsigned int length) {
327 kmem_free(kernel_map, (vm_address_t)ptr, length);
328 return;
329 }
330
331 void osdata_phys_free(void * ptr, unsigned int length) {
332 ml_static_mfree((vm_offset_t)ptr, length);
333 return;
334 }
335
336 void osdata_vm_deallocate(void * ptr, unsigned int length)
337 {
338 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
339 return;
340 }
341 };
342
343 #if PRAGMA_MARK
344 #pragma mark KXLD Allocation Callback
345 #endif
346 /*********************************************************************
347 * KXLD Allocation Callback
348 *********************************************************************/
349 kxld_addr_t
350 kern_allocate(
351 u_long size,
352 KXLDAllocateFlags * flags,
353 void * user_data)
354 {
355 vm_address_t result = 0; // returned
356 kern_return_t mach_result = KERN_FAILURE;
357 bool success = false;
358 OSKext * theKext = (OSKext *)user_data;
359 u_long roundSize = round_page(size);
360 OSData * linkBuffer = NULL; // must release
361
362 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
363 if (mach_result != KERN_SUCCESS) {
364 OSKextLog(theKext,
365 kOSKextLogErrorLevel |
366 kOSKextLogGeneralFlag,
367 "Can't allocate kernel memory to link %s.",
368 theKext->getIdentifierCString());
369 goto finish;
370 }
371
372 /* Create an OSData wrapper for the allocated buffer.
373 * Note that we do not set a dealloc function on it here.
374 * We have to call vm_map_unwire() on it in OSKext::unload()
375 * and an OSData dealloc function can't take all those parameters.
376 */
377 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
378 if (!linkBuffer) {
379 OSKextLog(theKext,
380 kOSKextLogErrorLevel |
381 kOSKextLogGeneralFlag,
382 "Can't allocate linked executable wrapper for %s.",
383 theKext->getIdentifierCString());
384 goto finish;
385 }
386
387 OSKextLog(theKext,
388 kOSKextLogProgressLevel |
389 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
390 "Allocated link buffer for kext %s at %p (%lu bytes).",
391 theKext->getIdentifierCString(),
392 (void *)result, (unsigned long)roundSize);
393
394 theKext->setLinkedExecutable(linkBuffer);
395
396 *flags = kKxldAllocateWritable;
397 success = true;
398
399 finish:
400 if (!success && result) {
401 kext_free(result, roundSize);
402 result = 0;
403 }
404
405 OSSafeRelease(linkBuffer);
406
407 return (kxld_addr_t)result;
408 }
409
410 /*********************************************************************
411 *********************************************************************/
412 void
413 kxld_log_callback(
414 KXLDLogSubsystem subsystem,
415 KXLDLogLevel level,
416 const char * format,
417 va_list argList,
418 void * user_data)
419 {
420 OSKext *theKext = (OSKext *) user_data;
421 OSKextLogSpec logSpec = 0;
422
423 switch (subsystem) {
424 case kKxldLogLinking:
425 logSpec |= kOSKextLogLinkFlag;
426 break;
427 case kKxldLogPatching:
428 logSpec |= kOSKextLogPatchFlag;
429 break;
430 }
431
432 switch (level) {
433 case kKxldLogExplicit:
434 logSpec |= kOSKextLogExplicitLevel;
435 break;
436 case kKxldLogErr:
437 logSpec |= kOSKextLogErrorLevel;
438 break;
439 case kKxldLogWarn:
440 logSpec |= kOSKextLogWarningLevel;
441 break;
442 case kKxldLogBasic:
443 logSpec |= kOSKextLogProgressLevel;
444 break;
445 case kKxldLogDetail:
446 logSpec |= kOSKextLogDetailLevel;
447 break;
448 case kKxldLogDebug:
449 logSpec |= kOSKextLogDebugLevel;
450 break;
451 }
452
453 OSKextVLog(theKext, logSpec, format, argList);
454 }
455
456 #if PRAGMA_MARK
457 #pragma mark Module Config (Startup & Shutdown)
458 #endif
459 /*********************************************************************
460 * Module Config (Class Definition & Class Methods)
461 *********************************************************************/
462 #define super OSObject
463 OSDefineMetaClassAndStructors(OSKext, OSObject)
464
465 /*********************************************************************
466 *********************************************************************/
467 /* static */
468 void
469 OSKext::initialize(void)
470 {
471 OSData * kernelExecutable = NULL; // do not release
472 u_char * kernelStart = NULL; // do not free
473 size_t kernelLength = 0;
474 OSString * scratchString = NULL; // must release
475 IORegistryEntry * registryRoot = NULL; // do not release
476 OSNumber * kernelCPUType = NULL; // must release
477 OSNumber * kernelCPUSubtype = NULL; // must release
478 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
479 bool setResult = false;
480 uint64_t * timestamp = 0;
481 char bootArgBuffer[16]; // for PE_parse_boot_argn w/strings
482
483 /* This must be the first thing allocated. Everything else grabs this lock.
484 */
485 sKextLock = IORecursiveLockAlloc();
486 sKextInnerLock = IORecursiveLockAlloc();
487 assert(sKextLock);
488 assert(sKextInnerLock);
489
490 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
491 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
492 sKernelRequests = OSArray::withCapacity(0);
493 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
494 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
495 sRequestCallbackRecords = OSArray::withCapacity(0);
496 assert(sKextsByID && sLoadedKexts && sKernelRequests &&
497 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
498 sRequestCallbackRecords);
499
500 /* Read the log flag boot-args and set the log flags.
501 */
502 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof("kextlog=0x00000000 "))) {
503 sBootArgLogFilterFound = true;
504 sKernelLogFilter = bootLogFilter;
505 // log this if any flags are set
506 OSKextLog(/* kext */ NULL,
507 kOSKextLogBasicLevel |
508 kOSKextLogFlagsMask,
509 "Kernel kext log filter 0x%x per kextlog boot arg.",
510 (unsigned)sKernelLogFilter);
511 }
512
513 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
514 sizeof(bootArgBuffer)) ? true : false;
515
516 if (sSafeBoot) {
517 OSKextLog(/* kext */ NULL,
518 kOSKextLogWarningLevel |
519 kOSKextLogGeneralFlag,
520 "SAFE BOOT DETECTED - "
521 "only valid OSBundleRequired kexts will be loaded.");
522 }
523
524 /* Set up an OSKext instance to represent the kernel itself.
525 */
526 sKernelKext = new OSKext;
527 assert(sKernelKext);
528
529 kernelStart = (u_char *)&_mh_execute_header;
530 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
531 kernelExecutable = OSData::withBytesNoCopy(
532 kernelStart, kernelLength);
533 assert(kernelExecutable);
534
535 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
536 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
537
538 sKernelKext->version = OSKextParseVersionString(osrelease);
539 sKernelKext->compatibleVersion = sKernelKext->version;
540 sKernelKext->linkedExecutable = kernelExecutable;
541 // linkState will be set first time we do a link
542
543 sKernelKext->flags.hasAllDependencies = 1;
544 sKernelKext->flags.kernelComponent = 1;
545 sKernelKext->flags.prelinked = 0;
546 sKernelKext->flags.loaded = 1;
547 sKernelKext->flags.started = 1;
548 sKernelKext->flags.CPPInitialized = 0;
549
550 sKernelKext->kmod_info = &g_kernel_kmod_info;
551 strlcpy(g_kernel_kmod_info.version, osrelease,
552 sizeof(g_kernel_kmod_info.version));
553 g_kernel_kmod_info.size = kernelLength;
554 g_kernel_kmod_info.id = sKernelKext->loadTag;
555
556 /* Cons up an info dict, so we don't have to have special-case
557 * checking all over.
558 */
559 sKernelKext->infoDict = OSDictionary::withCapacity(5);
560 assert(sKernelKext->infoDict);
561 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
562 sKernelKext->bundleID);
563 assert(setResult);
564 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
565 kOSBooleanTrue);
566 assert(setResult);
567
568 scratchString = OSString::withCStringNoCopy(osrelease);
569 assert(scratchString);
570 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
571 scratchString);
572 assert(setResult);
573 OSSafeReleaseNULL(scratchString);
574
575 scratchString = OSString::withCStringNoCopy("mach_kernel");
576 assert(scratchString);
577 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
578 scratchString);
579 assert(setResult);
580 OSSafeReleaseNULL(scratchString);
581
582 /* Add the kernel kext to the bookkeeping dictionaries. Note that
583 * the kernel kext doesn't have a kmod_info struct. copyInfo()
584 * gathers info from other places anyhow.
585 */
586 setResult = sKextsByID->setObject(sKernelKext->bundleID, sKernelKext);
587 assert(setResult);
588 setResult = sLoadedKexts->setObject(sKernelKext);
589 assert(setResult);
590 sKernelKext->release();
591
592 registryRoot = IORegistryEntry::getRegistryRoot();
593 kernelCPUType = OSNumber::withNumber(
594 (long long unsigned int)_mh_execute_header.cputype,
595 8 * sizeof(_mh_execute_header.cputype));
596 kernelCPUSubtype = OSNumber::withNumber(
597 (long long unsigned int)_mh_execute_header.cpusubtype,
598 8 * sizeof(_mh_execute_header.cpusubtype));
599 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
600
601 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType);
602 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype);
603
604 OSSafeRelease(kernelCPUType);
605 OSSafeRelease(kernelCPUSubtype);
606
607 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
608 *timestamp = 0;
609 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
610 *timestamp = 0;
611
612 OSKextLog(/* kext */ NULL,
613 kOSKextLogProgressLevel |
614 kOSKextLogGeneralFlag,
615 "Kext system initialized.");
616
617 return;
618 }
619
620 /*********************************************************************
621 * This could be in OSKextLib.cpp but we need to hold a lock
622 * while removing all the segments and sKextLock will do.
623 *********************************************************************/
624 /* static */
625 OSReturn
626 OSKext::removeKextBootstrap(void)
627 {
628 OSReturn result = kOSReturnError;
629
630 static bool alreadyDone = false;
631 boolean_t keepsyms = FALSE;
632
633 const char * dt_kernel_header_name = "Kernel-__HEADER";
634 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
635 kernel_mach_header_t * dt_mach_header = NULL;
636 int dt_mach_header_size = 0;
637 struct symtab_command * dt_symtab = NULL;
638 int dt_symtab_size = 0;
639 int dt_result = 0;
640
641 kernel_segment_command_t * seg_to_remove = NULL;
642 #if __ppc__ || __arm__
643 const char * dt_segment_name = NULL;
644 void * segment_paddress = NULL;
645 int segment_size = 0;
646 #endif
647
648 /* This must be the very first thing done by this function.
649 */
650 IORecursiveLockLock(sKextLock);
651
652 /* If we already did this, it's a success.
653 */
654 if (alreadyDone) {
655 result = kOSReturnSuccess;
656 goto finish;
657 }
658
659 OSKextLog(/* kext */ NULL,
660 kOSKextLogProgressLevel |
661 kOSKextLogGeneralFlag,
662 "Jettisoning kext bootstrap segments.");
663
664 PE_parse_boot_argn("keepsyms", &keepsyms, sizeof(keepsyms));
665
666 /*****
667 * Dispose of unnecessary stuff that the booter didn't need to load.
668 */
669 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
670 (void **)&dt_mach_header, &dt_mach_header_size);
671 if (dt_result == 0 && dt_mach_header) {
672 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
673 round_page_32(dt_mach_header_size));
674 }
675 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
676 (void **)&dt_symtab, &dt_symtab_size);
677 if (dt_result == 0 && dt_symtab) {
678 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
679 round_page_32(dt_symtab_size));
680 }
681
682 /*****
683 * KLD bootstrap segment.
684 */
685 // xxx - should rename KLD segment
686 seg_to_remove = getsegbyname("__KLD");
687 if (seg_to_remove) {
688 OSRuntimeUnloadCPPForSegment(seg_to_remove);
689 }
690
691 #if __ppc__ || __arm__
692 /* Free the memory that was set up by bootx.
693 */
694 dt_segment_name = "Kernel-__KLD";
695 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
696 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
697 (int)segment_size);
698 }
699 #elif __i386__ || __x86_64__
700 /* On x86, use the mapping data from the segment load command to
701 * unload KLD directly.
702 * This may invalidate any assumptions about "avail_start"
703 * defining the lower bound for valid physical addresses.
704 */
705 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
706 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
707 }
708 #else
709 #error arch
710 #endif
711
712 seg_to_remove = NULL;
713
714 /*****
715 * Prelinked kernel's symtab (if there is one).
716 */
717 kernel_section_t * sect;
718 sect = getsectbyname("__PRELINK", "__symtab");
719 if (sect && sect->addr && sect->size) {
720 ml_static_mfree(sect->addr, sect->size);
721 }
722
723 /*****
724 * Dump the LINKEDIT segment, unless keepsyms is set.
725 */
726 if (!keepsyms) {
727 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
728 if (seg_to_remove) {
729 OSRuntimeUnloadCPPForSegment(seg_to_remove);
730 }
731
732 #if __ppc__ || __arm__
733 dt_segment_name = "Kernel-__LINKEDIT";
734 if (0 == IODTGetLoaderInfo(dt_segment_name,
735 &segment_paddress, &segment_size)) {
736
737 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
738 (int)segment_size);
739 }
740 #elif __i386__ || __x86_64__
741 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
742 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
743 }
744 #else
745 #error arch
746 #endif
747 } else {
748 OSKextLog(/* kext */ NULL,
749 kOSKextLogBasicLevel |
750 kOSKextLogGeneralFlag,
751 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
752 }
753
754 seg_to_remove = NULL;
755
756 alreadyDone = true;
757 result = kOSReturnSuccess;
758
759 finish:
760
761 /* This must be the very last thing done before returning.
762 */
763 IORecursiveLockUnlock(sKextLock);
764
765 return result;
766 }
767
768 /*********************************************************************
769 *********************************************************************/
770 void
771 OSKext::flushNonloadedKexts(
772 Boolean flushPrelinkedKexts)
773 {
774 OSSet * prelinkedKexts = NULL; // must release
775 OSCollectionIterator * kextIterator = NULL; // must release
776 OSCollectionIterator * prelinkIterator = NULL; // must release
777 const OSSymbol * thisID = NULL; // do not release
778 OSKext * thisKext = NULL; // do not release
779 uint32_t count, i;
780
781 IORecursiveLockLock(sKextLock);
782
783 OSKextLog(/* kext */ NULL,
784 kOSKextLogProgressLevel |
785 kOSKextLogKextBookkeepingFlag,
786 "Flushing nonloaded kexts and other unused data.");
787
788 OSKext::considerDestroyingLinkContext();
789
790 /* If we aren't flushing unused prelinked kexts, we have to put them
791 * aside while we flush everything else so make a container for them.
792 */
793 if (!flushPrelinkedKexts) {
794 prelinkedKexts = OSSet::withCapacity(0);
795 if (!prelinkedKexts) {
796 goto finish;
797 }
798 }
799
800 /* Set aside prelinked kexts (in-use or not) and break
801 * any lingering inter-kext references for nonloaded kexts
802 * so they have min. retain counts.
803 */
804 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
805 if (!kextIterator) {
806 goto finish;
807 }
808
809 while ((thisID = OSDynamicCast(OSSymbol,
810 kextIterator->getNextObject()))) {
811
812 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
813
814 if (thisKext) {
815 if (prelinkedKexts && thisKext->isPrelinked()) {
816 prelinkedKexts->setObject(thisKext);
817 }
818 thisKext->flushDependencies(/* forceIfLoaded */ false);
819 }
820 }
821
822 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
823 */
824 sKextsByID->flushCollection();
825
826 /* Now put the loaded kexts back into the ID dictionary.
827 */
828 count = sLoadedKexts->getCount();
829 for (i = 0; i < count; i++) {
830 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
831 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
832 }
833
834 /* Finally, put back the prelinked kexts if we saved any.
835 */
836 if (prelinkedKexts) {
837 prelinkIterator = OSCollectionIterator::withCollection(prelinkedKexts);
838 if (!prelinkIterator) {
839 goto finish;
840 }
841
842 while ((thisKext = OSDynamicCast(OSKext,
843 prelinkIterator->getNextObject()))) {
844
845 sKextsByID->setObject(thisKext->getIdentifierCString(),
846 thisKext);
847 }
848 }
849
850 finish:
851 IORecursiveLockUnlock(sKextLock);
852
853 OSSafeRelease(prelinkedKexts);
854 OSSafeRelease(kextIterator);
855 OSSafeRelease(prelinkIterator);
856
857 return;
858 }
859
860 /*********************************************************************
861 *********************************************************************/
862 /* static */
863 void
864 OSKext::setKextdActive(Boolean active)
865 {
866 IORecursiveLockLock(sKextLock);
867 sKextdActive = active;
868 if (sKernelRequests->getCount()) {
869 OSKextPingKextd();
870 }
871 IORecursiveLockUnlock(sKextLock);
872
873 return;
874 }
875
876 /*********************************************************************
877 *********************************************************************/
878 /* static */
879 void
880 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
881 {
882 IORecursiveLockLock(sKextLock);
883 sDeferredLoadSucceeded = succeeded;
884 IORecursiveLockUnlock(sKextLock);
885
886 return;
887 }
888
889 /*********************************************************************
890 * Called from IOSystemShutdownNotification.
891 *********************************************************************/
892 /* static */
893 void
894 OSKext::willShutdown(void)
895 {
896 OSReturn checkResult = kOSReturnError;
897 OSDictionary * exitRequest = NULL; // must release
898
899 IORecursiveLockLock(sKextLock);
900
901 OSKext::setLoadEnabled(false);
902 OSKext::setUnloadEnabled(false);
903 OSKext::setAutounloadsEnabled(false);
904 OSKext::setKernelRequestsEnabled(false);
905
906 OSKextLog(/* kext */ NULL,
907 kOSKextLogProgressLevel |
908 kOSKextLogGeneralFlag,
909 "System shutdown; requesting immediate kextd exit.");
910
911 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit,
912 &exitRequest);
913 if (checkResult != kOSReturnSuccess) {
914 goto finish;
915 }
916 if (!sKernelRequests->setObject(exitRequest)) {
917 goto finish;
918 }
919
920 OSKextPingKextd();
921
922 finish:
923 IORecursiveLockUnlock(sKextLock);
924
925 OSSafeRelease(exitRequest);
926 return;
927 }
928
929 /*********************************************************************
930 *********************************************************************/
931 /* static */
932 bool
933 OSKext::getLoadEnabled(void)
934 {
935 bool result;
936
937 IORecursiveLockLock(sKextLock);
938 result = sLoadEnabled;
939 IORecursiveLockUnlock(sKextLock);
940 return result;
941 }
942
943 /*********************************************************************
944 *********************************************************************/
945 /* static */
946 bool
947 OSKext::setLoadEnabled(bool flag)
948 {
949 bool result;
950
951 IORecursiveLockLock(sKextLock);
952 result = sLoadEnabled;
953 sLoadEnabled = (flag ? true : false);
954
955 if (sLoadEnabled != result) {
956 OSKextLog(/* kext */ NULL,
957 kOSKextLogBasicLevel |
958 kOSKextLogLoadFlag,
959 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
960 }
961
962 IORecursiveLockUnlock(sKextLock);
963
964 return result;
965 }
966
967 /*********************************************************************
968 *********************************************************************/
969 /* static */
970 bool
971 OSKext::getUnloadEnabled(void)
972 {
973 bool result;
974
975 IORecursiveLockLock(sKextLock);
976 result = sUnloadEnabled;
977 IORecursiveLockUnlock(sKextLock);
978 return result;
979 }
980
981 /*********************************************************************
982 *********************************************************************/
983 /* static */
984 bool
985 OSKext::setUnloadEnabled(bool flag)
986 {
987 bool result;
988
989 IORecursiveLockLock(sKextLock);
990 result = sUnloadEnabled;
991 sUnloadEnabled = (flag ? true : false);
992 IORecursiveLockUnlock(sKextLock);
993
994 if (sUnloadEnabled != result) {
995 OSKextLog(/* kext */ NULL,
996 kOSKextLogBasicLevel |
997 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
998 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
999 }
1000
1001 return result;
1002 }
1003
1004 /*********************************************************************
1005 * Do not call any function that takes sKextLock here!
1006 *********************************************************************/
1007 /* static */
1008 bool
1009 OSKext::getAutounloadEnabled(void)
1010 {
1011 bool result;
1012
1013 IORecursiveLockLock(sKextInnerLock);
1014 result = sAutounloadEnabled ? true : false;
1015 IORecursiveLockUnlock(sKextInnerLock);
1016 return result;
1017 }
1018
1019 /*********************************************************************
1020 * Do not call any function that takes sKextLock here!
1021 *********************************************************************/
1022 /* static */
1023 bool
1024 OSKext::setAutounloadsEnabled(bool flag)
1025 {
1026 bool result;
1027
1028 IORecursiveLockLock(sKextInnerLock);
1029
1030 result = sAutounloadEnabled;
1031 sAutounloadEnabled = (flag ? true : false);
1032 if (!sAutounloadEnabled && sUnloadCallout) {
1033 thread_call_cancel(sUnloadCallout);
1034 }
1035
1036 if (sAutounloadEnabled != result) {
1037 OSKextLog(/* kext */ NULL,
1038 kOSKextLogBasicLevel |
1039 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1040 "Kext autounloading now %sabled.",
1041 sAutounloadEnabled ? "en" : "dis");
1042 }
1043
1044 IORecursiveLockUnlock(sKextInnerLock);
1045
1046 return result;
1047 }
1048
1049 /*********************************************************************
1050 *********************************************************************/
1051 /* instance method operating on OSKext field */
1052 bool
1053 OSKext::setAutounloadEnabled(bool flag)
1054 {
1055 bool result = flags.autounloadEnabled ? true : false;
1056 flags.autounloadEnabled = flag ? 1 : 0;
1057
1058 if (result != (flag ? true : false)) {
1059 OSKextLog(this,
1060 kOSKextLogProgressLevel |
1061 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1062 "Autounloading for kext %s now %sabled.",
1063 getIdentifierCString(),
1064 flags.autounloadEnabled ? "en" : "dis");
1065 }
1066 return result;
1067 }
1068
1069 /*********************************************************************
1070 *********************************************************************/
1071 /* static */
1072 bool
1073 OSKext::setKernelRequestsEnabled(bool flag)
1074 {
1075 bool result;
1076
1077 IORecursiveLockLock(sKextLock);
1078 result = sKernelRequestsEnabled;
1079 sKernelRequestsEnabled = flag ? true : false;
1080
1081 if (sKernelRequestsEnabled != result) {
1082 OSKextLog(/* kext */ NULL,
1083 kOSKextLogBasicLevel |
1084 kOSKextLogGeneralFlag,
1085 "Kernel requests now %sabled.",
1086 sKernelRequestsEnabled ? "en" : "dis");
1087 }
1088 IORecursiveLockUnlock(sKextLock);
1089 return result;
1090 }
1091
1092 /*********************************************************************
1093 *********************************************************************/
1094 /* static */
1095 bool
1096 OSKext::getKernelRequestsEnabled(void)
1097 {
1098 bool result;
1099
1100 IORecursiveLockLock(sKextLock);
1101 result = sKernelRequestsEnabled;
1102 IORecursiveLockUnlock(sKextLock);
1103 return result;
1104 }
1105
1106 #if PRAGMA_MARK
1107 #pragma mark Kext Life Cycle
1108 #endif
1109 /*********************************************************************
1110 *********************************************************************/
1111 OSKext *
1112 OSKext::withPrelinkedInfoDict(
1113 OSDictionary * anInfoDict)
1114 {
1115 OSKext * newKext = new OSKext;
1116
1117 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict)) {
1118 newKext->release();
1119 return NULL;
1120 }
1121
1122 return newKext;
1123 }
1124
1125 /*********************************************************************
1126 *********************************************************************/
1127 bool
1128 OSKext::initWithPrelinkedInfoDict(
1129 OSDictionary * anInfoDict)
1130 {
1131 bool result = false;
1132 kern_return_t alloc_result = KERN_SUCCESS;
1133 OSString * kextPath = NULL; // do not release
1134 OSNumber * addressNum = NULL; // reused; do not release
1135 OSNumber * lengthNum = NULL; // reused; do not release
1136 void * data = NULL; // do not free
1137 void * srcData = NULL; // do not free
1138 OSData * prelinkedExecutable = NULL; // must release
1139 void * linkStateCopy = NULL; // kmem_free on error
1140 uint32_t linkStateLength = 0;
1141 uint32_t length = 0; // reused
1142
1143 if (!super::init()) {
1144 goto finish;
1145 }
1146
1147 /* Get the path. Don't look for an arch-specific path property.
1148 */
1149 kextPath = OSDynamicCast(OSString,
1150 anInfoDict->getObject(kPrelinkBundlePathKey));
1151
1152 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1153 goto finish;
1154 }
1155
1156 /* Don't need the path to be in the info dictionary any more.
1157 */
1158 anInfoDict->removeObject(kPrelinkBundlePathKey);
1159
1160 /* If we have a link state, create an OSData wrapper for it.
1161 */
1162 addressNum = OSDynamicCast(OSNumber,
1163 anInfoDict->getObject(kPrelinkLinkStateKey));
1164 if (addressNum) {
1165 lengthNum = OSDynamicCast(OSNumber,
1166 anInfoDict->getObject(kPrelinkLinkStateSizeKey));
1167 if (!lengthNum) {
1168 OSKextLog(this,
1169 kOSKextLogErrorLevel |
1170 kOSKextLogArchiveFlag,
1171 "Kext %s can't find prelinked kext link state size.",
1172 getIdentifierCString());
1173 goto finish;
1174 }
1175
1176 data = (void *) (intptr_t) (addressNum->unsigned64BitValue());
1177 linkStateLength = (uint32_t) (lengthNum->unsigned32BitValue());
1178
1179 anInfoDict->removeObject(kPrelinkLinkStateKey);
1180 anInfoDict->removeObject(kPrelinkLinkStateSizeKey);
1181
1182 /* Copy the link state out of the booter-provided memory so it is in
1183 * the VM system and we can page it out.
1184 */
1185 alloc_result = kmem_alloc_pageable(kernel_map,
1186 (vm_offset_t *)&linkStateCopy, linkStateLength);
1187 if (alloc_result != KERN_SUCCESS) {
1188 OSKextLog(this,
1189 kOSKextLogErrorLevel |
1190 kOSKextLogArchiveFlag,
1191 "Kext %s failed to copy prelinked link state.",
1192 getIdentifierCString());
1193 goto finish;
1194 }
1195 memcpy(linkStateCopy, data, linkStateLength);
1196
1197 linkState = OSData::withBytesNoCopy(linkStateCopy, linkStateLength);
1198 if (!linkState) {
1199 OSKextLog(this,
1200 kOSKextLogErrorLevel |
1201 kOSKextLogArchiveFlag,
1202 "Kext %s failed to create link state wrapper.",
1203 getIdentifierCString());
1204 goto finish;
1205 }
1206 linkState->setDeallocFunction(osdata_kmem_free);
1207
1208 /* Clear linkStateCopy; the OSData owns it now so we mustn't free it.
1209 */
1210 linkStateCopy = NULL;
1211 }
1212
1213 /* Create an OSData wrapper around the linked executable.
1214 */
1215 addressNum = OSDynamicCast(OSNumber,
1216 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1217 if (addressNum) {
1218 lengthNum = OSDynamicCast(OSNumber,
1219 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1220 if (!lengthNum) {
1221 OSKextLog(this,
1222 kOSKextLogErrorLevel |
1223 kOSKextLogArchiveFlag,
1224 "Kext %s can't find prelinked kext executable size.",
1225 getIdentifierCString());
1226 goto finish;
1227 }
1228
1229 data = (void *) (intptr_t) (addressNum->unsigned64BitValue());
1230 length = (uint32_t) (lengthNum->unsigned32BitValue());
1231
1232 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1233 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1234
1235 /* If the kext's load address differs from its source address, allocate
1236 * space in the kext map at the load address and copy the kext over.
1237 */
1238 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1239 if (addressNum) {
1240 srcData = (void *) (intptr_t) (addressNum->unsigned64BitValue());
1241
1242 if (data != srcData) {
1243 #if __LP64__
1244 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1245 if (alloc_result != KERN_SUCCESS) {
1246 OSKextLog(this,
1247 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1248 "Failed to allocate space for prelinked kext %s.",
1249 getIdentifierCString());
1250 goto finish;
1251 }
1252 memcpy(data, srcData, length);
1253 #else
1254 OSKextLog(this,
1255 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1256 "Error: prelinked kext %s - source and load addresses "
1257 "differ on ILP32 architecture.",
1258 getIdentifierCString());
1259 goto finish;
1260 #endif /* __LP64__ */
1261 }
1262
1263 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1264 }
1265
1266 /* We don't need to set a dealloc function for the linked executable
1267 * because it is freed separately in OSKext::unload(), which must unwire
1268 * part of the memory.
1269 * xxx - do we *have* to do it that way?
1270 */
1271 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1272 if (!prelinkedExecutable) {
1273 OSKextLog(this,
1274 kOSKextLogErrorLevel |
1275 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1276 "Kext %s failed to create executable wrapper.",
1277 getIdentifierCString());
1278 goto finish;
1279 }
1280 setLinkedExecutable(prelinkedExecutable);
1281
1282 addressNum = OSDynamicCast(OSNumber,
1283 anInfoDict->getObject(kPrelinkKmodInfoKey));
1284 if (!addressNum) {
1285 OSKextLog(this,
1286 kOSKextLogErrorLevel |
1287 kOSKextLogArchiveFlag,
1288 "Kext %s can't find prelinked kext kmod_info address.",
1289 getIdentifierCString());
1290 goto finish;
1291 }
1292
1293 kmod_info = (kmod_info_t *) (intptr_t) (addressNum->unsigned64BitValue());
1294
1295 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1296 }
1297
1298 /* If the plist has a UUID for an interface, save that off.
1299 */
1300 if (isInterface()) {
1301 interfaceUUID = OSDynamicCast(OSData,
1302 anInfoDict->getObject(kPrelinkInterfaceUUIDKey));
1303 if (interfaceUUID) {
1304 interfaceUUID->retain();
1305 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1306 }
1307 }
1308
1309 flags.prelinked = true;
1310
1311 /* If we created a kext from prelink info,
1312 * we must be booting from a prelinked kernel.
1313 */
1314 sPrelinkBoot = true;
1315
1316 result = registerIdentifier();
1317
1318 finish:
1319
1320 /* If we didn't hand linkStateCopy off to an OSData, free it.
1321 */
1322 if (linkStateCopy) {
1323 kmem_free(kernel_map, (vm_offset_t)linkStateCopy, linkStateLength);
1324 }
1325
1326 OSSafeRelease(prelinkedExecutable);
1327
1328 return result;
1329 }
1330
1331 /*********************************************************************
1332 *********************************************************************/
1333 OSKext *
1334 OSKext::withBooterData(
1335 OSString * deviceTreeName,
1336 OSData * booterData)
1337 {
1338 OSKext * newKext = new OSKext;
1339
1340 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
1341 newKext->release();
1342 return NULL;
1343 }
1344
1345 return newKext;
1346 }
1347
1348 /*********************************************************************
1349 *********************************************************************/
1350 typedef struct _BooterKextFileInfo {
1351 uint32_t infoDictPhysAddr;
1352 uint32_t infoDictLength;
1353 uint32_t executablePhysAddr;
1354 uint32_t executableLength;
1355 uint32_t bundlePathPhysAddr;
1356 uint32_t bundlePathLength;
1357 } _BooterKextFileInfo;
1358
1359 bool
1360 OSKext::initWithBooterData(
1361 OSString * deviceTreeName,
1362 OSData * booterData)
1363 {
1364 bool result = false;
1365 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
1366 char * infoDictAddr = NULL; // do not free
1367 void * executableAddr = NULL; // do not free
1368 char * bundlePathAddr = NULL; // do not free
1369
1370 OSObject * parsedXML = NULL; // must release
1371 OSDictionary * theInfoDict = NULL; // do not release
1372 OSString * kextPath = NULL; // must release
1373 OSString * errorString = NULL; // must release
1374 OSData * executable = NULL; // must release
1375
1376 if (!super::init()) {
1377 goto finish;
1378 }
1379
1380 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
1381 if (!kextFileInfo) {
1382 OSKextLog(this,
1383 kOSKextLogErrorLevel |
1384 kOSKextLogGeneralFlag,
1385 "No booter-provided data for kext device tree entry %s.",
1386 deviceTreeName->getCStringNoCopy());
1387 goto finish;
1388 }
1389
1390 /* The info plist must exist or we can't read the kext.
1391 */
1392 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
1393 OSKextLog(this,
1394 kOSKextLogErrorLevel |
1395 kOSKextLogGeneralFlag,
1396 "No kext info dictionary for booter device tree entry %s.",
1397 deviceTreeName->getCStringNoCopy());
1398 goto finish;
1399 }
1400
1401 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
1402 if (!infoDictAddr) {
1403 OSKextLog(this,
1404 kOSKextLogErrorLevel |
1405 kOSKextLogGeneralFlag,
1406 "Can't translate physical address 0x%x of kext info dictionary "
1407 "for device tree entry %s.",
1408 (int)kextFileInfo->infoDictPhysAddr,
1409 deviceTreeName->getCStringNoCopy());
1410 goto finish;
1411 }
1412
1413 parsedXML = OSUnserializeXML(infoDictAddr, &errorString);
1414 if (parsedXML) {
1415 theInfoDict = OSDynamicCast(OSDictionary, parsedXML);
1416 }
1417 if (!theInfoDict) {
1418 const char * errorCString = "(unknown error)";
1419
1420 if (errorString && errorString->getCStringNoCopy()) {
1421 errorCString = errorString->getCStringNoCopy();
1422 } else if (parsedXML) {
1423 errorCString = "not a dictionary";
1424 }
1425 OSKextLog(this,
1426 kOSKextLogErrorLevel |
1427 kOSKextLogGeneralFlag,
1428 "Error unserializing info dictionary for device tree entry %s: %s.",
1429 deviceTreeName->getCStringNoCopy(), errorCString);
1430 goto finish;
1431 }
1432
1433 /* A bundle path is not mandatory.
1434 */
1435 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
1436 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
1437 if (!bundlePathAddr) {
1438 OSKextLog(this,
1439 kOSKextLogErrorLevel |
1440 kOSKextLogGeneralFlag,
1441 "Can't translate physical address 0x%x of kext bundle path "
1442 "for device tree entry %s.",
1443 (int)kextFileInfo->bundlePathPhysAddr,
1444 deviceTreeName->getCStringNoCopy());
1445 goto finish;
1446 }
1447 bundlePathAddr[kextFileInfo->bundlePathLength-1] = '\0'; // just in case!
1448
1449 kextPath = OSString::withCString(bundlePathAddr);
1450 if (!kextPath) {
1451 OSKextLog(this,
1452 kOSKextLogErrorLevel |
1453 kOSKextLogGeneralFlag,
1454 "Failed to create wrapper for device tree entry %s kext path %s.",
1455 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
1456 goto finish;
1457 }
1458 }
1459
1460 if (!setInfoDictionaryAndPath(theInfoDict, kextPath)) {
1461 goto finish;
1462 }
1463
1464 /* An executable is not mandatory.
1465 */
1466 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
1467 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
1468 if (!executableAddr) {
1469 OSKextLog(this,
1470 kOSKextLogErrorLevel |
1471 kOSKextLogGeneralFlag,
1472 "Can't translate physical address 0x%x of kext executable "
1473 "for device tree entry %s.",
1474 (int)kextFileInfo->executablePhysAddr,
1475 deviceTreeName->getCStringNoCopy());
1476 goto finish;
1477 }
1478
1479 executable = OSData::withBytesNoCopy(executableAddr,
1480 kextFileInfo->executableLength);
1481 if (!executable) {
1482 OSKextLog(this,
1483 kOSKextLogErrorLevel |
1484 kOSKextLogGeneralFlag,
1485 "Failed to create executable wrapper for device tree entry %s.",
1486 deviceTreeName->getCStringNoCopy());
1487 goto finish;
1488 }
1489
1490 /* A kext with an executable needs to retain the whole booterData
1491 * object to keep the executable in memory.
1492 */
1493 if (!setExecutable(executable, booterData)) {
1494 OSKextLog(this,
1495 kOSKextLogErrorLevel |
1496 kOSKextLogGeneralFlag,
1497 "Failed to set kext executable for device tree entry %s.",
1498 deviceTreeName->getCStringNoCopy());
1499 goto finish;
1500 }
1501 }
1502
1503 result = registerIdentifier();
1504
1505 finish:
1506 OSSafeRelease(parsedXML);
1507 OSSafeRelease(kextPath);
1508 OSSafeRelease(errorString);
1509 OSSafeRelease(executable);
1510
1511 return result;
1512 }
1513
1514 /*********************************************************************
1515 *********************************************************************/
1516 bool
1517 OSKext::registerIdentifier(void)
1518 {
1519 bool result = false;
1520 OSKext * existingKext = NULL; // do not release
1521 bool existingIsLoaded = false;
1522 bool existingIsPrelinked = false;
1523 OSKextVersion newVersion = -1;
1524 OSKextVersion existingVersion = -1;
1525 char newVersionCString[kOSKextVersionMaxLength];
1526 char existingVersionCString[kOSKextVersionMaxLength];
1527 OSData * newUUID = NULL; // must release
1528 OSData * existingUUID = NULL; // must release
1529
1530 /* Get the new kext's version for checks & log messages.
1531 */
1532 newVersion = getVersion();
1533 OSKextVersionGetString(newVersion, newVersionCString,
1534 kOSKextVersionMaxLength);
1535
1536 /* If we don't have an existing kext with this identifier,
1537 * just record the new kext and we're done!
1538 */
1539 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID));
1540 if (!existingKext) {
1541 sKextsByID->setObject(bundleID, this);
1542 result = true;
1543 goto finish;
1544 }
1545
1546 /* Get the existing kext's version for checks & log messages.
1547 */
1548 existingVersion = existingKext->getVersion();
1549 OSKextVersionGetString(existingVersion,
1550 existingVersionCString, kOSKextVersionMaxLength);
1551
1552 existingIsLoaded = existingKext->isLoaded();
1553 existingIsPrelinked = existingKext->isPrelinked();
1554
1555 /* If we have a kext with this identifier that's already loaded/prelinked,
1556 * we can't use the new one, but let's be really thorough and check how
1557 * the two are related for a precise diagnostic log message.
1558 *
1559 * Note that user space can't find out about nonloaded prelinked kexts,
1560 * so in this case we log a message when new & existing are equivalent
1561 * at the step rather than warning level, because we are always going
1562 * be getting a copy of the kext in the user load request mkext.
1563 */
1564 if (existingIsLoaded || existingIsPrelinked) {
1565 bool sameVersion = (newVersion == existingVersion);
1566 bool sameExecutable = true; // assume true unless we have UUIDs
1567
1568 /* Only get the UUID if the existing kext is loaded. Doing so
1569 * might have to uncompress an mkext executable and we shouldn't
1570 * take that hit when neither kext is loaded.
1571 */
1572 newUUID = copyUUID();
1573 existingUUID = existingKext->copyUUID();
1574
1575 /* I'm entirely too paranoid about checking equivalence of executables,
1576 * but I remember nasty problems with it in the past.
1577 *
1578 * - If we have UUIDs for both kexts, compare them.
1579 * - If only one kext has a UUID, they're definitely different.
1580 */
1581 if (newUUID && existingUUID) {
1582 sameExecutable = newUUID->isEqualTo(existingUUID);
1583 } else if (newUUID || existingUUID) {
1584 sameExecutable = false;
1585 }
1586
1587 if (!newUUID && !existingUUID) {
1588
1589 /* If there are no UUIDs, we can't really tell that the executables
1590 * are *different* without a lot of work; the loaded kext's
1591 * unrelocated executable is no longer around (and we never had it
1592 * in-kernel for a prelinked kext). We certainly don't want to do
1593 * a whole fake link for the new kext just to compare, either.
1594 */
1595
1596 OSKextVersionGetString(version, newVersionCString,
1597 sizeof(newVersionCString));
1598 OSKextLog(this,
1599 kOSKextLogWarningLevel |
1600 kOSKextLogKextBookkeepingFlag,
1601 "Notice - new kext %s, v%s matches %s kext "
1602 "but can't determine if executables are the same (no UUIDs).",
1603 getIdentifierCString(),
1604 newVersionCString,
1605 (existingIsLoaded ? "loaded" : "prelinked"));
1606 }
1607
1608 if (sameVersion && sameExecutable) {
1609 OSKextLog(this,
1610 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
1611 kOSKextLogKextBookkeepingFlag,
1612 "Refusing new kext %s, v%s: a %s copy is already present "
1613 "(same version and executable).",
1614 getIdentifierCString(), newVersionCString,
1615 (existingIsLoaded ? "loaded" : "prelinked"));
1616 } else {
1617 if (!sameVersion) {
1618 /* This condition is significant so log it under warnings.
1619 */
1620 OSKextLog(this,
1621 kOSKextLogWarningLevel |
1622 kOSKextLogKextBookkeepingFlag,
1623 "Refusing new kext %s, v%s: already have %s v%s.",
1624 getIdentifierCString(),
1625 newVersionCString,
1626 (existingIsLoaded ? "loaded" : "prelinked"),
1627 existingVersionCString);
1628 } else {
1629 /* This condition is significant so log it under warnings.
1630 */
1631 OSKextLog(this,
1632 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
1633 "Refusing new kext %s, v%s: a %s copy with a different "
1634 "executable UUID is already present.",
1635 getIdentifierCString(), newVersionCString,
1636 (existingIsLoaded ? "loaded" : "prelinked"));
1637 }
1638 }
1639 goto finish;
1640 } /* if (existingIsLoaded || existingIsPrelinked) */
1641
1642 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
1643 * user loads are happening or if we're still in early boot. User agents are
1644 * supposed to resolve dependencies topside and include only the exact
1645 * kexts needed; so we always accept the new kext (in fact we should never
1646 * see an older unloaded copy hanging around).
1647 */
1648 if (sUserLoadsActive) {
1649 sKextsByID->setObject(bundleID, this);
1650 result = true;
1651
1652 OSKextLog(this,
1653 kOSKextLogStepLevel |
1654 kOSKextLogKextBookkeepingFlag,
1655 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
1656 getIdentifierCString(),
1657 existingVersionCString,
1658 newVersionCString);
1659
1660 goto finish;
1661 }
1662
1663 /* During early boot, the kext with the highest version always wins out.
1664 * Prelinked kernels will never hit this, but mkexts and booter-read
1665 * kexts might have duplicates.
1666 */
1667 if (newVersion > existingVersion) {
1668 sKextsByID->setObject(bundleID, this);
1669 result = true;
1670
1671 OSKextLog(this,
1672 kOSKextLogStepLevel |
1673 kOSKextLogKextBookkeepingFlag,
1674 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
1675 existingVersionCString,
1676 getIdentifierCString(),
1677 newVersionCString);
1678
1679 } else {
1680 OSKextLog(this,
1681 kOSKextLogStepLevel |
1682 kOSKextLogKextBookkeepingFlag,
1683 "Kext %s is already registered with a higher/same version (v%s); "
1684 "dropping newly-added (v%s).",
1685 getIdentifierCString(),
1686 existingVersionCString,
1687 newVersionCString);
1688 }
1689
1690 /* result has been set appropriately by now. */
1691
1692 finish:
1693
1694 if (result) {
1695 OSKextLog(this,
1696 kOSKextLogStepLevel |
1697 kOSKextLogKextBookkeepingFlag,
1698 "Kext %s, v%s registered and available for loading.",
1699 getIdentifierCString(), newVersionCString);
1700 }
1701
1702 OSSafeRelease(newUUID);
1703 OSSafeRelease(existingUUID);
1704
1705 return result;
1706 }
1707
1708 /*********************************************************************
1709 * Does the bare minimum validation to look up a kext.
1710 * All other validation is done on the spot as needed.
1711 *
1712 * No need for lock, only called from init
1713 **********************************************************************/
1714 bool
1715 OSKext::setInfoDictionaryAndPath(
1716 OSDictionary * aDictionary,
1717 OSString * aPath)
1718 {
1719 bool result = false;
1720 OSString * bundleIDString = NULL; // do not release
1721 OSString * versionString = NULL; // do not release
1722 OSString * compatibleVersionString = NULL; // do not release
1723 const char * versionCString = NULL; // do not free
1724 const char * compatibleVersionCString = NULL; // do not free
1725 OSBoolean * scratchBool = NULL; // do not release
1726
1727 if (infoDict) {
1728 panic("Attempt to set info dictionary on a kext "
1729 "that already has one (%s).",
1730 getIdentifierCString());
1731 }
1732
1733 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
1734 goto finish;
1735 }
1736
1737 infoDict = aDictionary;
1738 infoDict->retain();
1739
1740 /* Check right away if the info dictionary has any log flags.
1741 */
1742 scratchBool = OSDynamicCast(OSBoolean,
1743 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
1744 if (scratchBool == kOSBooleanTrue) {
1745 flags.loggingEnabled = 1;
1746 }
1747
1748 /* The very next thing to get is the bundle identifier. Unlike
1749 * in user space, a kext with no bundle identifier gets axed
1750 * immediately.
1751 */
1752 bundleIDString = OSDynamicCast(OSString,
1753 getPropertyForHostArch(kCFBundleIdentifierKey));
1754 if (!bundleIDString) {
1755 OSKextLog(this,
1756 kOSKextLogErrorLevel |
1757 kOSKextLogValidationFlag,
1758 "CFBundleIdentifier missing/invalid type in kext %s.",
1759 aPath ? aPath->getCStringNoCopy() : "(unknown)");
1760 goto finish;
1761 }
1762 bundleID = OSSymbol::withString(bundleIDString);
1763 if (!bundleID) {
1764 OSKextLog(this,
1765 kOSKextLogErrorLevel |
1766 kOSKextLogValidationFlag,
1767 "Can't copy bundle identifier as symbol for kext %s.",
1768 bundleIDString->getCStringNoCopy());
1769 goto finish;
1770 }
1771
1772 /* Save the path if we got one (it should always be available but it's
1773 * just something nice to have for bookkeeping).
1774 */
1775 if (aPath) {
1776 path = aPath;
1777 path->retain();
1778 }
1779
1780 /*****
1781 * Minimal validation to initialize. We'll do other validation on the spot.
1782 */
1783 if (bundleID->getLength() >= KMOD_MAX_NAME) {
1784 OSKextLog(this,
1785 kOSKextLogErrorLevel |
1786 kOSKextLogValidationFlag,
1787 "Kext %s error - CFBundleIdentifier over max length %d.",
1788 getIdentifierCString(), KMOD_MAX_NAME - 1);
1789 goto finish;
1790 }
1791
1792 version = compatibleVersion = -1;
1793
1794 versionString = OSDynamicCast(OSString,
1795 getPropertyForHostArch(kCFBundleVersionKey));
1796 if (!versionString) {
1797 OSKextLog(this,
1798 kOSKextLogErrorLevel |
1799 kOSKextLogValidationFlag,
1800 "Kext %s error - CFBundleVersion missing/invalid type.",
1801 getIdentifierCString());
1802 goto finish;
1803 }
1804 versionCString = versionString->getCStringNoCopy();
1805 version = OSKextParseVersionString(versionCString);
1806 if (version < 0) {
1807 OSKextLog(this,
1808 kOSKextLogErrorLevel |
1809 kOSKextLogValidationFlag,
1810 "Kext %s error - CFBundleVersion bad value '%s'.",
1811 getIdentifierCString(), versionCString);
1812 goto finish;
1813 }
1814
1815 compatibleVersion = -1; // set to illegal value for kexts that don't have
1816
1817 compatibleVersionString = OSDynamicCast(OSString,
1818 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
1819 if (compatibleVersionString) {
1820 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
1821 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
1822 if (compatibleVersion < 0) {
1823 OSKextLog(this,
1824 kOSKextLogErrorLevel |
1825 kOSKextLogValidationFlag,
1826 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
1827 getIdentifierCString(), compatibleVersionCString);
1828 goto finish;
1829 }
1830
1831 if (compatibleVersion > version) {
1832 OSKextLog(this,
1833 kOSKextLogErrorLevel |
1834 kOSKextLogValidationFlag,
1835 "Kext %s error - %s %s > %s %s (must be <=).",
1836 getIdentifierCString(),
1837 kOSBundleCompatibleVersionKey, compatibleVersionCString,
1838 kCFBundleVersionKey, versionCString);
1839 goto finish;
1840 }
1841 }
1842
1843 /* Set flags for later use if the infoDict gets flushed. We only
1844 * check for true values, not false ones(!)
1845 */
1846 scratchBool = OSDynamicCast(OSBoolean,
1847 getPropertyForHostArch(kOSBundleIsInterfaceKey));
1848 if (scratchBool && scratchBool->isTrue()) {
1849 flags.interface = 1;
1850 }
1851
1852 scratchBool = OSDynamicCast(OSBoolean,
1853 getPropertyForHostArch(kOSKernelResourceKey));
1854 if (scratchBool && scratchBool->isTrue()) {
1855 flags.kernelComponent = 1;
1856 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
1857 flags.started = 1;
1858
1859 /* A kernel component has one implicit dependency on the kernel.
1860 */
1861 flags.hasAllDependencies = 1;
1862 }
1863
1864 result = true;
1865
1866 finish:
1867
1868 return result;
1869 }
1870
1871 /*********************************************************************
1872 * Not used for prelinked kernel boot as there is no unrelocated
1873 * executable.
1874 *********************************************************************/
1875 bool
1876 OSKext::setExecutable(
1877 OSData * anExecutable,
1878 OSData * externalData,
1879 bool externalDataIsMkext)
1880 {
1881 bool result = false;
1882 const char * executableKey = NULL; // do not free
1883
1884 if (!anExecutable) {
1885 infoDict->removeObject(_kOSKextExecutableKey);
1886 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
1887 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
1888 result = true;
1889 goto finish;
1890 }
1891
1892 if (infoDict->getObject(_kOSKextExecutableKey) ||
1893 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
1894
1895 panic("Attempt to set an executable on a kext "
1896 "that already has one (%s).",
1897 getIdentifierCString());
1898 goto finish;
1899 }
1900
1901 if (externalDataIsMkext) {
1902 executableKey = _kOSKextMkextExecutableReferenceKey;
1903 } else {
1904 executableKey = _kOSKextExecutableKey;
1905 }
1906
1907 if (anExecutable) {
1908 infoDict->setObject(executableKey, anExecutable);
1909 if (externalData) {
1910 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
1911 }
1912 }
1913
1914 result = true;
1915
1916 finish:
1917 return result;
1918 }
1919
1920 /*********************************************************************
1921 *********************************************************************/
1922 void
1923 OSKext::free(void)
1924 {
1925 if (isLoaded()) {
1926 panic("Attempt to free loaded kext %s.", getIdentifierCString());
1927 }
1928
1929 OSSafeRelease(infoDict);
1930 OSSafeRelease(bundleID);
1931 OSSafeRelease(path);
1932 OSSafeRelease(dependencies);
1933 OSSafeRelease(linkState);
1934 OSSafeRelease(linkedExecutable);
1935 OSSafeRelease(metaClasses);
1936 OSSafeRelease(interfaceUUID);
1937
1938 if (isInterface() && kmod_info) {
1939 kfree(kmod_info, sizeof(kmod_info_t));
1940 }
1941
1942 super::free();
1943 return;
1944 }
1945
1946 #if PRAGMA_MARK
1947 #pragma mark Mkext files
1948 #endif
1949 /*********************************************************************
1950 *********************************************************************/
1951 OSReturn
1952 OSKext::readMkextArchive(OSData * mkextData,
1953 uint32_t * checksumPtr)
1954 {
1955 OSReturn result = kOSKextReturnBadData;
1956 uint32_t mkextLength = 0;
1957 mkext_header * mkextHeader = 0; // do not free
1958 uint32_t mkextVersion = 0;
1959
1960 /* Note default return of kOSKextReturnBadData above.
1961 */
1962 mkextLength = mkextData->getLength();
1963 if (mkextLength < sizeof(mkext_basic_header)) {
1964 OSKextLog(/* kext */ NULL,
1965 kOSKextLogErrorLevel |
1966 kOSKextLogArchiveFlag,
1967 "Mkext archive too small to be valid.");
1968 goto finish;
1969 }
1970
1971 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
1972
1973 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
1974 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
1975 OSKextLog(/* kext */ NULL,
1976 kOSKextLogErrorLevel |
1977 kOSKextLogArchiveFlag,
1978 "Mkext archive has invalid magic or signature.");
1979 goto finish;
1980 }
1981
1982 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
1983 OSKextLog(/* kext */ NULL,
1984 kOSKextLogErrorLevel |
1985 kOSKextLogArchiveFlag,
1986 "Mkext archive recorded length doesn't match actual file length.");
1987 goto finish;
1988 }
1989
1990 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
1991
1992 if (mkextVersion == MKEXT_VERS_2) {
1993 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
1994 } else if (mkextVersion == MKEXT_VERS_1) {
1995 result = OSKext::readMkext1Archive(mkextData, checksumPtr);
1996 } else {
1997 OSKextLog(/* kext */ NULL,
1998 kOSKextLogErrorLevel |
1999 kOSKextLogArchiveFlag,
2000 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2001 result = kOSKextReturnUnsupported;
2002 }
2003
2004 finish:
2005 return result;
2006 }
2007
2008 /*********************************************************************
2009 * Assumes magic, signature, version, length have been checked.
2010 *
2011 * Doesn't do as much bounds-checking as it should, but we're dropping
2012 * mkext1 support from the kernel for SnowLeopard soon.
2013 *
2014 * Should keep track of all kexts created so far, and if we hit a
2015 * fatal error halfway through, remove those kexts. If we've dropped
2016 * an older version that had already been read, whoops! Might want to
2017 * add a level of buffering?
2018 *********************************************************************/
2019 /* static */
2020 OSReturn
2021 OSKext::readMkext1Archive(
2022 OSData * mkextData,
2023 uint32_t * checksumPtr)
2024 {
2025 OSReturn result = kOSReturnError;
2026 uint32_t mkextLength;
2027 mkext1_header * mkextHeader = 0; // do not free
2028 void * mkextEnd = 0; // do not free
2029 uint32_t mkextVersion;
2030 uint8_t * crc_address = 0;
2031 uint32_t checksum;
2032 uint32_t numKexts = 0;
2033
2034 OSData * infoDictDataObject = NULL; // must release
2035 OSObject * parsedXML = NULL; // must release
2036 OSDictionary * infoDict = NULL; // do not release
2037 OSString * errorString = NULL; // must release
2038 OSData * mkextExecutableInfo = NULL; // must release
2039 OSKext * theKext = NULL; // must release
2040
2041 mkextLength = mkextData->getLength();
2042 mkextHeader = (mkext1_header *)mkextData->getBytesNoCopy();
2043 mkextEnd = (char *)mkextHeader + mkextLength;
2044 mkextVersion = OSSwapBigToHostInt32(mkextHeader->version);
2045
2046 crc_address = (u_int8_t *)&mkextHeader->version;
2047 checksum = mkext_adler32(crc_address,
2048 (uintptr_t)mkextHeader +
2049 OSSwapBigToHostInt32(mkextHeader->length) - (uintptr_t)crc_address);
2050
2051 if (OSSwapBigToHostInt32(mkextHeader->adler32) != checksum) {
2052 OSKextLog(/* kext */ NULL,
2053 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2054 "Kext archive has a bad checksum.");
2055 result = kOSKextReturnBadData;
2056 goto finish;
2057 }
2058
2059 if (checksumPtr) {
2060 *checksumPtr = checksum;
2061 }
2062
2063 /* Check that the CPU type & subtype match that of the running kernel. */
2064 if (OSSwapBigToHostInt32(mkextHeader->cputype) != (UInt32)CPU_TYPE_ANY) {
2065 if ((UInt32)_mh_execute_header.cputype !=
2066 OSSwapBigToHostInt32(mkextHeader->cputype)) {
2067
2068 OSKextLog(/* kext */ NULL,
2069 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2070 "Kext archive doesn't contain software "
2071 "for this computer's CPU type.");
2072 result = kOSKextReturnArchNotFound;
2073 goto finish;
2074 }
2075 }
2076
2077 numKexts = OSSwapBigToHostInt32(mkextHeader->numkexts);
2078
2079 for (uint32_t i = 0; i < numKexts; i++) {
2080
2081 OSSafeReleaseNULL(infoDictDataObject);
2082 OSSafeReleaseNULL(infoDict);
2083 OSSafeReleaseNULL(mkextExecutableInfo);
2084 OSSafeReleaseNULL(errorString);
2085 OSSafeReleaseNULL(theKext);
2086
2087 mkext_kext * kextEntry = &mkextHeader->kext[i];
2088 mkext_file * infoDictPtr = &kextEntry->plist;
2089 mkext_file * executablePtr = &kextEntry->module;
2090 if (kextEntry >= mkextEnd) {
2091 OSKextLog(/* kext */ NULL,
2092 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2093 "Mkext file overrun.");
2094 result = kOSKextReturnBadData;
2095 goto finish;
2096 }
2097
2098 /* Note that we're pretty tolerant of errors in individual entries.
2099 * As long as we can keep processing, we do.
2100 */
2101 infoDictDataObject = OSKext::extractMkext1Entry(
2102 mkextHeader, infoDictPtr);
2103 if (!infoDictDataObject) {
2104 OSKextLog(/* kext */ NULL,
2105 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2106 "Can't uncompress info dictionary "
2107 "from mkext archive entry %d.", i);
2108 continue;
2109 }
2110
2111 parsedXML = OSUnserializeXML(
2112 (const char *)infoDictDataObject->getBytesNoCopy(),
2113 &errorString);
2114 if (parsedXML) {
2115 infoDict = OSDynamicCast(OSDictionary, parsedXML);
2116 }
2117 if (!infoDict) {
2118 const char * errorCString = "(unknown error)";
2119
2120 if (errorString && errorString->getCStringNoCopy()) {
2121 errorCString = errorString->getCStringNoCopy();
2122 } else if (parsedXML) {
2123 errorCString = "not a dictionary";
2124 }
2125 OSKextLog(/* kext */ NULL,
2126 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2127 "Error: Can't read XML property list "
2128 "for mkext archive entry %d: %s.", i, errorCString);
2129 continue;
2130 }
2131
2132 theKext = new OSKext;
2133 if (!theKext) {
2134 OSKextLog(/* kext */ NULL,
2135 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2136 "Kext allocation failure.");
2137 continue;
2138 }
2139
2140 /*****
2141 * Prepare an entry to hold the mkext entry info for the
2142 * compressed binary module, if there is one. If all four fields
2143 * of the module entry are zero, there isn't one.
2144 */
2145 if ((OSSwapBigToHostInt32(executablePtr->offset) ||
2146 OSSwapBigToHostInt32(executablePtr->compsize) ||
2147 OSSwapBigToHostInt32(executablePtr->realsize) ||
2148 OSSwapBigToHostInt32(executablePtr->modifiedsecs))) {
2149
2150 MkextEntryRef entryRef;
2151
2152 mkextExecutableInfo = OSData::withCapacity(sizeof(entryRef));
2153 if (!mkextExecutableInfo) {
2154 panic("Error: Couldn't allocate data object "
2155 "for mkext archive entry %d.\n", i);
2156 }
2157
2158 entryRef.mkext = (mkext_basic_header *)mkextHeader;
2159 entryRef.fileinfo = (uint8_t *)executablePtr;
2160 if (!mkextExecutableInfo->appendBytes(&entryRef,
2161 sizeof(entryRef))) {
2162
2163 OSKextLog(/* kext */ NULL,
2164 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2165 "Couldn't record executable info "
2166 "for mkext archive entry %d.", i);
2167 // we might hit a load error later but oh well
2168 // xxx - should probably remove theKext
2169 continue;
2170 }
2171
2172 }
2173
2174 /* Init can fail because of a data/runtime error, or because the
2175 * kext is a dup. Either way, we don't care here.
2176 */
2177 if (!theKext->initWithMkext1Info(infoDict, mkextExecutableInfo,
2178 mkextData)) {
2179
2180 // theKext is released at the top of the loop or in the finish block
2181 continue;
2182 }
2183
2184 /* If we got even one kext out of the mkext archive,
2185 * we have successfully read the archive, in that we
2186 * have data references into its mapped memory.
2187 */
2188 result = kOSReturnSuccess;
2189 }
2190
2191 finish:
2192
2193 OSSafeRelease(infoDictDataObject);
2194 OSSafeRelease(parsedXML);
2195 OSSafeRelease(errorString);
2196 OSSafeRelease(mkextExecutableInfo);
2197 OSSafeRelease(theKext);
2198
2199 return result;
2200 }
2201
2202 /*********************************************************************
2203 *********************************************************************/
2204 bool
2205 OSKext::initWithMkext1Info(
2206 OSDictionary * anInfoDict,
2207 OSData * executableWrapper,
2208 OSData * mkextData)
2209 {
2210 bool result = false;
2211
2212 // mkext1 doesn't allow for path (might stuff in info dict)
2213 if (!setInfoDictionaryAndPath(anInfoDict, /* path */ NULL)) {
2214 goto finish;
2215 }
2216
2217 if (!registerIdentifier()) {
2218 goto finish;
2219 }
2220
2221 if (!setExecutable(executableWrapper, mkextData, true)) {
2222 goto finish;
2223 }
2224
2225 result = true;
2226
2227 finish:
2228
2229 /* If we can't init, remove the kext from the lookup dictionary.
2230 * This is safe to call in init because there's an implicit retain.
2231 */
2232 if (!result) {
2233 OSKext::removeKext(this, /* removePersonalities? */ false);
2234 }
2235
2236 return result;
2237 }
2238
2239 /*********************************************************************
2240 * xxx - this should take the input data length
2241 *********************************************************************/
2242 /* static */
2243 OSData *
2244 OSKext::extractMkext1Entry(
2245 const void * mkextFileBase,
2246 const void * entry)
2247 {
2248 OSData * result = NULL;
2249 OSData * uncompressedData = NULL; // release on error
2250 const char * errmsg = NULL;
2251
2252 mkext_file * fileinfo;
2253 uint8_t * uncompressedDataBuffer = 0; // do not free (panic on alloc. fail)
2254 size_t uncompressed_size = 0;
2255 kern_return_t kern_result;
2256
2257 fileinfo = (mkext_file *)entry;
2258
2259 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
2260 size_t compressed_size = OSSwapBigToHostInt32(fileinfo->compsize);
2261 size_t expected_size = OSSwapBigToHostInt32(fileinfo->realsize);
2262
2263 // Add 1 for '\0' to terminate XML string (for plists)
2264 // (we really should have the archive format include that).
2265 size_t alloc_size = expected_size + 1;
2266 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
2267
2268 /* If these four fields are zero there's no file, but it's up to
2269 * the calling context to decide if that's an error.
2270 */
2271 if (offset == 0 && compressed_size == 0 &&
2272 expected_size == 0 && modifiedsecs == 0) {
2273 goto finish;
2274 }
2275
2276 kern_result = kmem_alloc(kernel_map,
2277 (vm_offset_t *)&uncompressedDataBuffer,
2278 alloc_size);
2279 if (kern_result != KERN_SUCCESS) {
2280 panic(ALLOC_FAIL);
2281 goto finish;
2282 }
2283
2284 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer,
2285 alloc_size);
2286 if (uncompressedData == NULL) {
2287 /* No need to free uncompressedDataBuffer here, either. */
2288 panic(ALLOC_FAIL);
2289 goto finish;
2290 }
2291 uncompressedData->setDeallocFunction(&osdata_kmem_free);
2292
2293 /* Do the decompression if necessary. Note that even if the file isn't
2294 * compressed, we want to make a copy so that we don't have the tie to
2295 * the larger mkext file buffer any more.
2296 * xxx - need to detect decompression overflow too
2297 */
2298 if (compressed_size != 0) {
2299 errmsg = "OSKext::uncompressMkext - "
2300 "uncompressed file shorter than expected";
2301 uncompressed_size = decompress_lzss(uncompressedDataBuffer,
2302 expected_size,
2303 ((uint8_t *)mkextFileBase) + offset,
2304 compressed_size);
2305 if (uncompressed_size != expected_size) {
2306 goto finish;
2307 }
2308 } else {
2309 memcpy(uncompressedDataBuffer,
2310 ((uint8_t *)mkextFileBase) + offset,
2311 expected_size);
2312 }
2313
2314 // Add a terminating nul character in case the data is XML.
2315 // (we really should have the archive format include that).
2316 uncompressedDataBuffer[expected_size] = '\0';
2317
2318 result = uncompressedData;
2319 errmsg = NULL;
2320
2321 finish:
2322 if (!result) {
2323 OSKextLog(/* kext */ NULL,
2324 kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
2325 "%s", errmsg);
2326
2327 if (uncompressedData) {
2328 uncompressedData->release();
2329 }
2330 }
2331 return result;
2332 }
2333
2334 /*********************************************************************
2335 * Assumes magic, signature, version, length have been checked.
2336 * xxx - need to add further bounds checking for each file entry
2337 *
2338 * Should keep track of all kexts created so far, and if we hit a
2339 * fatal error halfway through, remove those kexts. If we've dropped
2340 * an older version that had already been read, whoops! Might want to
2341 * add a level of buffering?
2342 *********************************************************************/
2343 /* static */
2344 OSReturn
2345 OSKext::readMkext2Archive(
2346 OSData * mkextData,
2347 OSDictionary ** mkextPlistOut,
2348 uint32_t * checksumPtr)
2349 {
2350 OSReturn result = kOSReturnError;
2351 uint32_t mkextLength;
2352 mkext2_header * mkextHeader = NULL; // do not free
2353 void * mkextEnd = NULL; // do not free
2354 uint32_t mkextVersion;
2355 uint8_t * crc_address = NULL;
2356 uint32_t checksum;
2357 uint32_t mkextPlistOffset;
2358 uint32_t mkextPlistCompressedSize;
2359 char * mkextPlistEnd = NULL; // do not free
2360 uint32_t mkextPlistFullSize;
2361 OSString * errorString = NULL; // must release
2362 OSData * mkextPlistUncompressedData = NULL; // must release
2363 const char * mkextPlistDataBuffer = NULL; // do not free
2364 OSObject * parsedXML = NULL; // must release
2365 OSDictionary * mkextPlist = NULL; // do not release
2366 OSArray * mkextInfoDictArray = NULL; // do not release
2367 uint32_t count, i;
2368
2369 mkextLength = mkextData->getLength();
2370 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2371 mkextEnd = (char *)mkextHeader + mkextLength;
2372 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2373
2374 crc_address = (u_int8_t *)&mkextHeader->version;
2375 checksum = mkext_adler32(crc_address,
2376 (uintptr_t)mkextHeader +
2377 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address);
2378
2379 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
2380 OSKextLog(/* kext */ NULL,
2381 kOSKextLogErrorLevel |
2382 kOSKextLogArchiveFlag,
2383 "Mkext archive has bad checksum.");
2384 result = kOSKextReturnBadData;
2385 goto finish;
2386 }
2387
2388 if (checksumPtr) {
2389 *checksumPtr = checksum;
2390 }
2391
2392 /* Check that the CPU type & subtype match that of the running kernel. */
2393 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
2394 OSKextLog(/* kext */ NULL,
2395 kOSKextLogErrorLevel |
2396 kOSKextLogArchiveFlag,
2397 "Mkext archive must have a specific CPU type.");
2398 result = kOSKextReturnBadData;
2399 goto finish;
2400 } else {
2401 if ((UInt32)_mh_execute_header.cputype !=
2402 MKEXT_GET_CPUTYPE(mkextHeader)) {
2403
2404 OSKextLog(/* kext */ NULL,
2405 kOSKextLogErrorLevel |
2406 kOSKextLogArchiveFlag,
2407 "Mkext archive does not match the running kernel's CPU type.");
2408 result = kOSKextReturnArchNotFound;
2409 goto finish;
2410 }
2411 }
2412
2413 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
2414 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
2415 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
2416 mkextPlistCompressedSize;
2417 if (mkextPlistEnd > mkextEnd) {
2418 OSKextLog(/* kext */ NULL,
2419 kOSKextLogErrorLevel |
2420 kOSKextLogArchiveFlag,
2421 "Mkext archive file overrun.");
2422 result = kOSKextReturnBadData;
2423 }
2424
2425 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
2426 if (mkextPlistCompressedSize) {
2427 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
2428 (UInt8 *)mkextHeader + mkextPlistOffset,
2429 "plist",
2430 mkextPlistCompressedSize, mkextPlistFullSize);
2431 if (!mkextPlistUncompressedData) {
2432 goto finish;
2433 }
2434 mkextPlistDataBuffer = (const char *)
2435 mkextPlistUncompressedData->getBytesNoCopy();
2436 } else {
2437 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
2438 }
2439
2440 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2441 */
2442 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, &errorString);
2443 if (parsedXML) {
2444 mkextPlist = OSDynamicCast(OSDictionary, parsedXML);
2445 }
2446 if (!mkextPlist) {
2447 const char * errorCString = "(unknown error)";
2448
2449 if (errorString && errorString->getCStringNoCopy()) {
2450 errorCString = errorString->getCStringNoCopy();
2451 } else if (parsedXML) {
2452 errorCString = "not a dictionary";
2453 }
2454 OSKextLog(/* kext */ NULL,
2455 kOSKextLogErrorLevel |
2456 kOSKextLogArchiveFlag,
2457 "Error unserializing mkext plist: %s.", errorCString);
2458 goto finish;
2459 }
2460
2461 /* If the caller needs the plist, hand it back and retain it.
2462 * (This function releases it at the end.)
2463 */
2464 if (mkextPlistOut) {
2465 *mkextPlistOut = mkextPlist;
2466 (*mkextPlistOut)->retain();
2467 }
2468
2469 mkextInfoDictArray = OSDynamicCast(OSArray,
2470 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
2471 if (!mkextInfoDictArray) {
2472 OSKextLog(/* kext */ NULL,
2473 kOSKextLogErrorLevel |
2474 kOSKextLogArchiveFlag,
2475 "Mkext archive contains no kext info dictionaries.");
2476 goto finish;
2477 }
2478
2479 count = mkextInfoDictArray->getCount();
2480 for (i = 0; i < count; i++) {
2481 OSDictionary * infoDict;
2482
2483
2484 infoDict = OSDynamicCast(OSDictionary,
2485 mkextInfoDictArray->getObject(i));
2486
2487 /* Create the kext for the entry, then release it, because the
2488 * kext system keeps them around until explicitly removed.
2489 * Any creation/registration failures are already logged for us.
2490 */
2491 OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
2492 OSSafeRelease(newKext);
2493 }
2494
2495 /* Even if we didn't keep any kexts from the mkext, we may have a load
2496 * request to process, so we are successful (no errors occurred).
2497 */
2498 result = kOSReturnSuccess;
2499
2500 finish:
2501
2502 OSSafeRelease(parsedXML);
2503 OSSafeRelease(mkextPlistUncompressedData);
2504 OSSafeRelease(errorString);
2505
2506 return result;
2507 }
2508
2509 /*********************************************************************
2510 *********************************************************************/
2511 /* static */
2512 OSKext *
2513 OSKext::withMkext2Info(
2514 OSDictionary * anInfoDict,
2515 OSData * mkextData)
2516 {
2517 OSKext * newKext = new OSKext;
2518
2519 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
2520 newKext->release();
2521 return NULL;
2522 }
2523
2524 return newKext;
2525 }
2526
2527 /*********************************************************************
2528 *********************************************************************/
2529 bool
2530 OSKext::initWithMkext2Info(
2531 OSDictionary * anInfoDict,
2532 OSData * mkextData)
2533 {
2534 bool result = false;
2535 OSString * kextPath = NULL; // do not release
2536 OSNumber * executableOffsetNum = NULL; // do not release
2537 OSCollectionIterator * iterator = NULL; // must release
2538 OSData * executable = NULL; // must release
2539
2540 if (!super::init()) {
2541 goto finish;
2542 }
2543
2544 /* Get the path. Don't look for an arch-specific path property.
2545 */
2546 kextPath = OSDynamicCast(OSString,
2547 anInfoDict->getObject(kMKEXTBundlePathKey));
2548
2549 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2550 goto finish;
2551 }
2552
2553 /* Don't need the path to be in the info dictionary any more.
2554 */
2555 anInfoDict->removeObject(kMKEXTBundlePathKey);
2556
2557 executableOffsetNum = OSDynamicCast(OSNumber,
2558 infoDict->getObject(kMKEXTExecutableKey));
2559 if (executableOffsetNum) {
2560 executable = createMkext2FileEntry(mkextData,
2561 executableOffsetNum, "executable");
2562 infoDict->removeObject(kMKEXTExecutableKey);
2563 if (!executable) {
2564 goto finish;
2565 }
2566 if (!setExecutable(executable, mkextData, true)) {
2567 goto finish;
2568 }
2569 }
2570
2571 result = registerIdentifier();
2572
2573 finish:
2574
2575 OSSafeRelease(executable);
2576 OSSafeRelease(iterator);
2577 return result;
2578 }
2579
2580 /*********************************************************************
2581 *********************************************************************/
2582 OSData *
2583 OSKext::createMkext2FileEntry(
2584 OSData * mkextData,
2585 OSNumber * offsetNum,
2586 const char * name)
2587 {
2588 OSData * result = NULL;
2589 MkextEntryRef entryRef;
2590 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
2591 uint32_t entryOffset = offsetNum->unsigned32BitValue();
2592
2593 result = OSData::withCapacity(sizeof(entryRef));
2594 if (!result) {
2595 goto finish;
2596 }
2597
2598 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
2599 entryRef.fileinfo = mkextBuffer + entryOffset;
2600 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
2601 OSSafeReleaseNULL(result);
2602 goto finish;
2603 }
2604
2605 finish:
2606 if (!result) {
2607 OSKextLog(this,
2608 kOSKextLogErrorLevel |
2609 kOSKextLogArchiveFlag,
2610 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2611 name, getIdentifierCString());
2612 }
2613 return result;
2614 }
2615
2616 /*********************************************************************
2617 *********************************************************************/
2618 extern "C" {
2619 static void * z_alloc(void *, u_int items, u_int size);
2620 static void z_free(void *, void *ptr);
2621
2622 typedef struct z_mem {
2623 uint32_t alloc_size;
2624 uint8_t data[0];
2625 } z_mem;
2626
2627 /*
2628 * Space allocation and freeing routines for use by zlib routines.
2629 */
2630 void *
2631 z_alloc(void * notused __unused, u_int num_items, u_int size)
2632 {
2633 void * result = NULL;
2634 z_mem * zmem = NULL;
2635 uint32_t total = num_items * size;
2636 uint32_t allocSize = total + sizeof(zmem);
2637
2638 zmem = (z_mem *)kalloc(allocSize);
2639 if (!zmem) {
2640 goto finish;
2641 }
2642 zmem->alloc_size = allocSize;
2643 result = (void *)&(zmem->data);
2644 finish:
2645 return result;
2646 }
2647
2648 void
2649 z_free(void * notused __unused, void * ptr)
2650 {
2651 uint32_t * skipper = (uint32_t *)ptr - 1;
2652 z_mem * zmem = (z_mem *)skipper;
2653 kfree((void *)zmem, zmem->alloc_size);
2654 return;
2655 }
2656 };
2657
2658 OSData *
2659 OSKext::extractMkext2FileData(
2660 UInt8 * data,
2661 const char * name,
2662 uint32_t compressedSize,
2663 uint32_t fullSize)
2664 {
2665 OSData * result = NULL;
2666
2667 OSData * uncompressedData = NULL; // release on error
2668
2669 uint8_t * uncompressedDataBuffer = 0; // do not free
2670 unsigned long uncompressedSize;
2671 z_stream zstream;
2672 bool zstream_inited = false;
2673 int zlib_result;
2674
2675 /* If the file isn't compressed, we want to make a copy
2676 * so that we don't have the tie to the larger mkext file buffer any more.
2677 */
2678 if (!compressedSize) {
2679 uncompressedData = OSData::withBytes(data, fullSize);
2680 // xxx - no check for failure?
2681 result = uncompressedData;
2682 goto finish;
2683 }
2684
2685 if (KERN_SUCCESS != kmem_alloc(kernel_map,
2686 (vm_offset_t*)&uncompressedDataBuffer, fullSize)) {
2687
2688 /* How's this for cheesy? The kernel is only asked to extract
2689 * kext plists so we tailor the log messages.
2690 */
2691 if (this == sKernelKext) {
2692 OSKextLog(this,
2693 kOSKextLogErrorLevel |
2694 kOSKextLogArchiveFlag,
2695 "Allocation failure extracting %s from mkext.", name);
2696 } else {
2697 OSKextLog(this,
2698 kOSKextLogErrorLevel |
2699 kOSKextLogArchiveFlag,
2700 "Allocation failure extracting %s from mkext for kext %s.",
2701 name, getIdentifierCString());
2702 }
2703
2704 goto finish;
2705 }
2706 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
2707 if (!uncompressedData) {
2708 if (this == sKernelKext) {
2709 OSKextLog(this,
2710 kOSKextLogErrorLevel |
2711 kOSKextLogArchiveFlag,
2712 "Allocation failure extracting %s from mkext.", name);
2713 } else {
2714 OSKextLog(this,
2715 kOSKextLogErrorLevel |
2716 kOSKextLogArchiveFlag,
2717 "Allocation failure extracting %s from mkext for kext %s.",
2718 name, getIdentifierCString());
2719 }
2720 goto finish;
2721 }
2722 uncompressedData->setDeallocFunction(&osdata_kmem_free);
2723
2724 if (this == sKernelKext) {
2725 OSKextLog(this,
2726 kOSKextLogDetailLevel |
2727 kOSKextLogArchiveFlag,
2728 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2729 name, compressedSize, fullSize);
2730 } else {
2731 OSKextLog(this,
2732 kOSKextLogDetailLevel |
2733 kOSKextLogArchiveFlag,
2734 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2735 getIdentifierCString(), name, compressedSize, fullSize);
2736 }
2737
2738 bzero(&zstream, sizeof(zstream));
2739 zstream.next_in = (UInt8 *)data;
2740 zstream.avail_in = compressedSize;
2741
2742 zstream.next_out = uncompressedDataBuffer;
2743 zstream.avail_out = fullSize;
2744
2745 zstream.zalloc = z_alloc;
2746 zstream.zfree = z_free;
2747
2748 zlib_result = inflateInit(&zstream);
2749 if (Z_OK != zlib_result) {
2750 if (this == sKernelKext) {
2751 OSKextLog(this,
2752 kOSKextLogErrorLevel |
2753 kOSKextLogArchiveFlag,
2754 "Mkext error; zlib inflateInit failed (%d) for %s.",
2755 zlib_result, name);
2756 } else {
2757 OSKextLog(this,
2758 kOSKextLogErrorLevel |
2759 kOSKextLogArchiveFlag,
2760 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
2761 getIdentifierCString(), zlib_result, name);
2762 }
2763 goto finish;
2764 } else {
2765 zstream_inited = true;
2766 }
2767
2768 zlib_result = inflate(&zstream, Z_FINISH);
2769
2770 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
2771 uncompressedSize = zstream.total_out;
2772 } else {
2773 if (this == sKernelKext) {
2774 OSKextLog(this,
2775 kOSKextLogErrorLevel |
2776 kOSKextLogArchiveFlag,
2777 "Mkext error; zlib inflate failed (%d) for %s.",
2778 zlib_result, name);
2779 } else {
2780 OSKextLog(this,
2781 kOSKextLogErrorLevel |
2782 kOSKextLogArchiveFlag,
2783 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
2784 getIdentifierCString(), zlib_result, name);
2785 }
2786 if (zstream.msg) {
2787 OSKextLog(this,
2788 kOSKextLogErrorLevel |
2789 kOSKextLogArchiveFlag,
2790 "zlib error: %s.", zstream.msg);
2791 }
2792 goto finish;
2793 }
2794
2795 if (uncompressedSize != fullSize) {
2796 if (this == sKernelKext) {
2797 OSKextLog(this,
2798 kOSKextLogErrorLevel |
2799 kOSKextLogArchiveFlag,
2800 "Mkext error; zlib inflate discrepancy for %s, "
2801 "uncompressed size != original size.", name);
2802 } else {
2803 OSKextLog(this,
2804 kOSKextLogErrorLevel |
2805 kOSKextLogArchiveFlag,
2806 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
2807 "uncompressed size != original size.",
2808 getIdentifierCString(), name);
2809 }
2810 goto finish;
2811 }
2812
2813 result = uncompressedData;
2814
2815 finish:
2816 /* Don't bother checking return, nothing we can do on fail.
2817 */
2818 if (zstream_inited) inflateEnd(&zstream);
2819
2820 if (!result) {
2821 OSSafeRelease(uncompressedData);
2822 }
2823
2824 return result;
2825 }
2826
2827 /*********************************************************************
2828 *********************************************************************/
2829 /* static */
2830 OSReturn
2831 OSKext::loadFromMkext(
2832 OSKextLogSpec clientLogFilter,
2833 char * mkextBuffer,
2834 uint32_t mkextBufferLength,
2835 char ** logInfoOut,
2836 uint32_t * logInfoLengthOut)
2837 {
2838 OSReturn result = kOSReturnError;
2839 OSReturn tempResult = kOSReturnError;
2840
2841 OSData * mkextData = NULL; // must release
2842 OSDictionary * mkextPlist = NULL; // must release
2843
2844 OSArray * logInfoArray = NULL; // must release
2845 OSSerialize * serializer = NULL; // must release
2846
2847 OSString * predicate = NULL; // do not release
2848 OSDictionary * requestArgs = NULL; // do not release
2849
2850 OSString * kextIdentifier = NULL; // do not release
2851 OSNumber * startKextExcludeNum = NULL; // do not release
2852 OSNumber * startMatchingExcludeNum = NULL; // do not release
2853 OSBoolean * delayAutounloadBool = NULL; // do not release
2854 OSArray * personalityNames = NULL; // do not release
2855
2856 /* Default values for these two options: regular autounload behavior,
2857 * load all kexts, send no personalities.
2858 */
2859 Boolean delayAutounload = false;
2860 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
2861 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
2862
2863 IORecursiveLockLock(sKextLock);
2864
2865 if (logInfoOut) {
2866 *logInfoOut = NULL;
2867 *logInfoLengthOut = 0;
2868 }
2869
2870 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
2871
2872 OSKextLog(/* kext */ NULL,
2873 kOSKextLogDebugLevel |
2874 kOSKextLogIPCFlag,
2875 "Received kext load request from user space.");
2876
2877 /* Regardless of processing, the fact that we have gotten here means some
2878 * user-space program is up and talking to us, so we'll switch our kext
2879 * registration to reflect that.
2880 */
2881 if (!sUserLoadsActive) {
2882 OSKextLog(/* kext */ NULL,
2883 kOSKextLogProgressLevel |
2884 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
2885 "Switching to late startup (user-space) kext loading policy.");
2886
2887 sUserLoadsActive = true;
2888 }
2889
2890 if (!sLoadEnabled) {
2891 OSKextLog(/* kext */ NULL,
2892 kOSKextLogErrorLevel |
2893 kOSKextLogLoadFlag,
2894 "Kext loading is disabled.");
2895 result = kOSKextReturnDisabled;
2896 goto finish;
2897 }
2898
2899 /* Note that we do not set a dealloc function on this OSData
2900 * object! No references to it can remain after the loadFromMkext()
2901 * call since we are in a MIG function, and will vm_deallocate()
2902 * the buffer.
2903 */
2904 mkextData = OSData::withBytesNoCopy(mkextBuffer,
2905 mkextBufferLength);
2906 if (!mkextData) {
2907 OSKextLog(/* kext */ NULL,
2908 kOSKextLogErrorLevel |
2909 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
2910 "Failed to create wrapper for kext load request.");
2911 result = kOSKextReturnNoMemory;
2912 goto finish;
2913 }
2914
2915 result = readMkext2Archive(mkextData, &mkextPlist, NULL);
2916 if (result != kOSReturnSuccess) {
2917 OSKextLog(/* kext */ NULL,
2918 kOSKextLogErrorLevel |
2919 kOSKextLogLoadFlag,
2920 "Failed to read kext load request.");
2921 goto finish;
2922 }
2923
2924 predicate = _OSKextGetRequestPredicate(mkextPlist);
2925 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
2926 OSKextLog(/* kext */ NULL,
2927 kOSKextLogErrorLevel |
2928 kOSKextLogLoadFlag,
2929 "Received kext load request with no predicate; skipping.");
2930 result = kOSKextReturnInvalidArgument;
2931 goto finish;
2932 }
2933
2934 requestArgs = OSDynamicCast(OSDictionary,
2935 mkextPlist->getObject(kKextRequestArgumentsKey));
2936 if (!requestArgs || !requestArgs->getCount()) {
2937 OSKextLog(/* kext */ NULL,
2938 kOSKextLogErrorLevel |
2939 kOSKextLogLoadFlag,
2940 "Received kext load request with no arguments.");
2941 result = kOSKextReturnInvalidArgument;
2942 goto finish;
2943 }
2944
2945 kextIdentifier = OSDynamicCast(OSString,
2946 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
2947 if (!kextIdentifier) {
2948 OSKextLog(/* kext */ NULL,
2949 kOSKextLogErrorLevel |
2950 kOSKextLogLoadFlag,
2951 "Received kext load request with no kext identifier.");
2952 result = kOSKextReturnInvalidArgument;
2953 goto finish;
2954 }
2955
2956 startKextExcludeNum = OSDynamicCast(OSNumber,
2957 requestArgs->getObject(kKextKextRequestArgumentStartExcludeKey));
2958 startMatchingExcludeNum = OSDynamicCast(OSNumber,
2959 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
2960 delayAutounloadBool = OSDynamicCast(OSBoolean,
2961 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
2962 personalityNames = OSDynamicCast(OSArray,
2963 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
2964
2965 if (delayAutounloadBool) {
2966 delayAutounload = delayAutounloadBool->getValue();
2967 }
2968 if (startKextExcludeNum) {
2969 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
2970 }
2971 if (startMatchingExcludeNum) {
2972 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
2973 }
2974
2975 OSKextLog(/* kext */ NULL,
2976 kOSKextLogProgressLevel |
2977 kOSKextLogIPCFlag,
2978 "Received request from user space to load kext %s.",
2979 kextIdentifier->getCStringNoCopy());
2980
2981 /* Load the kext, with no deferral, since this is a load from outside
2982 * the kernel.
2983 * xxx - Would like a better way to handle the default values for the
2984 * xxx - start/match opt args.
2985 */
2986 result = OSKext::loadKextWithIdentifier(
2987 kextIdentifier,
2988 /* allowDefer */ false,
2989 delayAutounload,
2990 startKextExcludeLevel,
2991 startMatchingExcludeLevel,
2992 personalityNames);
2993 if (result != kOSReturnSuccess) {
2994 goto finish;
2995 }
2996 /* If the load came down from kextd, it will shortly inform IOCatalogue
2997 * for matching via a separate IOKit calldown.
2998 */
2999
3000 finish:
3001
3002 /* Gather up the collected log messages for user space. Any
3003 * error messages past this call will not make it up as log messages
3004 * but will be in the system log.
3005 */
3006 logInfoArray = OSKext::clearUserSpaceLogFilter();
3007
3008 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3009 tempResult = OSKext::serializeLogInfo(logInfoArray,
3010 logInfoOut, logInfoLengthOut);
3011 if (tempResult != kOSReturnSuccess) {
3012 result = tempResult;
3013 }
3014 }
3015
3016 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3017
3018 /* Note: mkextDataObject will have been retained by every kext w/an
3019 * executable in it. That should all have been flushed out at the
3020 * and of the load operation, but you never know....
3021 */
3022 if (mkextData && mkextData->getRetainCount() > 1) {
3023 OSKextLog(/* kext */ NULL,
3024 kOSKextLogErrorLevel |
3025 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3026 "Kext load request buffer from user space still retained by a kext; "
3027 "probable memory leak.");
3028 }
3029
3030 IORecursiveLockUnlock(sKextLock);
3031
3032 OSSafeRelease(mkextData);
3033 OSSafeRelease(mkextPlist);
3034 OSSafeRelease(serializer);
3035 OSSafeRelease(logInfoArray);
3036
3037 return result;
3038 }
3039
3040 /*********************************************************************
3041 *********************************************************************/
3042 /* static */
3043 OSReturn
3044 OSKext::serializeLogInfo(
3045 OSArray * logInfoArray,
3046 char ** logInfoOut,
3047 uint32_t * logInfoLengthOut)
3048 {
3049 OSReturn result = kOSReturnError;
3050 char * buffer = NULL;
3051 kern_return_t kmem_result = KERN_FAILURE;
3052 OSSerialize * serializer = NULL; // must release; reused
3053 char * logInfo = NULL; // returned by reference
3054 uint32_t logInfoLength = 0;
3055
3056 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3057 OSKextLog(/* kext */ NULL,
3058 kOSKextLogErrorLevel |
3059 kOSKextLogIPCFlag,
3060 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3061 /* Bad programmer. */
3062 result = kOSKextReturnInvalidArgument;
3063 goto finish;
3064 }
3065
3066 serializer = OSSerialize::withCapacity(0);
3067 if (!serializer) {
3068 OSKextLog(/* kext */ NULL,
3069 kOSKextLogErrorLevel |
3070 kOSKextLogIPCFlag,
3071 "Failed to create serializer on log info for request from user space.");
3072 /* Incidental error; we're going to (try to) allow the request
3073 * itself to succeed. */
3074 }
3075
3076 if (!logInfoArray->serialize(serializer)) {
3077 OSKextLog(/* kext */ NULL,
3078 kOSKextLogErrorLevel |
3079 kOSKextLogIPCFlag,
3080 "Failed to serialize log info for request from user space.");
3081 /* Incidental error; we're going to (try to) allow the request
3082 * itself to succeed. */
3083 } else {
3084 logInfo = serializer->text();
3085 logInfoLength = serializer->getLength();
3086
3087 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, logInfoLength);
3088 if (kmem_result != KERN_SUCCESS) {
3089 OSKextLog(/* kext */ NULL,
3090 kOSKextLogErrorLevel |
3091 kOSKextLogIPCFlag,
3092 "Failed to copy log info for request from user space.");
3093 /* Incidental error; we're going to (try to) allow the request
3094 * to succeed. */
3095 } else {
3096 memcpy(buffer, logInfo, logInfoLength);
3097 *logInfoOut = buffer;
3098 *logInfoLengthOut = logInfoLength;
3099 }
3100 }
3101
3102 result = kOSReturnSuccess;
3103 finish:
3104 OSSafeRelease(serializer);
3105 return result;
3106 }
3107
3108 #if PRAGMA_MARK
3109 #pragma mark Instance Management Methods
3110 #endif
3111 /*********************************************************************
3112 *********************************************************************/
3113 OSKext *
3114 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3115 {
3116 OSKext * foundKext = NULL;
3117
3118 IORecursiveLockLock(sKextLock);
3119 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3120 if (foundKext) {
3121 foundKext->retain();
3122 }
3123 IORecursiveLockUnlock(sKextLock);
3124
3125 return foundKext;
3126 }
3127
3128 /*********************************************************************
3129 *********************************************************************/
3130 OSKext *
3131 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3132 {
3133 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3134 }
3135
3136 /*********************************************************************
3137 *********************************************************************/
3138 OSKext *
3139 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3140 {
3141 OSKext * foundKext = NULL; // returned
3142 uint32_t count, i;
3143
3144 IORecursiveLockLock(sKextLock);
3145
3146 count = sLoadedKexts->getCount();
3147 for (i = 0; i < count; i++) {
3148 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3149 if (thisKext->getLoadTag() == aTag) {
3150 foundKext = thisKext;
3151 foundKext->retain();
3152 goto finish;
3153 }
3154 }
3155
3156 finish:
3157 IORecursiveLockUnlock(sKextLock);
3158
3159 return foundKext;
3160 }
3161
3162 /*********************************************************************
3163 *********************************************************************/
3164 OSKext *
3165 OSKext::lookupKextWithAddress(vm_address_t address)
3166 {
3167 OSKext * foundKext = NULL; // returned
3168 uint32_t count, i;
3169
3170 IORecursiveLockLock(sKextLock);
3171
3172 count = sLoadedKexts->getCount();
3173 for (i = 0; i < count; i++) {
3174 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3175 if (thisKext->linkedExecutable) {
3176 vm_address_t kext_start =
3177 (vm_address_t)thisKext->linkedExecutable->getBytesNoCopy();
3178 vm_address_t kext_end = kext_start +
3179 thisKext->linkedExecutable->getLength();
3180
3181 if ((kext_start <= address) && (address < kext_end)) {
3182 foundKext = thisKext;
3183 foundKext->retain();
3184 goto finish;
3185 }
3186 }
3187 }
3188
3189 finish:
3190 IORecursiveLockUnlock(sKextLock);
3191
3192 return foundKext;
3193 }
3194
3195 /*********************************************************************
3196 *********************************************************************/
3197 /* static */
3198 bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
3199 {
3200 bool result = false;
3201 OSKext * foundKext = NULL; // returned
3202
3203 IORecursiveLockLock(sKextLock);
3204
3205 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3206 if (foundKext && foundKext->isLoaded()) {
3207 result = true;
3208 }
3209
3210 IORecursiveLockUnlock(sKextLock);
3211
3212 return result;
3213 }
3214
3215 /*********************************************************************
3216 * xxx - should spawn a separate thread so a kext can safely have
3217 * xxx - itself unloaded.
3218 *********************************************************************/
3219 /* static */
3220 OSReturn
3221 OSKext::removeKext(
3222 OSKext * aKext,
3223 bool terminateServicesAndRemovePersonalitiesFlag)
3224 {
3225 OSReturn result = kOSKextReturnInUse;
3226 OSKext * checkKext = NULL; // do not release
3227
3228 IORecursiveLockLock(sKextLock);
3229
3230 /* If the kext has no identifier, it failed to init
3231 * so isn't in sKextsByID and it isn't loaded.
3232 */
3233 if (!aKext->getIdentifier()) {
3234 result = kOSReturnSuccess;
3235 goto finish;
3236 }
3237
3238 checkKext = OSDynamicCast(OSKext,
3239 sKextsByID->getObject(aKext->getIdentifier()));
3240 if (checkKext != aKext) {
3241 result = kOSKextReturnNotFound;
3242 goto finish;
3243 }
3244
3245 if (aKext->isLoaded()) {
3246 /* If we are terminating, send the request to the IOCatalogue
3247 * (which will actually call us right back but that's ok we have
3248 * a recursive lock don't you know) but do not ask the IOCatalogue
3249 * to call back with an unload, we'll do that right here.
3250 */
3251 if (terminateServicesAndRemovePersonalitiesFlag) {
3252 result = gIOCatalogue->terminateDriversForModule(
3253 aKext->getIdentifierCString(), /* unload */ false);
3254 if (result != kOSReturnSuccess) {
3255 OSKextLog(aKext,
3256 kOSKextLogProgressLevel |
3257 kOSKextLogKextBookkeepingFlag,
3258 "Can't remove kext %s; services failed to terminate - 0x%x.",
3259 aKext->getIdentifierCString(), result);
3260 goto finish;
3261 }
3262 }
3263
3264 result = aKext->unload();
3265 if (result != kOSReturnSuccess) {
3266 goto finish;
3267 }
3268 }
3269
3270 /* Remove personalities as requested. This is a bit redundant for a loaded
3271 * kext as IOCatalogue::terminateDriversForModule() removes driver
3272 * personalities, but it doesn't restart matching, which we always want
3273 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3274 * that happens.
3275 */
3276 if (terminateServicesAndRemovePersonalitiesFlag) {
3277 aKext->removePersonalitiesFromCatalog();
3278 }
3279
3280 OSKextLog(aKext,
3281 kOSKextLogProgressLevel |
3282 kOSKextLogKextBookkeepingFlag,
3283 "Removing kext %s.",
3284 aKext->getIdentifierCString());
3285
3286 sKextsByID->removeObject(aKext->getIdentifier());
3287 result = kOSReturnSuccess;
3288
3289 finish:
3290 IORecursiveLockUnlock(sKextLock);
3291 return result;
3292 }
3293
3294 /*********************************************************************
3295 *********************************************************************/
3296 /* static */
3297 OSReturn
3298 OSKext::removeKextWithIdentifier(
3299 const char * kextIdentifier,
3300 bool terminateServicesAndRemovePersonalitiesFlag)
3301 {
3302 OSReturn result = kOSReturnError;
3303
3304 IORecursiveLockLock(sKextLock);
3305
3306 OSKext * aKext = OSDynamicCast(OSKext,
3307 sKextsByID->getObject(kextIdentifier));
3308 if (!aKext) {
3309 result = kOSKextReturnNotFound;
3310 OSKextLog(/* kext */ NULL,
3311 kOSKextLogErrorLevel |
3312 kOSKextLogKextBookkeepingFlag,
3313 "Can't remove kext %s - not found.",
3314 kextIdentifier);
3315 goto finish;
3316 }
3317
3318 result = OSKext::removeKext(aKext,
3319 terminateServicesAndRemovePersonalitiesFlag);
3320
3321 finish:
3322 IORecursiveLockUnlock(sKextLock);
3323
3324 return result;
3325 }
3326
3327 /*********************************************************************
3328 *********************************************************************/
3329 /* static */
3330 OSReturn
3331 OSKext::removeKextWithLoadTag(
3332 OSKextLoadTag loadTag,
3333 bool terminateServicesAndRemovePersonalitiesFlag)
3334 {
3335 OSReturn result = kOSReturnError;
3336 OSKext * foundKext = NULL;
3337 uint32_t count, i;
3338
3339 IORecursiveLockLock(sKextLock);
3340
3341 count = sLoadedKexts->getCount();
3342 for (i = 0; i < count; i++) {
3343 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3344 if (thisKext->loadTag == loadTag) {
3345 foundKext = thisKext;
3346 break;
3347 }
3348 }
3349
3350 if (!foundKext) {
3351 result = kOSKextReturnNotFound;
3352 OSKextLog(/* kext */ NULL,
3353 kOSKextLogErrorLevel |
3354 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3355 "Can't remove kext with load tag %d - not found.",
3356 loadTag);
3357 goto finish;
3358 }
3359
3360 result = OSKext::removeKext(foundKext,
3361 terminateServicesAndRemovePersonalitiesFlag);
3362
3363 finish:
3364 IORecursiveLockUnlock(sKextLock);
3365
3366 return result;
3367 }
3368
3369 /*********************************************************************
3370 *********************************************************************/
3371 OSDictionary *
3372 OSKext::copyKexts(void)
3373 {
3374 OSDictionary * result;
3375
3376 IORecursiveLockLock(sKextLock);
3377 result = OSDynamicCast(OSDictionary, sKextsByID->copyCollection());
3378 IORecursiveLockUnlock(sKextLock);
3379
3380 return result;
3381 }
3382
3383 #if PRAGMA_MARK
3384 #pragma mark Accessors
3385 #endif
3386 /*********************************************************************
3387 *********************************************************************/
3388 const OSSymbol *
3389 OSKext::getIdentifier(void)
3390 {
3391 return bundleID;
3392 }
3393
3394 /*********************************************************************
3395 * A kext must have a bundle identifier to even survive initialization;
3396 * this is guaranteed to exist past then.
3397 *********************************************************************/
3398 const char *
3399 OSKext::getIdentifierCString(void)
3400 {
3401 return bundleID->getCStringNoCopy();
3402 }
3403
3404 /*********************************************************************
3405 *********************************************************************/
3406 OSKextVersion
3407 OSKext::getVersion(void)
3408 {
3409 return version;
3410 }
3411
3412 /*********************************************************************
3413 *********************************************************************/
3414 OSKextVersion
3415 OSKext::getCompatibleVersion(void)
3416 {
3417 return compatibleVersion;
3418 }
3419
3420 /*********************************************************************
3421 *********************************************************************/
3422 bool
3423 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
3424 {
3425 if ((compatibleVersion > -1 && version > -1) &&
3426 (compatibleVersion <= version && aVersion <= version)) {
3427 return true;
3428 }
3429 return false;
3430 }
3431
3432 /*********************************************************************
3433 *********************************************************************/
3434 bool
3435 OSKext::declaresExecutable(void)
3436 {
3437 if (getPropertyForHostArch(kCFBundleExecutableKey)) {
3438 return true;
3439 }
3440 return false;
3441 }
3442
3443 /*********************************************************************
3444 *********************************************************************/
3445 OSData *
3446 OSKext::getExecutable(void)
3447 {
3448 OSData * result = NULL;
3449 OSData * extractedExecutable = NULL; // must release
3450 OSData * mkextExecutableRef = NULL; // do not release
3451
3452 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
3453 if (result) {
3454 goto finish;
3455 }
3456
3457 mkextExecutableRef = OSDynamicCast(OSData,
3458 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
3459
3460 if (mkextExecutableRef) {
3461
3462 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
3463 mkextExecutableRef->getBytesNoCopy();
3464 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
3465 if (mkextVersion == MKEXT_VERS_2) {
3466 mkext2_file_entry * fileinfo =
3467 (mkext2_file_entry *)mkextEntryRef->fileinfo;
3468 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
3469 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
3470 extractedExecutable = extractMkext2FileData(
3471 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
3472 compressedSize, fullSize);
3473 } else if (mkextVersion == MKEXT_VERS_1) {
3474 extractedExecutable = extractMkext1Entry(
3475 mkextEntryRef->mkext, mkextEntryRef->fileinfo);
3476 } else {
3477 OSKextLog(this, kOSKextLogErrorLevel |
3478 kOSKextLogArchiveFlag,
3479 "Kext %s - unknown mkext version 0x%x for executable.",
3480 getIdentifierCString(), mkextVersion);
3481 }
3482
3483 /* Regardless of success, remove the mkext executable,
3484 * and drop one reference on the mkext. (setExecutable() does not
3485 * replace, it removes, or panics if asked to replace.)
3486 */
3487 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3488 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3489
3490 if (extractedExecutable && extractedExecutable->getLength()) {
3491 if (!setExecutable(extractedExecutable)) {
3492 goto finish;
3493 }
3494 result = extractedExecutable;
3495 } else {
3496 goto finish;
3497 }
3498 }
3499
3500 finish:
3501
3502 OSSafeRelease(extractedExecutable);
3503
3504 return result;
3505 }
3506
3507 /*********************************************************************
3508 *********************************************************************/
3509 bool
3510 OSKext::isInterface(void)
3511 {
3512 return flags.interface;
3513 }
3514
3515 /*********************************************************************
3516 *********************************************************************/
3517 bool
3518 OSKext::isKernelComponent(void)
3519 {
3520 return flags.kernelComponent ? true : false;
3521 }
3522
3523 /*********************************************************************
3524 * We might want to check this recursively for all dependencies,
3525 * since a subtree of dependencies could get loaded before we hit
3526 * a dependency that isn't safe-boot-loadable.
3527 *
3528 * xxx - Might want to return false if OSBundleEnableKextLogging or
3529 * OSBundleDebugLevel
3530 * or IOKitDebug is nonzero too (we used to do that, but I don't see
3531 * the point except it's usually development drivers, which might
3532 * cause panics on startup, that have those properties). Heh; could
3533 * use a "kx" boot-arg!
3534 *********************************************************************/
3535 bool
3536 OSKext::isLoadableInSafeBoot(void)
3537 {
3538 bool result = false;
3539 OSString * required = NULL; // do not release
3540
3541
3542 required = OSDynamicCast(OSString,
3543 getPropertyForHostArch(kOSBundleRequiredKey));
3544 if (!required) {
3545 goto finish;
3546 }
3547 if (required->isEqualTo(kOSBundleRequiredRoot) ||
3548 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
3549 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
3550 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
3551 required->isEqualTo(kOSBundleRequiredConsole)) {
3552
3553 result = true;
3554 }
3555
3556 finish:
3557 return result;
3558 }
3559
3560 /*********************************************************************
3561 *********************************************************************/
3562 bool
3563 OSKext::isPrelinked(void)
3564 {
3565 return flags.prelinked ? true : false;
3566 }
3567
3568 /*********************************************************************
3569 *********************************************************************/
3570 bool OSKext::isLoaded(void)
3571 {
3572 return flags.loaded ? true : false;
3573 }
3574
3575 /*********************************************************************
3576 *********************************************************************/
3577 bool
3578 OSKext::isStarted(void)
3579 {
3580 return flags.started ? true : false;
3581 }
3582
3583 /*********************************************************************
3584 *********************************************************************/
3585 bool
3586 OSKext::isCPPInitialized(void)
3587 {
3588 return flags.CPPInitialized;
3589 }
3590
3591 /*********************************************************************
3592 *********************************************************************/
3593 void
3594 OSKext::setCPPInitialized(bool initialized)
3595 {
3596 flags.CPPInitialized = initialized;
3597 }
3598
3599 /*********************************************************************
3600 *********************************************************************/
3601 uint32_t
3602 OSKext::getLoadTag(void)
3603 {
3604 return loadTag;
3605 }
3606
3607 /*********************************************************************
3608 *********************************************************************/
3609 OSData *
3610 OSKext::copyUUID(void)
3611 {
3612 OSData * result = NULL;
3613 OSData * theExecutable = NULL; // do not release
3614 const kernel_mach_header_t * header = NULL;
3615 const struct load_command * load_cmd = NULL;
3616 const struct uuid_command * uuid_cmd = NULL;
3617 uint32_t i;
3618
3619 /* An interface kext doesn't have a linked executable with an LC_UUID,
3620 * we create one when it's linked.
3621 */
3622 if (interfaceUUID) {
3623 result = interfaceUUID;
3624 result->retain();
3625 goto finish;
3626 }
3627
3628 /* For real kexts, try to get the UUID from the linked executable,
3629 * or if is hasn't been linked yet, the unrelocated executable.
3630 */
3631 theExecutable = linkedExecutable;
3632 if (!theExecutable) {
3633 theExecutable = getExecutable();
3634 }
3635 if (!theExecutable) {
3636 goto finish;
3637 }
3638
3639 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
3640 load_cmd = (const struct load_command *)&header[1];
3641
3642 for (i = 0; i < header->ncmds; i++) {
3643 if (load_cmd->cmd == LC_UUID) {
3644 uuid_cmd = (struct uuid_command *)load_cmd;
3645 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
3646 goto finish;
3647 }
3648 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
3649 }
3650
3651 finish:
3652 return result;
3653 }
3654
3655 /*********************************************************************
3656 *********************************************************************/
3657 #if defined (__ppc__)
3658 #define ARCHNAME "ppc"
3659 #elif defined (__i386__)
3660 #define ARCHNAME "i386"
3661 #elif defined (__x86_64__)
3662 #define ARCHNAME "x86_64"
3663 #else
3664 #error architecture not supported
3665 #endif
3666
3667 #define ARCH_SEPARATOR_CHAR '_'
3668
3669 static char * makeHostArchKey(const char * key, uint32_t * keySizeOut)
3670 {
3671 char * result = NULL;
3672 uint32_t keyLength = strlen(key);
3673 uint32_t keySize;
3674
3675 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
3676 */
3677 keySize = 1 + 1 + strlen(key) + strlen(ARCHNAME);
3678 result = (char *)kalloc(keySize);
3679 if (!result) {
3680 goto finish;
3681 }
3682 strlcpy(result, key, keySize);
3683 result[keyLength++] = ARCH_SEPARATOR_CHAR;
3684 result[keyLength] = '\0';
3685 strlcat(result, ARCHNAME, keySize);
3686 *keySizeOut = keySize;
3687
3688 finish:
3689 return result;
3690 }
3691
3692 /*********************************************************************
3693 *********************************************************************/
3694 OSObject *
3695 OSKext::getPropertyForHostArch(const char * key)
3696 {
3697 OSObject * result = NULL; // do not release
3698 uint32_t hostArchKeySize = 0;
3699 char * hostArchKey = NULL; // must kfree
3700
3701 if (!key || !infoDict) {
3702 goto finish;
3703 }
3704
3705 /* Some properties are not allowed to be arch-variant:
3706 * - Any CFBundle... property.
3707 * - OSBundleIsInterface.
3708 * - OSKernelResource.
3709 */
3710 if (STRING_HAS_PREFIX(key, "OS") ||
3711 STRING_HAS_PREFIX(key, "IO")) {
3712
3713 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
3714 if (!hostArchKey) {
3715 OSKextLog(/* kext (this isn't about a kext) */ NULL,
3716 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3717 "Allocation failure.");
3718 goto finish;
3719 }
3720 result = infoDict->getObject(hostArchKey);
3721 }
3722
3723 if (!result) {
3724 result = infoDict->getObject(key);
3725 }
3726
3727 finish:
3728 if (hostArchKey) kfree(hostArchKey, hostArchKeySize);
3729 return result;
3730 }
3731
3732 #if PRAGMA_MARK
3733 #pragma mark Load/Start/Stop/Unload
3734 #endif
3735 /*********************************************************************
3736 *********************************************************************/
3737 OSReturn
3738 OSKext::loadKextWithIdentifier(
3739 const char * kextIdentifierCString,
3740 Boolean allowDeferFlag,
3741 Boolean delayAutounloadFlag,
3742 OSKextExcludeLevel startOpt,
3743 OSKextExcludeLevel startMatchingOpt,
3744 OSArray * personalityNames)
3745 {
3746 OSReturn result = kOSReturnError;
3747 OSString * kextIdentifier = NULL; // must release
3748
3749 kextIdentifier = OSString::withCString(kextIdentifierCString);
3750 if (!kextIdentifier) {
3751 result = kOSKextReturnNoMemory;
3752 goto finish;
3753 }
3754 result = OSKext::loadKextWithIdentifier(kextIdentifier,
3755 allowDeferFlag, delayAutounloadFlag,
3756 startOpt, startMatchingOpt, personalityNames);
3757
3758 finish:
3759 OSSafeRelease(kextIdentifier);
3760 return result;
3761 }
3762
3763
3764 /*********************************************************************
3765 *********************************************************************/
3766 OSReturn
3767 OSKext::loadKextWithIdentifier(
3768 OSString * kextIdentifier,
3769 Boolean allowDeferFlag,
3770 Boolean delayAutounloadFlag,
3771 OSKextExcludeLevel startOpt,
3772 OSKextExcludeLevel startMatchingOpt,
3773 OSArray * personalityNames)
3774 {
3775 OSReturn result = kOSReturnError;
3776 OSKext * theKext = NULL; // do not release
3777 OSDictionary * loadRequest = NULL; // must release
3778 const OSSymbol * kextIdentifierSymbol = NULL; // must release
3779
3780 IORecursiveLockLock(sKextLock);
3781
3782 if (!kextIdentifier) {
3783 result = kOSKextReturnInvalidArgument;
3784 goto finish;
3785 }
3786
3787 OSKext::recordIdentifierRequest(kextIdentifier);
3788
3789 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3790 if (!theKext) {
3791 if (!allowDeferFlag) {
3792 OSKextLog(/* kext */ NULL,
3793 kOSKextLogErrorLevel |
3794 kOSKextLogLoadFlag,
3795 "Can't load kext %s - not found.",
3796 kextIdentifier->getCStringNoCopy());
3797 goto finish;
3798 }
3799
3800 if (!sKernelRequestsEnabled) {
3801 OSKextLog(theKext,
3802 kOSKextLogErrorLevel |
3803 kOSKextLogLoadFlag,
3804 "Can't load kext %s - requests to user space are disabled.",
3805 kextIdentifier->getCStringNoCopy());
3806 result = kOSKextReturnDisabled;
3807 goto finish;
3808 }
3809
3810 /* Create a new request unless one is already sitting
3811 * in sKernelRequests for this bundle identifier
3812 */
3813 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
3814 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
3815 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
3816 &loadRequest);
3817 if (result != kOSReturnSuccess) {
3818 goto finish;
3819 }
3820 if (!_OSKextSetRequestArgument(loadRequest,
3821 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
3822
3823 result = kOSKextReturnNoMemory;
3824 goto finish;
3825 }
3826 if (!sKernelRequests->setObject(loadRequest)) {
3827 result = kOSKextReturnNoMemory;
3828 goto finish;
3829 }
3830
3831 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
3832 result = kOSKextReturnNoMemory;
3833 goto finish;
3834 }
3835
3836 OSKextLog(theKext,
3837 kOSKextLogDebugLevel |
3838 kOSKextLogLoadFlag,
3839 "Kext %s not found; queued load request to user space.",
3840 kextIdentifier->getCStringNoCopy());
3841 }
3842
3843 if (sKextdActive) {
3844 OSKextPingKextd();
3845 } else {
3846 OSKextLog(/* kext */ NULL,
3847 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
3848 kOSKextLogLoadFlag,
3849 "Not loading kext %s - not found and kextd not available in early boot.",
3850 kextIdentifier->getCStringNoCopy());
3851 }
3852
3853 result = kOSKextReturnDeferred;
3854 goto finish;
3855 }
3856
3857 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
3858
3859 if (result != kOSReturnSuccess) {
3860 OSKextLog(theKext,
3861 kOSKextLogErrorLevel |
3862 kOSKextLogLoadFlag,
3863 "Failed to load kext %s (error 0x%x).",
3864 kextIdentifier->getCStringNoCopy(), (int)result);
3865
3866 OSKext::removeKext(theKext,
3867 /* terminateService/removePersonalities */ true);
3868 goto finish;
3869 }
3870
3871 if (delayAutounloadFlag) {
3872 OSKextLog(theKext,
3873 kOSKextLogProgressLevel |
3874 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3875 "Setting delayed autounload for %s.",
3876 kextIdentifier->getCStringNoCopy());
3877 theKext->flags.delayAutounload = 1;
3878 }
3879
3880 finish:
3881 OSSafeRelease(loadRequest);
3882 OSSafeRelease(kextIdentifierSymbol);
3883
3884 IORecursiveLockUnlock(sKextLock);
3885
3886 return result;
3887 }
3888
3889 /*********************************************************************
3890 *********************************************************************/
3891 /* static */
3892 void
3893 OSKext::recordIdentifierRequest(
3894 OSString * kextIdentifier)
3895 {
3896 const OSSymbol * kextIdentifierSymbol = NULL; // must release
3897 bool fail = false;
3898
3899 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
3900 goto finish;
3901 }
3902
3903 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
3904 if (!kextIdentifierSymbol) {
3905 // xxx - this is really a basic alloc failure
3906 fail = true;
3907 goto finish;
3908 }
3909
3910 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
3911 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
3912 fail = true;
3913 } else {
3914 // xxx - need to find a way to associate this whole func w/the kext
3915 OSKextLog(/* kext */ NULL,
3916 // xxx - check level
3917 kOSKextLogStepLevel |
3918 kOSKextLogArchiveFlag,
3919 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
3920 kextIdentifier->getCStringNoCopy());
3921 }
3922 }
3923 finish:
3924
3925 if (fail) {
3926 OSKextLog(/* kext */ NULL,
3927 kOSKextLogErrorLevel |
3928 kOSKextLogArchiveFlag,
3929 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
3930 kextIdentifier->getCStringNoCopy());
3931 }
3932 OSSafeRelease(kextIdentifierSymbol);
3933 return;
3934 }
3935
3936 /*********************************************************************
3937 *********************************************************************/
3938 OSReturn
3939 OSKext::load(
3940 OSKextExcludeLevel startOpt,
3941 OSKextExcludeLevel startMatchingOpt,
3942 OSArray * personalityNames)
3943 {
3944 OSReturn result = kOSReturnError;
3945 kern_return_t kxldResult;
3946 OSKextExcludeLevel dependenciesStartOpt = startOpt;
3947 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
3948 unsigned int i, count;
3949 Boolean alreadyLoaded = false;
3950 OSKext * lastLoadedKext = NULL;
3951
3952 if (!sLoadEnabled) {
3953 if (!isLoaded() || (!isStarted() && startOpt != kOSKextExcludeNone) ||
3954 (startMatchingOpt != kOSKextExcludeNone)) {
3955
3956 OSKextLog(this,
3957 kOSKextLogErrorLevel |
3958 kOSKextLogLoadFlag,
3959 "Kext loading is disabled "
3960 "(attempt to load/start/start matching for kext %s).",
3961 getIdentifierCString());
3962 }
3963 result = kOSKextReturnDisabled;
3964 goto finish;
3965 }
3966
3967 if (isLoaded()) {
3968 alreadyLoaded = true;
3969 result = kOSReturnSuccess;
3970
3971 OSKextLog(this,
3972 kOSKextLogDebugLevel |
3973 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
3974 "Kext %s is already loaded.",
3975 getIdentifierCString());
3976 goto loaded;
3977 }
3978
3979 /* If we've pushed the next available load tag to the invalid value,
3980 * we can't load any more kexts.
3981 */
3982 if (sNextLoadTag == kOSKextInvalidLoadTag) {
3983 OSKextLog(this,
3984 kOSKextLogErrorLevel |
3985 kOSKextLogLoadFlag,
3986 "Can't load kext %s - no more load tags to assign.",
3987 getIdentifierCString());
3988 result = kOSKextReturnNoResources;
3989 goto finish;
3990 }
3991
3992 /* This is a bit of a hack, because we shouldn't be handling
3993 * personalities within the load function.
3994 */
3995 if (!declaresExecutable()) {
3996 result = kOSReturnSuccess;
3997 goto loaded;
3998 }
3999
4000 /* Are we in safe boot?
4001 */
4002 if (sSafeBoot && !isLoadableInSafeBoot()) {
4003 OSKextLog(this,
4004 kOSKextLogErrorLevel |
4005 kOSKextLogLoadFlag,
4006 "Can't load kext %s - not loadable during safe boot.",
4007 getIdentifierCString());
4008 result = kOSKextReturnBootLevel;
4009 goto finish;
4010 }
4011
4012 OSKextLog(this,
4013 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
4014 "Loading kext %s.",
4015 getIdentifierCString());
4016
4017
4018 if (!sKxldContext) {
4019 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
4020 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
4021 /* cputype */ 0, /* cpusubtype */ 0);
4022 if (kxldResult) {
4023 OSKextLog(this,
4024 kOSKextLogErrorLevel |
4025 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4026 "Can't load kext %s - failed to create link context.",
4027 getIdentifierCString());
4028 result = kOSKextReturnNoMemory;
4029 goto finish;
4030 }
4031 }
4032
4033 /* We only need to resolve dependencies once for the whole graph, but
4034 * resolveDependencies will just return if there's no work to do, so it's
4035 * safe to call it more than once.
4036 */
4037 if (!resolveDependencies()) {
4038 // xxx - check resolveDependencies() for log msg
4039 OSKextLog(this,
4040 kOSKextLogErrorLevel |
4041 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4042 "Can't load kext %s - failed to resolve library dependencies.",
4043 getIdentifierCString());
4044 result = kOSKextReturnDependencies;
4045 goto finish;
4046 }
4047
4048 /* If we are excluding just the kext being loaded now (and not its
4049 * dependencies), drop the exclusion level to none so dependencies
4050 * start and/or add their personalities.
4051 */
4052 if (dependenciesStartOpt == kOSKextExcludeKext) {
4053 dependenciesStartOpt = kOSKextExcludeNone;
4054 }
4055
4056 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
4057 dependenciesStartMatchingOpt = kOSKextExcludeNone;
4058 }
4059
4060 /* Load the dependencies, recursively.
4061 */
4062 count = getNumDependencies();
4063 for (i = 0; i < count; i++) {
4064 OSKext * dependency = OSDynamicCast(OSKext,
4065 dependencies->getObject(i));
4066 if (dependency == NULL) {
4067 OSKextLog(this,
4068 kOSKextLogErrorLevel |
4069 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4070 "Internal error loading kext %s; dependency disappeared.",
4071 getIdentifierCString());
4072 result = kOSKextReturnInternalError;
4073 goto finish;
4074 }
4075
4076 /* Dependencies must be started accorting to the opt,
4077 * but not given the personality names of the main kext.
4078 */
4079 result = dependency->load(dependenciesStartOpt,
4080 dependenciesStartMatchingOpt,
4081 /* personalityNames */ NULL);
4082 if (result != KERN_SUCCESS) {
4083 OSKextLog(this,
4084 kOSKextLogErrorLevel |
4085 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4086 "Dependency %s of kext %s failed to load.",
4087 dependency->getIdentifierCString(),
4088 getIdentifierCString());
4089
4090 OSKext::removeKext(dependency,
4091 /* terminateService/removePersonalities */ true);
4092 result = kOSKextReturnDependencyLoadError;
4093
4094 goto finish;
4095 }
4096 }
4097
4098 result = loadExecutable();
4099 if (result != KERN_SUCCESS) {
4100 goto finish;
4101 }
4102
4103 flags.loaded = true;
4104
4105 /* Add the kext to the list of loaded kexts and update the kmod_info
4106 * struct to point to that of the last loaded kext (which is the way
4107 * it's always been done, though I'd rather do them in order now).
4108 */
4109 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
4110 sLoadedKexts->setObject(this);
4111
4112 /* Keep the kernel itself out of the kmod list.
4113 */
4114 if (lastLoadedKext == sKernelKext) {
4115 lastLoadedKext = NULL;
4116 }
4117
4118 if (lastLoadedKext) {
4119 kmod_info->next = lastLoadedKext->kmod_info;
4120 }
4121
4122 /* Make the global kmod list point at the just-loaded kext. Note that the
4123 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4124 * although we do report it in kextstat these days by using the newer
4125 * OSArray of loaded kexts, which does contain it.
4126 *
4127 * (The OSKext object representing the kernel doesn't even have a kmod_info
4128 * struct, though I suppose we could stick a pointer to it from the
4129 * static struct in OSRuntime.cpp.)
4130 */
4131 kmod = kmod_info;
4132
4133 /* Save the list of loaded kexts in case we panic.
4134 */
4135 clock_get_uptime(&last_loaded_timestamp);
4136 OSKext::saveLoadedKextPanicList();
4137
4138 loaded:
4139 /* This is a bit of a hack, because we shouldn't be handling
4140 * personalities within the load function.
4141 */
4142 if (declaresExecutable() && (startOpt == kOSKextExcludeNone)) {
4143 result = start();
4144 if (result != kOSReturnSuccess) {
4145 OSKextLog(this,
4146 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4147 "Kext %s start failed (result 0x%x).",
4148 getIdentifierCString(), result);
4149 result = kOSKextReturnStartStopError;
4150 }
4151 }
4152
4153 /* If not excluding matching, send the personalities to the kernel.
4154 * This never affects the result of the load operation.
4155 */
4156 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
4157 sendPersonalitiesToCatalog(true, personalityNames);
4158 }
4159
4160 finish:
4161 if (result != kOSReturnSuccess) {
4162 OSKextLog(this,
4163 kOSKextLogErrorLevel |
4164 kOSKextLogLoadFlag,
4165 "Kext %s failed to load (0x%x).",
4166 getIdentifierCString(), (int)result);
4167 } else if (!alreadyLoaded) {
4168 OSKextLog(this,
4169 kOSKextLogProgressLevel |
4170 kOSKextLogLoadFlag,
4171 "Kext %s loaded.",
4172 getIdentifierCString());
4173 }
4174 return result;
4175 }
4176
4177 /*********************************************************************
4178 * called only by load()
4179 *********************************************************************/
4180 OSReturn
4181 OSKext::loadExecutable()
4182 {
4183 OSReturn result = kOSReturnError;
4184 kern_return_t kxldResult;
4185 u_char ** kxlddeps = NULL; // must kfree
4186 uint32_t num_kxlddeps = 0;
4187 uint32_t num_kmod_refs = 0;
4188 u_char * linkStateBytes = NULL; // do not free
4189 u_long linkStateLength = 0;
4190 u_char ** linkStateBytesPtr = NULL; // do not free
4191 u_long * linkStateLengthPtr = NULL; // do not free
4192 struct mach_header ** kxldHeaderPtr = NULL; // do not free
4193 struct mach_header * kxld_header = NULL; // xxx - need to free here?
4194 OSData * theExecutable = NULL; // do not release
4195 OSString * versString = NULL; // do not release
4196 const char * versCString = NULL; // do not free
4197 const char * string = NULL; // do not free
4198 unsigned int i;
4199
4200 /* We need the version string for a variety of bits below.
4201 */
4202 versString = OSDynamicCast(OSString,
4203 getPropertyForHostArch(kCFBundleVersionKey));
4204 if (!versString) {
4205 goto finish;
4206 }
4207 versCString = versString->getCStringNoCopy();
4208
4209 if (isKernelComponent()) {
4210 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
4211 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
4212 OSKextLog(this,
4213 kOSKextLogErrorLevel |
4214 kOSKextLogLoadFlag,
4215 "Kernel component %s has incorrect version %s; "
4216 "expected %s.",
4217 getIdentifierCString(),
4218 versCString, KERNEL6_VERSION);
4219 result = kOSKextReturnInternalError;
4220 goto finish;
4221 } else if (strcmp(versCString, osrelease)) {
4222 OSKextLog(this,
4223 kOSKextLogErrorLevel |
4224 kOSKextLogLoadFlag,
4225 "Kernel component %s has incorrect version %s; "
4226 "expected %s.",
4227 getIdentifierCString(),
4228 versCString, osrelease);
4229 result = kOSKextReturnInternalError;
4230 goto finish;
4231 }
4232 }
4233 }
4234
4235 if (isPrelinked()) {
4236 goto register_kmod;
4237 }
4238
4239 theExecutable = getExecutable();
4240 if (!theExecutable) {
4241 if (declaresExecutable()) {
4242 OSKextLog(this,
4243 kOSKextLogErrorLevel |
4244 kOSKextLogLoadFlag,
4245 "Can't load kext %s - executable is missing.",
4246 getIdentifierCString());
4247 result = kOSKextReturnValidation;
4248 goto finish;
4249 }
4250 goto register_kmod;
4251 }
4252
4253 if (isKernelComponent()) {
4254 num_kxlddeps = 1; // the kernel itself
4255 } else {
4256 num_kxlddeps = getNumDependencies();
4257 }
4258 if (!num_kxlddeps) {
4259 OSKextLog(this,
4260 kOSKextLogErrorLevel |
4261 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
4262 "Can't load kext %s - it has no library dependencies.",
4263 getIdentifierCString());
4264 goto finish;
4265 }
4266 kxlddeps = (u_char **)kalloc(num_kxlddeps * sizeof(*kxlddeps));
4267 if (!kxlddeps) {
4268 OSKextLog(this,
4269 kOSKextLogErrorLevel |
4270 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4271 "Can't allocate link context to load kext %s.",
4272 getIdentifierCString());
4273 goto finish;
4274 }
4275
4276 if (isKernelComponent()) {
4277 OSData * kernelLinkState = OSKext::getKernelLinkState();
4278 kxlddeps[0] = (u_char *)kernelLinkState->getBytesNoCopy();
4279 } else for (i = 0; i < num_kxlddeps; i++) {
4280 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
4281 if (!dependency->linkState) {
4282 // xxx - maybe we should panic here
4283 OSKextLog(this,
4284 kOSKextLogErrorLevel |
4285 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4286 "Can't load kext %s - link state missing.",
4287 getIdentifierCString());
4288 goto finish;
4289 }
4290 kxlddeps[i] = (u_char *)dependency->linkState->getBytesNoCopy();
4291 assert(kxlddeps[i]);
4292 }
4293
4294 /* We only need link state for a library kext.
4295 */
4296 if (compatibleVersion > -1 && (declaresExecutable() || isKernelComponent())) {
4297 linkStateBytesPtr = &linkStateBytes;
4298 linkStateLengthPtr = &linkStateLength;
4299 }
4300
4301 /* We only need the linked executable for a real kext.
4302 */
4303 if (!isInterface()) {
4304 kxldHeaderPtr = &kxld_header;
4305 }
4306
4307 #if DEBUG
4308 OSKextLog(this,
4309 kOSKextLogExplicitLevel |
4310 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
4311 "Kext %s - calling kxld_link_file:\n"
4312 " kxld_context: %p\n"
4313 " executable: %p executable_length: %d\n"
4314 " user_data: %p\n"
4315 " kxld_dependencies: %p num_dependencies: %d\n"
4316 " kxld_header_ptr: %p kmod_info_ptr: %p\n"
4317 " link_state_ptr: %p link_state_length_ptr: %p",
4318 getIdentifierCString(), kxldContext,
4319 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
4320 this, kxlddeps, num_kxlddeps,
4321 kxldHeaderPtr, kernelKmodInfoPtr,
4322 linkStateBytesPtr, linkStateLengthPtr);
4323 #endif
4324
4325 /* After this call, the linkedExecutable instance variable
4326 * should exist.
4327 */
4328 kxldResult = kxld_link_file(sKxldContext,
4329 (u_char *)theExecutable->getBytesNoCopy(),
4330 theExecutable->getLength(),
4331 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
4332 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info,
4333 linkStateBytesPtr, linkStateLengthPtr,
4334 /* symbolFile */ NULL, /* symbolFileSize */ NULL);
4335
4336 if (kxldResult != KERN_SUCCESS) {
4337 // xxx - add kxldResult here?
4338 OSKextLog(this,
4339 kOSKextLogErrorLevel |
4340 kOSKextLogLoadFlag,
4341 "Can't load kext %s - link failed.",
4342 getIdentifierCString());
4343 result = kOSKextReturnLinkError;
4344 goto finish;
4345 }
4346
4347 /* If we got a link state, wrap it in an OSData and keep it
4348 * around for later use linking other kexts that depend on this kext.
4349 */
4350 if (linkStateBytes && linkStateLength > 0) {
4351 linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
4352 assert(linkState);
4353 linkState->setDeallocFunction(&osdata_kmem_free);
4354 }
4355
4356 /* If this isn't an interface, We've written data & instructions into kernel
4357 * memory, so flush the data cache and invalidate the instruction cache.
4358 */
4359 if (!isInterface()) {
4360 flush_dcache(kmod_info->address, kmod_info->size, false);
4361 invalidate_icache(kmod_info->address, kmod_info->size, false);
4362 }
4363
4364 register_kmod:
4365
4366 if (isInterface()) {
4367
4368 /* Whip up a fake kmod_info entry for the interface kext.
4369 */
4370 kmod_info = (kmod_info_t *)kalloc(sizeof(kmod_info_t));
4371 if (!kmod_info) {
4372 result = KERN_MEMORY_ERROR;
4373 goto finish;
4374 }
4375
4376 /* A pseudokext has almost nothing in its kmod_info struct.
4377 */
4378 bzero(kmod_info, sizeof(kmod_info_t));
4379
4380 kmod_info->info_version = KMOD_INFO_VERSION;
4381
4382 /* An interface kext doesn't have a linkedExecutable, so save a
4383 * copy of the UUID out of the original executable via copyUUID()
4384 * while we still have the original executable.
4385 */
4386 interfaceUUID = copyUUID();
4387 }
4388
4389 kmod_info->id = loadTag = sNextLoadTag++;
4390 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
4391
4392 /* Stamp the bundle ID and version from the OSKext over anything
4393 * resident inside the kmod_info.
4394 */
4395 string = getIdentifierCString();
4396 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
4397
4398 string = versCString;
4399 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
4400
4401 /* Add the dependencies' kmod_info structs as kmod_references.
4402 */
4403 num_kmod_refs = getNumDependencies();
4404 if (num_kmod_refs) {
4405 kmod_info->reference_list = (kmod_reference_t *)kalloc(
4406 num_kmod_refs * sizeof(kmod_reference_t));
4407 if (!kmod_info->reference_list) {
4408 result = KERN_MEMORY_ERROR;
4409 goto finish;
4410 }
4411 bzero(kmod_info->reference_list,
4412 num_kmod_refs * sizeof(kmod_reference_t));
4413 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
4414 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
4415 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
4416 ref->info = refKext->kmod_info;
4417 ref->info->reference_count++;
4418
4419 if (refIndex + 1 < num_kmod_refs) {
4420 ref->next = kmod_info->reference_list + refIndex + 1;
4421 }
4422 }
4423 }
4424
4425 if (!isInterface() && linkedExecutable) {
4426 OSKextLog(this,
4427 kOSKextLogProgressLevel |
4428 kOSKextLogLoadFlag,
4429 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4430 kmod_info->name,
4431 (unsigned)kmod_info->size / PAGE_SIZE,
4432 (unsigned long)kmod_info->address,
4433 (unsigned)kmod_info->id);
4434 }
4435
4436 result = setVMProtections();
4437 if (result != KERN_SUCCESS) {
4438 goto finish;
4439 }
4440
4441 result = kOSReturnSuccess;
4442
4443 finish:
4444 if (kxlddeps) kfree(kxlddeps, (num_kxlddeps * sizeof(void *)));
4445
4446 /* We no longer need the unrelocated executable (which the linker
4447 * has altered anyhow).
4448 */
4449 setExecutable(NULL);
4450
4451 if (result != kOSReturnSuccess) {
4452 OSKextLog(this,
4453 kOSKextLogErrorLevel |
4454 kOSKextLogLoadFlag,
4455 "Failed to load executable for kext %s.",
4456 getIdentifierCString());
4457
4458 if (kmod_info && kmod_info->reference_list) {
4459 kfree(kmod_info->reference_list,
4460 num_kmod_refs * sizeof(kmod_reference_t));
4461 }
4462 if (isInterface()) {
4463 kfree(kmod_info, sizeof(kmod_info_t));
4464 }
4465 kmod_info = NULL;
4466 if (linkedExecutable) {
4467 linkedExecutable->release();
4468 linkedExecutable = NULL;
4469 }
4470 }
4471
4472 return result;
4473 }
4474
4475 /*********************************************************************
4476 * xxx - initWithPrelinkedInfoDict doesn't use this
4477 *********************************************************************/
4478 void
4479 OSKext::setLinkedExecutable(OSData * anExecutable)
4480 {
4481 if (linkedExecutable) {
4482 panic("Attempt to set linked executable on kext "
4483 "that already has one (%s).\n",
4484 getIdentifierCString());
4485 }
4486 linkedExecutable = anExecutable;
4487 linkedExecutable->retain();
4488 return;
4489 }
4490
4491 /*********************************************************************
4492 * called only by loadExecutable()
4493 *********************************************************************/
4494 OSReturn
4495 OSKext::setVMProtections(void)
4496 {
4497 vm_map_t kext_map = NULL;
4498 kernel_segment_command_t * seg = NULL;
4499 vm_map_offset_t start = 0;
4500 vm_map_offset_t end = 0;
4501 OSReturn result = kOSReturnError;
4502
4503 if (!kmod_info->address && !kmod_info->size) {
4504 result = kOSReturnSuccess;
4505 goto finish;
4506 }
4507
4508 /* Get the kext's vm map */
4509 kext_map = kext_get_vm_map(kmod_info);
4510 if (!kext_map) {
4511 result = KERN_MEMORY_ERROR;
4512 goto finish;
4513 }
4514
4515 /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
4516 * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
4517 * so the vm_map_protect calls below fail
4518 * I believe this happens in the call to vm_map_enter in kmem_init but I
4519 * need to confirm.
4520 */
4521 /* Protect the headers as read-only; they do not need to be wired */
4522 result = vm_map_protect(kext_map, kmod_info->address,
4523 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE);
4524 if (result != KERN_SUCCESS) {
4525 goto finish;
4526 }
4527
4528 /* Set the VM protections and wire down each of the segments */
4529 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
4530 while (seg) {
4531 start = round_page(seg->vmaddr);
4532 end = trunc_page(seg->vmaddr + seg->vmsize);
4533
4534 result = vm_map_protect(kext_map, start, end, seg->maxprot, TRUE);
4535 if (result != KERN_SUCCESS) {
4536 OSKextLog(this,
4537 kOSKextLogErrorLevel |
4538 kOSKextLogLoadFlag,
4539 "Kext %s failed to set maximum VM protections "
4540 "for segment %s - 0x%x.",
4541 getIdentifierCString(), seg->segname, (int)result);
4542 goto finish;
4543 }
4544
4545 result = vm_map_protect(kext_map, start, end, seg->initprot, FALSE);
4546 if (result != KERN_SUCCESS) {
4547 OSKextLog(this,
4548 kOSKextLogErrorLevel |
4549 kOSKextLogLoadFlag,
4550 "Kext %s failed to set initial VM protections "
4551 "for segment %s - 0x%x.",
4552 getIdentifierCString(), seg->segname, (int)result);
4553 goto finish;
4554 }
4555
4556 result = vm_map_wire(kext_map, start, end, seg->initprot, FALSE);
4557 if (result != KERN_SUCCESS) {
4558 goto finish;
4559 }
4560
4561 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
4562 }
4563
4564 finish:
4565 return result;
4566 }
4567
4568 /*********************************************************************
4569 *********************************************************************/
4570 OSReturn
4571 OSKext::validateKextMapping(bool startFlag)
4572 {
4573 OSReturn result = kOSReturnError;
4574 const char * whichOp = startFlag ? "start" : "stop";
4575 kern_return_t kern_result = 0;
4576 vm_map_t kext_map = NULL;
4577 mach_vm_address_t address = 0;
4578 mach_vm_size_t size = 0;
4579 uint32_t depth = 0;
4580 mach_msg_type_number_t count;
4581 vm_region_submap_short_info_data_64_t info;
4582
4583 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
4584 bzero(&info, sizeof(info));
4585
4586 // xxx - do we need a distinct OSReturn value for these or is "bad data"
4587 // xxx - sufficient?
4588
4589 /* Verify that the kmod_info and start/stop pointers are non-NULL.
4590 */
4591 if (!kmod_info) {
4592 OSKextLog(this,
4593 kOSKextLogErrorLevel |
4594 kOSKextLogLoadFlag,
4595 "Kext %s - NULL kmod_info pointer.",
4596 getIdentifierCString());
4597 result = kOSKextReturnBadData;
4598 goto finish;
4599 }
4600
4601 if (startFlag) {
4602 address = (mach_vm_address_t)kmod_info->start;
4603 } else {
4604 address = (mach_vm_address_t)kmod_info->stop;
4605 }
4606
4607 if (!address) {
4608 OSKextLog(this,
4609 kOSKextLogErrorLevel |
4610 kOSKextLogLoadFlag,
4611 "Kext %s - NULL module %s pointer.",
4612 getIdentifierCString(), whichOp);
4613 result = kOSKextReturnBadData;
4614 goto finish;
4615 }
4616
4617 kext_map = kext_get_vm_map(kmod_info);
4618 depth = (kernel_map == kext_map) ? 1 : 2;
4619
4620 /* Verify that the start/stop function lies within the kext's address range.
4621 */
4622 if (address < kmod_info->address + kmod_info->hdr_size ||
4623 kmod_info->address + kmod_info->size <= address)
4624 {
4625 OSKextLog(this,
4626 kOSKextLogErrorLevel |
4627 kOSKextLogLoadFlag,
4628 "Kext %s module %s pointer is outside of kext range "
4629 "(%s %p - kext at %p-%p)..",
4630 getIdentifierCString(),
4631 whichOp,
4632 whichOp,
4633 (void *)address,
4634 (void *)kmod_info->address,
4635 (void *)(kmod_info->address + kmod_info->size));
4636 result = kOSKextReturnBadData;
4637 goto finish;
4638 }
4639
4640 /* Only do these checks before calling the start function;
4641 * If anything goes wrong with the mapping while the kext is running,
4642 * we'll likely have panicked well before any attempt to stop the kext.
4643 */
4644 if (startFlag) {
4645
4646 /* Verify that the start/stop function is executable.
4647 */
4648 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
4649 (vm_region_recurse_info_t)&info, &count);
4650 if (kern_result != KERN_SUCCESS) {
4651 OSKextLog(this,
4652 kOSKextLogErrorLevel |
4653 kOSKextLogLoadFlag,
4654 "Kext %s - bad %s pointer %p.",
4655 getIdentifierCString(),
4656 whichOp, (void *)address);
4657 result = kOSKextReturnBadData;
4658 goto finish;
4659 }
4660
4661 if (!(info.protection & VM_PROT_EXECUTE)) {
4662 OSKextLog(this,
4663 kOSKextLogErrorLevel |
4664 kOSKextLogLoadFlag,
4665 "Kext %s - memory region containing module %s function "
4666 "is not executable.",
4667 getIdentifierCString(), whichOp);
4668 result = kOSKextReturnBadData;
4669 goto finish;
4670 }
4671
4672 /* Verify that the kext is backed by physical memory.
4673 */
4674 for (address = kmod_info->address;
4675 address < round_page(kmod_info->address + kmod_info->size);
4676 address += PAGE_SIZE)
4677 {
4678 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
4679 OSKextLog(this,
4680 kOSKextLogErrorLevel |
4681 kOSKextLogLoadFlag,
4682 "Kext %s - page %p is not backed by physical memory.",
4683 getIdentifierCString(),
4684 (void *)address);
4685 result = kOSKextReturnBadData;
4686 goto finish;
4687 }
4688 }
4689 }
4690
4691 result = kOSReturnSuccess;
4692 finish:
4693 return result;
4694 }
4695
4696 /*********************************************************************
4697 *********************************************************************/
4698 OSReturn
4699 OSKext::start(bool startDependenciesFlag)
4700 {
4701 OSReturn result = kOSReturnError;
4702 kern_return_t (* startfunc)(kmod_info_t *, void *);
4703 unsigned int i, count;
4704 void * kmodStartData = NULL; // special handling needed
4705 #if CONFIG_MACF_KEXT
4706 mach_msg_type_number_t kmodStartDataCount = 0;
4707 #endif /* CONFIG_MACF_KEXT */
4708
4709 if (isStarted() || isInterface() || isKernelComponent()) {
4710 result = kOSReturnSuccess;
4711 goto finish;
4712 }
4713
4714 if (!isLoaded()) {
4715 OSKextLog(this,
4716 kOSKextLogErrorLevel |
4717 kOSKextLogLoadFlag,
4718 "Attempt to start nonloaded kext %s.",
4719 getIdentifierCString());
4720 result = kOSKextReturnInvalidArgument;
4721 goto finish;
4722 }
4723
4724 result = validateKextMapping(/* start? */ true);
4725 if (result != kOSReturnSuccess) {
4726 goto finish;
4727 }
4728
4729 startfunc = kmod_info->start;
4730
4731 count = getNumDependencies();
4732 for (i = 0; i < count; i++) {
4733 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
4734 if (dependency == NULL) {
4735 OSKextLog(this,
4736 kOSKextLogErrorLevel |
4737 kOSKextLogLoadFlag,
4738 "Kext %s start - internal error, dependency disappeared.",
4739 getIdentifierCString());
4740 goto finish;
4741 }
4742 if (!dependency->isStarted()) {
4743 if (startDependenciesFlag) {
4744 OSReturn dependencyResult =
4745 dependency->start(startDependenciesFlag);
4746 if (dependencyResult != KERN_SUCCESS) {
4747 OSKextLog(this,
4748 kOSKextLogErrorLevel |
4749 kOSKextLogLoadFlag,
4750 "Kext %s start - dependency %s failed to start (error 0x%x).",
4751 getIdentifierCString(),
4752 dependency->getIdentifierCString(),
4753 dependencyResult);
4754 goto finish;
4755 }
4756 } else {
4757 OSKextLog(this,
4758 kOSKextLogErrorLevel |
4759 kOSKextLogLoadFlag,
4760 "Not starting %s - dependency %s not started yet.",
4761 getIdentifierCString(),
4762 dependency->getIdentifierCString());
4763 result = kOSKextReturnStartStopError; // xxx - make new return?
4764 goto finish;
4765 }
4766 }
4767 }
4768
4769 #if CONFIG_MACF_KEXT
4770 /* See if the kext has any MAC framework module data in its plist.
4771 * This is passed in as arg #2 of the kext's start routine,
4772 * which is otherwise reserved for any other kext.
4773 */
4774 kmodStartData = MACFCopyModuleDataForKext(this, &kmodStartDataCount);
4775 #endif /* CONFIG_MACF_KEXT */
4776
4777 OSKextLog(this,
4778 kOSKextLogDetailLevel |
4779 kOSKextLogLoadFlag,
4780 "Kext %s calling module start function.",
4781 getIdentifierCString());
4782
4783 flags.starting = 1;
4784
4785 #if !__i386__ && !__ppc__
4786 result = OSRuntimeInitializeCPP(kmod_info, NULL);
4787 if (result == KERN_SUCCESS) {
4788 #endif
4789
4790 result = startfunc(kmod_info, kmodStartData);
4791
4792 #if !__i386__ && !__ppc__
4793 if (result != KERN_SUCCESS) {
4794 (void) OSRuntimeFinalizeCPP(kmod_info, NULL);
4795 }
4796 }
4797 #endif
4798
4799 flags.starting = 0;
4800
4801 /* On success overlap the setting of started/starting. On failure just
4802 * clear starting.
4803 */
4804 if (result == KERN_SUCCESS) {
4805 flags.started = 1;
4806
4807 // xxx - log start error from kernel?
4808 OSKextLog(this,
4809 kOSKextLogProgressLevel |
4810 kOSKextLogLoadFlag,
4811 "Kext %s is now started.",
4812 getIdentifierCString());
4813 } else {
4814 invokeOrCancelRequestCallbacks(
4815 /* result not actually used */ kOSKextReturnStartStopError,
4816 /* invokeFlag */ false);
4817 OSKextLog(this,
4818 kOSKextLogProgressLevel |
4819 kOSKextLogLoadFlag,
4820 "Kext %s did not start (return code 0x%x).",
4821 getIdentifierCString(), result);
4822 }
4823
4824 finish:
4825 #if CONFIG_MACF_KEXT
4826 /* Free the module data for a MAC framework kext. When we start using
4827 * param #2 we'll have to distinguish and free/release appropriately.
4828 *
4829 * xxx - I'm pretty sure the old codepath freed the data and that it's
4830 * xxx - up to the kext to copy it.
4831 */
4832 if (kmodStartData) {
4833 kmem_free(kernel_map, (vm_offset_t)kmodStartData, kmodStartDataCount);
4834 }
4835 #endif /* CONFIG_MACF_KEXT */
4836
4837 return result;
4838 }
4839
4840 /*********************************************************************
4841 *********************************************************************/
4842 /* static */
4843 bool OSKext::canUnloadKextWithIdentifier(
4844 OSString * kextIdentifier,
4845 bool checkClassesFlag)
4846 {
4847 bool result = false;
4848 OSKext * aKext = NULL; // do not release
4849
4850 IORecursiveLockLock(sKextLock);
4851
4852 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4853
4854 if (!aKext) {
4855 goto finish; // can't unload what's not loaded
4856 }
4857
4858 if (aKext->isLoaded()) {
4859 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
4860 goto finish;
4861 }
4862 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
4863 goto finish;
4864 }
4865 }
4866
4867 result = true;
4868
4869 finish:
4870 IORecursiveLockUnlock(sKextLock);
4871 return result;
4872 }
4873
4874 /*********************************************************************
4875 *********************************************************************/
4876 OSReturn
4877 OSKext::stop(void)
4878 {
4879 OSReturn result = kOSReturnError;
4880 kern_return_t (*stopfunc)(kmod_info_t *, void *);
4881
4882 if (!isStarted() || isInterface()) {
4883 result = kOSReturnSuccess;
4884 goto finish;
4885 }
4886
4887 if (!isLoaded()) {
4888 OSKextLog(this,
4889 kOSKextLogErrorLevel |
4890 kOSKextLogLoadFlag,
4891 "Attempt to stop nonloaded kext %s.",
4892 getIdentifierCString());
4893 result = kOSKextReturnInvalidArgument;
4894 goto finish;
4895 }
4896
4897 /* Refuse to stop if we have clients or instances. It is up to
4898 * the caller to make sure those aren't true.
4899 */
4900 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
4901 OSKextLog(this,
4902 kOSKextLogErrorLevel |
4903 kOSKextLogLoadFlag,
4904 "Kext %s - C++ instances; can't stop.",
4905 getIdentifierCString());
4906 result = kOSKextReturnInUse;
4907 goto finish;
4908 }
4909
4910 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
4911
4912 OSKextLog(this,
4913 kOSKextLogErrorLevel |
4914 kOSKextLogLoadFlag,
4915 "Kext %s - has references (linkage or tracking object); "
4916 "can't stop.",
4917 getIdentifierCString());
4918 result = kOSKextReturnInUse;
4919 goto finish;
4920 }
4921
4922 /* Note: If validateKextMapping fails on the stop & unload path,
4923 * we are in serious trouble and a kernel panic is likely whether
4924 * we stop & unload the kext or not.
4925 */
4926 result = validateKextMapping(/* start? */ false);
4927 if (result != kOSReturnSuccess) {
4928 goto finish;
4929 }
4930
4931 /* Save the list of loaded kexts in case we panic.
4932 */
4933 OSKext::saveUnloadedKextPanicList(this);
4934
4935 stopfunc = kmod_info->stop;
4936 if (stopfunc) {
4937 OSKextLog(this,
4938 kOSKextLogDetailLevel |
4939 kOSKextLogLoadFlag,
4940 "Kext %s calling module stop function.",
4941 getIdentifierCString());
4942
4943 flags.stopping = 1;
4944
4945 result = stopfunc(kmod_info, /* userData */ NULL);
4946 #if !__i386__ && !__ppc__
4947 if (result == KERN_SUCCESS) {
4948 result = OSRuntimeFinalizeCPP(kmod_info, NULL);
4949 }
4950 #endif
4951
4952 flags.stopping = 0;
4953
4954 if (result == KERN_SUCCESS) {
4955 flags.started = 0;
4956
4957 OSKextLog(this,
4958 kOSKextLogDetailLevel |
4959 kOSKextLogLoadFlag,
4960 "Kext %s is now stopped and ready to unload.",
4961 getIdentifierCString());
4962 } else {
4963 OSKextLog(this,
4964 kOSKextLogErrorLevel |
4965 kOSKextLogLoadFlag,
4966 "Kext %s did not stop (return code 0x%x).",
4967 getIdentifierCString(), result);
4968 result = kOSKextReturnStartStopError;
4969 }
4970 }
4971
4972 finish:
4973 return result;
4974 }
4975
4976 /*********************************************************************
4977 *********************************************************************/
4978 OSReturn
4979 OSKext::unload(void)
4980 {
4981 OSReturn result = kOSReturnError;
4982 unsigned int index;
4983 uint32_t num_kmod_refs = 0;
4984
4985 if (!sUnloadEnabled) {
4986 OSKextLog(this,
4987 kOSKextLogErrorLevel |
4988 kOSKextLogLoadFlag,
4989 "Kext unloading is disabled (%s).",
4990 this->getIdentifierCString());
4991
4992 result = kOSKextReturnDisabled;
4993 goto finish;
4994 }
4995
4996 /* Refuse to unload if we have clients or instances. It is up to
4997 * the caller to make sure those aren't true.
4998 */
4999 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
5000 // xxx - Don't log under errors? this is more of an info thing
5001 OSKextLog(this,
5002 kOSKextLogErrorLevel |
5003 kOSKextLogKextBookkeepingFlag,
5004 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5005 getIdentifierCString());
5006 result = kOSKextReturnInUse;
5007 goto finish;
5008 }
5009
5010
5011 if (hasOSMetaClassInstances()) {
5012 OSKextLog(this,
5013 kOSKextLogErrorLevel |
5014 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5015 "Can't unload kext %s; classes have instances:",
5016 getIdentifierCString());
5017 reportOSMetaClassInstances(kOSKextLogErrorLevel |
5018 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
5019 result = kOSKextReturnInUse;
5020 goto finish;
5021 }
5022
5023 if (!isLoaded()) {
5024 result = kOSReturnSuccess;
5025 goto finish;
5026 }
5027
5028 if (isKernelComponent()) {
5029 result = kOSKextReturnInvalidArgument;
5030 goto finish;
5031 }
5032
5033 /* Note that the kext is unloading before running any code that
5034 * might be in the kext (request callbacks, module stop function).
5035 * We will deny certain requests made against a kext in the process
5036 * of unloading.
5037 */
5038 flags.unloading = 1;
5039
5040 if (isStarted()) {
5041 result = stop();
5042 if (result != KERN_SUCCESS) {
5043 OSKextLog(this,
5044 kOSKextLogErrorLevel |
5045 kOSKextLogLoadFlag,
5046 "Kext %s can't unload - module stop returned 0x%x.",
5047 getIdentifierCString(), (unsigned)result);
5048 result = kOSKextReturnStartStopError;
5049 goto finish;
5050 }
5051 }
5052
5053 OSKextLog(this,
5054 kOSKextLogProgressLevel |
5055 kOSKextLogLoadFlag,
5056 "Kext %s unloading.",
5057 getIdentifierCString());
5058
5059 /* Even if we don't call the stop function, we want to be sure we
5060 * have no OSMetaClass references before unloading the kext executable
5061 * from memory. OSMetaClasses may have pointers into the kext executable
5062 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5063 */
5064 if (metaClasses) {
5065 metaClasses->flushCollection();
5066 }
5067
5068 /* Remove the kext from the list of loaded kexts, patch the gap
5069 * in the kmod_info_t linked list, and reset "kmod" to point to the
5070 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5071 */
5072 index = sLoadedKexts->getNextIndexOfObject(this, 0);
5073 if (index != (unsigned int)-1) {
5074
5075 sLoadedKexts->removeObject(index);
5076
5077 OSKext * nextKext = OSDynamicCast(OSKext,
5078 sLoadedKexts->getObject(index));
5079
5080 if (nextKext) {
5081 if (index > 0) {
5082 OSKext * gapKext = OSDynamicCast(OSKext,
5083 sLoadedKexts->getObject(index - 1));
5084
5085 nextKext->kmod_info->next = gapKext->kmod_info;
5086
5087 } else /* index == 0 */ {
5088 nextKext->kmod_info->next = NULL;
5089 }
5090 }
5091
5092 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5093 if (lastKext && lastKext != sKernelKext) {
5094 kmod = lastKext->kmod_info;
5095 } else {
5096 kmod = NULL; // clear the global kmod variable
5097 }
5098 }
5099
5100 /* Clear out the kmod references that we're keeping for compatibility
5101 * with current panic backtrace code & kgmacros.
5102 * xxx - will want to update those bits sometime and remove this.
5103 */
5104 num_kmod_refs = getNumDependencies();
5105 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
5106 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
5107 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
5108 ref->info->reference_count--;
5109 }
5110 kfree(kmod_info->reference_list,
5111 num_kmod_refs * sizeof(kmod_reference_t));
5112 }
5113
5114 /* If we have a linked executable, release & clear it, and then
5115 * unwire & deallocate the buffer the OSData wrapped.
5116 */
5117 if (linkedExecutable) {
5118 vm_map_t kext_map;
5119
5120 /* linkedExecutable is just a wrapper for the executable and doesn't
5121 * free it.
5122 */
5123 linkedExecutable->release();
5124 linkedExecutable = NULL;
5125
5126 OSKextLog(this,
5127 kOSKextLogProgressLevel |
5128 kOSKextLogLoadFlag,
5129 "Kext %s unwiring and unmapping linked executable.",
5130 getIdentifierCString());
5131
5132 kext_map = kext_get_vm_map(kmod_info);
5133 if (kext_map) {
5134 // xxx - do we have to do this before freeing? Why can't we just free it?
5135 // xxx - we should be able to set a dealloc func on the linkedExecutable
5136 result = vm_map_unwire(kext_map,
5137 kmod_info->address + kmod_info->hdr_size,
5138 kmod_info->address + kmod_info->size, FALSE);
5139 if (result == KERN_SUCCESS) {
5140 kext_free(kmod_info->address, kmod_info->size);
5141 }
5142 }
5143 }
5144
5145 /* An interface kext has a fake kmod_info that was allocated,
5146 * so we have to free it.
5147 */
5148 if (isInterface()) {
5149 kfree(kmod_info, sizeof(kmod_info_t));
5150 }
5151
5152 kmod_info = NULL;
5153
5154 flags.loaded = false;
5155 flushDependencies();
5156
5157 OSKextLog(this,
5158 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5159 "Kext %s unloaded.", getIdentifierCString());
5160
5161 finish:
5162 OSKext::saveLoadedKextPanicList();
5163
5164 flags.unloading = 0;
5165 return result;
5166 }
5167
5168 /*********************************************************************
5169 *********************************************************************/
5170 static void
5171 _OSKextConsiderDestroyingLinkContext(
5172 __unused thread_call_param_t p0,
5173 __unused thread_call_param_t p1)
5174 {
5175 /* Once both recursive locks are taken in correct order, we shouldn't
5176 * have to worry about further recursive lock takes.
5177 */
5178 IORecursiveLockLock(sKextLock);
5179 IORecursiveLockLock(sKextInnerLock);
5180
5181 /* The first time we destroy the kxldContext is in the first
5182 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5183 * before calling this function. Thereafter any call to this function
5184 * will actually destroy the context.
5185 */
5186 if (sConsiderUnloadsCalled && sKxldContext) {
5187 kxld_destroy_context(sKxldContext);
5188 sKxldContext = NULL;
5189 }
5190
5191 /* Free the thread_call that was allocated to execute this function.
5192 */
5193 if (sDestroyLinkContextThread) {
5194 if (!thread_call_free(sDestroyLinkContextThread)) {
5195 OSKextLog(/* kext */ NULL,
5196 kOSKextLogErrorLevel |
5197 kOSKextLogGeneralFlag,
5198 "thread_call_free() failed for kext link context.");
5199 }
5200 sDestroyLinkContextThread = 0;
5201 }
5202
5203 IORecursiveLockUnlock(sKextInnerLock);
5204 IORecursiveLockUnlock(sKextLock);
5205
5206 return;
5207 }
5208
5209 /*********************************************************************
5210 * Destroying the kxldContext requires checking variables under both
5211 * sKextInnerLock and sKextLock, so we do it on a separate thread
5212 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5213 * call relationship.
5214 *
5215 * Do not call any function that takes sKextLock here! This function
5216 * can be invoked with sKextInnerLock, and the two must always
5217 * be taken in the order: sKextLock -> sKextInnerLock.
5218 *********************************************************************/
5219 /* static */
5220 void
5221 OSKext::considerDestroyingLinkContext(void)
5222 {
5223 IORecursiveLockLock(sKextInnerLock);
5224
5225 /* If we have already queued a thread to destroy the link context,
5226 * don't bother resetting; that thread will take care of it.
5227 */
5228 if (sDestroyLinkContextThread) {
5229 goto finish;
5230 }
5231
5232 /* The function to be invoked in the thread will deallocate
5233 * this thread_call, so don't share it around.
5234 */
5235 sDestroyLinkContextThread = thread_call_allocate(
5236 &_OSKextConsiderDestroyingLinkContext, 0);
5237 if (!sDestroyLinkContextThread) {
5238 OSKextLog(/* kext */ NULL,
5239 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
5240 "Can't create thread to destroy kext link context.");
5241 goto finish;
5242 }
5243
5244 thread_call_enter(sDestroyLinkContextThread);
5245
5246 finish:
5247 IORecursiveLockUnlock(sKextInnerLock);
5248 return;
5249 }
5250
5251 /*********************************************************************
5252 *********************************************************************/
5253 OSData *
5254 OSKext::getKernelLinkState()
5255 {
5256 kern_return_t kxldResult;
5257 u_char * kernel = NULL;
5258 size_t kernelLength;
5259 u_char * linkStateBytes = NULL;
5260 u_long linkStateLength;
5261 OSData * linkState = NULL;
5262
5263 if (sKernelKext && sKernelKext->linkState) {
5264 goto finish;
5265 }
5266
5267 kernel = (u_char *)&_mh_execute_header;
5268 kernelLength = getlastaddr() - (vm_offset_t)kernel;
5269
5270 kxldResult = kxld_link_file(sKxldContext,
5271 kernel,
5272 kernelLength,
5273 kOSKextKernelIdentifier,
5274 /* callbackData */ NULL,
5275 /* dependencies */ NULL,
5276 /* numDependencies */ 0,
5277 /* linkedObjectOut */ NULL,
5278 /* kmod_info_kern out */ NULL,
5279 &linkStateBytes,
5280 &linkStateLength,
5281 /* symbolFile */ NULL,
5282 /* symbolFileSize */ NULL);
5283 if (kxldResult) {
5284 panic("Can't generate kernel link state; no kexts can be loaded.");
5285 goto finish;
5286 }
5287
5288 linkState = OSData::withBytesNoCopy(linkStateBytes, linkStateLength);
5289 linkState->setDeallocFunction(&osdata_kmem_free);
5290 sKernelKext->linkState = linkState;
5291
5292 finish:
5293 return sKernelKext->linkState;
5294 }
5295
5296 #if PRAGMA_MARK
5297 #pragma mark Autounload
5298 #endif
5299 /*********************************************************************
5300 * This is a static method because the kext will be deallocated if it
5301 * does unload!
5302 *********************************************************************/
5303 OSReturn
5304 OSKext::autounloadKext(OSKext * aKext)
5305 {
5306 OSReturn result = kOSKextReturnInUse;
5307
5308 /* Check for external references to this kext (usu. dependents),
5309 * instances of defined classes (or classes derived from them),
5310 * outstanding requests.
5311 */
5312 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
5313 !aKext->flags.autounloadEnabled ||
5314 aKext->isKernelComponent()) {
5315
5316 goto finish;
5317 }
5318
5319 /* Skip a delay-autounload kext, once.
5320 */
5321 if (aKext->flags.delayAutounload) {
5322 OSKextLog(aKext,
5323 kOSKextLogProgressLevel |
5324 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5325 "Kext %s has delayed autounload set; skipping and clearing flag.",
5326 aKext->getIdentifierCString());
5327 aKext->flags.delayAutounload = 0;
5328 goto finish;
5329 }
5330
5331 if (aKext->hasOSMetaClassInstances() ||
5332 aKext->countRequestCallbacks()) {
5333 goto finish;
5334 }
5335
5336 result = OSKext::removeKext(aKext);
5337
5338 finish:
5339
5340 return result;
5341 }
5342
5343 /*********************************************************************
5344 *********************************************************************/
5345 void
5346 _OSKextConsiderUnloads(
5347 __unused thread_call_param_t p0,
5348 __unused thread_call_param_t p1)
5349 {
5350 bool didUnload = false;
5351 unsigned int count, i;
5352
5353 /* Once both recursive locks are taken in correct order, we shouldn't
5354 * have to worry about further recursive lock takes.
5355 */
5356 IORecursiveLockLock(sKextLock);
5357 IORecursiveLockLock(sKextInnerLock);
5358
5359 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
5360
5361 /* If the system is powering down, don't try to unload anything.
5362 */
5363 if (sSystemSleep) {
5364 goto finish;
5365 }
5366
5367 OSKextLog(/* kext */ NULL,
5368 kOSKextLogProgressLevel |
5369 kOSKextLogLoadFlag,
5370 "Checking for unused kexts to autounload.");
5371
5372 /*****
5373 * Remove any request callbacks marked as stale,
5374 * and mark as stale any currently in flight.
5375 */
5376 count = sRequestCallbackRecords->getCount();
5377 if (count) {
5378 i = count - 1;
5379 do {
5380 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
5381 sRequestCallbackRecords->getObject(i));
5382 OSBoolean * stale = OSDynamicCast(OSBoolean,
5383 callbackRecord->getObject(kKextRequestStaleKey));
5384
5385 if (stale && stale->isTrue()) {
5386 OSKext::invokeRequestCallback(callbackRecord,
5387 kOSKextReturnTimeout);
5388 } else {
5389 callbackRecord->setObject(kKextRequestStaleKey,
5390 kOSBooleanTrue);
5391 }
5392 } while (i--);
5393 }
5394
5395 /*****
5396 * Make multiple passes through the array of loaded kexts until
5397 * we don't unload any. This handles unwinding of dependency
5398 * chains. We have to go *backwards* through the array because
5399 * kexts are removed from it when unloaded, and we cannot make
5400 * a copy or we'll mess up the retain counts we rely on to
5401 * check whether a kext will unload. If only we could have
5402 * nonretaining collections like CF has....
5403 */
5404 do {
5405 didUnload = false;
5406
5407 count = sLoadedKexts->getCount();
5408 if (count) {
5409 i = count - 1;
5410 do {
5411 OSKext * thisKext = OSDynamicCast(OSKext,
5412 sLoadedKexts->getObject(i));
5413 didUnload = (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
5414 } while (i--);
5415 }
5416 } while (didUnload);
5417
5418 finish:
5419 sConsiderUnloadsPending = false;
5420 sConsiderUnloadsExecuted = true;
5421
5422 (void) OSKext::considerRebuildOfPrelinkedKernel();
5423
5424 IORecursiveLockUnlock(sKextInnerLock);
5425 IORecursiveLockUnlock(sKextLock);
5426
5427 return;
5428 }
5429
5430 /*********************************************************************
5431 * Do not call any function that takes sKextLock here!
5432 *********************************************************************/
5433 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
5434 {
5435 AbsoluteTime when;
5436
5437 IORecursiveLockLock(sKextInnerLock);
5438
5439 if (!sUnloadCallout) {
5440 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, 0);
5441 }
5442
5443 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
5444 goto finish;
5445 }
5446
5447 thread_call_cancel(sUnloadCallout);
5448 if (OSKext::getAutounloadEnabled() && !sSystemSleep) {
5449 clock_interval_to_deadline(sConsiderUnloadDelay,
5450 1000 * 1000 * 1000, &when);
5451
5452 OSKextLog(/* kext */ NULL,
5453 kOSKextLogProgressLevel |
5454 kOSKextLogLoadFlag,
5455 "%scheduling %sscan for unused kexts in %lu seconds.",
5456 sConsiderUnloadsPending ? "Res" : "S",
5457 sConsiderUnloadsCalled ? "" : "initial ",
5458 (unsigned long)sConsiderUnloadDelay);
5459
5460 sConsiderUnloadsPending = true;
5461 thread_call_enter_delayed(sUnloadCallout, when);
5462 }
5463
5464 finish:
5465 /* The kxld context should be reused throughout boot. We mark the end of
5466 * period as the first time considerUnloads() is called, and we destroy
5467 * the first kxld context in that function. Afterwards, it will be
5468 * destroyed in flushNonloadedKexts.
5469 */
5470 if (!sConsiderUnloadsCalled) {
5471 sConsiderUnloadsCalled = true;
5472 OSKext::considerDestroyingLinkContext();
5473 }
5474
5475 IORecursiveLockUnlock(sKextInnerLock);
5476 return;
5477 }
5478
5479 /*********************************************************************
5480 * Do not call any function that takes sKextLock here!
5481 *********************************************************************/
5482 extern "C" {
5483
5484 IOReturn OSKextSystemSleepOrWake(UInt32 messageType)
5485 {
5486 IORecursiveLockLock(sKextInnerLock);
5487
5488 /* If the system is going to sleep, cancel the reaper thread timer,
5489 * and note that we're in a sleep state in case it just fired but hasn't
5490 * taken the lock yet. If we are coming back from sleep, just
5491 * clear the sleep flag; IOService's normal operation will cause
5492 * unloads to be considered soon enough.
5493 */
5494 if (messageType == kIOMessageSystemWillSleep) {
5495 if (sUnloadCallout) {
5496 thread_call_cancel(sUnloadCallout);
5497 }
5498 sSystemSleep = true;
5499 } else if (messageType == kIOMessageSystemHasPoweredOn) {
5500 sSystemSleep = false;
5501 }
5502 IORecursiveLockUnlock(sKextInnerLock);
5503
5504 return kIOReturnSuccess;
5505 }
5506
5507 };
5508
5509
5510 #if PRAGMA_MARK
5511 #pragma mark Prelinked Kernel
5512 #endif
5513 /*********************************************************************
5514 * Do not access sConsiderUnloads... variables other than
5515 * sConsiderUnloadsExecuted in this function. They are guarded by a
5516 * different lock.
5517 *********************************************************************/
5518 /* static */
5519 void
5520 OSKext::considerRebuildOfPrelinkedKernel(void)
5521 {
5522 OSReturn checkResult = kOSReturnError;
5523 static bool requestedPrelink = false;
5524 OSDictionary * prelinkRequest = NULL; // must release
5525
5526 IORecursiveLockLock(sKextLock);
5527
5528 if (!sDeferredLoadSucceeded || !sConsiderUnloadsExecuted ||
5529 sSafeBoot || requestedPrelink)
5530 {
5531 goto finish;
5532 }
5533
5534 OSKextLog(/* kext */ NULL,
5535 kOSKextLogProgressLevel |
5536 kOSKextLogArchiveFlag,
5537 "Requesting build of prelinked kernel.");
5538
5539 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
5540 &prelinkRequest);
5541 if (checkResult != kOSReturnSuccess) {
5542 goto finish;
5543 }
5544
5545 if (!sKernelRequests->setObject(prelinkRequest)) {
5546 goto finish;
5547 }
5548
5549 OSKextPingKextd();
5550 requestedPrelink = true;
5551
5552 finish:
5553 IORecursiveLockUnlock(sKextLock);
5554 OSSafeRelease(prelinkRequest);
5555 return;
5556 }
5557
5558 #if PRAGMA_MARK
5559 #pragma mark Dependencies
5560 #endif
5561 /*********************************************************************
5562 *********************************************************************/
5563 bool
5564 OSKext::resolveDependencies(
5565 OSArray * loopStack)
5566 {
5567 bool result = false;
5568 OSArray * localLoopStack = NULL; // must release
5569 bool addedToLoopStack = false;
5570 OSDictionary * libraries = NULL; // do not release
5571 OSCollectionIterator * libraryIterator = NULL; // must release
5572 OSString * libraryID = NULL; // do not release
5573 OSString * infoString = NULL; // do not release
5574 OSString * readableString = NULL; // do not release
5575 OSKext * libraryKext = NULL; // do not release
5576 bool hasRawKernelDependency = false;
5577 bool hasKernelDependency = false;
5578 bool hasKPIDependency = false;
5579 bool hasPrivateKPIDependency = false;
5580 unsigned int count;
5581
5582 /* A kernel component will automatically have this flag set,
5583 * and a loaded kext should also have it set (as should all its
5584 * loaded dependencies).
5585 */
5586 if (flags.hasAllDependencies) {
5587 result = true;
5588 goto finish;
5589 }
5590
5591 /* Check for loops in the dependency graph.
5592 */
5593 if (loopStack) {
5594 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
5595 OSKextLog(this,
5596 kOSKextLogErrorLevel |
5597 kOSKextLogDependenciesFlag,
5598 "Kext %s has a dependency loop; can't resolve dependencies.",
5599 getIdentifierCString());
5600 goto finish;
5601 }
5602 } else {
5603 OSKextLog(this,
5604 kOSKextLogStepLevel |
5605 kOSKextLogDependenciesFlag,
5606 "Kext %s resolving dependencies.",
5607 getIdentifierCString());
5608
5609 loopStack = OSArray::withCapacity(6); // any small capacity will do
5610 if (!loopStack) {
5611 OSKextLog(this,
5612 kOSKextLogErrorLevel |
5613 kOSKextLogDependenciesFlag,
5614 "Kext %s can't create bookkeeping stack to resolve dependencies.",
5615 getIdentifierCString());
5616 goto finish;
5617 }
5618 localLoopStack = loopStack;
5619 }
5620 if (!loopStack->setObject(this)) {
5621 OSKextLog(this,
5622 kOSKextLogErrorLevel |
5623 kOSKextLogDependenciesFlag,
5624 "Kext %s - internal error resolving dependencies.",
5625 getIdentifierCString());
5626 goto finish;
5627 }
5628 addedToLoopStack = true;
5629
5630 /* Purge any existing kexts in the dependency list and start over.
5631 */
5632 flushDependencies();
5633 if (dependencies) {
5634 OSKextLog(this,
5635 kOSKextLogErrorLevel |
5636 kOSKextLogDependenciesFlag,
5637 "Kext %s - internal error resolving dependencies.",
5638 getIdentifierCString());
5639 }
5640
5641 libraries = OSDynamicCast(OSDictionary,
5642 getPropertyForHostArch(kOSBundleLibrariesKey));
5643 if (libraries == NULL || libraries->getCount() == 0) {
5644 OSKextLog(this,
5645 kOSKextLogErrorLevel |
5646 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5647 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
5648 getIdentifierCString(), kOSBundleLibrariesKey);
5649 goto finish;
5650 }
5651
5652 /* Make a new array to hold the dependencies (flush freed the old one).
5653 */
5654 dependencies = OSArray::withCapacity(libraries->getCount());
5655 if (!dependencies) {
5656 OSKextLog(this,
5657 kOSKextLogErrorLevel |
5658 kOSKextLogDependenciesFlag,
5659 "Kext %s - can't allocate dependencies array.",
5660 getIdentifierCString());
5661 goto finish;
5662 }
5663
5664 // xxx - compat: We used to add an implicit dependency on kernel 6.0
5665 // xxx - compat: if none were declared.
5666
5667 libraryIterator = OSCollectionIterator::withCollection(libraries);
5668 if (!libraryIterator) {
5669 OSKextLog(this,
5670 kOSKextLogErrorLevel |
5671 kOSKextLogDependenciesFlag,
5672 "Kext %s - can't allocate dependencies iterator.",
5673 getIdentifierCString());
5674 goto finish;
5675 }
5676
5677 while ((libraryID = OSDynamicCast(OSString,
5678 libraryIterator->getNextObject()))) {
5679
5680 const char * library_id = libraryID->getCStringNoCopy();
5681
5682 OSString * libraryVersion = OSDynamicCast(OSString,
5683 libraries->getObject(libraryID));
5684 if (libraryVersion == NULL) {
5685 OSKextLog(this,
5686 kOSKextLogErrorLevel |
5687 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5688 "Kext %s - illegal type in OSBundleLibraries.",
5689 getIdentifierCString());
5690 goto finish;
5691 }
5692
5693 OSKextVersion libraryVers =
5694 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
5695 if (libraryVers == -1) {
5696 OSKextLog(this,
5697 kOSKextLogErrorLevel |
5698 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5699 "Kext %s - invalid library version %s.",
5700 getIdentifierCString(),
5701 libraryVersion->getCStringNoCopy());
5702 goto finish;
5703 }
5704
5705 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
5706 if (libraryKext == NULL) {
5707 OSKextLog(this,
5708 kOSKextLogErrorLevel |
5709 kOSKextLogDependenciesFlag,
5710 "Kext %s - library kext %s not found.",
5711 getIdentifierCString(), library_id);
5712 goto finish;
5713 }
5714
5715 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
5716 OSKextLog(this,
5717 kOSKextLogErrorLevel |
5718 kOSKextLogDependenciesFlag,
5719 "Kext %s - library kext %s not compatible "
5720 "with requested version %s.",
5721 getIdentifierCString(), library_id,
5722 libraryVersion->getCStringNoCopy());
5723 goto finish;
5724 }
5725
5726 if (!libraryKext->resolveDependencies(loopStack)) {
5727 goto finish;
5728 }
5729
5730 /* Add the library directly only if it has an executable to link.
5731 * Otherwise it's just used to collect other dependencies, so put
5732 * *its* dependencies on the list for this kext.
5733 */
5734 // xxx - We are losing info here; would like to make fake entries or
5735 // xxx - keep these in the dependency graph for loaded kexts.
5736 // xxx - I really want to make kernel components not a special case!
5737 if (libraryKext->declaresExecutable() ||
5738 libraryKext->isInterface()) {
5739
5740 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
5741 dependencies->setObject(libraryKext);
5742
5743 OSKextLog(this,
5744 kOSKextLogDetailLevel |
5745 kOSKextLogDependenciesFlag,
5746 "Kext %s added dependency %s.",
5747 getIdentifierCString(),
5748 libraryKext->getIdentifierCString());
5749 }
5750 } else {
5751 int numLibDependencies = libraryKext->getNumDependencies();
5752 OSArray * libraryDependencies = libraryKext->getDependencies();
5753 int index;
5754
5755 if (numLibDependencies) {
5756 // xxx - this msg level should be 1 lower than the per-kext one
5757 OSKextLog(this,
5758 kOSKextLogDetailLevel |
5759 kOSKextLogDependenciesFlag,
5760 "Kext %s pulling %d dependencies from codeless library %s.",
5761 getIdentifierCString(),
5762 numLibDependencies,
5763 libraryKext->getIdentifierCString());
5764 }
5765 for (index = 0; index < numLibDependencies; index++) {
5766 OSKext * thisLibDependency = OSDynamicCast(OSKext,
5767 libraryDependencies->getObject(index));
5768 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
5769 dependencies->setObject(thisLibDependency);
5770 OSKextLog(this,
5771 kOSKextLogDetailLevel |
5772 kOSKextLogDependenciesFlag,
5773 "Kext %s added dependency %s from codeless library %s.",
5774 getIdentifierCString(),
5775 thisLibDependency->getIdentifierCString(),
5776 libraryKext->getIdentifierCString());
5777 }
5778 }
5779 }
5780
5781 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
5782 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB)-1)) {
5783
5784 hasRawKernelDependency = true;
5785 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
5786 hasKernelDependency = true;
5787 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
5788 hasKPIDependency = true;
5789 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI)-1)) {
5790 hasPrivateKPIDependency = true;
5791 }
5792 }
5793 }
5794
5795 #if __LP64__
5796 if (hasRawKernelDependency || hasKernelDependency) {
5797 OSKextLog(this,
5798 kOSKextLogErrorLevel |
5799 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5800 "Error - kext %s declares %s dependencies. "
5801 "Only %s* dependencies are supported for 64-bit kexts.",
5802 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
5803 goto finish;
5804 }
5805 if (!hasKPIDependency) {
5806 OSKextLog(this,
5807 kOSKextLogWarningLevel |
5808 kOSKextLogDependenciesFlag,
5809 "Warning - kext %s declares no %s* dependencies. "
5810 "If it uses any KPIs, the link may fail with undefined symbols.",
5811 getIdentifierCString(), KPI_LIB_PREFIX);
5812 }
5813 #else /* __LP64__ */
5814 // xxx - will change to flatly disallow "kernel" dependencies at some point
5815 // xxx - is it invalid to do both "com.apple.kernel" and any
5816 // xxx - "com.apple.kernel.*"?
5817
5818 if (hasRawKernelDependency && hasKernelDependency) {
5819 OSKextLog(this,
5820 kOSKextLogErrorLevel |
5821 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
5822 "Error - kext %s declares dependencies on both "
5823 "%s and %s.",
5824 getIdentifierCString(), KERNEL_LIB, KERNEL6_LIB);
5825 goto finish;
5826 }
5827
5828 if ((hasRawKernelDependency || hasKernelDependency) && hasKPIDependency) {
5829 OSKextLog(this,
5830 kOSKextLogWarningLevel |
5831 kOSKextLogDependenciesFlag,
5832 "Warning - kext %s has immediate dependencies on both "
5833 "%s* and %s* components; use only one style.",
5834 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
5835 }
5836
5837 if (!hasRawKernelDependency && !hasKernelDependency && !hasKPIDependency) {
5838 // xxx - do we want to use validation flag for these too?
5839 OSKextLog(this,
5840 kOSKextLogWarningLevel |
5841 kOSKextLogDependenciesFlag,
5842 "Warning - %s declares no kernel dependencies; using %s.",
5843 getIdentifierCString(), KERNEL6_LIB);
5844 OSKext * kernelKext = OSDynamicCast(OSKext,
5845 sKextsByID->getObject(KERNEL6_LIB));
5846 if (kernelKext) {
5847 dependencies->setObject(kernelKext);
5848 } else {
5849 OSKextLog(this,
5850 kOSKextLogErrorLevel |
5851 kOSKextLogDependenciesFlag,
5852 "Error - Library %s not found for %s.",
5853 KERNEL6_LIB, getIdentifierCString());
5854 }
5855 }
5856
5857 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
5858 * its indirect dependencies to simulate old-style linking. XXX - Should
5859 * check for duplicates.
5860 */
5861 if (!hasRawKernelDependency && !hasKPIDependency) {
5862 unsigned int i;
5863
5864 count = getNumDependencies();
5865
5866 /* We add to the dependencies array in this loop, but do not iterate
5867 * past its original count.
5868 */
5869 for (i = 0; i < count; i++) {
5870 OSKext * dependencyKext = OSDynamicCast(OSKext,
5871 dependencies->getObject(i));
5872 dependencyKext->addBleedthroughDependencies(dependencies);
5873 }
5874 }
5875 #endif /* __LP64__ */
5876
5877 if (hasPrivateKPIDependency) {
5878 bool hasApplePrefix = false;
5879 bool infoCopyrightIsValid = false;
5880 bool readableCopyrightIsValid = false;
5881
5882 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
5883 APPLE_KEXT_PREFIX);
5884
5885 infoString = OSDynamicCast(OSString,
5886 getPropertyForHostArch("CFBundleGetInfoString"));
5887 if (infoString) {
5888 infoCopyrightIsValid =
5889 kxld_validate_copyright_string(infoString->getCStringNoCopy());
5890 }
5891
5892 readableString = OSDynamicCast(OSString,
5893 getPropertyForHostArch("NSHumanReadableCopyright"));
5894 if (readableString) {
5895 readableCopyrightIsValid =
5896 kxld_validate_copyright_string(readableString->getCStringNoCopy());
5897 }
5898
5899 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
5900 OSKextLog(this,
5901 kOSKextLogErrorLevel |
5902 kOSKextLogDependenciesFlag,
5903 "Error - kext %s declares a dependency on %s. "
5904 "Only Apple kexts may declare a dependency on %s.",
5905 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
5906 goto finish;
5907 }
5908 }
5909
5910 result = true;
5911 flags.hasAllDependencies = 1;
5912
5913 finish:
5914
5915 if (addedToLoopStack) {
5916 count = loopStack->getCount();
5917 if (count > 0 && (this == loopStack->getObject(count - 1))) {
5918 loopStack->removeObject(count - 1);
5919 } else {
5920 OSKextLog(this,
5921 kOSKextLogErrorLevel |
5922 kOSKextLogDependenciesFlag,
5923 "Kext %s - internal error resolving dependencies.",
5924 getIdentifierCString());
5925 }
5926 }
5927
5928 if (result && localLoopStack) {
5929 OSKextLog(this,
5930 kOSKextLogStepLevel |
5931 kOSKextLogDependenciesFlag,
5932 "Kext %s successfully resolved dependencies.",
5933 getIdentifierCString());
5934 }
5935
5936 OSSafeRelease(localLoopStack);
5937 OSSafeRelease(libraryIterator);
5938
5939 return result;
5940 }
5941
5942 /*********************************************************************
5943 *********************************************************************/
5944 bool
5945 OSKext::addBleedthroughDependencies(OSArray * anArray)
5946 {
5947 bool result = false;
5948 unsigned int dependencyIndex, dependencyCount;
5949
5950 dependencyCount = getNumDependencies();
5951
5952 for (dependencyIndex = 0;
5953 dependencyIndex < dependencyCount;
5954 dependencyIndex++) {
5955
5956 OSKext * dependency = OSDynamicCast(OSKext,
5957 dependencies->getObject(dependencyIndex));
5958 if (!dependency) {
5959 OSKextLog(this,
5960 kOSKextLogErrorLevel |
5961 kOSKextLogDependenciesFlag,
5962 "Kext %s - internal error propagating compatibility dependencies.",
5963 getIdentifierCString());
5964 goto finish;
5965 }
5966 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
5967 anArray->setObject(dependency);
5968 }
5969 dependency->addBleedthroughDependencies(anArray);
5970 }
5971
5972 result = true;
5973
5974 finish:
5975 return result;
5976 }
5977
5978 /*********************************************************************
5979 *********************************************************************/
5980 bool
5981 OSKext::flushDependencies(bool forceFlag)
5982 {
5983 bool result = false;
5984
5985 /* Only clear the dependencies if the kext isn't loaded;
5986 * we need the info for loaded kexts to track references.
5987 */
5988 if (!isLoaded() || forceFlag) {
5989 if (dependencies) {
5990 // xxx - check level
5991 OSKextLog(this,
5992 kOSKextLogProgressLevel |
5993 kOSKextLogDependenciesFlag,
5994 "Kext %s flushing dependencies.",
5995 getIdentifierCString());
5996 OSSafeReleaseNULL(dependencies);
5997
5998 }
5999 if (!isKernelComponent()) {
6000 flags.hasAllDependencies = 0;
6001 }
6002 result = true;
6003 }
6004
6005 return result;
6006 }
6007
6008 /*********************************************************************
6009 *********************************************************************/
6010 uint32_t
6011 OSKext::getNumDependencies(void)
6012 {
6013 if (!dependencies) {
6014 return 0;
6015 }
6016 return dependencies->getCount();
6017 }
6018
6019 /*********************************************************************
6020 *********************************************************************/
6021 OSArray *
6022 OSKext::getDependencies(void)
6023 {
6024 return dependencies;
6025 }
6026
6027 #if PRAGMA_MARK
6028 #pragma mark OSMetaClass Support
6029 #endif
6030 /*********************************************************************
6031 *********************************************************************/
6032 OSReturn
6033 OSKext::addClass(
6034 OSMetaClass * aClass,
6035 uint32_t numClasses)
6036 {
6037 OSReturn result = kOSMetaClassNoInsKModSet;
6038
6039 if (!metaClasses) {
6040 metaClasses = OSSet::withCapacity(numClasses);
6041 if (!metaClasses) {
6042 goto finish;
6043 }
6044 }
6045
6046 if (metaClasses->containsObject(aClass)) {
6047 OSKextLog(this,
6048 kOSKextLogWarningLevel |
6049 kOSKextLogLoadFlag,
6050 "Notice - kext %s has already registered class %s.",
6051 getIdentifierCString(),
6052 aClass->getClassName());
6053 result = kOSReturnSuccess;
6054 goto finish;
6055 }
6056
6057 if (!metaClasses->setObject(aClass)) {
6058 goto finish;
6059 } else {
6060 OSKextLog(this,
6061 kOSKextLogDetailLevel |
6062 kOSKextLogLoadFlag,
6063 "Kext %s registered class %s.",
6064 getIdentifierCString(),
6065 aClass->getClassName());
6066 }
6067
6068 if (!flags.autounloadEnabled) {
6069 const OSMetaClass * metaScan = NULL; // do not release
6070
6071 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
6072 if (metaScan == OSTypeID(IOService)) {
6073
6074 OSKextLog(this,
6075 kOSKextLogProgressLevel |
6076 kOSKextLogLoadFlag,
6077 "Kext %s has IOService subclass %s; enabling autounload.",
6078 getIdentifierCString(),
6079 aClass->getClassName());
6080
6081 flags.autounloadEnabled = 1;
6082 break;
6083 }
6084 }
6085 }
6086
6087 result = kOSReturnSuccess;
6088
6089 finish:
6090 if (result != kOSReturnSuccess) {
6091 OSKextLog(this,
6092 kOSKextLogErrorLevel |
6093 kOSKextLogLoadFlag,
6094 "Kext %s failed to register class %s.",
6095 getIdentifierCString(),
6096 aClass->getClassName());
6097 }
6098
6099 return result;
6100 }
6101
6102 /*********************************************************************
6103 *********************************************************************/
6104 OSReturn
6105 OSKext::removeClass(
6106 OSMetaClass * aClass)
6107 {
6108 OSReturn result = kOSMetaClassNoKModSet;
6109
6110 if (!metaClasses) {
6111 goto finish;
6112 }
6113
6114 if (!metaClasses->containsObject(aClass)) {
6115 OSKextLog(this,
6116 kOSKextLogWarningLevel |
6117 kOSKextLogLoadFlag,
6118 "Notice - kext %s asked to unregister unknown class %s.",
6119 getIdentifierCString(),
6120 aClass->getClassName());
6121 result = kOSReturnSuccess;
6122 goto finish;
6123 }
6124
6125 OSKextLog(this,
6126 kOSKextLogDetailLevel |
6127 kOSKextLogLoadFlag,
6128 "Kext %s unregistering class %s.",
6129 getIdentifierCString(),
6130 aClass->getClassName());
6131
6132 metaClasses->removeObject(aClass);
6133
6134 result = kOSReturnSuccess;
6135
6136 finish:
6137 if (result != kOSReturnSuccess) {
6138 OSKextLog(this,
6139 kOSKextLogErrorLevel |
6140 kOSKextLogLoadFlag,
6141 "Failed to unregister kext %s class %s.",
6142 getIdentifierCString(),
6143 aClass->getClassName());
6144 }
6145 return result;
6146 }
6147
6148 /*********************************************************************
6149 *********************************************************************/
6150 OSSet *
6151 OSKext::getMetaClasses(void)
6152 {
6153 return metaClasses;
6154 }
6155
6156 /*********************************************************************
6157 *********************************************************************/
6158 bool
6159 OSKext::hasOSMetaClassInstances(void)
6160 {
6161 bool result = false;
6162 OSCollectionIterator * classIterator = NULL; // must release
6163 OSMetaClass * checkClass = NULL; // do not release
6164
6165 if (!metaClasses) {
6166 goto finish;
6167 }
6168
6169 classIterator = OSCollectionIterator::withCollection(metaClasses);
6170 if (!classIterator) {
6171 // xxx - log alloc failure?
6172 goto finish;
6173 }
6174 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
6175 if (checkClass->getInstanceCount()) {
6176 result = true;
6177 goto finish;
6178 }
6179 }
6180
6181 finish:
6182
6183 OSSafeRelease(classIterator);
6184 return result;
6185 }
6186
6187 /*********************************************************************
6188 *********************************************************************/
6189 /* static */
6190 void
6191 OSKext::reportOSMetaClassInstances(
6192 const char * kextIdentifier,
6193 OSKextLogSpec msgLogSpec)
6194 {
6195 OSKext * theKext = NULL; // must release
6196
6197 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
6198 if (!theKext) {
6199 goto finish;
6200 }
6201
6202 theKext->reportOSMetaClassInstances(msgLogSpec);
6203 finish:
6204 OSSafeRelease(theKext);
6205 return;
6206 }
6207
6208 /*********************************************************************
6209 *********************************************************************/
6210 void
6211 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
6212 {
6213 OSCollectionIterator * classIterator = NULL; // must release
6214 OSMetaClass * checkClass = NULL; // do not release
6215
6216 if (!metaClasses) {
6217 goto finish;
6218 }
6219
6220 classIterator = OSCollectionIterator::withCollection(metaClasses);
6221 if (!classIterator) {
6222 goto finish;
6223 }
6224 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
6225 if (checkClass->getInstanceCount()) {
6226 OSKextLog(this,
6227 msgLogSpec,
6228 " Kext %s class %s has %d instance%s.",
6229 getIdentifierCString(),
6230 checkClass->getClassName(),
6231 checkClass->getInstanceCount(),
6232 checkClass->getInstanceCount() == 1 ? "" : "s");
6233 }
6234 }
6235
6236 finish:
6237 OSSafeRelease(classIterator);
6238 return;
6239 }
6240
6241 #if PRAGMA_MARK
6242 #pragma mark User-Space Requests
6243 #endif
6244 /*********************************************************************
6245 * XXX - this function is a big ugly mess
6246 *********************************************************************/
6247 /* static */
6248 OSReturn
6249 OSKext::handleRequest(
6250 host_priv_t hostPriv,
6251 OSKextLogSpec clientLogFilter,
6252 char * requestBuffer,
6253 uint32_t requestLength,
6254 char ** responseOut,
6255 uint32_t * responseLengthOut,
6256 char ** logInfoOut,
6257 uint32_t * logInfoLengthOut)
6258 {
6259 OSReturn result = kOSReturnError;
6260 kern_return_t kmem_result = KERN_FAILURE;
6261
6262 char * response = NULL; // returned by reference
6263 uint32_t responseLength = 0;
6264
6265 OSObject * parsedXML = NULL; // must release
6266 OSDictionary * requestDict = NULL; // do not release
6267 OSString * errorString = NULL; // must release
6268
6269 OSData * responseData = NULL; // must release
6270 OSObject * responseObject = NULL; // must release
6271
6272 OSSerialize * serializer = NULL; // must release
6273
6274 OSArray * logInfoArray = NULL; // must release
6275
6276 OSString * predicate = NULL; // do not release
6277 OSString * kextIdentifier = NULL; // do not release
6278 OSArray * kextIdentifiers = NULL; // do not release
6279 OSKext * theKext = NULL; // do not release
6280 OSBoolean * boolArg = NULL; // do not release
6281
6282 IORecursiveLockLock(sKextLock);
6283
6284 if (responseOut) {
6285 *responseOut = NULL;
6286 *responseLengthOut = 0;
6287 }
6288 if (logInfoOut) {
6289 *logInfoOut = NULL;
6290 *logInfoLengthOut = 0;
6291 }
6292
6293 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
6294
6295 /* XML must be nul-terminated.
6296 */
6297 if (requestBuffer[requestLength - 1] != '\0') {
6298 OSKextLog(/* kext */ NULL,
6299 kOSKextLogErrorLevel |
6300 kOSKextLogIPCFlag,
6301 "Invalid request from user space (not nul-terminated).");
6302 result = kOSKextReturnBadData;
6303 goto finish;
6304 }
6305 parsedXML = OSUnserializeXML((const char *)requestBuffer, &errorString);
6306 if (parsedXML) {
6307 requestDict = OSDynamicCast(OSDictionary, parsedXML);
6308 }
6309 if (!requestDict) {
6310 const char * errorCString = "(unknown error)";
6311
6312 if (errorString && errorString->getCStringNoCopy()) {
6313 errorCString = errorString->getCStringNoCopy();
6314 } else if (parsedXML) {
6315 errorCString = "not a dictionary";
6316 }
6317 OSKextLog(/* kext */ NULL,
6318 kOSKextLogErrorLevel |
6319 kOSKextLogIPCFlag,
6320 "Error unserializing request from user space: %s.",
6321 errorCString);
6322 result = kOSKextReturnSerialization;
6323 goto finish;
6324 }
6325
6326 predicate = _OSKextGetRequestPredicate(requestDict);
6327 if (!predicate) {
6328 OSKextLog(/* kext */ NULL,
6329 kOSKextLogErrorLevel |
6330 kOSKextLogIPCFlag,
6331 "Recieved kext request from user space with no predicate.");
6332 result = kOSKextReturnInvalidArgument;
6333 goto finish;
6334 }
6335
6336 OSKextLog(/* kext */ NULL,
6337 kOSKextLogDebugLevel |
6338 kOSKextLogIPCFlag,
6339 "Received '%s' request from user space.",
6340 predicate->getCStringNoCopy());
6341
6342 result = kOSKextReturnNotPrivileged;
6343 if (hostPriv == HOST_PRIV_NULL) {
6344 if (!predicate->isEqualTo(kKextRequestPredicateGetLoaded) &&
6345 !predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState) &&
6346 !predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
6347
6348 goto finish;
6349 }
6350 }
6351
6352 /* Get common args in anticipation of use.
6353 */
6354 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
6355 requestDict, kKextRequestArgumentBundleIdentifierKey));
6356 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
6357 requestDict, kKextRequestArgumentBundleIdentifierKey));
6358 if (kextIdentifier) {
6359 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6360 }
6361 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
6362 requestDict, kKextRequestArgumentValueKey));
6363
6364 result = kOSKextReturnInvalidArgument;
6365
6366 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
6367 if (!kextIdentifier) {
6368 OSKextLog(/* kext */ NULL,
6369 kOSKextLogErrorLevel |
6370 kOSKextLogIPCFlag,
6371 "Invalid arguments to kext start request.");
6372 } else if (!theKext) {
6373 OSKextLog(/* kext */ NULL,
6374 kOSKextLogErrorLevel |
6375 kOSKextLogIPCFlag,
6376 "Kext %s not found for start request.",
6377 kextIdentifier->getCStringNoCopy());
6378 result = kOSKextReturnNotFound;
6379 } else {
6380 result = theKext->start();
6381 }
6382
6383 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
6384 if (!kextIdentifier) {
6385 OSKextLog(/* kext */ NULL,
6386 kOSKextLogErrorLevel |
6387 kOSKextLogIPCFlag,
6388 "Invalid arguments to kext stop request.");
6389 } else if (!theKext) {
6390 OSKextLog(/* kext */ NULL,
6391 kOSKextLogErrorLevel |
6392 kOSKextLogIPCFlag,
6393 "Kext %s not found for stop request.",
6394 kextIdentifier->getCStringNoCopy());
6395 result = kOSKextReturnNotFound;
6396 } else {
6397 result = theKext->stop();
6398 }
6399
6400 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
6401 if (!kextIdentifier) {
6402 OSKextLog(/* kext */ NULL,
6403 kOSKextLogErrorLevel |
6404 kOSKextLogIPCFlag,
6405 "Invalid arguments to kext unload request.");
6406 } else if (!theKext) {
6407 OSKextLog(/* kext */ NULL,
6408 kOSKextLogErrorLevel |
6409 kOSKextLogIPCFlag,
6410 "Kext %s not found for unload request.",
6411 kextIdentifier->getCStringNoCopy());
6412 result = kOSKextReturnNotFound;
6413 } else {
6414 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
6415 _OSKextGetRequestArgument(requestDict,
6416 kKextRequestArgumentTerminateIOServicesKey));
6417 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
6418 }
6419
6420 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
6421 result = OSKext::dispatchResource(requestDict);
6422
6423 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
6424 OSBoolean * delayAutounloadBool = NULL;
6425
6426 delayAutounloadBool = OSDynamicCast(OSBoolean,
6427 _OSKextGetRequestArgument(requestDict,
6428 kKextRequestArgumentDelayAutounloadKey));
6429
6430 /* If asked to delay autounload, reset the timer if it's currently set.
6431 * (That is, don't schedule an unload if one isn't already pending.
6432 */
6433 if (delayAutounloadBool == kOSBooleanTrue) {
6434 OSKext::considerUnloads(/* rescheduleOnly? */ true);
6435 }
6436
6437 responseObject = OSDynamicCast(OSObject,
6438 OSKext::copyLoadedKextInfo(kextIdentifiers));
6439 if (!responseObject) {
6440 result = kOSKextReturnInternalError;
6441 } else {
6442 OSKextLog(/* kext */ NULL,
6443 kOSKextLogDebugLevel |
6444 kOSKextLogIPCFlag,
6445 "Returning loaded kext info.");
6446 result = kOSReturnSuccess;
6447 }
6448
6449 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLoadAddress)) {
6450 OSNumber * addressNum = NULL; // released as responseObject
6451 kernel_segment_command_t * textseg = getsegbyname("__TEXT");
6452
6453 if (!textseg) {
6454 OSKextLog(/* kext */ NULL,
6455 kOSKextLogErrorLevel |
6456 kOSKextLogGeneralFlag | kOSKextLogIPCFlag,
6457 "Can't find text segment for kernel load address.");
6458 result = kOSReturnError;
6459 goto finish;
6460 }
6461
6462 OSKextLog(/* kext */ NULL,
6463 kOSKextLogDebugLevel |
6464 kOSKextLogIPCFlag,
6465 "Returning kernel load address 0x%llx.",
6466 (unsigned long long)textseg->vmaddr);
6467 addressNum = OSNumber::withNumber((long long unsigned int)textseg->vmaddr,
6468 8 * sizeof(long long unsigned int));
6469 responseObject = OSDynamicCast(OSObject, addressNum);
6470 result = kOSReturnSuccess;
6471
6472 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelLinkState)) {
6473 OSKextLog(/* kext */ NULL,
6474 kOSKextLogDebugLevel |
6475 kOSKextLogIPCFlag,
6476 "Returning kernel link state.");
6477 responseData = sKernelKext->linkState;
6478 responseData->retain();
6479 result = kOSReturnSuccess;
6480
6481 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
6482
6483 /* Hand the current sKernelRequests array to the caller
6484 * (who must release it), and make a new one.
6485 */
6486 responseObject = OSDynamicCast(OSObject, sKernelRequests);
6487 sKernelRequests = OSArray::withCapacity(0);
6488 sPostedKextLoadIdentifiers->flushCollection();
6489 OSKextLog(/* kext */ NULL,
6490 kOSKextLogDebugLevel |
6491 kOSKextLogIPCFlag,
6492 "Returning kernel requests.");
6493 result = kOSReturnSuccess;
6494
6495 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
6496
6497 /* Return the set of all requested bundle identifiers */
6498 responseObject = OSDynamicCast(OSObject, sAllKextLoadIdentifiers);
6499 responseObject->retain();
6500 OSKextLog(/* kext */ NULL,
6501 kOSKextLogDebugLevel |
6502 kOSKextLogIPCFlag,
6503 "Returning load requests.");
6504 result = kOSReturnSuccess;
6505 }
6506
6507 /**********
6508 * Now we have handle the request, or not. Gather up the response & logging
6509 * info to ship to user space.
6510 *********/
6511
6512 /* Note: Nothing in OSKext is supposed to retain requestDict,
6513 * but you never know....
6514 */
6515 if (requestDict->getRetainCount() > 1) {
6516 OSKextLog(/* kext */ NULL,
6517 kOSKextLogWarningLevel |
6518 kOSKextLogIPCFlag,
6519 "Request from user space still retained by a kext; "
6520 "probable memory leak.");
6521 }
6522
6523 if (responseData && responseObject) {
6524 OSKextLog(/* kext */ NULL,
6525 kOSKextLogErrorLevel |
6526 kOSKextLogIPCFlag,
6527 "Mistakenly generated both data & plist responses to user request "
6528 "(returning only data).");
6529 }
6530
6531 if (responseData && responseData->getLength() && responseOut) {
6532
6533 response = (char *)responseData->getBytesNoCopy();
6534 responseLength = responseData->getLength();
6535 } else if (responseOut && responseObject) {
6536 serializer = OSSerialize::withCapacity(0);
6537 if (!serializer) {
6538 result = kOSKextReturnNoMemory;
6539 goto finish;
6540 }
6541
6542 if (!responseObject->serialize(serializer)) {
6543 OSKextLog(/* kext */ NULL,
6544 kOSKextLogErrorLevel |
6545 kOSKextLogIPCFlag,
6546 "Failed to serialize response to request from user space.");
6547 result = kOSKextReturnSerialization;
6548 goto finish;
6549 }
6550
6551 response = (char *)serializer->text();
6552 responseLength = serializer->getLength();
6553 }
6554
6555 if (responseOut && response) {
6556 char * buffer;
6557
6558 /* This kmem_alloc sets the return value of the function.
6559 */
6560 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
6561 responseLength);
6562 if (kmem_result != KERN_SUCCESS) {
6563 OSKextLog(/* kext */ NULL,
6564 kOSKextLogErrorLevel |
6565 kOSKextLogIPCFlag,
6566 "Failed to copy response to request from user space.");
6567 result = kmem_result;
6568 goto finish;
6569 } else {
6570 memcpy(buffer, response, responseLength);
6571 *responseOut = buffer;
6572 *responseLengthOut = responseLength;
6573 }
6574 }
6575
6576 finish:
6577
6578 /* Gather up the collected log messages for user space. Any messages
6579 * messages past this call will not make it up as log messages but
6580 * will be in the system log. Note that we ignore the return of the
6581 * serialize; it has no bearing on the operation at hand even if we
6582 * fail to get the log messages.
6583 */
6584 logInfoArray = OSKext::clearUserSpaceLogFilter();
6585
6586 if (logInfoArray && logInfoOut && logInfoLengthOut) {
6587 (void)OSKext::serializeLogInfo(logInfoArray,
6588 logInfoOut, logInfoLengthOut);
6589 }
6590
6591 IORecursiveLockUnlock(sKextLock);
6592
6593 OSSafeRelease(requestDict);
6594 OSSafeRelease(errorString);
6595 OSSafeRelease(responseData);
6596 OSSafeRelease(responseObject);
6597 OSSafeRelease(serializer);
6598 OSSafeRelease(logInfoArray);
6599
6600 return result;
6601 }
6602
6603 /*********************************************************************
6604 *********************************************************************/
6605 /* static */
6606 OSArray *
6607 OSKext::copyLoadedKextInfo(OSArray * kextIdentifiers)
6608 {
6609 OSArray * result = NULL;
6610 OSDictionary * kextInfo = NULL; // must release
6611 uint32_t count, i;
6612 uint32_t idCount = 0;
6613 uint32_t idIndex = 0;
6614
6615 IORecursiveLockLock(sKextLock);
6616
6617 /* Empty list of bundle ids is equivalent to no list (get all).
6618 */
6619 if (kextIdentifiers && !kextIdentifiers->getCount()) {
6620 kextIdentifiers = NULL;
6621 } else if (kextIdentifiers) {
6622 idCount = kextIdentifiers->getCount();
6623 }
6624
6625 count = sLoadedKexts->getCount();
6626 result = OSArray::withCapacity(count);
6627 if (!result) {
6628 goto finish;
6629 }
6630 for (i = 0; i < count; i++) {
6631 OSKext * thisKext = NULL; // do not release
6632 Boolean includeThis = true;
6633
6634 if (kextInfo) {
6635 kextInfo->release();
6636 kextInfo = NULL;
6637 }
6638 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6639 if (!thisKext) {
6640 continue;
6641 }
6642
6643 /* Skip current kext if we have a list of bundle IDs and
6644 * it isn't in the list.
6645 */
6646 if (kextIdentifiers) {
6647 const OSString * thisKextID = thisKext->getIdentifier();
6648
6649 includeThis = false;
6650
6651 for (idIndex = 0; idIndex < idCount; idIndex++) {
6652 const OSString * thisRequestID = OSDynamicCast(OSString,
6653 kextIdentifiers->getObject(idIndex));
6654 if (thisKextID->isEqualTo(thisRequestID)) {
6655 includeThis = true;
6656 break;
6657 }
6658 }
6659 }
6660
6661 if (!includeThis) {
6662 continue;
6663 }
6664
6665 kextInfo = thisKext->copyInfo();
6666 result->setObject(kextInfo);
6667 }
6668
6669 finish:
6670 IORecursiveLockUnlock(sKextLock);
6671
6672 if (kextInfo) kextInfo->release();
6673
6674 return result;
6675 }
6676
6677 /*********************************************************************
6678 Load Tag
6679 Bundle ID
6680 Bundle Version
6681 Path
6682 Load Address
6683 Load Size
6684 Wired Size
6685 Version
6686 Dependency Load Tags
6687 # Dependent References
6688 UUID
6689 RetainCount
6690 *********************************************************************/
6691 #define _OSKextLoadInfoDictCapacity (12)
6692
6693 OSDictionary *
6694 OSKext::copyInfo(void)
6695 {
6696 OSDictionary * result = NULL;
6697 bool success = false;
6698 OSNumber * cpuTypeNumber = NULL; // must release
6699 OSNumber * cpuSubtypeNumber = NULL; // must release
6700 OSString * versionString = NULL; // do not release
6701 OSData * uuid = NULL; // must release
6702 OSNumber * scratchNumber = NULL; // must release
6703 OSArray * dependencyLoadTags = NULL; // must release
6704 OSCollectionIterator * metaClassIterator = NULL; // must release
6705 OSArray * metaClassInfo = NULL; // must release
6706 OSDictionary * metaClassDict = NULL; // must release
6707 OSMetaClass * thisMetaClass = NULL; // do not release
6708 OSString * metaClassName = NULL; // must release
6709 OSString * superclassName = NULL; // must release
6710 uint32_t count, i;
6711
6712 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
6713 if (!result) {
6714 goto finish;
6715 }
6716
6717 /* CPU Type & Subtype.
6718 * Use the CPU type of the kernel for all (loaded) kexts.
6719 * xxx - should we not include this for the kernel components,
6720 * xxx - or for any interface? they have mach-o files, they're just weird.
6721 */
6722 if (linkedExecutable || (this == sKernelKext)) {
6723
6724 cpuTypeNumber = OSNumber::withNumber(
6725 (long long unsigned int)_mh_execute_header.cputype,
6726 8 * sizeof(_mh_execute_header.cputype));
6727 if (cpuTypeNumber) {
6728 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber);
6729 }
6730 }
6731
6732 // I don't want to rely on a mach header for nonkernel kexts, yet
6733 if (this == sKernelKext) {
6734 cpuSubtypeNumber = OSNumber::withNumber(
6735 (long long unsigned int)_mh_execute_header.cputype,
6736 8 * sizeof(_mh_execute_header.cputype));
6737 if (cpuSubtypeNumber) {
6738 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber);
6739 }
6740 }
6741
6742 /* CFBundleIdentifier.
6743 */
6744 result->setObject(kCFBundleIdentifierKey, bundleID);
6745
6746 /* CFBundleVersion.
6747 */
6748 versionString = OSDynamicCast(OSString,
6749 getPropertyForHostArch(kCFBundleVersionKey));
6750 if (versionString) {
6751 result->setObject(kCFBundleVersionKey, versionString);
6752 }
6753
6754 /* OSBundleCompatibleVersion.
6755 */
6756 versionString = OSDynamicCast(OSString,
6757 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
6758 if (versionString) {
6759 result->setObject(kOSBundleCompatibleVersionKey, versionString);
6760 }
6761
6762 /* Path.
6763 */
6764 if (path) {
6765 result->setObject(kOSBundlePathKey, path);
6766 }
6767
6768 /* UUID.
6769 */
6770 uuid = copyUUID();
6771 if (uuid) {
6772 result->setObject(kOSBundleUUIDKey, uuid);
6773 }
6774
6775 /*****
6776 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
6777 */
6778 result->setObject(kOSKernelResourceKey,
6779 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
6780
6781 result->setObject(kOSBundleIsInterfaceKey,
6782 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
6783
6784 result->setObject(kOSBundlePrelinkedKey,
6785 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
6786
6787 result->setObject(kOSBundleStartedKey,
6788 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
6789
6790 /* LoadTag (Index).
6791 */
6792 scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
6793 /* numBits */ 8 * sizeof(loadTag));
6794 if (scratchNumber) {
6795 result->setObject(kOSBundleLoadTagKey, scratchNumber);
6796 OSSafeReleaseNULL(scratchNumber);
6797 }
6798
6799 /* LoadAddress, LoadSize.
6800 */
6801 if (isInterface() || linkedExecutable) {
6802 /* These go to userspace via serialization, so we don't want any doubts
6803 * about their size.
6804 */
6805 uint64_t loadAddress = 0;
6806 uint32_t loadSize = 0;
6807 uint32_t wiredSize = 0;
6808
6809 /* Interfaces always report 0 load address & size.
6810 * Just the way they roll.
6811 *
6812 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
6813 * xxx - shouldn't have one!
6814 */
6815 if (linkedExecutable /* && !isInterface() */) {
6816 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
6817 loadSize = linkedExecutable->getLength();
6818
6819 /* If we have a kmod_info struct, calculated the wired size
6820 * from that. Otherwise it's the full load size.
6821 */
6822 if (kmod_info) {
6823 wiredSize = loadSize - kmod_info->hdr_size;
6824 } else {
6825 wiredSize = loadSize;
6826 }
6827 }
6828
6829 scratchNumber = OSNumber::withNumber(
6830 (unsigned long long)(loadAddress),
6831 /* numBits */ 8 * sizeof(loadAddress));
6832 if (scratchNumber) {
6833 result->setObject(kOSBundleLoadAddressKey, scratchNumber);
6834 OSSafeReleaseNULL(scratchNumber);
6835 }
6836 scratchNumber = OSNumber::withNumber(
6837 (unsigned long long)(loadSize),
6838 /* numBits */ 8 * sizeof(loadSize));
6839 if (scratchNumber) {
6840 result->setObject(kOSBundleLoadSizeKey, scratchNumber);
6841 OSSafeReleaseNULL(scratchNumber);
6842 }
6843 scratchNumber = OSNumber::withNumber(
6844 (unsigned long long)(wiredSize),
6845 /* numBits */ 8 * sizeof(wiredSize));
6846 if (scratchNumber) {
6847 result->setObject(kOSBundleWiredSizeKey, scratchNumber);
6848 OSSafeReleaseNULL(scratchNumber);
6849 }
6850 }
6851
6852 /* OSBundleDependencies. In descending order for
6853 * easy compatibility with kextstat(8).
6854 */
6855 if ((count = getNumDependencies())) {
6856 dependencyLoadTags = OSArray::withCapacity(count);
6857 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags);
6858
6859 i = count - 1;
6860 do {
6861 OSKext * dependency = OSDynamicCast(OSKext,
6862 dependencies->getObject(i));
6863
6864 OSSafeReleaseNULL(scratchNumber);
6865
6866 if (!dependency) {
6867 continue;
6868 }
6869 scratchNumber = OSNumber::withNumber(
6870 (unsigned long long)dependency->getLoadTag(),
6871 /* numBits*/ 8 * sizeof(loadTag));
6872 if (scratchNumber) {
6873 dependencyLoadTags->setObject(scratchNumber);
6874 }
6875 } while (i--);
6876 }
6877
6878 OSSafeReleaseNULL(scratchNumber);
6879
6880 /* OSBundleMetaClasses.
6881 */
6882 if (metaClasses && metaClasses->getCount()) {
6883 metaClassIterator = OSCollectionIterator::withCollection(metaClasses);
6884 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
6885 if (!metaClassIterator || !metaClassInfo) {
6886 goto finish;
6887 }
6888 result->setObject(kOSBundleClassesKey, metaClassInfo);
6889
6890 while ( (thisMetaClass = OSDynamicCast(OSMetaClass,
6891 metaClassIterator->getNextObject())) ) {
6892
6893 OSSafeReleaseNULL(metaClassDict);
6894 OSSafeReleaseNULL(metaClassName);
6895 OSSafeReleaseNULL(superclassName);
6896 OSSafeReleaseNULL(scratchNumber);
6897
6898 metaClassDict = OSDictionary::withCapacity(3);
6899 if (!metaClassDict) {
6900 goto finish;
6901 }
6902
6903 metaClassName = OSString::withCString(thisMetaClass->getClassName());
6904 if (thisMetaClass->getSuperClass()) {
6905 superclassName = OSString::withCString(
6906 thisMetaClass->getSuperClass()->getClassName());
6907 }
6908 scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
6909 8 * sizeof(unsigned int));
6910 if (!metaClassDict || !metaClassName || !superclassName ||
6911 !scratchNumber) {
6912
6913 goto finish;
6914 }
6915
6916 metaClassInfo->setObject(metaClassDict);
6917 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName);
6918 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName);
6919 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber);
6920 }
6921 }
6922
6923 /* OSBundleRetainCount.
6924 */
6925 OSSafeReleaseNULL(scratchNumber);
6926 {
6927 int extRetainCount = getRetainCount() - 1;
6928 if (isLoaded()) {
6929 extRetainCount--;
6930 }
6931 scratchNumber = OSNumber::withNumber(
6932 (int)extRetainCount,
6933 /* numBits*/ 8 * sizeof(int));
6934 if (scratchNumber) {
6935 result->setObject(kOSBundleRetainCountKey, scratchNumber);
6936 }
6937 }
6938
6939 success = true;
6940 finish:
6941 OSSafeRelease(cpuTypeNumber);
6942 OSSafeRelease(cpuSubtypeNumber);
6943 OSSafeRelease(uuid);
6944 OSSafeRelease(scratchNumber);
6945 OSSafeRelease(dependencyLoadTags);
6946 OSSafeRelease(metaClassIterator);
6947 OSSafeRelease(metaClassInfo);
6948 OSSafeRelease(metaClassDict);
6949 OSSafeRelease(metaClassName);
6950 OSSafeRelease(superclassName);
6951 if (!success) {
6952 OSSafeReleaseNULL(result);
6953 }
6954 return result;
6955 }
6956
6957 /*********************************************************************
6958 *********************************************************************/
6959 /* static */
6960 OSReturn
6961 OSKext::requestResource(
6962 const char * kextIdentifierCString,
6963 const char * resourceNameCString,
6964 OSKextRequestResourceCallback callback,
6965 void * context,
6966 OSKextRequestTag * requestTagOut)
6967 {
6968 OSReturn result = kOSReturnError;
6969 OSKext * callbackKext = NULL; // must release (looked up)
6970
6971 OSKextRequestTag requestTag = -1;
6972 OSNumber * requestTagNum = NULL; // must release
6973
6974 OSDictionary * requestDict = NULL; // must release
6975 OSString * kextIdentifier = NULL; // must release
6976 OSString * resourceName = NULL; // must release
6977
6978 OSDictionary * callbackRecord = NULL; // must release
6979 OSData * callbackWrapper = NULL; // must release
6980
6981 OSData * contextWrapper = NULL; // must release
6982
6983 IORecursiveLockLock(sKextLock);
6984
6985 if (requestTagOut) {
6986 *requestTagOut = kOSKextRequestTagInvalid;
6987 }
6988
6989 if (!kextIdentifierCString || !resourceNameCString || !callback) {
6990 result = kOSKextReturnInvalidArgument;
6991 goto finish;
6992 }
6993
6994 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
6995 if (!callbackKext) {
6996 OSKextLog(/* kext */ NULL,
6997 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
6998 "Resource request has bad callback address.");
6999 result = kOSKextReturnInvalidArgument;
7000 goto finish;
7001 }
7002 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
7003 OSKextLog(/* kext */ NULL,
7004 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7005 "Resource request callback is in a kext that is not started.");
7006 result = kOSKextReturnInvalidArgument;
7007 goto finish;
7008 }
7009
7010 /* Do not allow any new requests to be made on a kext that is unloading.
7011 */
7012 if (callbackKext->flags.stopping) {
7013 result = kOSKextReturnStopping;
7014 goto finish;
7015 }
7016
7017 /* If we're wrapped the next available request tag around to the negative
7018 * numbers, we can't service any more requests.
7019 */
7020 if (sNextRequestTag == kOSKextRequestTagInvalid) {
7021 OSKextLog(/* kext */ NULL,
7022 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7023 "No more request tags available; restart required.");
7024 result = kOSKextReturnNoResources;
7025 goto finish;
7026 }
7027 requestTag = sNextRequestTag++;
7028
7029 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
7030 &requestDict);
7031 if (result != kOSReturnSuccess) {
7032 goto finish;
7033 }
7034
7035 kextIdentifier = OSString::withCString(kextIdentifierCString);
7036 resourceName = OSString::withCString(resourceNameCString);
7037 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
7038 8 * sizeof(requestTag));
7039 if (!kextIdentifier ||
7040 !resourceName ||
7041 !requestTagNum ||
7042 !_OSKextSetRequestArgument(requestDict,
7043 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
7044 !_OSKextSetRequestArgument(requestDict,
7045 kKextRequestArgumentNameKey, resourceName) ||
7046 !_OSKextSetRequestArgument(requestDict,
7047 kKextRequestArgumentRequestTagKey, requestTagNum)) {
7048
7049 result = kOSKextReturnNoMemory;
7050 goto finish;
7051 }
7052
7053 callbackRecord = OSDynamicCast(OSDictionary, requestDict->copyCollection());
7054 if (!callbackRecord) {
7055 result = kOSKextReturnNoMemory;
7056 goto finish;
7057 }
7058 // we validate callback address at call time
7059 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
7060 if (context) {
7061 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
7062 }
7063 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord,
7064 kKextRequestArgumentCallbackKey, callbackWrapper)) {
7065
7066 result = kOSKextReturnNoMemory;
7067 goto finish;
7068 }
7069
7070 if (context) {
7071 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord,
7072 kKextRequestArgumentContextKey, contextWrapper)) {
7073
7074 result = kOSKextReturnNoMemory;
7075 goto finish;
7076 }
7077 }
7078
7079 /* Only post the requests after all the other potential failure points
7080 * have been passed.
7081 */
7082 if (!sKernelRequests->setObject(requestDict) ||
7083 !sRequestCallbackRecords->setObject(callbackRecord)) {
7084
7085 result = kOSKextReturnNoMemory;
7086 goto finish;
7087 }
7088
7089 OSKextPingKextd();
7090
7091 result = kOSReturnSuccess;
7092 if (requestTagOut) {
7093 *requestTagOut = requestTag;
7094 }
7095
7096 finish:
7097
7098 /* If we didn't succeed, yank the request & callback
7099 * from their holding arrays.
7100 */
7101 if (result != kOSReturnSuccess) {
7102 unsigned int index;
7103
7104 index = sKernelRequests->getNextIndexOfObject(requestDict, 0);
7105 if (index != (unsigned int)-1) {
7106 sKernelRequests->removeObject(index);
7107 }
7108 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord, 0);
7109 if (index != (unsigned int)-1) {
7110 sRequestCallbackRecords->removeObject(index);
7111 }
7112 }
7113
7114 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7115
7116 IORecursiveLockUnlock(sKextLock);
7117
7118 if (callbackKext) callbackKext->release();
7119 if (requestTagNum) requestTagNum->release();
7120
7121 if (requestDict) requestDict->release();
7122 if (kextIdentifier) kextIdentifier->release();
7123 if (resourceName) resourceName->release();
7124
7125 if (callbackRecord) callbackRecord->release();
7126 if (callbackWrapper) callbackWrapper->release();
7127 if (contextWrapper) contextWrapper->release();
7128
7129 return result;
7130 }
7131
7132 /*********************************************************************
7133 *********************************************************************/
7134 /* static */
7135 OSReturn
7136 OSKext::dequeueCallbackForRequestTag(
7137 OSKextRequestTag requestTag,
7138 OSDictionary ** callbackRecordOut)
7139 {
7140 OSReturn result = kOSReturnError;
7141 OSNumber * requestTagNum = NULL; // must release
7142
7143 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
7144 8 * sizeof(requestTag));
7145 if (!requestTagNum) {
7146 goto finish;
7147 }
7148
7149 result = OSKext::dequeueCallbackForRequestTag(requestTagNum,
7150 callbackRecordOut);
7151
7152 finish:
7153 OSSafeRelease(requestTagNum);
7154
7155 return result;
7156 }
7157
7158 /*********************************************************************
7159 *********************************************************************/
7160 /* static */
7161 OSReturn
7162 OSKext::dequeueCallbackForRequestTag(
7163 OSNumber * requestTagNum,
7164 OSDictionary ** callbackRecordOut)
7165 {
7166 OSReturn result = kOSKextReturnInvalidArgument;
7167 OSDictionary * callbackRecord = NULL; // retain if matched!
7168 OSNumber * callbackTagNum = NULL; // do not release
7169 unsigned int count, i;
7170
7171 IORecursiveLockLock(sKextLock);
7172
7173 result = kOSReturnError;
7174 count = sRequestCallbackRecords->getCount();
7175 for (i = 0; i < count; i++) {
7176 callbackRecord = OSDynamicCast(OSDictionary,
7177 sRequestCallbackRecords->getObject(i));
7178 if (!callbackRecord) {
7179 goto finish;
7180 }
7181
7182 /* If we don't find a tag, we basically have a leak here. Maybe
7183 * we should just remove it.
7184 */
7185 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
7186 callbackRecord, kKextRequestArgumentRequestTagKey));
7187 if (!callbackTagNum) {
7188 goto finish;
7189 }
7190
7191 /* We could be even more paranoid and check that all the incoming
7192 * args match what's in the callback record.
7193 */
7194 if (callbackTagNum->isEqualTo(requestTagNum)) {
7195 if (callbackRecordOut) {
7196 *callbackRecordOut = callbackRecord;
7197 callbackRecord->retain();
7198 }
7199 sRequestCallbackRecords->removeObject(i);
7200 result = kOSReturnSuccess;
7201 goto finish;
7202 }
7203 }
7204 result = kOSKextReturnNotFound;
7205
7206 finish:
7207 IORecursiveLockUnlock(sKextLock);
7208 return result;
7209 }
7210
7211 /*********************************************************************
7212 *********************************************************************/
7213 /* static */
7214 OSReturn
7215 OSKext::dispatchResource(OSDictionary * requestDict)
7216 {
7217 OSReturn result = kOSReturnError;
7218 OSDictionary * callbackRecord = NULL; // must release
7219 OSNumber * requestTag = NULL; // do not release
7220 OSNumber * requestResult = NULL; // do not release
7221 OSData * dataObj = NULL; // do not release
7222 uint32_t dataLength = 0;
7223 const void * dataPtr = NULL; // do not free
7224 OSData * callbackWrapper = NULL; // do not release
7225 OSKextRequestResourceCallback callback = NULL;
7226 OSData * contextWrapper = NULL; // do not release
7227 void * context = NULL; // do not free
7228 OSKext * callbackKext = NULL; // must release (looked up)
7229
7230 IORecursiveLockLock(sKextLock);
7231
7232 /* Get the args from the request. Right now we need the tag
7233 * to look up the callback record, and the result for invoking the callback.
7234 */
7235 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
7236 kKextRequestArgumentRequestTagKey));
7237 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
7238 kKextRequestArgumentResultKey));
7239 if (!requestTag || !requestResult) {
7240 result = kOSKextReturnInvalidArgument;
7241 goto finish;
7242 }
7243
7244 /* Look for a callback record matching this request's tag.
7245 */
7246 result = dequeueCallbackForRequestTag(requestTag, &callbackRecord);
7247 if (result != kOSReturnSuccess) {
7248 goto finish;
7249 }
7250
7251 /*****
7252 * Get the context pointer of the callback record (if there is one).
7253 */
7254 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord,
7255 kKextRequestArgumentContextKey));
7256 context = _OSKextExtractPointer(contextWrapper);
7257 if (contextWrapper && !context) {
7258 goto finish;
7259 }
7260
7261 callbackWrapper = OSDynamicCast(OSData,
7262 _OSKextGetRequestArgument(callbackRecord,
7263 kKextRequestArgumentCallbackKey));
7264 callback = (OSKextRequestResourceCallback)
7265 _OSKextExtractPointer(callbackWrapper);
7266 if (!callback) {
7267 goto finish;
7268 }
7269
7270 /* Check for a data obj. We might not have one and that's ok, that means
7271 * we didn't find the requested resource, and we still have to tell the
7272 * caller that via the callback.
7273 */
7274 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
7275 kKextRequestArgumentValueKey));
7276 if (dataObj) {
7277 dataPtr = dataObj->getBytesNoCopy();
7278 dataLength = dataObj->getLength();
7279 }
7280
7281 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
7282 if (!callbackKext) {
7283 OSKextLog(/* kext */ NULL,
7284 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7285 "Can't invoke callback for resource request; "
7286 "no kext loaded at callback address %p.",
7287 callback);
7288 goto finish;
7289 }
7290 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
7291 OSKextLog(/* kext */ NULL,
7292 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
7293 "Can't invoke kext resource callback; "
7294 "kext at callback address %p is not running.",
7295 callback);
7296 goto finish;
7297 }
7298
7299 (void)callback(requestTag->unsigned32BitValue(),
7300 (OSReturn)requestResult->unsigned32BitValue(),
7301 dataPtr, dataLength, context);
7302
7303 result = kOSReturnSuccess;
7304
7305 finish:
7306 if (callbackKext) callbackKext->release();
7307 if (callbackRecord) callbackRecord->release();
7308
7309 IORecursiveLockUnlock(sKextLock);
7310 return result;
7311 }
7312
7313 /*********************************************************************
7314 *********************************************************************/
7315 /* static */
7316 void
7317 OSKext::invokeRequestCallback(
7318 OSDictionary * callbackRecord,
7319 OSReturn callbackResult)
7320 {
7321 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
7322 OSNumber * resultNum = NULL; // must release
7323
7324 if (!predicate) {
7325 goto finish;
7326 }
7327
7328 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
7329 8 * sizeof(callbackResult));
7330 if (!resultNum) {
7331 goto finish;
7332 }
7333
7334 /* Insert the result into the callback record and dispatch it as if it
7335 * were the reply coming down from user space.
7336 */
7337 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
7338 resultNum);
7339
7340 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
7341 /* This removes the pending callback record.
7342 */
7343 OSKext::dispatchResource(callbackRecord);
7344 }
7345
7346 finish:
7347 if (resultNum) resultNum->release();
7348 return;
7349 }
7350
7351 /*********************************************************************
7352 *********************************************************************/
7353 /* static */
7354 OSReturn
7355 OSKext::cancelRequest(
7356 OSKextRequestTag requestTag,
7357 void ** contextOut)
7358 {
7359 OSReturn result = kOSKextReturnNoMemory;
7360 OSDictionary * callbackRecord = NULL; // must release
7361 OSData * contextWrapper = NULL; // do not release
7362
7363 result = OSKext::dequeueCallbackForRequestTag(requestTag,
7364 &callbackRecord);
7365
7366 if (result == kOSReturnSuccess && contextOut) {
7367 contextWrapper = OSDynamicCast(OSData,
7368 _OSKextGetRequestArgument(callbackRecord,
7369 kKextRequestArgumentContextKey));
7370 *contextOut = _OSKextExtractPointer(contextWrapper);
7371 }
7372
7373 if (callbackRecord) callbackRecord->release();
7374
7375 return result;
7376 }
7377
7378 /*********************************************************************
7379 *********************************************************************/
7380 void
7381 OSKext::invokeOrCancelRequestCallbacks(
7382 OSReturn callbackResult,
7383 bool invokeFlag)
7384 {
7385 unsigned int count, i;
7386
7387 IORecursiveLockLock(sKextLock);
7388
7389 count = sRequestCallbackRecords->getCount();
7390 if (!count) {
7391 goto finish;
7392 }
7393
7394 i = count - 1;
7395 do {
7396 OSDictionary * request = OSDynamicCast(OSDictionary,
7397 sRequestCallbackRecords->getObject(i));
7398
7399 if (!request) {
7400 continue;
7401 }
7402 OSData * callbackWrapper = OSDynamicCast(OSData,
7403 _OSKextGetRequestArgument(request,
7404 kKextRequestArgumentCallbackKey));
7405
7406 if (!callbackWrapper) {
7407 sRequestCallbackRecords->removeObject(i);
7408 continue;
7409 }
7410
7411 vm_address_t callbackAddress = (vm_address_t)
7412 _OSKextExtractPointer(callbackWrapper);
7413
7414 if ((kmod_info->address <= callbackAddress) &&
7415 (callbackAddress < (kmod_info->address + kmod_info->size))) {
7416
7417 if (invokeFlag) {
7418 /* This removes the callback record.
7419 */
7420 invokeRequestCallback(request, callbackResult);
7421 } else {
7422 sRequestCallbackRecords->removeObject(i);
7423 }
7424 }
7425 } while (i--);
7426
7427 finish:
7428 IORecursiveLockUnlock(sKextLock);
7429 return;
7430 }
7431
7432 /*********************************************************************
7433 *********************************************************************/
7434 uint32_t
7435 OSKext::countRequestCallbacks(void)
7436 {
7437 uint32_t result = 0;
7438 unsigned int count, i;
7439
7440 IORecursiveLockLock(sKextLock);
7441
7442 count = sRequestCallbackRecords->getCount();
7443 if (!count) {
7444 goto finish;
7445 }
7446
7447 i = count - 1;
7448 do {
7449 OSDictionary * request = OSDynamicCast(OSDictionary,
7450 sRequestCallbackRecords->getObject(i));
7451
7452 if (!request) {
7453 continue;
7454 }
7455 OSData * callbackWrapper = OSDynamicCast(OSData,
7456 _OSKextGetRequestArgument(request,
7457 kKextRequestArgumentCallbackKey));
7458
7459 if (!callbackWrapper) {
7460 continue;
7461 }
7462
7463 vm_address_t callbackAddress = (vm_address_t)
7464 _OSKextExtractPointer(callbackWrapper);
7465
7466 if ((kmod_info->address <= callbackAddress) &&
7467 (callbackAddress < (kmod_info->address + kmod_info->size))) {
7468
7469 result++;
7470 }
7471 } while (i--);
7472
7473 finish:
7474 IORecursiveLockUnlock(sKextLock);
7475 return result;
7476 }
7477
7478 /*********************************************************************
7479 *********************************************************************/
7480 static OSReturn _OSKextCreateRequest(
7481 const char * predicate,
7482 OSDictionary ** requestP)
7483 {
7484 OSReturn result = kOSKextReturnNoMemory;
7485 OSDictionary * request = NULL; // must release on error
7486 OSDictionary * args = NULL; // must release
7487
7488 request = OSDictionary::withCapacity(2);
7489 if (!request) {
7490 goto finish;
7491 }
7492 result = _OSDictionarySetCStringValue(request,
7493 kKextRequestPredicateKey, predicate);
7494 if (result != kOSReturnSuccess) {
7495 goto finish;
7496 }
7497 result = kOSReturnSuccess;
7498
7499 finish:
7500 if (result != kOSReturnSuccess) {
7501 if (request) request->release();
7502 } else {
7503 *requestP = request;
7504 }
7505 if (args) args->release();
7506
7507 return result;
7508 }
7509
7510 /*********************************************************************
7511 *********************************************************************/
7512 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict)
7513 {
7514 return OSDynamicCast(OSString,
7515 requestDict->getObject(kKextRequestPredicateKey));
7516 }
7517
7518 /*********************************************************************
7519 *********************************************************************/
7520 static OSObject * _OSKextGetRequestArgument(
7521 OSDictionary * requestDict,
7522 const char * argName)
7523 {
7524 OSDictionary * args = OSDynamicCast(OSDictionary,
7525 requestDict->getObject(kKextRequestArgumentsKey));
7526 if (args) {
7527 return args->getObject(argName);
7528 }
7529 return NULL;
7530 }
7531
7532 /*********************************************************************
7533 *********************************************************************/
7534 static bool _OSKextSetRequestArgument(
7535 OSDictionary * requestDict,
7536 const char * argName,
7537 OSObject * value)
7538 {
7539 OSDictionary * args = OSDynamicCast(OSDictionary,
7540 requestDict->getObject(kKextRequestArgumentsKey));
7541 if (!args) {
7542 args = OSDictionary::withCapacity(2);
7543 if (!args) {
7544 goto finish;
7545 }
7546 requestDict->setObject(kKextRequestArgumentsKey, args);
7547 args->release();
7548 }
7549 if (args) {
7550 return args->setObject(argName, value);
7551 }
7552 finish:
7553 return false;
7554 }
7555
7556 /*********************************************************************
7557 *********************************************************************/
7558 static void * _OSKextExtractPointer(OSData * wrapper)
7559 {
7560 void * result = NULL;
7561 const void * resultPtr = NULL;
7562
7563 if (!wrapper) {
7564 goto finish;
7565 }
7566 resultPtr = wrapper->getBytesNoCopy();
7567 result = *(void **)resultPtr;
7568 finish:
7569 return result;
7570 }
7571
7572 /*********************************************************************
7573 *********************************************************************/
7574 static OSReturn _OSDictionarySetCStringValue(
7575 OSDictionary * dict,
7576 const char * cKey,
7577 const char * cValue)
7578 {
7579 OSReturn result = kOSKextReturnNoMemory;
7580 const OSSymbol * key = NULL; // must release
7581 OSString * value = NULL; // must release
7582
7583 key = OSSymbol::withCString(cKey);
7584 value = OSString::withCString(cValue);
7585 if (!key || !value) {
7586 goto finish;
7587 }
7588 if (dict->setObject(key, value)) {
7589 result = kOSReturnSuccess;
7590 }
7591
7592 finish:
7593 if (key) key->release();
7594 if (value) value->release();
7595
7596 return result;
7597 }
7598
7599 #if PRAGMA_MARK
7600 #pragma mark Personalities (IOKit Drivers)
7601 #endif
7602 /*********************************************************************
7603 *********************************************************************/
7604 /* static */
7605 OSArray *
7606 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
7607 {
7608 OSArray * result = NULL; // returned
7609 OSCollectionIterator * kextIterator = NULL; // must release
7610 OSArray * personalities = NULL; // must release
7611 OSCollectionIterator * personalitiesIterator = NULL; // must release
7612
7613 OSString * kextID = NULL; // do not release
7614 OSKext * theKext = NULL; // do not release
7615
7616 IORecursiveLockLock(sKextLock);
7617
7618 /* Let's conservatively guess that any given kext has around 3
7619 * personalities for now.
7620 */
7621 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
7622 if (!result) {
7623 goto finish;
7624 }
7625
7626 kextIterator = OSCollectionIterator::withCollection(sKextsByID);
7627 if (!kextIterator) {
7628 goto finish;
7629 }
7630
7631 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
7632 if (personalitiesIterator) {
7633 personalitiesIterator->release();
7634 personalitiesIterator = NULL;
7635 }
7636 if (personalities) {
7637 personalities->release();
7638 personalities = NULL;
7639 }
7640
7641 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
7642 if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
7643 personalities = theKext->copyPersonalitiesArray();
7644 if (!personalities) {
7645 continue;
7646 }
7647 result->merge(personalities);
7648 } else {
7649 // xxx - check for better place to put this log msg
7650 OSKextLog(theKext,
7651 kOSKextLogWarningLevel |
7652 kOSKextLogLoadFlag,
7653 "Kext %s is not loadable during safe boot; "
7654 "omitting its personalities.",
7655 theKext->getIdentifierCString());
7656 }
7657
7658 }
7659
7660 finish:
7661 IORecursiveLockUnlock(sKextLock);
7662
7663 if (kextIterator) kextIterator->release();
7664 if (personalitiesIterator) personalitiesIterator->release();
7665 if (personalities) personalities->release();
7666
7667 return result;
7668 }
7669
7670 /*********************************************************************
7671 *********************************************************************/
7672 /* static */
7673 void
7674 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
7675 {
7676 int numPersonalities = 0;
7677
7678 OSKextLog(/* kext */ NULL,
7679 kOSKextLogStepLevel |
7680 kOSKextLogLoadFlag,
7681 "Sending all eligible registered kexts' personalities "
7682 "to the IOCatalogue %s.",
7683 startMatching ? "and starting matching" : "but not starting matching");
7684
7685 OSArray * personalities = OSKext::copyAllKextPersonalities(
7686 /* filterSafeBootFlag */ true);
7687
7688 if (personalities) {
7689 gIOCatalogue->addDrivers(personalities, startMatching);
7690 numPersonalities = personalities->getCount();
7691 personalities->release();
7692 }
7693
7694 OSKextLog(/* kext */ NULL,
7695 kOSKextLogStepLevel |
7696 kOSKextLogLoadFlag,
7697 "%d kext personalit%s sent to the IOCatalogue; %s.",
7698 numPersonalities, numPersonalities > 0 ? "ies" : "y",
7699 startMatching ? "matching started" : "matching not started");
7700 return;
7701 }
7702
7703 /*********************************************************************
7704 * Do not make a deep copy, just convert the IOKitPersonalities dict
7705 * to an array for sending to the IOCatalogue.
7706 *********************************************************************/
7707 OSArray *
7708 OSKext::copyPersonalitiesArray(void)
7709 {
7710 OSArray * result = NULL;
7711 OSDictionary * personalities = NULL; // do not release
7712 OSCollectionIterator * personalitiesIterator = NULL; // must release
7713
7714 OSString * personalityName = NULL; // do not release
7715 OSString * personalityBundleIdentifier = NULL; // do not release
7716
7717 personalities = OSDynamicCast(OSDictionary,
7718 getPropertyForHostArch(kIOKitPersonalitiesKey));
7719 if (!personalities) {
7720 goto finish;
7721 }
7722
7723 result = OSArray::withCapacity(personalities->getCount());
7724 if (!result) {
7725 goto finish;
7726 }
7727
7728 personalitiesIterator =
7729 OSCollectionIterator::withCollection(personalities);
7730 if (!personalitiesIterator) {
7731 goto finish;
7732 }
7733 while ((personalityName = OSDynamicCast(OSString,
7734 personalitiesIterator->getNextObject()))) {
7735
7736 OSDictionary * personality = OSDynamicCast(OSDictionary,
7737 personalities->getObject(personalityName));
7738
7739 /******
7740 * If the personality doesn't have a CFBundleIdentifier, or if it
7741 * differs from the kext's, insert the kext's ID so we can find it.
7742 * The publisher ID is used to remove personalities from bundles
7743 * correctly.
7744 */
7745 personalityBundleIdentifier = OSDynamicCast(OSString,
7746 personality->getObject(kCFBundleIdentifierKey));
7747
7748 if (!personalityBundleIdentifier) {
7749 personality->setObject(kCFBundleIdentifierKey, bundleID);
7750 } else if (!personalityBundleIdentifier->isEqualTo(bundleID)) {
7751 personality->setObject(kIOPersonalityPublisherKey, bundleID);
7752 }
7753
7754 result->setObject(personality);
7755 }
7756
7757 finish:
7758 if (personalitiesIterator) personalitiesIterator->release();
7759
7760 return result;
7761 }
7762
7763 /*********************************************************************
7764 Might want to change this to a bool return?
7765 *********************************************************************/
7766 void
7767 OSKext::sendPersonalitiesToCatalog(
7768 bool startMatching,
7769 OSArray * personalityNames)
7770 {
7771 OSArray * personalitiesToSend = NULL; // must release
7772 OSDictionary * kextPersonalities = NULL; // do not release
7773 int count, i;
7774
7775 if (sSafeBoot && !isLoadableInSafeBoot()) {
7776 OSKextLog(this,
7777 kOSKextLogErrorLevel |
7778 kOSKextLogLoadFlag,
7779 "Kext %s is not loadable during safe boot; "
7780 "not sending personalities to the IOCatalogue.",
7781 getIdentifierCString());
7782 return;
7783 }
7784
7785 if (!personalityNames || !personalityNames->getCount()) {
7786 personalitiesToSend = copyPersonalitiesArray();
7787 } else {
7788 kextPersonalities = OSDynamicCast(OSDictionary,
7789 getPropertyForHostArch(kIOKitPersonalitiesKey));
7790 if (!kextPersonalities || !kextPersonalities->getCount()) {
7791 goto finish;
7792 }
7793 personalitiesToSend = OSArray::withCapacity(0);
7794 if (!personalitiesToSend) {
7795 goto finish;
7796 }
7797 count = personalityNames->getCount();
7798 for (i = 0; i < count; i++) {
7799 OSString * name = OSDynamicCast(OSString,
7800 personalityNames->getObject(i));
7801 if (!name) {
7802 continue;
7803 }
7804 OSDictionary * personality = OSDynamicCast(OSDictionary,
7805 kextPersonalities->getObject(name));
7806 if (personality) {
7807 personalitiesToSend->setObject(personality);
7808 }
7809 }
7810 }
7811 if (personalitiesToSend) {
7812 unsigned numPersonalities = personalitiesToSend->getCount();
7813 OSKextLog(this,
7814 kOSKextLogStepLevel |
7815 kOSKextLogLoadFlag,
7816 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
7817 getIdentifierCString(),
7818 numPersonalities,
7819 numPersonalities > 1 ? "ies" : "y",
7820 startMatching ? " and starting matching" : " but not starting matching");
7821 gIOCatalogue->addDrivers(personalitiesToSend, startMatching);
7822 }
7823 finish:
7824 if (personalitiesToSend) {
7825 personalitiesToSend->release();
7826 }
7827 return;
7828 }
7829
7830 /*********************************************************************
7831 *********************************************************************/
7832 void
7833 OSKext::removePersonalitiesFromCatalog(void)
7834 {
7835 OSDictionary * personality = NULL; // do not release
7836
7837 personality = OSDictionary::withCapacity(1);
7838 if (!personality) {
7839 goto finish;
7840 }
7841 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
7842
7843 OSKextLog(this,
7844 kOSKextLogStepLevel |
7845 kOSKextLogLoadFlag,
7846 "Kext %s removing all personalities naming it from the IOCatalogue.",
7847 getIdentifierCString());
7848
7849 /* Have the IOCatalog remove all personalities matching this kext's
7850 * bundle ID and trigger matching anew.
7851 */
7852 gIOCatalogue->removeDrivers(personality, /* startMatching */ true);
7853
7854 finish:
7855 if (personality) personality->release();
7856
7857 return;
7858 }
7859
7860
7861 #if PRAGMA_MARK
7862 #pragma mark Logging
7863 #endif
7864 /*********************************************************************
7865 * Do not call any function that takes sKextLock here!
7866 *********************************************************************/
7867 /* static */
7868 OSKextLogSpec
7869 OSKext::setUserSpaceLogFilter(
7870 OSKextLogSpec userLogFilter,
7871 bool captureFlag)
7872 {
7873 OSKextLogSpec result;
7874
7875 IORecursiveLockLock(sKextInnerLock);
7876
7877 result = sUserSpaceKextLogFilter;
7878 sUserSpaceKextLogFilter = userLogFilter;
7879
7880 /* If the config flag itself is changing, log the state change
7881 * going both ways, before setting up the user-space log arrays,
7882 * so that this is only logged in the kernel.
7883 */
7884 if (sUserSpaceKextLogFilter != result) {
7885 OSKextLog(/* kext */ NULL,
7886 kOSKextLogDebugLevel |
7887 kOSKextLogGeneralFlag,
7888 "User-space log flags changed from 0x%x to 0x%x.",
7889 result, sUserSpaceKextLogFilter);
7890 }
7891
7892 if (userLogFilter && captureFlag &&
7893 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
7894
7895 // xxx - do some measurements for a good initial capacity?
7896 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
7897 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
7898
7899 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
7900 OSKextLog(/* kext */ NULL,
7901 kOSKextLogErrorLevel |
7902 kOSKextLogGeneralFlag,
7903 "Failed to allocate user-space log message arrays.");
7904 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
7905 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
7906 }
7907 }
7908
7909 IORecursiveLockUnlock(sKextInnerLock);
7910
7911 return result;
7912 }
7913
7914 /*********************************************************************
7915 * Do not call any function that takes sKextLock here!
7916 *********************************************************************/
7917 /* static */
7918 OSArray *
7919 OSKext::clearUserSpaceLogFilter(void)
7920 {
7921 OSArray * result = NULL;
7922 OSKextLogSpec oldLogFilter;
7923
7924 IORecursiveLockLock(sKextInnerLock);
7925
7926 result = OSArray::withCapacity(2);
7927 if (result) {
7928 result->setObject(sUserSpaceLogSpecArray);
7929 result->setObject(sUserSpaceLogMessageArray);
7930 }
7931 OSSafeReleaseNULL(sUserSpaceLogSpecArray);
7932 OSSafeReleaseNULL(sUserSpaceLogMessageArray);
7933
7934 oldLogFilter = sUserSpaceKextLogFilter;
7935 sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
7936
7937 /* If the config flag itself is changing, log the state change
7938 * going both ways, after tearing down the user-space log
7939 * arrays, so this is only logged within the kernel.
7940 */
7941 if (oldLogFilter != sUserSpaceKextLogFilter) {
7942 OSKextLog(/* kext */ NULL,
7943 kOSKextLogDebugLevel |
7944 kOSKextLogGeneralFlag,
7945 "User-space log flags changed from 0x%x to 0x%x.",
7946 oldLogFilter, sUserSpaceKextLogFilter);
7947 }
7948
7949 IORecursiveLockUnlock(sKextInnerLock);
7950
7951 return result;
7952 }
7953
7954 /*********************************************************************
7955 * Do not call any function that takes sKextLock here!
7956 *********************************************************************/
7957 /* static */
7958 OSKextLogSpec
7959 OSKext::getUserSpaceLogFilter(void)
7960 {
7961 OSKextLogSpec result;
7962
7963 IORecursiveLockLock(sKextInnerLock);
7964 result = sUserSpaceKextLogFilter;
7965 IORecursiveLockUnlock(sKextInnerLock);
7966
7967 return result;
7968 }
7969
7970 /*********************************************************************
7971 * This function is called by OSMetaClass during kernel C++ setup.
7972 * Be careful what you access here; assume only OSKext::initialize()
7973 * has been called.
7974 *
7975 * Do not call any function that takes sKextLock here!
7976 *********************************************************************/
7977 #define VTRESET "\033[0m"
7978
7979 #define VTBOLD "\033[1m"
7980 #define VTUNDER "\033[4m"
7981
7982 #define VTRED "\033[31m"
7983 #define VTGREEN "\033[32m"
7984 #define VTYELLOW "\033[33m"
7985 #define VTBLUE "\033[34m"
7986 #define VTMAGENTA "\033[35m"
7987 #define VTCYAN "\033[36m"
7988
7989 inline const char * colorForFlags(OSKextLogSpec flags)
7990 {
7991 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
7992
7993 switch (logLevel) {
7994 case kOSKextLogErrorLevel:
7995 return VTRED VTBOLD;
7996 break;
7997 case kOSKextLogWarningLevel:
7998 return VTRED;
7999 break;
8000 case kOSKextLogBasicLevel:
8001 return VTYELLOW VTUNDER;
8002 break;
8003 case kOSKextLogProgressLevel:
8004 return VTYELLOW;
8005 break;
8006 case kOSKextLogStepLevel:
8007 return VTGREEN;
8008 break;
8009 case kOSKextLogDetailLevel:
8010 return VTCYAN;
8011 break;
8012 case kOSKextLogDebugLevel:
8013 return VTMAGENTA;
8014 break;
8015 default:
8016 return ""; // white
8017 break;
8018 }
8019 return "";
8020 }
8021
8022 inline bool logSpecMatch(
8023 OSKextLogSpec msgLogSpec,
8024 OSKextLogSpec logFilter)
8025 {
8026 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
8027 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
8028 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
8029
8030 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
8031 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
8032 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
8033
8034 /* Explicit messages always get logged.
8035 */
8036 if (msgLevel == kOSKextLogExplicitLevel) {
8037 return true;
8038 }
8039
8040 /* Warnings and errors are logged regardless of the flags.
8041 */
8042 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
8043 return true;
8044 }
8045
8046 /* A verbose message that isn't for a logging-enabled kext and isn't global
8047 * does *not* get logged.
8048 */
8049 if (!msgKextGlobal && !filterKextGlobal) {
8050 return false;
8051 }
8052
8053 /* Warnings and errors are logged regardless of the flags.
8054 * All other messages must fit the flags and
8055 * have a level at or below the filter.
8056 *
8057 */
8058 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
8059 return true;
8060 }
8061 return false;
8062 }
8063
8064 extern "C" {
8065
8066 void
8067 OSKextLog(
8068 OSKext * aKext,
8069 OSKextLogSpec msgLogSpec,
8070 const char * format, ...)
8071 {
8072 va_list argList;
8073
8074 va_start(argList, format);
8075 OSKextVLog(aKext, msgLogSpec, format, argList);
8076 va_end(argList);
8077 }
8078
8079 void
8080 OSKextVLog(
8081 OSKext * aKext,
8082 OSKextLogSpec msgLogSpec,
8083 const char * format,
8084 va_list srcArgList)
8085 {
8086 extern int disableConsoleOutput;
8087
8088 bool logForKernel = false;
8089 bool logForUser = false;
8090 va_list argList;
8091 char stackBuffer[120];
8092 uint32_t length = 0;
8093 char * allocBuffer = NULL; // must kfree
8094 OSNumber * logSpecNum = NULL; // must release
8095 OSString * logString = NULL; // must release
8096 char * buffer = stackBuffer; // do not free
8097
8098 IORecursiveLockLock(sKextInnerLock);
8099
8100 /* Set the kext/global bit in the message spec if we have no
8101 * kext or if the kext requests logging.
8102 */
8103 if (!aKext || aKext->flags.loggingEnabled) {
8104 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
8105 }
8106
8107 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
8108 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
8109 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
8110 }
8111
8112 if (! (logForKernel || logForUser) ) {
8113 goto finish;
8114 }
8115
8116 /* No goto from here until past va_end()!
8117 */
8118 va_copy(argList, srcArgList);
8119 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
8120 va_end(argList);
8121
8122 if (length + 1 >= sizeof(stackBuffer)) {
8123 allocBuffer = (char *)kalloc((length + 1) * sizeof(char));
8124 if (!allocBuffer) {
8125 goto finish;
8126 }
8127
8128 /* No goto from here until past va_end()!
8129 */
8130 va_copy(argList, srcArgList);
8131 vsnprintf(allocBuffer, length + 1, format, argList);
8132 va_end(argList);
8133
8134 buffer = allocBuffer;
8135 }
8136
8137 /* If user space wants the log message, queue it up.
8138 */
8139 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
8140 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
8141 logString = OSString::withCString(buffer);
8142 if (logSpecNum && logString) {
8143 sUserSpaceLogSpecArray->setObject(logSpecNum);
8144 sUserSpaceLogMessageArray->setObject(logString);
8145 }
8146 }
8147
8148 /* Always log messages from the kernel according to the kernel's
8149 * log flags.
8150 */
8151 if (logForKernel) {
8152
8153 /* If we are in console mode and have a custom log filter,
8154 * colorize the log message.
8155 */
8156 if (!disableConsoleOutput && sBootArgLogFilterFound) {
8157 const char * color = ""; // do not free
8158 color = colorForFlags(msgLogSpec);
8159 printf("%s%s%s\n", colorForFlags(msgLogSpec),
8160 buffer, color[0] ? VTRESET : "");
8161 } else {
8162 printf("%s\n", buffer);
8163 }
8164 }
8165
8166 finish:
8167 if (allocBuffer) {
8168 kfree(allocBuffer, (length + 1) * sizeof(char));
8169 }
8170 OSSafeRelease(logString);
8171 OSSafeRelease(logSpecNum);
8172 IORecursiveLockUnlock(sKextInnerLock);
8173 return;
8174 }
8175
8176 }; /* extern "C" */
8177
8178 #if PRAGMA_MARK
8179 #pragma mark Backtrace Dump & kmod_get_info() support
8180 #endif
8181 /*********************************************************************
8182 *********************************************************************/
8183 /* static */
8184 void
8185 OSKext::printKextsInBacktrace(
8186 vm_offset_t * addr,
8187 unsigned int cnt,
8188 int (* printf_func)(const char *fmt, ...),
8189 bool lockFlag)
8190 {
8191 vm_offset_t * kscan_addr = NULL;
8192 kmod_info_t * k = NULL;
8193 kmod_reference_t * r = NULL;
8194 unsigned int i;
8195 int found_kmod = 0;
8196
8197 if (lockFlag) {
8198 IORecursiveLockLock(sKextLock);
8199 }
8200
8201 for (k = kmod; k; k = k->next) {
8202 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)k)) == 0) {
8203 (*printf_func)(" kmod scan stopped due to missing "
8204 "kmod page: %p\n", k);
8205 break;
8206 }
8207 if (!k->address) {
8208 continue; // skip fake entries for built-in kernel components
8209 }
8210 for (i = 0, kscan_addr = addr; i < cnt; i++, kscan_addr++) {
8211 if ((*kscan_addr >= k->address) &&
8212 (*kscan_addr < (k->address + k->size))) {
8213
8214 if (!found_kmod) {
8215 (*printf_func)(" Kernel Extensions in backtrace "
8216 "(with dependencies):\n");
8217 }
8218 found_kmod = 1;
8219 (*printf_func)(" %s(%s)@%p->%p\n",
8220 k->name, k->version, k->address, k->address + k->size - 1);
8221
8222 for (r = k->reference_list; r; r = r->next) {
8223 kmod_info_t * rinfo;
8224
8225 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)r)) == 0) {
8226 (*printf_func)(" kmod dependency scan stopped "
8227 "due to missing dependency page: %p\n", r);
8228 break;
8229 }
8230
8231 rinfo = r->info;
8232
8233 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
8234 (*printf_func)(" kmod dependency scan stopped "
8235 "due to missing kmod page: %p\n", rinfo);
8236 break;
8237 }
8238
8239 if (!rinfo->address) {
8240 continue; // skip fake entries for built-ins
8241 }
8242
8243 (*printf_func)(" dependency: %s(%s)@%p\n",
8244 rinfo->name, rinfo->version, rinfo->address);
8245 }
8246
8247 break; // only report this kmod for one backtrace address
8248 }
8249 }
8250 }
8251
8252 if (lockFlag) {
8253 IORecursiveLockUnlock(sKextLock);
8254 }
8255
8256 return;
8257 }
8258
8259 /*******************************************************************************
8260 * substitute() looks at an input string (a pointer within a larger buffer)
8261 * for a match to a substring, and on match it writes the marker & substitution
8262 * character to an output string, updating the scan (from) and
8263 * output (to) indexes as appropriate.
8264 *******************************************************************************/
8265 static int substitute(
8266 const char * scan_string,
8267 char * string_out,
8268 uint32_t * to_index,
8269 uint32_t * from_index,
8270 const char * substring,
8271 char marker,
8272 char substitution);
8273
8274 /* string_out must be at least KMOD_MAX_NAME bytes.
8275 */
8276 static int
8277 substitute(
8278 const char * scan_string,
8279 char * string_out,
8280 uint32_t * to_index,
8281 uint32_t * from_index,
8282 const char * substring,
8283 char marker,
8284 char substitution)
8285 {
8286 uint32_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
8287
8288 /* On a substring match, append the marker (if there is one) and then
8289 * the substitution character, updating the output (to) index accordingly.
8290 * Then update the input (from) length by the length of the substring
8291 * that got replaced.
8292 */
8293 if (!strncmp(scan_string, substring, substring_length)) {
8294 if (marker) {
8295 string_out[(*to_index)++] = marker;
8296 }
8297 string_out[(*to_index)++] = substitution;
8298 (*from_index) += substring_length;
8299 return 1;
8300 }
8301 return 0;
8302 }
8303
8304 /*******************************************************************************
8305 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
8306 * KMOD_MAX_NAME characters and performs various substitutions of common
8307 * prefixes & substrings as defined by tables in kext_panic_report.h.
8308 *******************************************************************************/
8309 static void compactIdentifier(
8310 const char * identifier,
8311 char * identifier_out,
8312 char ** identifier_out_end);
8313
8314 static void
8315 compactIdentifier(
8316 const char * identifier,
8317 char * identifier_out,
8318 char ** identifier_out_end)
8319 {
8320 uint32_t from_index, to_index;
8321 uint32_t scan_from_index = 0;
8322 uint32_t scan_to_index = 0;
8323 subs_entry_t * subs_entry = NULL;
8324 int did_sub = 0;
8325
8326 from_index = to_index = 0;
8327 identifier_out[0] = '\0';
8328
8329 /* Replace certain identifier prefixes with shorter @+character sequences.
8330 * Check the return value of substitute() so we only replace the prefix.
8331 */
8332 for (subs_entry = &kext_identifier_prefix_subs[0];
8333 subs_entry->substring && !did_sub;
8334 subs_entry++) {
8335
8336 did_sub = substitute(identifier, identifier_out,
8337 &scan_to_index, &scan_from_index,
8338 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
8339 }
8340 did_sub = 0;
8341
8342 /* Now scan through the identifier looking for the common substrings
8343 * and replacing them with shorter !+character sequences via substitute().
8344 */
8345 for (/* see above */;
8346 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
8347 /* see loop */) {
8348
8349 const char * scan_string = &identifier[scan_from_index];
8350
8351 did_sub = 0;
8352
8353 if (scan_from_index) {
8354 for (subs_entry = &kext_identifier_substring_subs[0];
8355 subs_entry->substring && !did_sub;
8356 subs_entry++) {
8357
8358 did_sub = substitute(scan_string, identifier_out,
8359 &scan_to_index, &scan_from_index,
8360 subs_entry->substring, '!', subs_entry->substitute);
8361 }
8362 }
8363
8364 /* If we didn't substitute, copy the input character to the output.
8365 */
8366 if (!did_sub) {
8367 identifier_out[scan_to_index++] = identifier[scan_from_index++];
8368 }
8369 }
8370
8371 identifier_out[scan_to_index] = '\0';
8372 if (identifier_out_end) {
8373 *identifier_out_end = &identifier_out[scan_to_index];
8374 }
8375
8376 return;
8377 }
8378
8379 /*******************************************************************************
8380 * assemble_identifier_and_version() adds to a string buffer a compacted
8381 * bundle identifier followed by a version string.
8382 *******************************************************************************/
8383
8384 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
8385 */
8386 static int assemble_identifier_and_version(
8387 kmod_info_t * kmod_info,
8388 char * identPlusVers);
8389 static int
8390 assemble_identifier_and_version(
8391 kmod_info_t * kmod_info,
8392 char * identPlusVers)
8393 {
8394 int result = 0;
8395
8396 compactIdentifier(kmod_info->name, identPlusVers, NULL);
8397 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
8398 identPlusVers[result++] = '\t'; // increment for real char
8399 identPlusVers[result] = '\0'; // don't increment for nul char
8400 result = strlcat(identPlusVers, kmod_info->version, KMOD_MAX_NAME);
8401
8402 return result;
8403 }
8404
8405 /*******************************************************************************
8406 *******************************************************************************/
8407 #define LAST_LOADED " - last loaded "
8408 #define LAST_LOADED_TS_WIDTH (16)
8409
8410 /* static */
8411 uint32_t
8412 OSKext::saveLoadedKextPanicListTyped(
8413 const char * prefix,
8414 int invertFlag,
8415 int libsFlag,
8416 char * paniclist,
8417 uint32_t list_size,
8418 uint32_t * list_length_ptr)
8419 {
8420 uint32_t result = 0;
8421 int error = 0;
8422 unsigned int count, i;
8423
8424 count = sLoadedKexts->getCount();
8425 if (!count) {
8426 goto finish;
8427 }
8428
8429 i = count - 1;
8430 do {
8431 OSKext * theKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
8432 kmod_info_t * kmod_info = theKext->kmod_info;
8433 int match;
8434 char identPlusVers[2*KMOD_MAX_NAME];
8435 uint32_t identPlusVersLength;
8436 char timestampBuffer[17]; // enough for a uint64_t
8437
8438 /* Skip all built-in kexts.
8439 */
8440 if (theKext->isKernelComponent()) {
8441 continue;
8442 }
8443
8444 /* Filter for kmod name (bundle identifier).
8445 */
8446 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
8447 if ((match && invertFlag) || (!match && !invertFlag)) {
8448 continue;
8449 }
8450
8451 /* Filter for libraries (kexts that have a compatible version).
8452 */
8453 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
8454 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
8455
8456 continue;
8457 }
8458
8459 if (!kmod_info ||
8460 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
8461
8462 printf("kext scan stopped due to missing kmod_info page: %p\n",
8463 kmod_info);
8464 error = 1;
8465 goto finish;
8466 }
8467
8468 identPlusVersLength = assemble_identifier_and_version(kmod_info,
8469 identPlusVers);
8470 if (!identPlusVersLength) {
8471 printf("error saving loaded kext info\n");
8472 goto finish;
8473 }
8474
8475 /* We're going to note the last-loaded kext in the list.
8476 */
8477 if (i + 1 == count) {
8478 snprintf(timestampBuffer, sizeof(timestampBuffer), "%llu",
8479 AbsoluteTime_to_scalar(&last_loaded_timestamp));
8480 identPlusVersLength += sizeof(LAST_LOADED) - 1 +
8481 strnlen(timestampBuffer, sizeof(timestampBuffer));
8482 }
8483
8484 /* Adding 1 for the newline.
8485 */
8486 if (*list_length_ptr + identPlusVersLength + 1 >= list_size) {
8487 goto finish;
8488 }
8489
8490 *list_length_ptr = strlcat(paniclist, identPlusVers, list_size);
8491 if (i + 1 == count) {
8492 *list_length_ptr = strlcat(paniclist, LAST_LOADED, list_size);
8493 *list_length_ptr = strlcat(paniclist, timestampBuffer, list_size);
8494 }
8495 *list_length_ptr = strlcat(paniclist, "\n", list_size);
8496
8497 } while (i--);
8498
8499 finish:
8500 if (!error) {
8501 if (*list_length_ptr + 1 <= list_size) {
8502 result = list_size - (*list_length_ptr + 1);
8503 }
8504 }
8505
8506 return result;
8507 }
8508
8509 /*********************************************************************
8510 *********************************************************************/
8511 /* static */
8512 void
8513 OSKext::saveLoadedKextPanicList(void)
8514 {
8515 char * newlist = NULL;
8516 uint32_t newlist_size = 0;
8517 uint32_t newlist_length = 0;
8518
8519 IORecursiveLockLock(sKextLock);
8520
8521 newlist_length = 0;
8522 newlist_size = KEXT_PANICLIST_SIZE;
8523 newlist = (char *)kalloc(newlist_size);
8524
8525 if (!newlist) {
8526 OSKextLog(/* kext */ NULL,
8527 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
8528 "Couldn't allocate kext panic log buffer.");
8529 goto finish;
8530 }
8531
8532 newlist[0] = '\0';
8533
8534 // non-"com.apple." kexts
8535 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
8536 /* libs? */ -1, newlist, newlist_size, &newlist_length)) {
8537
8538 goto finish;
8539 }
8540 // "com.apple." nonlibrary kexts
8541 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8542 /* libs? */ 0, newlist, newlist_size, &newlist_length)) {
8543
8544 goto finish;
8545 }
8546 // "com.apple." library kexts
8547 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8548 /* libs? */ 1, newlist, newlist_size, &newlist_length)) {
8549
8550 goto finish;
8551 }
8552
8553 if (loaded_kext_paniclist) {
8554 kfree(loaded_kext_paniclist, loaded_kext_paniclist_size);
8555 }
8556 loaded_kext_paniclist = newlist;
8557 loaded_kext_paniclist_size = newlist_size;
8558 loaded_kext_paniclist_length = newlist_length;
8559
8560 finish:
8561 IORecursiveLockUnlock(sKextLock);
8562 return;
8563 }
8564
8565 /*********************************************************************
8566 *********************************************************************/
8567 /* static */
8568 void
8569 OSKext::saveUnloadedKextPanicList(OSKext * aKext)
8570 {
8571 char * newlist = NULL;
8572 uint32_t newlist_size = 0;
8573 uint32_t newlist_length = 0;
8574 char identPlusVers[2*KMOD_MAX_NAME];
8575 uint32_t identPlusVersLength;
8576
8577 if (!aKext->kmod_info) {
8578 return; // do not goto finish here b/c of lock
8579 }
8580
8581 IORecursiveLockLock(sKextLock);
8582
8583 clock_get_uptime(&last_unloaded_timestamp);
8584 last_unloaded_address = (void *)aKext->kmod_info->address;
8585 last_unloaded_size = aKext->kmod_info->size;
8586
8587
8588 identPlusVersLength = assemble_identifier_and_version(aKext->kmod_info,
8589 identPlusVers);
8590 if (!identPlusVersLength) {
8591 printf("error saving unloaded kext info\n");
8592 goto finish;
8593 }
8594
8595 newlist_length = identPlusVersLength;
8596 newlist_size = newlist_length + 1;
8597 newlist = (char *)kalloc(newlist_size);
8598
8599 if (!newlist) {
8600 printf("couldn't allocate kext panic log buffer\n");
8601 goto finish;
8602 }
8603
8604 newlist[0] = '\0';
8605
8606 strlcpy(newlist, identPlusVers, newlist_size);
8607
8608 if (unloaded_kext_paniclist) {
8609 kfree(unloaded_kext_paniclist, unloaded_kext_paniclist_size);
8610 }
8611 unloaded_kext_paniclist = newlist;
8612 unloaded_kext_paniclist_size = newlist_size;
8613 unloaded_kext_paniclist_length = newlist_length;
8614
8615 finish:
8616 IORecursiveLockUnlock(sKextLock);
8617 return;
8618 }
8619
8620 /*********************************************************************
8621 *********************************************************************/
8622 #if __LP64__
8623 #define __kLoadSizeEscape "0x%lld"
8624 #else
8625 #define __kLoadSizeEscape "0x%ld"
8626 #endif /* __LP64__ */
8627
8628 /* static */
8629 void
8630 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
8631 {
8632 printf_func("unloaded kexts:\n");
8633 if (unloaded_kext_paniclist &&
8634 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) unloaded_kext_paniclist) &&
8635 unloaded_kext_paniclist[0]) {
8636
8637 printf_func(
8638 "%.*s (addr %p, size " __kLoadSizeEscape ") - last unloaded %llu\n",
8639 unloaded_kext_paniclist_length, unloaded_kext_paniclist,
8640 last_unloaded_address, last_unloaded_size,
8641 AbsoluteTime_to_scalar(&last_unloaded_timestamp));
8642 } else {
8643 printf_func("(none)\n");
8644 }
8645 printf_func("loaded kexts:\n");
8646 if (loaded_kext_paniclist &&
8647 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
8648 loaded_kext_paniclist[0]) {
8649
8650 printf_func("%.*s", loaded_kext_paniclist_length, loaded_kext_paniclist);
8651 } else {
8652 printf_func("(none)\n");
8653 }
8654 return;
8655 }
8656
8657 /*********************************************************************
8658 *********************************************************************/
8659 #if __ppc__ || __i386__
8660 /* static */
8661 kern_return_t
8662 OSKext::getKmodInfo(
8663 kmod_info_array_t * kmodList,
8664 mach_msg_type_number_t * kmodCount)
8665 {
8666 kern_return_t result = KERN_FAILURE;
8667 vm_offset_t data;
8668 kmod_info_t * k, * kmod_info_scan_ptr;
8669 kmod_reference_t * r, * ref_scan_ptr;
8670 int ref_count;
8671 unsigned size = 0;
8672
8673 *kmodList = (kmod_info_t *)0;
8674 *kmodCount = 0;
8675
8676 IORecursiveLockLock(sKextLock);
8677
8678 k = kmod;
8679 while (k) {
8680 size += sizeof(kmod_info_t);
8681 r = k->reference_list;
8682 while (r) {
8683 size +=sizeof(kmod_reference_t);
8684 r = r->next;
8685 }
8686 k = k->next;
8687 }
8688 if (!size) {
8689 result = KERN_SUCCESS;
8690 goto finish;
8691 }
8692
8693 result = kmem_alloc(kernel_map, &data, size);
8694 if (result != KERN_SUCCESS) {
8695 goto finish;
8696 }
8697
8698 /* Copy each kmod_info struct sequentially into the data buffer.
8699 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
8700 * the kernel space address is used to match refs, and a zero 'next' flags
8701 * the end of kmod_infos in the data buffer and the beginning of references.
8702 */
8703 k = kmod;
8704 kmod_info_scan_ptr = (kmod_info_t *)data;
8705 while (k) {
8706 *kmod_info_scan_ptr = *k;
8707 if (k->next) {
8708 kmod_info_scan_ptr->next = k;
8709 }
8710 kmod_info_scan_ptr++;
8711 k = k->next;
8712 }
8713
8714 /* Now add references after the kmod_info structs in the same buffer.
8715 * Update each kmod_info with the ref_count so we can associate
8716 * references with kmod_info structs.
8717 */
8718 k = kmod;
8719 ref_scan_ptr = (kmod_reference_t *)kmod_info_scan_ptr;
8720 kmod_info_scan_ptr = (kmod_info_t *)data;
8721 while (k) {
8722 r = k->reference_list;
8723 ref_count = 0;
8724 while (r) {
8725 /* Note the last kmod_info in the data buffer has its next == 0.
8726 * Since there can only be one like that,
8727 * this case is handled by the caller.
8728 */
8729 *ref_scan_ptr = *r;
8730 ref_scan_ptr++;
8731 r = r->next;
8732 ref_count++;
8733 }
8734 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
8735 * struct for the client to interpret.
8736 */
8737 kmod_info_scan_ptr->reference_list = (kmod_reference_t *)(long)ref_count;
8738 kmod_info_scan_ptr++;
8739 k = k->next;
8740 }
8741
8742 result = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmodList);
8743 if (result != KERN_SUCCESS) {
8744 goto finish;
8745 }
8746
8747 *kmodCount = size;
8748 result = KERN_SUCCESS;
8749
8750 finish:
8751 IORecursiveLockUnlock(sKextLock);
8752
8753 if (result != KERN_SUCCESS && data) {
8754 kmem_free(kernel_map, data, size);
8755 *kmodList = (kmod_info_t *)0;
8756 *kmodCount = 0;
8757 }
8758 return result;
8759 }
8760 #endif /* __ppc__ || __i386__ */
8761 #if PRAGMA_MARK
8762 #pragma mark MAC Framework Support
8763 #endif
8764 /*********************************************************************
8765 *********************************************************************/
8766 #if CONFIG_MACF_KEXT
8767 /* MAC Framework support */
8768
8769 /*
8770 * define IOC_DEBUG to display run-time debugging information
8771 * #define IOC_DEBUG 1
8772 */
8773
8774 #ifdef IOC_DEBUG
8775 #define DPRINTF(x) printf x
8776 #else
8777 #define IOC_DEBUG
8778 #define DPRINTF(x)
8779 #endif
8780
8781 /*********************************************************************
8782 *********************************************************************/
8783 static bool
8784 MACFObjectIsPrimitiveType(OSObject * obj)
8785 {
8786 const OSMetaClass * typeID = NULL; // do not release
8787
8788 typeID = OSTypeIDInst(obj);
8789 if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
8790 typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData)) {
8791
8792 return true;
8793 }
8794 return false;
8795 }
8796
8797 /*********************************************************************
8798 *********************************************************************/
8799 static int
8800 MACFLengthForObject(OSObject * obj)
8801 {
8802 const OSMetaClass * typeID = NULL; // do not release
8803 int len;
8804
8805 typeID = OSTypeIDInst(obj);
8806 if (typeID == OSTypeID(OSString)) {
8807 OSString * stringObj = OSDynamicCast(OSString, obj);
8808 len = stringObj->getLength() + 1;
8809 } else if (typeID == OSTypeID(OSNumber)) {
8810 len = sizeof("4294967295"); /* UINT32_MAX */
8811 } else if (typeID == OSTypeID(OSBoolean)) {
8812 OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
8813 len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
8814 } else if (typeID == OSTypeID(OSData)) {
8815 OSData * dataObj = OSDynamicCast(OSData, obj);
8816 len = dataObj->getLength();
8817 } else {
8818 len = 0;
8819 }
8820 return len;
8821 }
8822
8823 /*********************************************************************
8824 *********************************************************************/
8825 static void
8826 MACFInitElementFromObject(
8827 struct mac_module_data_element * element,
8828 OSObject * value)
8829 {
8830 const OSMetaClass * typeID = NULL; // do not release
8831
8832 typeID = OSTypeIDInst(value);
8833 if (typeID == OSTypeID(OSString)) {
8834 OSString * stringObj = OSDynamicCast(OSString, value);
8835 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8836 element->value_size = stringObj->getLength() + 1;
8837 DPRINTF(("osdict: string %s size %d\n",
8838 stringObj->getCStringNoCopy(), element->value_size));
8839 memcpy(element->value, stringObj->getCStringNoCopy(),
8840 element->value_size);
8841 } else if (typeID == OSTypeID(OSNumber)) {
8842 OSNumber * numberObj = OSDynamicCast(OSNumber, value);
8843 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8844 element->value_size = sprintf(element->value, "%u",
8845 numberObj->unsigned32BitValue()) + 1;
8846 } else if (typeID == OSTypeID(OSBoolean)) {
8847 OSBoolean * boolObj = OSDynamicCast(OSBoolean, value);
8848 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8849 if (boolObj->isTrue()) {
8850 strcpy(element->value, "true");
8851 element->value_size = 5;
8852 } else {
8853 strcpy(element->value, "false");
8854 element->value_size = 6;
8855 }
8856 } else if (typeID == OSTypeID(OSData)) {
8857 OSData * dataObj = OSDynamicCast(OSData, value);
8858 element->value_type = MAC_DATA_TYPE_PRIMITIVE;
8859 element->value_size = dataObj->getLength();
8860 DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
8861 memcpy(element->value, dataObj->getBytesNoCopy(),
8862 element->value_size);
8863 }
8864 return;
8865 }
8866
8867 /*********************************************************************
8868 * This function takes an OSDictionary and returns a struct mac_module_data
8869 * list.
8870 *********************************************************************/
8871 static struct mac_module_data *
8872 MACFEncodeOSDictionary(OSDictionary * dict)
8873 {
8874 struct mac_module_data * result = NULL; // do not free
8875 const OSMetaClass * typeID = NULL; // do not release
8876 OSString * key = NULL; // do not release
8877 OSCollectionIterator * keyIterator = NULL; // must release
8878 struct mac_module_data_element * element = NULL; // do not free
8879 unsigned int strtabsize = 0;
8880 unsigned int listtabsize = 0;
8881 unsigned int dicttabsize = 0;
8882 unsigned int nkeys = 0;
8883 unsigned int datalen = 0;
8884 char * strtab = NULL; // do not free
8885 char * listtab = NULL; // do not free
8886 char * dicttab = NULL; // do not free
8887 vm_offset_t data_addr = 0;
8888
8889 keyIterator = OSCollectionIterator::withCollection(dict);
8890 if (!keyIterator) {
8891 goto finish;
8892 }
8893
8894 /* Iterate over OSModuleData to figure out total size */
8895 while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
8896
8897 // Get the key's value and determine its type
8898 OSObject * value = dict->getObject(key);
8899 if (!value) {
8900 continue;
8901 }
8902
8903 typeID = OSTypeIDInst(value);
8904 if (MACFObjectIsPrimitiveType(value)) {
8905 strtabsize += MACFLengthForObject(value);
8906 }
8907 else if (typeID == OSTypeID(OSArray)) {
8908 unsigned int k, cnt, nents;
8909 OSArray * arrayObj = OSDynamicCast(OSArray, value);
8910
8911 nents = 0;
8912 cnt = arrayObj->getCount();
8913 for (k = 0; k < cnt; k++) {
8914 value = arrayObj->getObject(k);
8915 typeID = OSTypeIDInst(value);
8916 if (MACFObjectIsPrimitiveType(value)) {
8917 listtabsize += MACFLengthForObject(value);
8918 nents++;
8919 }
8920 else if (typeID == OSTypeID(OSDictionary)) {
8921 unsigned int dents = 0;
8922 OSDictionary * dictObj = NULL; // do not release
8923 OSString * dictkey = NULL; // do not release
8924 OSCollectionIterator * dictIterator = NULL; // must release
8925
8926 dictObj = OSDynamicCast(OSDictionary, value);
8927 dictIterator = OSCollectionIterator::withCollection(dictObj);
8928 if (!dictIterator) {
8929 goto finish;
8930 }
8931 while ((dictkey = OSDynamicCast(OSString,
8932 dictIterator->getNextObject()))) {
8933
8934 OSObject * dictvalue = NULL; // do not release
8935
8936 dictvalue = dictObj->getObject(dictkey);
8937 if (!dictvalue) {
8938 continue;
8939 }
8940 if (MACFObjectIsPrimitiveType(dictvalue)) {
8941 strtabsize += MACFLengthForObject(dictvalue);
8942 } else {
8943 continue; /* Only handle primitive types here. */
8944 }
8945 /*
8946 * Allow for the "arraynnn/" prefix in the key length.
8947 */
8948 strtabsize += dictkey->getLength() + 1;
8949 dents++;
8950 }
8951 dictIterator->release();
8952 if (dents-- > 0) {
8953 dicttabsize += sizeof(struct mac_module_data_list) +
8954 dents * sizeof(struct mac_module_data_element);
8955 nents++;
8956 }
8957 }
8958 else {
8959 continue; /* Skip everything else. */
8960 }
8961 }
8962 if (nents == 0) {
8963 continue;
8964 }
8965 listtabsize += sizeof(struct mac_module_data_list) +
8966 (nents - 1) * sizeof(struct mac_module_data_element);
8967 } else {
8968 continue; /* skip anything else */
8969 }
8970 strtabsize += key->getLength() + 1;
8971 nkeys++;
8972 }
8973 if (nkeys == 0) {
8974 goto finish;
8975 }
8976
8977 /*
8978 * Allocate and fill in the module data structures.
8979 */
8980 datalen = sizeof(struct mac_module_data) +
8981 sizeof(mac_module_data_element) * (nkeys - 1) +
8982 strtabsize + listtabsize + dicttabsize;
8983 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
8984 datalen, strtabsize, listtabsize, dicttabsize));
8985 if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS) {
8986 goto finish;
8987 }
8988 result = (mac_module_data *)data_addr;
8989 result->base_addr = data_addr;
8990 result->size = datalen;
8991 result->count = nkeys;
8992 strtab = (char *)&result->data[nkeys];
8993 listtab = strtab + strtabsize;
8994 dicttab = listtab + listtabsize;
8995 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
8996 data_addr, strtab, listtab, dicttab, data_addr + datalen));
8997
8998 keyIterator->reset();
8999 nkeys = 0;
9000 element = &result->data[0];
9001 DPRINTF(("osdict: element %p\n", element));
9002 while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
9003
9004 // Get the key's value and determine its type
9005 OSObject * value = dict->getObject(key);
9006 if (!value) {
9007 continue;
9008 }
9009
9010 /* Store key */
9011 DPRINTF(("osdict: element @%p\n", element));
9012 element->key = strtab;
9013 element->key_size = key->getLength() + 1;
9014 DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(),
9015 element->key_size, strtab));
9016 memcpy(element->key, key->getCStringNoCopy(), element->key_size);
9017
9018 typeID = OSTypeIDInst(value);
9019 if (MACFObjectIsPrimitiveType(value)) {
9020 /* Store value */
9021 element->value = element->key + element->key_size;
9022 DPRINTF(("osdict: primitive element value %p\n", element->value));
9023 MACFInitElementFromObject(element, value);
9024 strtab += element->key_size + element->value_size;
9025 DPRINTF(("osdict: new strtab %p\n", strtab));
9026 } else if (typeID == OSTypeID(OSArray)) {
9027 unsigned int k, cnt, nents;
9028 char *astrtab;
9029 struct mac_module_data_list *arrayhd;
9030 struct mac_module_data_element *ele;
9031 OSArray *arrayObj = OSDynamicCast(OSArray, value);
9032
9033 element->value = listtab;
9034 DPRINTF(("osdict: array element value %p\n", element->value));
9035 element->value_type = MAC_DATA_TYPE_ARRAY;
9036 arrayhd = (struct mac_module_data_list *)element->value;
9037 arrayhd->type = 0;
9038 DPRINTF(("osdict: arrayhd %p\n", arrayhd));
9039 nents = 0;
9040 astrtab = strtab + element->key_size;
9041 ele = &(arrayhd->list[0]);
9042 cnt = arrayObj->getCount();
9043 for (k = 0; k < cnt; k++) {
9044 value = arrayObj->getObject(k);
9045 DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
9046 ele->key = NULL;
9047 ele->key_size = 0;
9048 typeID = OSTypeIDInst(value);
9049 if (MACFObjectIsPrimitiveType(value)) {
9050 if (arrayhd->type != 0 &&
9051 arrayhd->type != MAC_DATA_TYPE_PRIMITIVE) {
9052
9053 continue;
9054 }
9055 arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
9056 ele->value = astrtab;
9057 MACFInitElementFromObject(ele, value);
9058 astrtab += ele->value_size;
9059 DPRINTF(("osdict: array new astrtab %p\n", astrtab));
9060 } else if (typeID == OSTypeID(OSDictionary)) {
9061 unsigned int dents;
9062 char * dstrtab = NULL; // do not free
9063 OSDictionary * dictObj = NULL; // do not release
9064 OSString * dictkey = NULL; // do not release
9065 OSCollectionIterator * dictIterator = NULL; // must release
9066 struct mac_module_data_list * dicthd = NULL; // do not free
9067 struct mac_module_data_element * dele = NULL; // do not free
9068
9069 if (arrayhd->type != 0 &&
9070 arrayhd->type != MAC_DATA_TYPE_DICT) {
9071
9072 continue;
9073 }
9074 dictObj = OSDynamicCast(OSDictionary, value);
9075 dictIterator = OSCollectionIterator::withCollection(dictObj);
9076 if (!dictIterator) {
9077 goto finish;
9078 }
9079 DPRINTF(("osdict: dict\n"));
9080 ele->value = dicttab;
9081 ele->value_type = MAC_DATA_TYPE_DICT;
9082 dicthd = (struct mac_module_data_list *)ele->value;
9083 DPRINTF(("osdict: dicthd %p\n", dicthd));
9084 dstrtab = astrtab;
9085 dents = 0;
9086 while ((dictkey = OSDynamicCast(OSString,
9087 dictIterator->getNextObject()))) {
9088
9089 OSObject * dictvalue = NULL; // do not release
9090
9091 dictvalue = dictObj->getObject(dictkey);
9092 if (!dictvalue) {
9093 continue;
9094 }
9095 dele = &(dicthd->list[dents]);
9096 DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
9097 if (MACFObjectIsPrimitiveType(dictvalue)) {
9098 dele->key = dstrtab;
9099 dele->key_size = dictkey->getLength() + 1;
9100 DPRINTF(("osdict: dictkey %s size %d @%p\n",
9101 dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
9102 memcpy(dele->key, dictkey->getCStringNoCopy(),
9103 dele->key_size);
9104 dele->value = dele->key + dele->key_size;
9105 MACFInitElementFromObject(dele, dictvalue);
9106 dstrtab += dele->key_size + dele->value_size;
9107 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
9108 } else {
9109 continue; /* Only handle primitive types here. */
9110 }
9111 dents++;
9112 }
9113 dictIterator->release();
9114 if (dents == 0) {
9115 continue;
9116 }
9117 arrayhd->type = MAC_DATA_TYPE_DICT;
9118 ele->value_size = sizeof(struct mac_module_data_list) +
9119 (dents - 1) * sizeof(struct mac_module_data_element);
9120 DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
9121 dicttab += ele->value_size;
9122 DPRINTF(("osdict: new dicttab %p\n", dicttab));
9123 dicthd->count = dents;
9124 astrtab = dstrtab;
9125 } else {
9126 continue; /* Skip everything else. */
9127 }
9128 nents++;
9129 ele++;
9130 }
9131 if (nents == 0) {
9132 continue;
9133 }
9134 element->value_size = sizeof(struct mac_module_data_list) +
9135 (nents - 1) * sizeof(struct mac_module_data_element);
9136 listtab += element->value_size;
9137 DPRINTF(("osdict: new listtab %p\n", listtab));
9138 arrayhd->count = nents;
9139 strtab = astrtab;
9140 DPRINTF(("osdict: new strtab %p\n", strtab));
9141 } else {
9142 continue; /* skip anything else */
9143 }
9144 element++;
9145 }
9146 DPRINTF(("result list @%p, key %p value %p\n",
9147 result, result->data[0].key, result->data[0].value));
9148 finish:
9149 if (keyIterator) keyIterator->release();
9150 return result;
9151 }
9152
9153 /*********************************************************************
9154 * This function takes a plist and looks for an OSModuleData dictionary.
9155 * If it is found, an encoded copy is returned. The value must be
9156 * kmem_free()'d.
9157 *********************************************************************/
9158 static void *
9159 MACFCopyModuleDataForKext(
9160 OSKext * theKext,
9161 mach_msg_type_number_t * datalen)
9162
9163 {
9164 struct mac_module_data * result = NULL;
9165 OSDictionary * kextModuleData = NULL; // do not release
9166 vm_map_copy_t copy = 0;
9167
9168 kextModuleData = OSDynamicCast(OSDictionary,
9169 theKext->getPropertyForHostArch("OSModuleData"));
9170 if (!kextModuleData) {
9171 goto finish;
9172 }
9173
9174 result = MACFEncodeOSDictionary(kextModuleData);
9175 if (!result) {
9176 goto finish;
9177 }
9178 *datalen = module_data->size;
9179
9180 finish:
9181 return (void *)result;
9182 }
9183 #endif /* CONFIG_MACF_KEXT */