2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #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>
45 #include <libkern/OSKextLibPrivate.h>
46 #include <libkern/c++/OSKext.h>
47 #include <libkern/c++/OSLib.h>
49 #include <IOKit/IOLib.h>
50 #include <IOKit/IOCatalogue.h>
51 #include <IOKit/IORegistryEntry.h>
52 #include <IOKit/IOService.h>
55 #pragma mark External & Internal Function Protos
57 /*********************************************************************
58 *********************************************************************/
60 // in libkern/OSKextLib.cpp, not in header for a reason.
61 extern kern_return_t
OSKextPingKextd(void);
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
);
68 extern ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
); /* osfmk/machine/pmap.h */
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
,
82 static void * _OSKextExtractPointer(OSData
* wrapper
);
83 static OSReturn
_OSDictionarySetCStringValue(
88 static void * MACFCopyModuleDataForKext(
90 mach_msg_type_number_t
* datalen
);
91 #endif /* CONFIG_MACF_KEXT */
94 #pragma mark Constants & Macros
96 /*********************************************************************
98 *********************************************************************/
100 /* A typical Snow Leopard system has a bit under 120 kexts loaded.
101 * Use this number to create containers.
103 #define kOSKextTypicalLoadCount (120)
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.
108 #define kOSKextMinRetainCount (1)
109 #define kOSKextMinLoadedRetainCount (2)
112 * Strings and substrings used in dependency resolution.
114 #define APPLE_KEXT_PREFIX "com.apple."
115 #define KERNEL_LIB "com.apple.kernel"
117 #define PRIVATE_KPI "com.apple.kpi.private"
119 /* Version for compatbility pseudokexts (com.apple.kernel.*),
120 * compatible back to v6.0.
122 #define KERNEL6_LIB "com.apple.kernel.6.0"
123 #define KERNEL6_VERSION "7.9.9"
125 #define KERNEL_LIB_PREFIX "com.apple.kernel."
126 #define KPI_LIB_PREFIX "com.apple.kpi."
128 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
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 *********************************************************************/
135 /* A usable, uncompressed file is stored under this key.
137 #define _kOSKextExecutableKey "_OSKextExecutable"
139 /* An indirect reference to the executable file from an mkext
140 * is stored under this key.
142 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
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.
148 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
151 #pragma mark Typedefs
153 /*********************************************************************
155 *********************************************************************/
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.
162 * It contains the mkextVersion in case we ever wind up supporting
163 * multiple mkext formats. Mkext format 1 is officially retired as of
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
172 #pragma mark Global and static Module Variables
174 /*********************************************************************
175 * Global & static variables, used to keep track of kexts.
176 *********************************************************************/
178 static bool sPrelinkBoot
= false;
179 static bool sSafeBoot
= false;
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.
188 static IORecursiveLock
* sKextLock
= NULL
;
190 static OSDictionary
* sKextsByID
= NULL
;
191 static OSArray
* sLoadedKexts
= NULL
;
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
;
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;
205 static bool sUserLoadsActive
= false;
206 static bool sKextdActive
= false;
207 static bool sDeferredLoadSucceeded
= false;
208 static bool sConsiderUnloadsExecuted
= false;
210 static bool sKernelRequestsEnabled
= true;
211 static bool sLoadEnabled
= true;
212 static bool sUnloadEnabled
= true;
214 /*********************************************************************
215 * Stuff for the OSKext representing the kernel itself.
217 static OSKext
* sKernelKext
= NULL
;
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.
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.
231 kmod_info_t g_kernel_kmod_info
= {
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()
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
;
253 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
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
;
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
;
266 static uint64_t last_unloaded_size
= 0;
268 static uint32_t last_unloaded_size
= 0;
269 #endif /* __LP64__ */
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:
280 * * OSKext::considerUnloads()
282 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
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.
290 * All static variables from here to the closing comment block fall
291 * under sKextInnerLock.
293 static IORecursiveLock
* sKextInnerLock
= NULL
;
295 static bool sAutounloadEnabled
= true;
296 static bool sConsiderUnloadsCalled
= false;
297 static bool sConsiderUnloadsPending
= false;
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
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");
311 static OSKextLogSpec sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
312 static OSArray
* sUserSpaceLogSpecArray
= NULL
;
313 static OSArray
* sUserSpaceLogMessageArray
= NULL
;
316 * End scope for sKextInnerLock-protected variables.
317 *********************************************************************/
320 #pragma mark OSData callbacks (need to move to OSData)
322 /*********************************************************************
323 * C functions used for callbacks.
324 *********************************************************************/
326 void osdata_kmem_free(void * ptr
, unsigned int length
) {
327 kmem_free(kernel_map
, (vm_address_t
)ptr
, length
);
331 void osdata_phys_free(void * ptr
, unsigned int length
) {
332 ml_static_mfree((vm_offset_t
)ptr
, length
);
336 void osdata_vm_deallocate(void * ptr
, unsigned int length
)
338 (void)vm_deallocate(kernel_map
, (vm_offset_t
)ptr
, length
);
344 #pragma mark KXLD Allocation Callback
346 /*********************************************************************
347 * KXLD Allocation Callback
348 *********************************************************************/
352 KXLDAllocateFlags
* flags
,
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
362 mach_result
= kext_alloc(&result
, roundSize
, /* fixed */ FALSE
);
363 if (mach_result
!= KERN_SUCCESS
) {
365 kOSKextLogErrorLevel
|
366 kOSKextLogGeneralFlag
,
367 "Can't allocate kernel memory to link %s.",
368 theKext
->getIdentifierCString());
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.
377 linkBuffer
= OSData::withBytesNoCopy((void *)result
, roundSize
);
380 kOSKextLogErrorLevel
|
381 kOSKextLogGeneralFlag
,
382 "Can't allocate linked executable wrapper for %s.",
383 theKext
->getIdentifierCString());
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
);
394 theKext
->setLinkedExecutable(linkBuffer
);
396 *flags
= kKxldAllocateWritable
;
400 if (!success
&& result
) {
401 kext_free(result
, roundSize
);
405 OSSafeRelease(linkBuffer
);
407 return (kxld_addr_t
)result
;
410 /*********************************************************************
411 *********************************************************************/
414 KXLDLogSubsystem subsystem
,
420 OSKext
*theKext
= (OSKext
*) user_data
;
421 OSKextLogSpec logSpec
= 0;
424 case kKxldLogLinking
:
425 logSpec
|= kOSKextLogLinkFlag
;
427 case kKxldLogPatching
:
428 logSpec
|= kOSKextLogPatchFlag
;
433 case kKxldLogExplicit
:
434 logSpec
|= kOSKextLogExplicitLevel
;
437 logSpec
|= kOSKextLogErrorLevel
;
440 logSpec
|= kOSKextLogWarningLevel
;
443 logSpec
|= kOSKextLogProgressLevel
;
446 logSpec
|= kOSKextLogDetailLevel
;
449 logSpec
|= kOSKextLogDebugLevel
;
453 OSKextVLog(theKext
, logSpec
, format
, argList
);
457 #pragma mark Module Config (Startup & Shutdown)
459 /*********************************************************************
460 * Module Config (Class Definition & Class Methods)
461 *********************************************************************/
462 #define super OSObject
463 OSDefineMetaClassAndStructors(OSKext
, OSObject
)
465 /*********************************************************************
466 *********************************************************************/
469 OSKext::initialize(void)
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
483 /* This must be the first thing allocated. Everything else grabs this lock.
485 sKextLock
= IORecursiveLockAlloc();
486 sKextInnerLock
= IORecursiveLockAlloc();
488 assert(sKextInnerLock
);
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
);
500 /* Read the log flag boot-args and set the log flags.
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
|
509 "Kernel kext log filter 0x%x per kextlog boot arg.",
510 (unsigned)sKernelLogFilter
);
513 sSafeBoot
= PE_parse_boot_argn("-x", bootArgBuffer
,
514 sizeof(bootArgBuffer
)) ? true : false;
517 OSKextLog(/* kext */ NULL
,
518 kOSKextLogWarningLevel
|
519 kOSKextLogGeneralFlag
,
520 "SAFE BOOT DETECTED - "
521 "only valid OSBundleRequired kexts will be loaded.");
524 /* Set up an OSKext instance to represent the kernel itself.
526 sKernelKext
= new OSKext
;
529 kernelStart
= (u_char
*)&_mh_execute_header
;
530 kernelLength
= getlastaddr() - (vm_offset_t
)kernelStart
;
531 kernelExecutable
= OSData::withBytesNoCopy(
532 kernelStart
, kernelLength
);
533 assert(kernelExecutable
);
535 sKernelKext
->loadTag
= sNextLoadTag
++; // the kernel is load tag 0
536 sKernelKext
->bundleID
= OSSymbol::withCString(kOSKextKernelIdentifier
);
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
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;
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
;
556 /* Cons up an info dict, so we don't have to have special-case
559 sKernelKext
->infoDict
= OSDictionary::withCapacity(5);
560 assert(sKernelKext
->infoDict
);
561 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleIdentifierKey
,
562 sKernelKext
->bundleID
);
564 setResult
= sKernelKext
->infoDict
->setObject(kOSKernelResourceKey
,
568 scratchString
= OSString::withCStringNoCopy(osrelease
);
569 assert(scratchString
);
570 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleVersionKey
,
573 OSSafeReleaseNULL(scratchString
);
575 scratchString
= OSString::withCStringNoCopy("mach_kernel");
576 assert(scratchString
);
577 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleNameKey
,
580 OSSafeReleaseNULL(scratchString
);
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.
586 setResult
= sKextsByID
->setObject(sKernelKext
->bundleID
, sKernelKext
);
588 setResult
= sLoadedKexts
->setObject(sKernelKext
);
590 sKernelKext
->release();
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
);
601 registryRoot
->setProperty(kOSKernelCPUTypeKey
, kernelCPUType
);
602 registryRoot
->setProperty(kOSKernelCPUSubtypeKey
, kernelCPUSubtype
);
604 OSSafeRelease(kernelCPUType
);
605 OSSafeRelease(kernelCPUSubtype
);
607 timestamp
= __OSAbsoluteTimePtr(&last_loaded_timestamp
);
609 timestamp
= __OSAbsoluteTimePtr(&last_unloaded_timestamp
);
612 OSKextLog(/* kext */ NULL
,
613 kOSKextLogProgressLevel
|
614 kOSKextLogGeneralFlag
,
615 "Kext system initialized.");
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 *********************************************************************/
626 OSKext::removeKextBootstrap(void)
628 OSReturn result
= kOSReturnError
;
630 static bool alreadyDone
= false;
631 boolean_t keepsyms
= FALSE
;
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;
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;
648 /* This must be the very first thing done by this function.
650 IORecursiveLockLock(sKextLock
);
652 /* If we already did this, it's a success.
655 result
= kOSReturnSuccess
;
659 OSKextLog(/* kext */ NULL
,
660 kOSKextLogProgressLevel
|
661 kOSKextLogGeneralFlag
,
662 "Jettisoning kext bootstrap segments.");
664 PE_parse_boot_argn("keepsyms", &keepsyms
, sizeof(keepsyms
));
667 * Dispose of unnecessary stuff that the booter didn't need to load.
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
));
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
));
683 * KLD bootstrap segment.
685 // xxx - should rename KLD segment
686 seg_to_remove
= getsegbyname("__KLD");
688 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
691 #if __ppc__ || __arm__
692 /* Free the memory that was set up by bootx.
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
,
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.
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
);
712 seg_to_remove
= NULL
;
715 * Prelinked kernel's symtab (if there is one).
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
);
724 * Dump the LINKEDIT segment, unless keepsyms is set.
727 seg_to_remove
= (kernel_segment_command_t
*)getsegbyname("__LINKEDIT");
729 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
732 #if __ppc__ || __arm__
733 dt_segment_name
= "Kernel-__LINKEDIT";
734 if (0 == IODTGetLoaderInfo(dt_segment_name
,
735 &segment_paddress
, &segment_size
)) {
737 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
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
);
748 OSKextLog(/* kext */ NULL
,
749 kOSKextLogBasicLevel
|
750 kOSKextLogGeneralFlag
,
751 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
754 seg_to_remove
= NULL
;
757 result
= kOSReturnSuccess
;
761 /* This must be the very last thing done before returning.
763 IORecursiveLockUnlock(sKextLock
);
768 /*********************************************************************
769 *********************************************************************/
771 OSKext::flushNonloadedKexts(
772 Boolean flushPrelinkedKexts
)
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
781 IORecursiveLockLock(sKextLock
);
783 OSKextLog(/* kext */ NULL
,
784 kOSKextLogProgressLevel
|
785 kOSKextLogKextBookkeepingFlag
,
786 "Flushing nonloaded kexts and other unused data.");
788 OSKext::considerDestroyingLinkContext();
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.
793 if (!flushPrelinkedKexts
) {
794 prelinkedKexts
= OSSet::withCapacity(0);
795 if (!prelinkedKexts
) {
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.
804 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
809 while ((thisID
= OSDynamicCast(OSSymbol
,
810 kextIterator
->getNextObject()))) {
812 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
815 if (prelinkedKexts
&& thisKext
->isPrelinked()) {
816 prelinkedKexts
->setObject(thisKext
);
818 thisKext
->flushDependencies(/* forceIfLoaded */ false);
822 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
824 sKextsByID
->flushCollection();
826 /* Now put the loaded kexts back into the ID dictionary.
828 count
= sLoadedKexts
->getCount();
829 for (i
= 0; i
< count
; i
++) {
830 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
831 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
834 /* Finally, put back the prelinked kexts if we saved any.
836 if (prelinkedKexts
) {
837 prelinkIterator
= OSCollectionIterator::withCollection(prelinkedKexts
);
838 if (!prelinkIterator
) {
842 while ((thisKext
= OSDynamicCast(OSKext
,
843 prelinkIterator
->getNextObject()))) {
845 sKextsByID
->setObject(thisKext
->getIdentifierCString(),
851 IORecursiveLockUnlock(sKextLock
);
853 OSSafeRelease(prelinkedKexts
);
854 OSSafeRelease(kextIterator
);
855 OSSafeRelease(prelinkIterator
);
860 /*********************************************************************
861 *********************************************************************/
864 OSKext::setKextdActive(Boolean active
)
866 IORecursiveLockLock(sKextLock
);
867 sKextdActive
= active
;
868 if (sKernelRequests
->getCount()) {
871 IORecursiveLockUnlock(sKextLock
);
876 /*********************************************************************
877 *********************************************************************/
880 OSKext::setDeferredLoadSucceeded(Boolean succeeded
)
882 IORecursiveLockLock(sKextLock
);
883 sDeferredLoadSucceeded
= succeeded
;
884 IORecursiveLockUnlock(sKextLock
);
889 /*********************************************************************
890 * Called from IOSystemShutdownNotification.
891 *********************************************************************/
894 OSKext::willShutdown(void)
896 OSReturn checkResult
= kOSReturnError
;
897 OSDictionary
* exitRequest
= NULL
; // must release
899 IORecursiveLockLock(sKextLock
);
901 OSKext::setLoadEnabled(false);
902 OSKext::setUnloadEnabled(false);
903 OSKext::setAutounloadsEnabled(false);
904 OSKext::setKernelRequestsEnabled(false);
906 OSKextLog(/* kext */ NULL
,
907 kOSKextLogProgressLevel
|
908 kOSKextLogGeneralFlag
,
909 "System shutdown; requesting immediate kextd exit.");
911 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit
,
913 if (checkResult
!= kOSReturnSuccess
) {
916 if (!sKernelRequests
->setObject(exitRequest
)) {
923 IORecursiveLockUnlock(sKextLock
);
925 OSSafeRelease(exitRequest
);
929 /*********************************************************************
930 *********************************************************************/
933 OSKext::getLoadEnabled(void)
937 IORecursiveLockLock(sKextLock
);
938 result
= sLoadEnabled
;
939 IORecursiveLockUnlock(sKextLock
);
943 /*********************************************************************
944 *********************************************************************/
947 OSKext::setLoadEnabled(bool flag
)
951 IORecursiveLockLock(sKextLock
);
952 result
= sLoadEnabled
;
953 sLoadEnabled
= (flag
? true : false);
955 if (sLoadEnabled
!= result
) {
956 OSKextLog(/* kext */ NULL
,
957 kOSKextLogBasicLevel
|
959 "Kext loading now %sabled.", sLoadEnabled
? "en" : "dis");
962 IORecursiveLockUnlock(sKextLock
);
967 /*********************************************************************
968 *********************************************************************/
971 OSKext::getUnloadEnabled(void)
975 IORecursiveLockLock(sKextLock
);
976 result
= sUnloadEnabled
;
977 IORecursiveLockUnlock(sKextLock
);
981 /*********************************************************************
982 *********************************************************************/
985 OSKext::setUnloadEnabled(bool flag
)
989 IORecursiveLockLock(sKextLock
);
990 result
= sUnloadEnabled
;
991 sUnloadEnabled
= (flag
? true : false);
992 IORecursiveLockUnlock(sKextLock
);
994 if (sUnloadEnabled
!= result
) {
995 OSKextLog(/* kext */ NULL
,
996 kOSKextLogBasicLevel
|
997 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
998 "Kext unloading now %sabled.", sUnloadEnabled
? "en" : "dis");
1004 /*********************************************************************
1005 * Do not call any function that takes sKextLock here!
1006 *********************************************************************/
1009 OSKext::getAutounloadEnabled(void)
1013 IORecursiveLockLock(sKextInnerLock
);
1014 result
= sAutounloadEnabled
? true : false;
1015 IORecursiveLockUnlock(sKextInnerLock
);
1019 /*********************************************************************
1020 * Do not call any function that takes sKextLock here!
1021 *********************************************************************/
1024 OSKext::setAutounloadsEnabled(bool flag
)
1028 IORecursiveLockLock(sKextInnerLock
);
1030 result
= sAutounloadEnabled
;
1031 sAutounloadEnabled
= (flag
? true : false);
1032 if (!sAutounloadEnabled
&& sUnloadCallout
) {
1033 thread_call_cancel(sUnloadCallout
);
1036 if (sAutounloadEnabled
!= result
) {
1037 OSKextLog(/* kext */ NULL
,
1038 kOSKextLogBasicLevel
|
1039 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1040 "Kext autounloading now %sabled.",
1041 sAutounloadEnabled
? "en" : "dis");
1044 IORecursiveLockUnlock(sKextInnerLock
);
1049 /*********************************************************************
1050 *********************************************************************/
1051 /* instance method operating on OSKext field */
1053 OSKext::setAutounloadEnabled(bool flag
)
1055 bool result
= flags
.autounloadEnabled
? true : false;
1056 flags
.autounloadEnabled
= flag
? 1 : 0;
1058 if (result
!= (flag
? true : false)) {
1060 kOSKextLogProgressLevel
|
1061 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
1062 "Autounloading for kext %s now %sabled.",
1063 getIdentifierCString(),
1064 flags
.autounloadEnabled
? "en" : "dis");
1069 /*********************************************************************
1070 *********************************************************************/
1073 OSKext::setKernelRequestsEnabled(bool flag
)
1077 IORecursiveLockLock(sKextLock
);
1078 result
= sKernelRequestsEnabled
;
1079 sKernelRequestsEnabled
= flag
? true : false;
1081 if (sKernelRequestsEnabled
!= result
) {
1082 OSKextLog(/* kext */ NULL
,
1083 kOSKextLogBasicLevel
|
1084 kOSKextLogGeneralFlag
,
1085 "Kernel requests now %sabled.",
1086 sKernelRequestsEnabled
? "en" : "dis");
1088 IORecursiveLockUnlock(sKextLock
);
1092 /*********************************************************************
1093 *********************************************************************/
1096 OSKext::getKernelRequestsEnabled(void)
1100 IORecursiveLockLock(sKextLock
);
1101 result
= sKernelRequestsEnabled
;
1102 IORecursiveLockUnlock(sKextLock
);
1107 #pragma mark Kext Life Cycle
1109 /*********************************************************************
1110 *********************************************************************/
1112 OSKext::withPrelinkedInfoDict(
1113 OSDictionary
* anInfoDict
)
1115 OSKext
* newKext
= new OSKext
;
1117 if (newKext
&& !newKext
->initWithPrelinkedInfoDict(anInfoDict
)) {
1125 /*********************************************************************
1126 *********************************************************************/
1128 OSKext::initWithPrelinkedInfoDict(
1129 OSDictionary
* anInfoDict
)
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
1143 if (!super::init()) {
1147 /* Get the path. Don't look for an arch-specific path property.
1149 kextPath
= OSDynamicCast(OSString
,
1150 anInfoDict
->getObject(kPrelinkBundlePathKey
));
1152 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
1156 /* Don't need the path to be in the info dictionary any more.
1158 anInfoDict
->removeObject(kPrelinkBundlePathKey
);
1160 /* If we have a link state, create an OSData wrapper for it.
1162 addressNum
= OSDynamicCast(OSNumber
,
1163 anInfoDict
->getObject(kPrelinkLinkStateKey
));
1165 lengthNum
= OSDynamicCast(OSNumber
,
1166 anInfoDict
->getObject(kPrelinkLinkStateSizeKey
));
1169 kOSKextLogErrorLevel
|
1170 kOSKextLogArchiveFlag
,
1171 "Kext %s can't find prelinked kext link state size.",
1172 getIdentifierCString());
1176 data
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1177 linkStateLength
= (uint32_t) (lengthNum
->unsigned32BitValue());
1179 anInfoDict
->removeObject(kPrelinkLinkStateKey
);
1180 anInfoDict
->removeObject(kPrelinkLinkStateSizeKey
);
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.
1185 alloc_result
= kmem_alloc_pageable(kernel_map
,
1186 (vm_offset_t
*)&linkStateCopy
, linkStateLength
);
1187 if (alloc_result
!= KERN_SUCCESS
) {
1189 kOSKextLogErrorLevel
|
1190 kOSKextLogArchiveFlag
,
1191 "Kext %s failed to copy prelinked link state.",
1192 getIdentifierCString());
1195 memcpy(linkStateCopy
, data
, linkStateLength
);
1197 linkState
= OSData::withBytesNoCopy(linkStateCopy
, linkStateLength
);
1200 kOSKextLogErrorLevel
|
1201 kOSKextLogArchiveFlag
,
1202 "Kext %s failed to create link state wrapper.",
1203 getIdentifierCString());
1206 linkState
->setDeallocFunction(osdata_kmem_free
);
1208 /* Clear linkStateCopy; the OSData owns it now so we mustn't free it.
1210 linkStateCopy
= NULL
;
1213 /* Create an OSData wrapper around the linked executable.
1215 addressNum
= OSDynamicCast(OSNumber
,
1216 anInfoDict
->getObject(kPrelinkExecutableLoadKey
));
1218 lengthNum
= OSDynamicCast(OSNumber
,
1219 anInfoDict
->getObject(kPrelinkExecutableSizeKey
));
1222 kOSKextLogErrorLevel
|
1223 kOSKextLogArchiveFlag
,
1224 "Kext %s can't find prelinked kext executable size.",
1225 getIdentifierCString());
1229 data
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1230 length
= (uint32_t) (lengthNum
->unsigned32BitValue());
1232 anInfoDict
->removeObject(kPrelinkExecutableLoadKey
);
1233 anInfoDict
->removeObject(kPrelinkExecutableSizeKey
);
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.
1238 addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject(kPrelinkExecutableSourceKey
));
1240 srcData
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1242 if (data
!= srcData
) {
1244 alloc_result
= kext_alloc((vm_offset_t
*)&data
, length
, /* fixed */ TRUE
);
1245 if (alloc_result
!= KERN_SUCCESS
) {
1247 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1248 "Failed to allocate space for prelinked kext %s.",
1249 getIdentifierCString());
1252 memcpy(data
, srcData
, length
);
1255 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1256 "Error: prelinked kext %s - source and load addresses "
1257 "differ on ILP32 architecture.",
1258 getIdentifierCString());
1260 #endif /* __LP64__ */
1263 anInfoDict
->removeObject(kPrelinkExecutableSourceKey
);
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?
1271 prelinkedExecutable
= OSData::withBytesNoCopy(data
, length
);
1272 if (!prelinkedExecutable
) {
1274 kOSKextLogErrorLevel
|
1275 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1276 "Kext %s failed to create executable wrapper.",
1277 getIdentifierCString());
1280 setLinkedExecutable(prelinkedExecutable
);
1282 addressNum
= OSDynamicCast(OSNumber
,
1283 anInfoDict
->getObject(kPrelinkKmodInfoKey
));
1286 kOSKextLogErrorLevel
|
1287 kOSKextLogArchiveFlag
,
1288 "Kext %s can't find prelinked kext kmod_info address.",
1289 getIdentifierCString());
1293 kmod_info
= (kmod_info_t
*) (intptr_t) (addressNum
->unsigned64BitValue());
1295 anInfoDict
->removeObject(kPrelinkKmodInfoKey
);
1298 /* If the plist has a UUID for an interface, save that off.
1300 if (isInterface()) {
1301 interfaceUUID
= OSDynamicCast(OSData
,
1302 anInfoDict
->getObject(kPrelinkInterfaceUUIDKey
));
1303 if (interfaceUUID
) {
1304 interfaceUUID
->retain();
1305 anInfoDict
->removeObject(kPrelinkInterfaceUUIDKey
);
1309 flags
.prelinked
= true;
1311 /* If we created a kext from prelink info,
1312 * we must be booting from a prelinked kernel.
1314 sPrelinkBoot
= true;
1316 result
= registerIdentifier();
1320 /* If we didn't hand linkStateCopy off to an OSData, free it.
1322 if (linkStateCopy
) {
1323 kmem_free(kernel_map
, (vm_offset_t
)linkStateCopy
, linkStateLength
);
1326 OSSafeRelease(prelinkedExecutable
);
1331 /*********************************************************************
1332 *********************************************************************/
1334 OSKext::withBooterData(
1335 OSString
* deviceTreeName
,
1336 OSData
* booterData
)
1338 OSKext
* newKext
= new OSKext
;
1340 if (newKext
&& !newKext
->initWithBooterData(deviceTreeName
, booterData
)) {
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
;
1360 OSKext::initWithBooterData(
1361 OSString
* deviceTreeName
,
1362 OSData
* booterData
)
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
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
1376 if (!super::init()) {
1380 kextFileInfo
= (_BooterKextFileInfo
*)booterData
->getBytesNoCopy();
1381 if (!kextFileInfo
) {
1383 kOSKextLogErrorLevel
|
1384 kOSKextLogGeneralFlag
,
1385 "No booter-provided data for kext device tree entry %s.",
1386 deviceTreeName
->getCStringNoCopy());
1390 /* The info plist must exist or we can't read the kext.
1392 if (!kextFileInfo
->infoDictPhysAddr
|| !kextFileInfo
->infoDictLength
) {
1394 kOSKextLogErrorLevel
|
1395 kOSKextLogGeneralFlag
,
1396 "No kext info dictionary for booter device tree entry %s.",
1397 deviceTreeName
->getCStringNoCopy());
1401 infoDictAddr
= (char *)ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
1402 if (!infoDictAddr
) {
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());
1413 parsedXML
= OSUnserializeXML(infoDictAddr
, &errorString
);
1415 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
1418 const char * errorCString
= "(unknown error)";
1420 if (errorString
&& errorString
->getCStringNoCopy()) {
1421 errorCString
= errorString
->getCStringNoCopy();
1422 } else if (parsedXML
) {
1423 errorCString
= "not a dictionary";
1426 kOSKextLogErrorLevel
|
1427 kOSKextLogGeneralFlag
,
1428 "Error unserializing info dictionary for device tree entry %s: %s.",
1429 deviceTreeName
->getCStringNoCopy(), errorCString
);
1433 /* A bundle path is not mandatory.
1435 if (kextFileInfo
->bundlePathPhysAddr
&& kextFileInfo
->bundlePathLength
) {
1436 bundlePathAddr
= (char *)ml_static_ptovirt(kextFileInfo
->bundlePathPhysAddr
);
1437 if (!bundlePathAddr
) {
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());
1447 bundlePathAddr
[kextFileInfo
->bundlePathLength
-1] = '\0'; // just in case!
1449 kextPath
= OSString::withCString(bundlePathAddr
);
1452 kOSKextLogErrorLevel
|
1453 kOSKextLogGeneralFlag
,
1454 "Failed to create wrapper for device tree entry %s kext path %s.",
1455 deviceTreeName
->getCStringNoCopy(), bundlePathAddr
);
1460 if (!setInfoDictionaryAndPath(theInfoDict
, kextPath
)) {
1464 /* An executable is not mandatory.
1466 if (kextFileInfo
->executablePhysAddr
&& kextFileInfo
->executableLength
) {
1467 executableAddr
= (void *)ml_static_ptovirt(kextFileInfo
->executablePhysAddr
);
1468 if (!executableAddr
) {
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());
1479 executable
= OSData::withBytesNoCopy(executableAddr
,
1480 kextFileInfo
->executableLength
);
1483 kOSKextLogErrorLevel
|
1484 kOSKextLogGeneralFlag
,
1485 "Failed to create executable wrapper for device tree entry %s.",
1486 deviceTreeName
->getCStringNoCopy());
1490 /* A kext with an executable needs to retain the whole booterData
1491 * object to keep the executable in memory.
1493 if (!setExecutable(executable
, booterData
)) {
1495 kOSKextLogErrorLevel
|
1496 kOSKextLogGeneralFlag
,
1497 "Failed to set kext executable for device tree entry %s.",
1498 deviceTreeName
->getCStringNoCopy());
1503 result
= registerIdentifier();
1506 OSSafeRelease(parsedXML
);
1507 OSSafeRelease(kextPath
);
1508 OSSafeRelease(errorString
);
1509 OSSafeRelease(executable
);
1514 /*********************************************************************
1515 *********************************************************************/
1517 OSKext::registerIdentifier(void)
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
1530 /* Get the new kext's version for checks & log messages.
1532 newVersion
= getVersion();
1533 OSKextVersionGetString(newVersion
, newVersionCString
,
1534 kOSKextVersionMaxLength
);
1536 /* If we don't have an existing kext with this identifier,
1537 * just record the new kext and we're done!
1539 existingKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
));
1540 if (!existingKext
) {
1541 sKextsByID
->setObject(bundleID
, this);
1546 /* Get the existing kext's version for checks & log messages.
1548 existingVersion
= existingKext
->getVersion();
1549 OSKextVersionGetString(existingVersion
,
1550 existingVersionCString
, kOSKextVersionMaxLength
);
1552 existingIsLoaded
= existingKext
->isLoaded();
1553 existingIsPrelinked
= existingKext
->isPrelinked();
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.
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.
1564 if (existingIsLoaded
|| existingIsPrelinked
) {
1565 bool sameVersion
= (newVersion
== existingVersion
);
1566 bool sameExecutable
= true; // assume true unless we have UUIDs
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.
1572 newUUID
= copyUUID();
1573 existingUUID
= existingKext
->copyUUID();
1575 /* I'm entirely too paranoid about checking equivalence of executables,
1576 * but I remember nasty problems with it in the past.
1578 * - If we have UUIDs for both kexts, compare them.
1579 * - If only one kext has a UUID, they're definitely different.
1581 if (newUUID
&& existingUUID
) {
1582 sameExecutable
= newUUID
->isEqualTo(existingUUID
);
1583 } else if (newUUID
|| existingUUID
) {
1584 sameExecutable
= false;
1587 if (!newUUID
&& !existingUUID
) {
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.
1596 OSKextVersionGetString(version
, newVersionCString
,
1597 sizeof(newVersionCString
));
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(),
1605 (existingIsLoaded
? "loaded" : "prelinked"));
1608 if (sameVersion
&& sameExecutable
) {
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"));
1618 /* This condition is significant so log it under warnings.
1621 kOSKextLogWarningLevel
|
1622 kOSKextLogKextBookkeepingFlag
,
1623 "Refusing new kext %s, v%s: already have %s v%s.",
1624 getIdentifierCString(),
1626 (existingIsLoaded
? "loaded" : "prelinked"),
1627 existingVersionCString
);
1629 /* This condition is significant so log it under warnings.
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"));
1640 } /* if (existingIsLoaded || existingIsPrelinked) */
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).
1648 if (sUserLoadsActive
) {
1649 sKextsByID
->setObject(bundleID
, this);
1653 kOSKextLogStepLevel
|
1654 kOSKextLogKextBookkeepingFlag
,
1655 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
1656 getIdentifierCString(),
1657 existingVersionCString
,
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.
1667 if (newVersion
> existingVersion
) {
1668 sKextsByID
->setObject(bundleID
, this);
1672 kOSKextLogStepLevel
|
1673 kOSKextLogKextBookkeepingFlag
,
1674 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
1675 existingVersionCString
,
1676 getIdentifierCString(),
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
,
1690 /* result has been set appropriately by now. */
1696 kOSKextLogStepLevel
|
1697 kOSKextLogKextBookkeepingFlag
,
1698 "Kext %s, v%s registered and available for loading.",
1699 getIdentifierCString(), newVersionCString
);
1702 OSSafeRelease(newUUID
);
1703 OSSafeRelease(existingUUID
);
1708 /*********************************************************************
1709 * Does the bare minimum validation to look up a kext.
1710 * All other validation is done on the spot as needed.
1712 * No need for lock, only called from init
1713 **********************************************************************/
1715 OSKext::setInfoDictionaryAndPath(
1716 OSDictionary
* aDictionary
,
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
1728 panic("Attempt to set info dictionary on a kext "
1729 "that already has one (%s).",
1730 getIdentifierCString());
1733 if (!aDictionary
|| !OSDynamicCast(OSDictionary
, aDictionary
)) {
1737 infoDict
= aDictionary
;
1740 /* Check right away if the info dictionary has any log flags.
1742 scratchBool
= OSDynamicCast(OSBoolean
,
1743 getPropertyForHostArch(kOSBundleEnableKextLoggingKey
));
1744 if (scratchBool
== kOSBooleanTrue
) {
1745 flags
.loggingEnabled
= 1;
1748 /* The very next thing to get is the bundle identifier. Unlike
1749 * in user space, a kext with no bundle identifier gets axed
1752 bundleIDString
= OSDynamicCast(OSString
,
1753 getPropertyForHostArch(kCFBundleIdentifierKey
));
1754 if (!bundleIDString
) {
1756 kOSKextLogErrorLevel
|
1757 kOSKextLogValidationFlag
,
1758 "CFBundleIdentifier missing/invalid type in kext %s.",
1759 aPath
? aPath
->getCStringNoCopy() : "(unknown)");
1762 bundleID
= OSSymbol::withString(bundleIDString
);
1765 kOSKextLogErrorLevel
|
1766 kOSKextLogValidationFlag
,
1767 "Can't copy bundle identifier as symbol for kext %s.",
1768 bundleIDString
->getCStringNoCopy());
1772 /* Save the path if we got one (it should always be available but it's
1773 * just something nice to have for bookkeeping).
1781 * Minimal validation to initialize. We'll do other validation on the spot.
1783 if (bundleID
->getLength() >= KMOD_MAX_NAME
) {
1785 kOSKextLogErrorLevel
|
1786 kOSKextLogValidationFlag
,
1787 "Kext %s error - CFBundleIdentifier over max length %d.",
1788 getIdentifierCString(), KMOD_MAX_NAME
- 1);
1792 version
= compatibleVersion
= -1;
1794 versionString
= OSDynamicCast(OSString
,
1795 getPropertyForHostArch(kCFBundleVersionKey
));
1796 if (!versionString
) {
1798 kOSKextLogErrorLevel
|
1799 kOSKextLogValidationFlag
,
1800 "Kext %s error - CFBundleVersion missing/invalid type.",
1801 getIdentifierCString());
1804 versionCString
= versionString
->getCStringNoCopy();
1805 version
= OSKextParseVersionString(versionCString
);
1808 kOSKextLogErrorLevel
|
1809 kOSKextLogValidationFlag
,
1810 "Kext %s error - CFBundleVersion bad value '%s'.",
1811 getIdentifierCString(), versionCString
);
1815 compatibleVersion
= -1; // set to illegal value for kexts that don't have
1817 compatibleVersionString
= OSDynamicCast(OSString
,
1818 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
1819 if (compatibleVersionString
) {
1820 compatibleVersionCString
= compatibleVersionString
->getCStringNoCopy();
1821 compatibleVersion
= OSKextParseVersionString(compatibleVersionCString
);
1822 if (compatibleVersion
< 0) {
1824 kOSKextLogErrorLevel
|
1825 kOSKextLogValidationFlag
,
1826 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
1827 getIdentifierCString(), compatibleVersionCString
);
1831 if (compatibleVersion
> version
) {
1833 kOSKextLogErrorLevel
|
1834 kOSKextLogValidationFlag
,
1835 "Kext %s error - %s %s > %s %s (must be <=).",
1836 getIdentifierCString(),
1837 kOSBundleCompatibleVersionKey
, compatibleVersionCString
,
1838 kCFBundleVersionKey
, versionCString
);
1843 /* Set flags for later use if the infoDict gets flushed. We only
1844 * check for true values, not false ones(!)
1846 scratchBool
= OSDynamicCast(OSBoolean
,
1847 getPropertyForHostArch(kOSBundleIsInterfaceKey
));
1848 if (scratchBool
&& scratchBool
->isTrue()) {
1849 flags
.interface
= 1;
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...
1859 /* A kernel component has one implicit dependency on the kernel.
1861 flags
.hasAllDependencies
= 1;
1871 /*********************************************************************
1872 * Not used for prelinked kernel boot as there is no unrelocated
1874 *********************************************************************/
1876 OSKext::setExecutable(
1877 OSData
* anExecutable
,
1878 OSData
* externalData
,
1879 bool externalDataIsMkext
)
1881 bool result
= false;
1882 const char * executableKey
= NULL
; // do not free
1884 if (!anExecutable
) {
1885 infoDict
->removeObject(_kOSKextExecutableKey
);
1886 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
1887 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
1892 if (infoDict
->getObject(_kOSKextExecutableKey
) ||
1893 infoDict
->getObject(_kOSKextMkextExecutableReferenceKey
)) {
1895 panic("Attempt to set an executable on a kext "
1896 "that already has one (%s).",
1897 getIdentifierCString());
1901 if (externalDataIsMkext
) {
1902 executableKey
= _kOSKextMkextExecutableReferenceKey
;
1904 executableKey
= _kOSKextExecutableKey
;
1908 infoDict
->setObject(executableKey
, anExecutable
);
1910 infoDict
->setObject(_kOSKextExecutableExternalDataKey
, externalData
);
1920 /*********************************************************************
1921 *********************************************************************/
1926 panic("Attempt to free loaded kext %s.", getIdentifierCString());
1929 OSSafeRelease(infoDict
);
1930 OSSafeRelease(bundleID
);
1931 OSSafeRelease(path
);
1932 OSSafeRelease(dependencies
);
1933 OSSafeRelease(linkState
);
1934 OSSafeRelease(linkedExecutable
);
1935 OSSafeRelease(metaClasses
);
1936 OSSafeRelease(interfaceUUID
);
1938 if (isInterface() && kmod_info
) {
1939 kfree(kmod_info
, sizeof(kmod_info_t
));
1947 #pragma mark Mkext files
1949 /*********************************************************************
1950 *********************************************************************/
1952 OSKext::readMkextArchive(OSData
* mkextData
,
1953 uint32_t * checksumPtr
)
1955 OSReturn result
= kOSKextReturnBadData
;
1956 uint32_t mkextLength
= 0;
1957 mkext_header
* mkextHeader
= 0; // do not free
1958 uint32_t mkextVersion
= 0;
1960 /* Note default return of kOSKextReturnBadData above.
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.");
1971 mkextHeader
= (mkext_header
*)mkextData
->getBytesNoCopy();
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.");
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.");
1990 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
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
);
1997 OSKextLog(/* kext */ NULL
,
1998 kOSKextLogErrorLevel
|
1999 kOSKextLogArchiveFlag
,
2000 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion
);
2001 result
= kOSKextReturnUnsupported
;
2008 /*********************************************************************
2009 * Assumes magic, signature, version, length have been checked.
2011 * Doesn't do as much bounds-checking as it should, but we're dropping
2012 * mkext1 support from the kernel for SnowLeopard soon.
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 *********************************************************************/
2021 OSKext::readMkext1Archive(
2023 uint32_t * checksumPtr
)
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;
2032 uint32_t numKexts
= 0;
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
2041 mkextLength
= mkextData
->getLength();
2042 mkextHeader
= (mkext1_header
*)mkextData
->getBytesNoCopy();
2043 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2044 mkextVersion
= OSSwapBigToHostInt32(mkextHeader
->version
);
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
);
2051 if (OSSwapBigToHostInt32(mkextHeader
->adler32
) != checksum
) {
2052 OSKextLog(/* kext */ NULL
,
2053 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2054 "Kext archive has a bad checksum.");
2055 result
= kOSKextReturnBadData
;
2060 *checksumPtr
= checksum
;
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
)) {
2068 OSKextLog(/* kext */ NULL
,
2069 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2070 "Kext archive doesn't contain software "
2071 "for this computer's CPU type.");
2072 result
= kOSKextReturnArchNotFound
;
2077 numKexts
= OSSwapBigToHostInt32(mkextHeader
->numkexts
);
2079 for (uint32_t i
= 0; i
< numKexts
; i
++) {
2081 OSSafeReleaseNULL(infoDictDataObject
);
2082 OSSafeReleaseNULL(infoDict
);
2083 OSSafeReleaseNULL(mkextExecutableInfo
);
2084 OSSafeReleaseNULL(errorString
);
2085 OSSafeReleaseNULL(theKext
);
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
;
2098 /* Note that we're pretty tolerant of errors in individual entries.
2099 * As long as we can keep processing, we do.
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
);
2111 parsedXML
= OSUnserializeXML(
2112 (const char *)infoDictDataObject
->getBytesNoCopy(),
2115 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
2118 const char * errorCString
= "(unknown error)";
2120 if (errorString
&& errorString
->getCStringNoCopy()) {
2121 errorCString
= errorString
->getCStringNoCopy();
2122 } else if (parsedXML
) {
2123 errorCString
= "not a dictionary";
2125 OSKextLog(/* kext */ NULL
,
2126 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2127 "Error: Can't read XML property list "
2128 "for mkext archive entry %d: %s.", i
, errorCString
);
2132 theKext
= new OSKext
;
2134 OSKextLog(/* kext */ NULL
,
2135 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2136 "Kext allocation failure.");
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.
2145 if ((OSSwapBigToHostInt32(executablePtr
->offset
) ||
2146 OSSwapBigToHostInt32(executablePtr
->compsize
) ||
2147 OSSwapBigToHostInt32(executablePtr
->realsize
) ||
2148 OSSwapBigToHostInt32(executablePtr
->modifiedsecs
))) {
2150 MkextEntryRef entryRef
;
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
);
2158 entryRef
.mkext
= (mkext_basic_header
*)mkextHeader
;
2159 entryRef
.fileinfo
= (uint8_t *)executablePtr
;
2160 if (!mkextExecutableInfo
->appendBytes(&entryRef
,
2161 sizeof(entryRef
))) {
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
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.
2177 if (!theKext
->initWithMkext1Info(infoDict
, mkextExecutableInfo
,
2180 // theKext is released at the top of the loop or in the finish block
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.
2188 result
= kOSReturnSuccess
;
2193 OSSafeRelease(infoDictDataObject
);
2194 OSSafeRelease(parsedXML
);
2195 OSSafeRelease(errorString
);
2196 OSSafeRelease(mkextExecutableInfo
);
2197 OSSafeRelease(theKext
);
2202 /*********************************************************************
2203 *********************************************************************/
2205 OSKext::initWithMkext1Info(
2206 OSDictionary
* anInfoDict
,
2207 OSData
* executableWrapper
,
2210 bool result
= false;
2212 // mkext1 doesn't allow for path (might stuff in info dict)
2213 if (!setInfoDictionaryAndPath(anInfoDict
, /* path */ NULL
)) {
2217 if (!registerIdentifier()) {
2221 if (!setExecutable(executableWrapper
, mkextData
, true)) {
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.
2233 OSKext::removeKext(this, /* removePersonalities? */ false);
2239 /*********************************************************************
2240 * xxx - this should take the input data length
2241 *********************************************************************/
2244 OSKext::extractMkext1Entry(
2245 const void * mkextFileBase
,
2248 OSData
* result
= NULL
;
2249 OSData
* uncompressedData
= NULL
; // release on error
2250 const char * errmsg
= NULL
;
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
;
2257 fileinfo
= (mkext_file
*)entry
;
2259 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
2260 size_t compressed_size
= OSSwapBigToHostInt32(fileinfo
->compsize
);
2261 size_t expected_size
= OSSwapBigToHostInt32(fileinfo
->realsize
);
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
);
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.
2271 if (offset
== 0 && compressed_size
== 0 &&
2272 expected_size
== 0 && modifiedsecs
== 0) {
2276 kern_result
= kmem_alloc(kernel_map
,
2277 (vm_offset_t
*)&uncompressedDataBuffer
,
2279 if (kern_result
!= KERN_SUCCESS
) {
2284 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
,
2286 if (uncompressedData
== NULL
) {
2287 /* No need to free uncompressedDataBuffer here, either. */
2291 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
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
2298 if (compressed_size
!= 0) {
2299 errmsg
= "OSKext::uncompressMkext - "
2300 "uncompressed file shorter than expected";
2301 uncompressed_size
= decompress_lzss(uncompressedDataBuffer
,
2303 ((uint8_t *)mkextFileBase
) + offset
,
2305 if (uncompressed_size
!= expected_size
) {
2309 memcpy(uncompressedDataBuffer
,
2310 ((uint8_t *)mkextFileBase
) + offset
,
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';
2318 result
= uncompressedData
;
2323 OSKextLog(/* kext */ NULL
,
2324 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2327 if (uncompressedData
) {
2328 uncompressedData
->release();
2334 /*********************************************************************
2335 * Assumes magic, signature, version, length have been checked.
2336 * xxx - need to add further bounds checking for each file entry
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 *********************************************************************/
2345 OSKext::readMkext2Archive(
2347 OSDictionary
** mkextPlistOut
,
2348 uint32_t * checksumPtr
)
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
;
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
2369 mkextLength
= mkextData
->getLength();
2370 mkextHeader
= (mkext2_header
*)mkextData
->getBytesNoCopy();
2371 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2372 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
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
);
2379 if (MKEXT_GET_CHECKSUM(mkextHeader
) != checksum
) {
2380 OSKextLog(/* kext */ NULL
,
2381 kOSKextLogErrorLevel
|
2382 kOSKextLogArchiveFlag
,
2383 "Mkext archive has bad checksum.");
2384 result
= kOSKextReturnBadData
;
2389 *checksumPtr
= checksum
;
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
;
2401 if ((UInt32
)_mh_execute_header
.cputype
!=
2402 MKEXT_GET_CPUTYPE(mkextHeader
)) {
2404 OSKextLog(/* kext */ NULL
,
2405 kOSKextLogErrorLevel
|
2406 kOSKextLogArchiveFlag
,
2407 "Mkext archive does not match the running kernel's CPU type.");
2408 result
= kOSKextReturnArchNotFound
;
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
;
2425 mkextPlistFullSize
= MKEXT2_GET_PLIST_FULLSIZE(mkextHeader
);
2426 if (mkextPlistCompressedSize
) {
2427 mkextPlistUncompressedData
= sKernelKext
->extractMkext2FileData(
2428 (UInt8
*)mkextHeader
+ mkextPlistOffset
,
2430 mkextPlistCompressedSize
, mkextPlistFullSize
);
2431 if (!mkextPlistUncompressedData
) {
2434 mkextPlistDataBuffer
= (const char *)
2435 mkextPlistUncompressedData
->getBytesNoCopy();
2437 mkextPlistDataBuffer
= (const char *)mkextHeader
+ mkextPlistOffset
;
2440 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2442 parsedXML
= OSUnserializeXML(mkextPlistDataBuffer
, &errorString
);
2444 mkextPlist
= OSDynamicCast(OSDictionary
, parsedXML
);
2447 const char * errorCString
= "(unknown error)";
2449 if (errorString
&& errorString
->getCStringNoCopy()) {
2450 errorCString
= errorString
->getCStringNoCopy();
2451 } else if (parsedXML
) {
2452 errorCString
= "not a dictionary";
2454 OSKextLog(/* kext */ NULL
,
2455 kOSKextLogErrorLevel
|
2456 kOSKextLogArchiveFlag
,
2457 "Error unserializing mkext plist: %s.", errorCString
);
2461 /* If the caller needs the plist, hand it back and retain it.
2462 * (This function releases it at the end.)
2464 if (mkextPlistOut
) {
2465 *mkextPlistOut
= mkextPlist
;
2466 (*mkextPlistOut
)->retain();
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.");
2479 count
= mkextInfoDictArray
->getCount();
2480 for (i
= 0; i
< count
; i
++) {
2481 OSDictionary
* infoDict
;
2484 infoDict
= OSDynamicCast(OSDictionary
,
2485 mkextInfoDictArray
->getObject(i
));
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.
2491 OSKext
* newKext
= OSKext::withMkext2Info(infoDict
, mkextData
);
2492 OSSafeRelease(newKext
);
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).
2498 result
= kOSReturnSuccess
;
2502 OSSafeRelease(parsedXML
);
2503 OSSafeRelease(mkextPlistUncompressedData
);
2504 OSSafeRelease(errorString
);
2509 /*********************************************************************
2510 *********************************************************************/
2513 OSKext::withMkext2Info(
2514 OSDictionary
* anInfoDict
,
2517 OSKext
* newKext
= new OSKext
;
2519 if (newKext
&& !newKext
->initWithMkext2Info(anInfoDict
, mkextData
)) {
2527 /*********************************************************************
2528 *********************************************************************/
2530 OSKext::initWithMkext2Info(
2531 OSDictionary
* anInfoDict
,
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
2540 if (!super::init()) {
2544 /* Get the path. Don't look for an arch-specific path property.
2546 kextPath
= OSDynamicCast(OSString
,
2547 anInfoDict
->getObject(kMKEXTBundlePathKey
));
2549 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
2553 /* Don't need the path to be in the info dictionary any more.
2555 anInfoDict
->removeObject(kMKEXTBundlePathKey
);
2557 executableOffsetNum
= OSDynamicCast(OSNumber
,
2558 infoDict
->getObject(kMKEXTExecutableKey
));
2559 if (executableOffsetNum
) {
2560 executable
= createMkext2FileEntry(mkextData
,
2561 executableOffsetNum
, "executable");
2562 infoDict
->removeObject(kMKEXTExecutableKey
);
2566 if (!setExecutable(executable
, mkextData
, true)) {
2571 result
= registerIdentifier();
2575 OSSafeRelease(executable
);
2576 OSSafeRelease(iterator
);
2580 /*********************************************************************
2581 *********************************************************************/
2583 OSKext::createMkext2FileEntry(
2585 OSNumber
* offsetNum
,
2588 OSData
* result
= NULL
;
2589 MkextEntryRef entryRef
;
2590 uint8_t * mkextBuffer
= (uint8_t *)mkextData
->getBytesNoCopy();
2591 uint32_t entryOffset
= offsetNum
->unsigned32BitValue();
2593 result
= OSData::withCapacity(sizeof(entryRef
));
2598 entryRef
.mkext
= (mkext_basic_header
*)mkextBuffer
;
2599 entryRef
.fileinfo
= mkextBuffer
+ entryOffset
;
2600 if (!result
->appendBytes(&entryRef
, sizeof(entryRef
))) {
2601 OSSafeReleaseNULL(result
);
2608 kOSKextLogErrorLevel
|
2609 kOSKextLogArchiveFlag
,
2610 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2611 name
, getIdentifierCString());
2616 /*********************************************************************
2617 *********************************************************************/
2619 static void * z_alloc(void *, u_int items
, u_int size
);
2620 static void z_free(void *, void *ptr
);
2622 typedef struct z_mem
{
2623 uint32_t alloc_size
;
2628 * Space allocation and freeing routines for use by zlib routines.
2631 z_alloc(void * notused __unused
, u_int num_items
, u_int size
)
2633 void * result
= NULL
;
2634 z_mem
* zmem
= NULL
;
2635 uint32_t total
= num_items
* size
;
2636 uint32_t allocSize
= total
+ sizeof(zmem
);
2638 zmem
= (z_mem
*)kalloc(allocSize
);
2642 zmem
->alloc_size
= allocSize
;
2643 result
= (void *)&(zmem
->data
);
2649 z_free(void * notused __unused
, void * ptr
)
2651 uint32_t * skipper
= (uint32_t *)ptr
- 1;
2652 z_mem
* zmem
= (z_mem
*)skipper
;
2653 kfree((void *)zmem
, zmem
->alloc_size
);
2659 OSKext::extractMkext2FileData(
2662 uint32_t compressedSize
,
2665 OSData
* result
= NULL
;
2667 OSData
* uncompressedData
= NULL
; // release on error
2669 uint8_t * uncompressedDataBuffer
= 0; // do not free
2670 unsigned long uncompressedSize
;
2672 bool zstream_inited
= false;
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.
2678 if (!compressedSize
) {
2679 uncompressedData
= OSData::withBytes(data
, fullSize
);
2680 // xxx - no check for failure?
2681 result
= uncompressedData
;
2685 if (KERN_SUCCESS
!= kmem_alloc(kernel_map
,
2686 (vm_offset_t
*)&uncompressedDataBuffer
, fullSize
)) {
2688 /* How's this for cheesy? The kernel is only asked to extract
2689 * kext plists so we tailor the log messages.
2691 if (this == sKernelKext
) {
2693 kOSKextLogErrorLevel
|
2694 kOSKextLogArchiveFlag
,
2695 "Allocation failure extracting %s from mkext.", name
);
2698 kOSKextLogErrorLevel
|
2699 kOSKextLogArchiveFlag
,
2700 "Allocation failure extracting %s from mkext for kext %s.",
2701 name
, getIdentifierCString());
2706 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
, fullSize
);
2707 if (!uncompressedData
) {
2708 if (this == sKernelKext
) {
2710 kOSKextLogErrorLevel
|
2711 kOSKextLogArchiveFlag
,
2712 "Allocation failure extracting %s from mkext.", name
);
2715 kOSKextLogErrorLevel
|
2716 kOSKextLogArchiveFlag
,
2717 "Allocation failure extracting %s from mkext for kext %s.",
2718 name
, getIdentifierCString());
2722 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
2724 if (this == sKernelKext
) {
2726 kOSKextLogDetailLevel
|
2727 kOSKextLogArchiveFlag
,
2728 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2729 name
, compressedSize
, fullSize
);
2732 kOSKextLogDetailLevel
|
2733 kOSKextLogArchiveFlag
,
2734 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2735 getIdentifierCString(), name
, compressedSize
, fullSize
);
2738 bzero(&zstream
, sizeof(zstream
));
2739 zstream
.next_in
= (UInt8
*)data
;
2740 zstream
.avail_in
= compressedSize
;
2742 zstream
.next_out
= uncompressedDataBuffer
;
2743 zstream
.avail_out
= fullSize
;
2745 zstream
.zalloc
= z_alloc
;
2746 zstream
.zfree
= z_free
;
2748 zlib_result
= inflateInit(&zstream
);
2749 if (Z_OK
!= zlib_result
) {
2750 if (this == sKernelKext
) {
2752 kOSKextLogErrorLevel
|
2753 kOSKextLogArchiveFlag
,
2754 "Mkext error; zlib inflateInit failed (%d) for %s.",
2758 kOSKextLogErrorLevel
|
2759 kOSKextLogArchiveFlag
,
2760 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
2761 getIdentifierCString(), zlib_result
, name
);
2765 zstream_inited
= true;
2768 zlib_result
= inflate(&zstream
, Z_FINISH
);
2770 if (zlib_result
== Z_STREAM_END
|| zlib_result
== Z_OK
) {
2771 uncompressedSize
= zstream
.total_out
;
2773 if (this == sKernelKext
) {
2775 kOSKextLogErrorLevel
|
2776 kOSKextLogArchiveFlag
,
2777 "Mkext error; zlib inflate failed (%d) for %s.",
2781 kOSKextLogErrorLevel
|
2782 kOSKextLogArchiveFlag
,
2783 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
2784 getIdentifierCString(), zlib_result
, name
);
2788 kOSKextLogErrorLevel
|
2789 kOSKextLogArchiveFlag
,
2790 "zlib error: %s.", zstream
.msg
);
2795 if (uncompressedSize
!= fullSize
) {
2796 if (this == sKernelKext
) {
2798 kOSKextLogErrorLevel
|
2799 kOSKextLogArchiveFlag
,
2800 "Mkext error; zlib inflate discrepancy for %s, "
2801 "uncompressed size != original size.", name
);
2804 kOSKextLogErrorLevel
|
2805 kOSKextLogArchiveFlag
,
2806 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
2807 "uncompressed size != original size.",
2808 getIdentifierCString(), name
);
2813 result
= uncompressedData
;
2816 /* Don't bother checking return, nothing we can do on fail.
2818 if (zstream_inited
) inflateEnd(&zstream
);
2821 OSSafeRelease(uncompressedData
);
2827 /*********************************************************************
2828 *********************************************************************/
2831 OSKext::loadFromMkext(
2832 OSKextLogSpec clientLogFilter
,
2834 uint32_t mkextBufferLength
,
2836 uint32_t * logInfoLengthOut
)
2838 OSReturn result
= kOSReturnError
;
2839 OSReturn tempResult
= kOSReturnError
;
2841 OSData
* mkextData
= NULL
; // must release
2842 OSDictionary
* mkextPlist
= NULL
; // must release
2844 OSArray
* logInfoArray
= NULL
; // must release
2845 OSSerialize
* serializer
= NULL
; // must release
2847 OSString
* predicate
= NULL
; // do not release
2848 OSDictionary
* requestArgs
= NULL
; // do not release
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
2856 /* Default values for these two options: regular autounload behavior,
2857 * load all kexts, send no personalities.
2859 Boolean delayAutounload
= false;
2860 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
2861 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeAll
;
2863 IORecursiveLockLock(sKextLock
);
2867 *logInfoLengthOut
= 0;
2870 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
2872 OSKextLog(/* kext */ NULL
,
2873 kOSKextLogDebugLevel
|
2875 "Received kext load request from user space.");
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.
2881 if (!sUserLoadsActive
) {
2882 OSKextLog(/* kext */ NULL
,
2883 kOSKextLogProgressLevel
|
2884 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
2885 "Switching to late startup (user-space) kext loading policy.");
2887 sUserLoadsActive
= true;
2890 if (!sLoadEnabled
) {
2891 OSKextLog(/* kext */ NULL
,
2892 kOSKextLogErrorLevel
|
2894 "Kext loading is disabled.");
2895 result
= kOSKextReturnDisabled
;
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()
2904 mkextData
= OSData::withBytesNoCopy(mkextBuffer
,
2907 OSKextLog(/* kext */ NULL
,
2908 kOSKextLogErrorLevel
|
2909 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
2910 "Failed to create wrapper for kext load request.");
2911 result
= kOSKextReturnNoMemory
;
2915 result
= readMkext2Archive(mkextData
, &mkextPlist
, NULL
);
2916 if (result
!= kOSReturnSuccess
) {
2917 OSKextLog(/* kext */ NULL
,
2918 kOSKextLogErrorLevel
|
2920 "Failed to read kext load request.");
2924 predicate
= _OSKextGetRequestPredicate(mkextPlist
);
2925 if (!predicate
|| !predicate
->isEqualTo(kKextRequestPredicateLoad
)) {
2926 OSKextLog(/* kext */ NULL
,
2927 kOSKextLogErrorLevel
|
2929 "Received kext load request with no predicate; skipping.");
2930 result
= kOSKextReturnInvalidArgument
;
2934 requestArgs
= OSDynamicCast(OSDictionary
,
2935 mkextPlist
->getObject(kKextRequestArgumentsKey
));
2936 if (!requestArgs
|| !requestArgs
->getCount()) {
2937 OSKextLog(/* kext */ NULL
,
2938 kOSKextLogErrorLevel
|
2940 "Received kext load request with no arguments.");
2941 result
= kOSKextReturnInvalidArgument
;
2945 kextIdentifier
= OSDynamicCast(OSString
,
2946 requestArgs
->getObject(kKextRequestArgumentBundleIdentifierKey
));
2947 if (!kextIdentifier
) {
2948 OSKextLog(/* kext */ NULL
,
2949 kOSKextLogErrorLevel
|
2951 "Received kext load request with no kext identifier.");
2952 result
= kOSKextReturnInvalidArgument
;
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
));
2965 if (delayAutounloadBool
) {
2966 delayAutounload
= delayAutounloadBool
->getValue();
2968 if (startKextExcludeNum
) {
2969 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
2971 if (startMatchingExcludeNum
) {
2972 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
2975 OSKextLog(/* kext */ NULL
,
2976 kOSKextLogProgressLevel
|
2978 "Received request from user space to load kext %s.",
2979 kextIdentifier
->getCStringNoCopy());
2981 /* Load the kext, with no deferral, since this is a load from outside
2983 * xxx - Would like a better way to handle the default values for the
2984 * xxx - start/match opt args.
2986 result
= OSKext::loadKextWithIdentifier(
2988 /* allowDefer */ false,
2990 startKextExcludeLevel
,
2991 startMatchingExcludeLevel
,
2993 if (result
!= kOSReturnSuccess
) {
2996 /* If the load came down from kextd, it will shortly inform IOCatalogue
2997 * for matching via a separate IOKit calldown.
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.
3006 logInfoArray
= OSKext::clearUserSpaceLogFilter();
3008 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
3009 tempResult
= OSKext::serializeLogInfo(logInfoArray
,
3010 logInfoOut
, logInfoLengthOut
);
3011 if (tempResult
!= kOSReturnSuccess
) {
3012 result
= tempResult
;
3016 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
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....
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.");
3030 IORecursiveLockUnlock(sKextLock
);
3032 OSSafeRelease(mkextData
);
3033 OSSafeRelease(mkextPlist
);
3034 OSSafeRelease(serializer
);
3035 OSSafeRelease(logInfoArray
);
3040 /*********************************************************************
3041 *********************************************************************/
3044 OSKext::serializeLogInfo(
3045 OSArray
* logInfoArray
,
3047 uint32_t * logInfoLengthOut
)
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;
3056 if (!logInfoArray
|| !logInfoOut
|| !logInfoLengthOut
) {
3057 OSKextLog(/* kext */ NULL
,
3058 kOSKextLogErrorLevel
|
3060 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3061 /* Bad programmer. */
3062 result
= kOSKextReturnInvalidArgument
;
3066 serializer
= OSSerialize::withCapacity(0);
3068 OSKextLog(/* kext */ NULL
,
3069 kOSKextLogErrorLevel
|
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. */
3076 if (!logInfoArray
->serialize(serializer
)) {
3077 OSKextLog(/* kext */ NULL
,
3078 kOSKextLogErrorLevel
|
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. */
3084 logInfo
= serializer
->text();
3085 logInfoLength
= serializer
->getLength();
3087 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
, logInfoLength
);
3088 if (kmem_result
!= KERN_SUCCESS
) {
3089 OSKextLog(/* kext */ NULL
,
3090 kOSKextLogErrorLevel
|
3092 "Failed to copy log info for request from user space.");
3093 /* Incidental error; we're going to (try to) allow the request
3096 memcpy(buffer
, logInfo
, logInfoLength
);
3097 *logInfoOut
= buffer
;
3098 *logInfoLengthOut
= logInfoLength
;
3102 result
= kOSReturnSuccess
;
3104 OSSafeRelease(serializer
);
3109 #pragma mark Instance Management Methods
3111 /*********************************************************************
3112 *********************************************************************/
3114 OSKext::lookupKextWithIdentifier(const char * kextIdentifier
)
3116 OSKext
* foundKext
= NULL
;
3118 IORecursiveLockLock(sKextLock
);
3119 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3121 foundKext
->retain();
3123 IORecursiveLockUnlock(sKextLock
);
3128 /*********************************************************************
3129 *********************************************************************/
3131 OSKext::lookupKextWithIdentifier(OSString
* kextIdentifier
)
3133 return OSKext::lookupKextWithIdentifier(kextIdentifier
->getCStringNoCopy());
3136 /*********************************************************************
3137 *********************************************************************/
3139 OSKext::lookupKextWithLoadTag(uint32_t aTag
)
3141 OSKext
* foundKext
= NULL
; // returned
3144 IORecursiveLockLock(sKextLock
);
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();
3157 IORecursiveLockUnlock(sKextLock
);
3162 /*********************************************************************
3163 *********************************************************************/
3165 OSKext::lookupKextWithAddress(vm_address_t address
)
3167 OSKext
* foundKext
= NULL
; // returned
3170 IORecursiveLockLock(sKextLock
);
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();
3181 if ((kext_start
<= address
) && (address
< kext_end
)) {
3182 foundKext
= thisKext
;
3183 foundKext
->retain();
3190 IORecursiveLockUnlock(sKextLock
);
3195 /*********************************************************************
3196 *********************************************************************/
3198 bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
3200 bool result
= false;
3201 OSKext
* foundKext
= NULL
; // returned
3203 IORecursiveLockLock(sKextLock
);
3205 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3206 if (foundKext
&& foundKext
->isLoaded()) {
3210 IORecursiveLockUnlock(sKextLock
);
3215 /*********************************************************************
3216 * xxx - should spawn a separate thread so a kext can safely have
3217 * xxx - itself unloaded.
3218 *********************************************************************/
3223 bool terminateServicesAndRemovePersonalitiesFlag
)
3225 OSReturn result
= kOSKextReturnInUse
;
3226 OSKext
* checkKext
= NULL
; // do not release
3228 IORecursiveLockLock(sKextLock
);
3230 /* If the kext has no identifier, it failed to init
3231 * so isn't in sKextsByID and it isn't loaded.
3233 if (!aKext
->getIdentifier()) {
3234 result
= kOSReturnSuccess
;
3238 checkKext
= OSDynamicCast(OSKext
,
3239 sKextsByID
->getObject(aKext
->getIdentifier()));
3240 if (checkKext
!= aKext
) {
3241 result
= kOSKextReturnNotFound
;
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.
3251 if (terminateServicesAndRemovePersonalitiesFlag
) {
3252 result
= gIOCatalogue
->terminateDriversForModule(
3253 aKext
->getIdentifierCString(), /* unload */ false);
3254 if (result
!= kOSReturnSuccess
) {
3256 kOSKextLogProgressLevel
|
3257 kOSKextLogKextBookkeepingFlag
,
3258 "Can't remove kext %s; services failed to terminate - 0x%x.",
3259 aKext
->getIdentifierCString(), result
);
3264 result
= aKext
->unload();
3265 if (result
!= kOSReturnSuccess
) {
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
3276 if (terminateServicesAndRemovePersonalitiesFlag
) {
3277 aKext
->removePersonalitiesFromCatalog();
3281 kOSKextLogProgressLevel
|
3282 kOSKextLogKextBookkeepingFlag
,
3283 "Removing kext %s.",
3284 aKext
->getIdentifierCString());
3286 sKextsByID
->removeObject(aKext
->getIdentifier());
3287 result
= kOSReturnSuccess
;
3290 IORecursiveLockUnlock(sKextLock
);
3294 /*********************************************************************
3295 *********************************************************************/
3298 OSKext::removeKextWithIdentifier(
3299 const char * kextIdentifier
,
3300 bool terminateServicesAndRemovePersonalitiesFlag
)
3302 OSReturn result
= kOSReturnError
;
3304 IORecursiveLockLock(sKextLock
);
3306 OSKext
* aKext
= OSDynamicCast(OSKext
,
3307 sKextsByID
->getObject(kextIdentifier
));
3309 result
= kOSKextReturnNotFound
;
3310 OSKextLog(/* kext */ NULL
,
3311 kOSKextLogErrorLevel
|
3312 kOSKextLogKextBookkeepingFlag
,
3313 "Can't remove kext %s - not found.",
3318 result
= OSKext::removeKext(aKext
,
3319 terminateServicesAndRemovePersonalitiesFlag
);
3322 IORecursiveLockUnlock(sKextLock
);
3327 /*********************************************************************
3328 *********************************************************************/
3331 OSKext::removeKextWithLoadTag(
3332 OSKextLoadTag loadTag
,
3333 bool terminateServicesAndRemovePersonalitiesFlag
)
3335 OSReturn result
= kOSReturnError
;
3336 OSKext
* foundKext
= NULL
;
3339 IORecursiveLockLock(sKextLock
);
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
;
3351 result
= kOSKextReturnNotFound
;
3352 OSKextLog(/* kext */ NULL
,
3353 kOSKextLogErrorLevel
|
3354 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3355 "Can't remove kext with load tag %d - not found.",
3360 result
= OSKext::removeKext(foundKext
,
3361 terminateServicesAndRemovePersonalitiesFlag
);
3364 IORecursiveLockUnlock(sKextLock
);
3369 /*********************************************************************
3370 *********************************************************************/
3372 OSKext::copyKexts(void)
3374 OSDictionary
* result
;
3376 IORecursiveLockLock(sKextLock
);
3377 result
= OSDynamicCast(OSDictionary
, sKextsByID
->copyCollection());
3378 IORecursiveLockUnlock(sKextLock
);
3384 #pragma mark Accessors
3386 /*********************************************************************
3387 *********************************************************************/
3389 OSKext::getIdentifier(void)
3394 /*********************************************************************
3395 * A kext must have a bundle identifier to even survive initialization;
3396 * this is guaranteed to exist past then.
3397 *********************************************************************/
3399 OSKext::getIdentifierCString(void)
3401 return bundleID
->getCStringNoCopy();
3404 /*********************************************************************
3405 *********************************************************************/
3407 OSKext::getVersion(void)
3412 /*********************************************************************
3413 *********************************************************************/
3415 OSKext::getCompatibleVersion(void)
3417 return compatibleVersion
;
3420 /*********************************************************************
3421 *********************************************************************/
3423 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
3425 if ((compatibleVersion
> -1 && version
> -1) &&
3426 (compatibleVersion
<= version
&& aVersion
<= version
)) {
3432 /*********************************************************************
3433 *********************************************************************/
3435 OSKext::declaresExecutable(void)
3437 if (getPropertyForHostArch(kCFBundleExecutableKey
)) {
3443 /*********************************************************************
3444 *********************************************************************/
3446 OSKext::getExecutable(void)
3448 OSData
* result
= NULL
;
3449 OSData
* extractedExecutable
= NULL
; // must release
3450 OSData
* mkextExecutableRef
= NULL
; // do not release
3452 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
3457 mkextExecutableRef
= OSDynamicCast(OSData
,
3458 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
3460 if (mkextExecutableRef
) {
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
);
3477 OSKextLog(this, kOSKextLogErrorLevel
|
3478 kOSKextLogArchiveFlag
,
3479 "Kext %s - unknown mkext version 0x%x for executable.",
3480 getIdentifierCString(), mkextVersion
);
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.)
3487 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
3488 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
3490 if (extractedExecutable
&& extractedExecutable
->getLength()) {
3491 if (!setExecutable(extractedExecutable
)) {
3494 result
= extractedExecutable
;
3502 OSSafeRelease(extractedExecutable
);
3507 /*********************************************************************
3508 *********************************************************************/
3510 OSKext::isInterface(void)
3512 return flags
.interface
;
3515 /*********************************************************************
3516 *********************************************************************/
3518 OSKext::isKernelComponent(void)
3520 return flags
.kernelComponent
? true : false;
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.
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 *********************************************************************/
3536 OSKext::isLoadableInSafeBoot(void)
3538 bool result
= false;
3539 OSString
* required
= NULL
; // do not release
3542 required
= OSDynamicCast(OSString
,
3543 getPropertyForHostArch(kOSBundleRequiredKey
));
3547 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
3548 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
3549 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
3550 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
3551 required
->isEqualTo(kOSBundleRequiredConsole
)) {
3560 /*********************************************************************
3561 *********************************************************************/
3563 OSKext::isPrelinked(void)
3565 return flags
.prelinked
? true : false;
3568 /*********************************************************************
3569 *********************************************************************/
3570 bool OSKext::isLoaded(void)
3572 return flags
.loaded
? true : false;
3575 /*********************************************************************
3576 *********************************************************************/
3578 OSKext::isStarted(void)
3580 return flags
.started
? true : false;
3583 /*********************************************************************
3584 *********************************************************************/
3586 OSKext::isCPPInitialized(void)
3588 return flags
.CPPInitialized
;
3591 /*********************************************************************
3592 *********************************************************************/
3594 OSKext::setCPPInitialized(bool initialized
)
3596 flags
.CPPInitialized
= initialized
;
3599 /*********************************************************************
3600 *********************************************************************/
3602 OSKext::getLoadTag(void)
3607 /*********************************************************************
3608 *********************************************************************/
3610 OSKext::copyUUID(void)
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
;
3619 /* An interface kext doesn't have a linked executable with an LC_UUID,
3620 * we create one when it's linked.
3622 if (interfaceUUID
) {
3623 result
= interfaceUUID
;
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.
3631 theExecutable
= linkedExecutable
;
3632 if (!theExecutable
) {
3633 theExecutable
= getExecutable();
3635 if (!theExecutable
) {
3639 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
3640 load_cmd
= (const struct load_command
*)&header
[1];
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
));
3648 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
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"
3664 #error architecture not supported
3667 #define ARCH_SEPARATOR_CHAR '_'
3669 static char * makeHostArchKey(const char * key
, uint32_t * keySizeOut
)
3671 char * result
= NULL
;
3672 uint32_t keyLength
= strlen(key
);
3675 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
3677 keySize
= 1 + 1 + strlen(key
) + strlen(ARCHNAME
);
3678 result
= (char *)kalloc(keySize
);
3682 strlcpy(result
, key
, keySize
);
3683 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
3684 result
[keyLength
] = '\0';
3685 strlcat(result
, ARCHNAME
, keySize
);
3686 *keySizeOut
= keySize
;
3692 /*********************************************************************
3693 *********************************************************************/
3695 OSKext::getPropertyForHostArch(const char * key
)
3697 OSObject
* result
= NULL
; // do not release
3698 uint32_t hostArchKeySize
= 0;
3699 char * hostArchKey
= NULL
; // must kfree
3701 if (!key
|| !infoDict
) {
3705 /* Some properties are not allowed to be arch-variant:
3706 * - Any CFBundle... property.
3707 * - OSBundleIsInterface.
3708 * - OSKernelResource.
3710 if (STRING_HAS_PREFIX(key
, "OS") ||
3711 STRING_HAS_PREFIX(key
, "IO")) {
3713 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
3715 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
3716 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
3717 "Allocation failure.");
3720 result
= infoDict
->getObject(hostArchKey
);
3724 result
= infoDict
->getObject(key
);
3728 if (hostArchKey
) kfree(hostArchKey
, hostArchKeySize
);
3733 #pragma mark Load/Start/Stop/Unload
3735 /*********************************************************************
3736 *********************************************************************/
3738 OSKext::loadKextWithIdentifier(
3739 const char * kextIdentifierCString
,
3740 Boolean allowDeferFlag
,
3741 Boolean delayAutounloadFlag
,
3742 OSKextExcludeLevel startOpt
,
3743 OSKextExcludeLevel startMatchingOpt
,
3744 OSArray
* personalityNames
)
3746 OSReturn result
= kOSReturnError
;
3747 OSString
* kextIdentifier
= NULL
; // must release
3749 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
3750 if (!kextIdentifier
) {
3751 result
= kOSKextReturnNoMemory
;
3754 result
= OSKext::loadKextWithIdentifier(kextIdentifier
,
3755 allowDeferFlag
, delayAutounloadFlag
,
3756 startOpt
, startMatchingOpt
, personalityNames
);
3759 OSSafeRelease(kextIdentifier
);
3764 /*********************************************************************
3765 *********************************************************************/
3767 OSKext::loadKextWithIdentifier(
3768 OSString
* kextIdentifier
,
3769 Boolean allowDeferFlag
,
3770 Boolean delayAutounloadFlag
,
3771 OSKextExcludeLevel startOpt
,
3772 OSKextExcludeLevel startMatchingOpt
,
3773 OSArray
* personalityNames
)
3775 OSReturn result
= kOSReturnError
;
3776 OSKext
* theKext
= NULL
; // do not release
3777 OSDictionary
* loadRequest
= NULL
; // must release
3778 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
3780 IORecursiveLockLock(sKextLock
);
3782 if (!kextIdentifier
) {
3783 result
= kOSKextReturnInvalidArgument
;
3787 OSKext::recordIdentifierRequest(kextIdentifier
);
3789 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3791 if (!allowDeferFlag
) {
3792 OSKextLog(/* kext */ NULL
,
3793 kOSKextLogErrorLevel
|
3795 "Can't load kext %s - not found.",
3796 kextIdentifier
->getCStringNoCopy());
3800 if (!sKernelRequestsEnabled
) {
3802 kOSKextLogErrorLevel
|
3804 "Can't load kext %s - requests to user space are disabled.",
3805 kextIdentifier
->getCStringNoCopy());
3806 result
= kOSKextReturnDisabled
;
3810 /* Create a new request unless one is already sitting
3811 * in sKernelRequests for this bundle identifier
3813 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
3814 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
3815 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
3817 if (result
!= kOSReturnSuccess
) {
3820 if (!_OSKextSetRequestArgument(loadRequest
,
3821 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
3823 result
= kOSKextReturnNoMemory
;
3826 if (!sKernelRequests
->setObject(loadRequest
)) {
3827 result
= kOSKextReturnNoMemory
;
3831 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
3832 result
= kOSKextReturnNoMemory
;
3837 kOSKextLogDebugLevel
|
3839 "Kext %s not found; queued load request to user space.",
3840 kextIdentifier
->getCStringNoCopy());
3846 OSKextLog(/* kext */ NULL
,
3847 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
3849 "Not loading kext %s - not found and kextd not available in early boot.",
3850 kextIdentifier
->getCStringNoCopy());
3853 result
= kOSKextReturnDeferred
;
3857 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
3859 if (result
!= kOSReturnSuccess
) {
3861 kOSKextLogErrorLevel
|
3863 "Failed to load kext %s (error 0x%x).",
3864 kextIdentifier
->getCStringNoCopy(), (int)result
);
3866 OSKext::removeKext(theKext
,
3867 /* terminateService/removePersonalities */ true);
3871 if (delayAutounloadFlag
) {
3873 kOSKextLogProgressLevel
|
3874 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3875 "Setting delayed autounload for %s.",
3876 kextIdentifier
->getCStringNoCopy());
3877 theKext
->flags
.delayAutounload
= 1;
3881 OSSafeRelease(loadRequest
);
3882 OSSafeRelease(kextIdentifierSymbol
);
3884 IORecursiveLockUnlock(sKextLock
);
3889 /*********************************************************************
3890 *********************************************************************/
3893 OSKext::recordIdentifierRequest(
3894 OSString
* kextIdentifier
)
3896 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
3899 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
3903 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
3904 if (!kextIdentifierSymbol
) {
3905 // xxx - this is really a basic alloc failure
3910 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
3911 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
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());
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());
3932 OSSafeRelease(kextIdentifierSymbol
);
3936 /*********************************************************************
3937 *********************************************************************/
3940 OSKextExcludeLevel startOpt
,
3941 OSKextExcludeLevel startMatchingOpt
,
3942 OSArray
* personalityNames
)
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
;
3952 if (!sLoadEnabled
) {
3953 if (!isLoaded() || (!isStarted() && startOpt
!= kOSKextExcludeNone
) ||
3954 (startMatchingOpt
!= kOSKextExcludeNone
)) {
3957 kOSKextLogErrorLevel
|
3959 "Kext loading is disabled "
3960 "(attempt to load/start/start matching for kext %s).",
3961 getIdentifierCString());
3963 result
= kOSKextReturnDisabled
;
3968 alreadyLoaded
= true;
3969 result
= kOSReturnSuccess
;
3972 kOSKextLogDebugLevel
|
3973 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3974 "Kext %s is already loaded.",
3975 getIdentifierCString());
3979 /* If we've pushed the next available load tag to the invalid value,
3980 * we can't load any more kexts.
3982 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
3984 kOSKextLogErrorLevel
|
3986 "Can't load kext %s - no more load tags to assign.",
3987 getIdentifierCString());
3988 result
= kOSKextReturnNoResources
;
3992 /* This is a bit of a hack, because we shouldn't be handling
3993 * personalities within the load function.
3995 if (!declaresExecutable()) {
3996 result
= kOSReturnSuccess
;
4000 /* Are we in safe boot?
4002 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
4004 kOSKextLogErrorLevel
|
4006 "Can't load kext %s - not loadable during safe boot.",
4007 getIdentifierCString());
4008 result
= kOSKextReturnBootLevel
;
4013 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
4015 getIdentifierCString());
4018 if (!sKxldContext
) {
4019 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
4020 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
4021 /* cputype */ 0, /* cpusubtype */ 0);
4024 kOSKextLogErrorLevel
|
4025 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4026 "Can't load kext %s - failed to create link context.",
4027 getIdentifierCString());
4028 result
= kOSKextReturnNoMemory
;
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.
4037 if (!resolveDependencies()) {
4038 // xxx - check resolveDependencies() for log msg
4040 kOSKextLogErrorLevel
|
4041 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4042 "Can't load kext %s - failed to resolve library dependencies.",
4043 getIdentifierCString());
4044 result
= kOSKextReturnDependencies
;
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.
4052 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
4053 dependenciesStartOpt
= kOSKextExcludeNone
;
4056 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
4057 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
4060 /* Load the dependencies, recursively.
4062 count
= getNumDependencies();
4063 for (i
= 0; i
< count
; i
++) {
4064 OSKext
* dependency
= OSDynamicCast(OSKext
,
4065 dependencies
->getObject(i
));
4066 if (dependency
== NULL
) {
4068 kOSKextLogErrorLevel
|
4069 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4070 "Internal error loading kext %s; dependency disappeared.",
4071 getIdentifierCString());
4072 result
= kOSKextReturnInternalError
;
4076 /* Dependencies must be started accorting to the opt,
4077 * but not given the personality names of the main kext.
4079 result
= dependency
->load(dependenciesStartOpt
,
4080 dependenciesStartMatchingOpt
,
4081 /* personalityNames */ NULL
);
4082 if (result
!= KERN_SUCCESS
) {
4084 kOSKextLogErrorLevel
|
4085 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4086 "Dependency %s of kext %s failed to load.",
4087 dependency
->getIdentifierCString(),
4088 getIdentifierCString());
4090 OSKext::removeKext(dependency
,
4091 /* terminateService/removePersonalities */ true);
4092 result
= kOSKextReturnDependencyLoadError
;
4098 result
= loadExecutable();
4099 if (result
!= KERN_SUCCESS
) {
4103 flags
.loaded
= true;
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).
4109 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
4110 sLoadedKexts
->setObject(this);
4112 /* Keep the kernel itself out of the kmod list.
4114 if (lastLoadedKext
== sKernelKext
) {
4115 lastLoadedKext
= NULL
;
4118 if (lastLoadedKext
) {
4119 kmod_info
->next
= lastLoadedKext
->kmod_info
;
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.
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.)
4133 /* Save the list of loaded kexts in case we panic.
4135 clock_get_uptime(&last_loaded_timestamp
);
4136 OSKext::saveLoadedKextPanicList();
4139 /* This is a bit of a hack, because we shouldn't be handling
4140 * personalities within the load function.
4142 if (declaresExecutable() && (startOpt
== kOSKextExcludeNone
)) {
4144 if (result
!= kOSReturnSuccess
) {
4146 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
4147 "Kext %s start failed (result 0x%x).",
4148 getIdentifierCString(), result
);
4149 result
= kOSKextReturnStartStopError
;
4153 /* If not excluding matching, send the personalities to the kernel.
4154 * This never affects the result of the load operation.
4156 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
4157 sendPersonalitiesToCatalog(true, personalityNames
);
4161 if (result
!= kOSReturnSuccess
) {
4163 kOSKextLogErrorLevel
|
4165 "Kext %s failed to load (0x%x).",
4166 getIdentifierCString(), (int)result
);
4167 } else if (!alreadyLoaded
) {
4169 kOSKextLogProgressLevel
|
4172 getIdentifierCString());
4177 /*********************************************************************
4178 * called only by load()
4179 *********************************************************************/
4181 OSKext::loadExecutable()
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
4200 /* We need the version string for a variety of bits below.
4202 versString
= OSDynamicCast(OSString
,
4203 getPropertyForHostArch(kCFBundleVersionKey
));
4207 versCString
= versString
->getCStringNoCopy();
4209 if (isKernelComponent()) {
4210 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
4211 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
4213 kOSKextLogErrorLevel
|
4215 "Kernel component %s has incorrect version %s; "
4217 getIdentifierCString(),
4218 versCString
, KERNEL6_VERSION
);
4219 result
= kOSKextReturnInternalError
;
4221 } else if (strcmp(versCString
, osrelease
)) {
4223 kOSKextLogErrorLevel
|
4225 "Kernel component %s has incorrect version %s; "
4227 getIdentifierCString(),
4228 versCString
, osrelease
);
4229 result
= kOSKextReturnInternalError
;
4235 if (isPrelinked()) {
4239 theExecutable
= getExecutable();
4240 if (!theExecutable
) {
4241 if (declaresExecutable()) {
4243 kOSKextLogErrorLevel
|
4245 "Can't load kext %s - executable is missing.",
4246 getIdentifierCString());
4247 result
= kOSKextReturnValidation
;
4253 if (isKernelComponent()) {
4254 num_kxlddeps
= 1; // the kernel itself
4256 num_kxlddeps
= getNumDependencies();
4258 if (!num_kxlddeps
) {
4260 kOSKextLogErrorLevel
|
4261 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4262 "Can't load kext %s - it has no library dependencies.",
4263 getIdentifierCString());
4266 kxlddeps
= (u_char
**)kalloc(num_kxlddeps
* sizeof(*kxlddeps
));
4269 kOSKextLogErrorLevel
|
4270 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4271 "Can't allocate link context to load kext %s.",
4272 getIdentifierCString());
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
4284 kOSKextLogErrorLevel
|
4285 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4286 "Can't load kext %s - link state missing.",
4287 getIdentifierCString());
4290 kxlddeps
[i
] = (u_char
*)dependency
->linkState
->getBytesNoCopy();
4291 assert(kxlddeps
[i
]);
4294 /* We only need link state for a library kext.
4296 if (compatibleVersion
> -1 && (declaresExecutable() || isKernelComponent())) {
4297 linkStateBytesPtr
= &linkStateBytes
;
4298 linkStateLengthPtr
= &linkStateLength
;
4301 /* We only need the linked executable for a real kext.
4303 if (!isInterface()) {
4304 kxldHeaderPtr
= &kxld_header
;
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"
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
);
4325 /* After this call, the linkedExecutable instance variable
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
);
4336 if (kxldResult
!= KERN_SUCCESS
) {
4337 // xxx - add kxldResult here?
4339 kOSKextLogErrorLevel
|
4341 "Can't load kext %s - link failed.",
4342 getIdentifierCString());
4343 result
= kOSKextReturnLinkError
;
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.
4350 if (linkStateBytes
&& linkStateLength
> 0) {
4351 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
4353 linkState
->setDeallocFunction(&osdata_kmem_free
);
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.
4359 if (!isInterface()) {
4360 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
4361 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
4366 if (isInterface()) {
4368 /* Whip up a fake kmod_info entry for the interface kext.
4370 kmod_info
= (kmod_info_t
*)kalloc(sizeof(kmod_info_t
));
4372 result
= KERN_MEMORY_ERROR
;
4376 /* A pseudokext has almost nothing in its kmod_info struct.
4378 bzero(kmod_info
, sizeof(kmod_info_t
));
4380 kmod_info
->info_version
= KMOD_INFO_VERSION
;
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.
4386 interfaceUUID
= copyUUID();
4389 kmod_info
->id
= loadTag
= sNextLoadTag
++;
4390 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
4392 /* Stamp the bundle ID and version from the OSKext over anything
4393 * resident inside the kmod_info.
4395 string
= getIdentifierCString();
4396 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
4398 string
= versCString
;
4399 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
4401 /* Add the dependencies' kmod_info structs as kmod_references.
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
;
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
++;
4419 if (refIndex
+ 1 < num_kmod_refs
) {
4420 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
4425 if (!isInterface() && linkedExecutable
) {
4427 kOSKextLogProgressLevel
|
4429 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4431 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
4432 (unsigned long)kmod_info
->address
,
4433 (unsigned)kmod_info
->id
);
4436 result
= setVMProtections();
4437 if (result
!= KERN_SUCCESS
) {
4441 result
= kOSReturnSuccess
;
4444 if (kxlddeps
) kfree(kxlddeps
, (num_kxlddeps
* sizeof(void *)));
4446 /* We no longer need the unrelocated executable (which the linker
4447 * has altered anyhow).
4449 setExecutable(NULL
);
4451 if (result
!= kOSReturnSuccess
) {
4453 kOSKextLogErrorLevel
|
4455 "Failed to load executable for kext %s.",
4456 getIdentifierCString());
4458 if (kmod_info
&& kmod_info
->reference_list
) {
4459 kfree(kmod_info
->reference_list
,
4460 num_kmod_refs
* sizeof(kmod_reference_t
));
4462 if (isInterface()) {
4463 kfree(kmod_info
, sizeof(kmod_info_t
));
4466 if (linkedExecutable
) {
4467 linkedExecutable
->release();
4468 linkedExecutable
= NULL
;
4475 /*********************************************************************
4476 * xxx - initWithPrelinkedInfoDict doesn't use this
4477 *********************************************************************/
4479 OSKext::setLinkedExecutable(OSData
* anExecutable
)
4481 if (linkedExecutable
) {
4482 panic("Attempt to set linked executable on kext "
4483 "that already has one (%s).\n",
4484 getIdentifierCString());
4486 linkedExecutable
= anExecutable
;
4487 linkedExecutable
->retain();
4491 /*********************************************************************
4492 * called only by loadExecutable()
4493 *********************************************************************/
4495 OSKext::setVMProtections(void)
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
;
4503 if (!kmod_info
->address
&& !kmod_info
->size
) {
4504 result
= kOSReturnSuccess
;
4508 /* Get the kext's vm map */
4509 kext_map
= kext_get_vm_map(kmod_info
);
4511 result
= KERN_MEMORY_ERROR
;
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
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
) {
4528 /* Set the VM protections and wire down each of the segments */
4529 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
4531 start
= round_page(seg
->vmaddr
);
4532 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
4534 result
= vm_map_protect(kext_map
, start
, end
, seg
->maxprot
, TRUE
);
4535 if (result
!= KERN_SUCCESS
) {
4537 kOSKextLogErrorLevel
|
4539 "Kext %s failed to set maximum VM protections "
4540 "for segment %s - 0x%x.",
4541 getIdentifierCString(), seg
->segname
, (int)result
);
4545 result
= vm_map_protect(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4546 if (result
!= KERN_SUCCESS
) {
4548 kOSKextLogErrorLevel
|
4550 "Kext %s failed to set initial VM protections "
4551 "for segment %s - 0x%x.",
4552 getIdentifierCString(), seg
->segname
, (int)result
);
4556 result
= vm_map_wire(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4557 if (result
!= KERN_SUCCESS
) {
4561 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
4568 /*********************************************************************
4569 *********************************************************************/
4571 OSKext::validateKextMapping(bool startFlag
)
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;
4580 mach_msg_type_number_t count
;
4581 vm_region_submap_short_info_data_64_t info
;
4583 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
4584 bzero(&info
, sizeof(info
));
4586 // xxx - do we need a distinct OSReturn value for these or is "bad data"
4587 // xxx - sufficient?
4589 /* Verify that the kmod_info and start/stop pointers are non-NULL.
4593 kOSKextLogErrorLevel
|
4595 "Kext %s - NULL kmod_info pointer.",
4596 getIdentifierCString());
4597 result
= kOSKextReturnBadData
;
4602 address
= (mach_vm_address_t
)kmod_info
->start
;
4604 address
= (mach_vm_address_t
)kmod_info
->stop
;
4609 kOSKextLogErrorLevel
|
4611 "Kext %s - NULL module %s pointer.",
4612 getIdentifierCString(), whichOp
);
4613 result
= kOSKextReturnBadData
;
4617 kext_map
= kext_get_vm_map(kmod_info
);
4618 depth
= (kernel_map
== kext_map
) ? 1 : 2;
4620 /* Verify that the start/stop function lies within the kext's address range.
4622 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
4623 kmod_info
->address
+ kmod_info
->size
<= address
)
4626 kOSKextLogErrorLevel
|
4628 "Kext %s module %s pointer is outside of kext range "
4629 "(%s %p - kext at %p-%p)..",
4630 getIdentifierCString(),
4634 (void *)kmod_info
->address
,
4635 (void *)(kmod_info
->address
+ kmod_info
->size
));
4636 result
= kOSKextReturnBadData
;
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.
4646 /* Verify that the start/stop function is executable.
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
) {
4652 kOSKextLogErrorLevel
|
4654 "Kext %s - bad %s pointer %p.",
4655 getIdentifierCString(),
4656 whichOp
, (void *)address
);
4657 result
= kOSKextReturnBadData
;
4661 if (!(info
.protection
& VM_PROT_EXECUTE
)) {
4663 kOSKextLogErrorLevel
|
4665 "Kext %s - memory region containing module %s function "
4666 "is not executable.",
4667 getIdentifierCString(), whichOp
);
4668 result
= kOSKextReturnBadData
;
4672 /* Verify that the kext is backed by physical memory.
4674 for (address
= kmod_info
->address
;
4675 address
< round_page(kmod_info
->address
+ kmod_info
->size
);
4676 address
+= PAGE_SIZE
)
4678 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
4680 kOSKextLogErrorLevel
|
4682 "Kext %s - page %p is not backed by physical memory.",
4683 getIdentifierCString(),
4685 result
= kOSKextReturnBadData
;
4691 result
= kOSReturnSuccess
;
4696 /*********************************************************************
4697 *********************************************************************/
4699 OSKext::start(bool startDependenciesFlag
)
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 */
4709 if (isStarted() || isInterface() || isKernelComponent()) {
4710 result
= kOSReturnSuccess
;
4716 kOSKextLogErrorLevel
|
4718 "Attempt to start nonloaded kext %s.",
4719 getIdentifierCString());
4720 result
= kOSKextReturnInvalidArgument
;
4724 result
= validateKextMapping(/* start? */ true);
4725 if (result
!= kOSReturnSuccess
) {
4729 startfunc
= kmod_info
->start
;
4731 count
= getNumDependencies();
4732 for (i
= 0; i
< count
; i
++) {
4733 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
4734 if (dependency
== NULL
) {
4736 kOSKextLogErrorLevel
|
4738 "Kext %s start - internal error, dependency disappeared.",
4739 getIdentifierCString());
4742 if (!dependency
->isStarted()) {
4743 if (startDependenciesFlag
) {
4744 OSReturn dependencyResult
=
4745 dependency
->start(startDependenciesFlag
);
4746 if (dependencyResult
!= KERN_SUCCESS
) {
4748 kOSKextLogErrorLevel
|
4750 "Kext %s start - dependency %s failed to start (error 0x%x).",
4751 getIdentifierCString(),
4752 dependency
->getIdentifierCString(),
4758 kOSKextLogErrorLevel
|
4760 "Not starting %s - dependency %s not started yet.",
4761 getIdentifierCString(),
4762 dependency
->getIdentifierCString());
4763 result
= kOSKextReturnStartStopError
; // xxx - make new return?
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.
4774 kmodStartData
= MACFCopyModuleDataForKext(this, &kmodStartDataCount
);
4775 #endif /* CONFIG_MACF_KEXT */
4778 kOSKextLogDetailLevel
|
4780 "Kext %s calling module start function.",
4781 getIdentifierCString());
4785 #if !__i386__ && !__ppc__
4786 result
= OSRuntimeInitializeCPP(kmod_info
, NULL
);
4787 if (result
== KERN_SUCCESS
) {
4790 result
= startfunc(kmod_info
, kmodStartData
);
4792 #if !__i386__ && !__ppc__
4793 if (result
!= KERN_SUCCESS
) {
4794 (void) OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4801 /* On success overlap the setting of started/starting. On failure just
4804 if (result
== KERN_SUCCESS
) {
4807 // xxx - log start error from kernel?
4809 kOSKextLogProgressLevel
|
4811 "Kext %s is now started.",
4812 getIdentifierCString());
4814 invokeOrCancelRequestCallbacks(
4815 /* result not actually used */ kOSKextReturnStartStopError
,
4816 /* invokeFlag */ false);
4818 kOSKextLogProgressLevel
|
4820 "Kext %s did not start (return code 0x%x).",
4821 getIdentifierCString(), result
);
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.
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.
4832 if (kmodStartData
) {
4833 kmem_free(kernel_map
, (vm_offset_t
)kmodStartData
, kmodStartDataCount
);
4835 #endif /* CONFIG_MACF_KEXT */
4840 /*********************************************************************
4841 *********************************************************************/
4843 bool OSKext::canUnloadKextWithIdentifier(
4844 OSString
* kextIdentifier
,
4845 bool checkClassesFlag
)
4847 bool result
= false;
4848 OSKext
* aKext
= NULL
; // do not release
4850 IORecursiveLockLock(sKextLock
);
4852 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4855 goto finish
; // can't unload what's not loaded
4858 if (aKext
->isLoaded()) {
4859 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
4862 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
4870 IORecursiveLockUnlock(sKextLock
);
4874 /*********************************************************************
4875 *********************************************************************/
4879 OSReturn result
= kOSReturnError
;
4880 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
4882 if (!isStarted() || isInterface()) {
4883 result
= kOSReturnSuccess
;
4889 kOSKextLogErrorLevel
|
4891 "Attempt to stop nonloaded kext %s.",
4892 getIdentifierCString());
4893 result
= kOSKextReturnInvalidArgument
;
4897 /* Refuse to stop if we have clients or instances. It is up to
4898 * the caller to make sure those aren't true.
4900 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4902 kOSKextLogErrorLevel
|
4904 "Kext %s - C++ instances; can't stop.",
4905 getIdentifierCString());
4906 result
= kOSKextReturnInUse
;
4910 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4913 kOSKextLogErrorLevel
|
4915 "Kext %s - has references (linkage or tracking object); "
4917 getIdentifierCString());
4918 result
= kOSKextReturnInUse
;
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.
4926 result
= validateKextMapping(/* start? */ false);
4927 if (result
!= kOSReturnSuccess
) {
4931 /* Save the list of loaded kexts in case we panic.
4933 OSKext::saveUnloadedKextPanicList(this);
4935 stopfunc
= kmod_info
->stop
;
4938 kOSKextLogDetailLevel
|
4940 "Kext %s calling module stop function.",
4941 getIdentifierCString());
4945 result
= stopfunc(kmod_info
, /* userData */ NULL
);
4946 #if !__i386__ && !__ppc__
4947 if (result
== KERN_SUCCESS
) {
4948 result
= OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4954 if (result
== KERN_SUCCESS
) {
4958 kOSKextLogDetailLevel
|
4960 "Kext %s is now stopped and ready to unload.",
4961 getIdentifierCString());
4964 kOSKextLogErrorLevel
|
4966 "Kext %s did not stop (return code 0x%x).",
4967 getIdentifierCString(), result
);
4968 result
= kOSKextReturnStartStopError
;
4976 /*********************************************************************
4977 *********************************************************************/
4979 OSKext::unload(void)
4981 OSReturn result
= kOSReturnError
;
4983 uint32_t num_kmod_refs
= 0;
4985 if (!sUnloadEnabled
) {
4987 kOSKextLogErrorLevel
|
4989 "Kext unloading is disabled (%s).",
4990 this->getIdentifierCString());
4992 result
= kOSKextReturnDisabled
;
4996 /* Refuse to unload if we have clients or instances. It is up to
4997 * the caller to make sure those aren't true.
4999 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5000 // xxx - Don't log under errors? this is more of an info thing
5002 kOSKextLogErrorLevel
|
5003 kOSKextLogKextBookkeepingFlag
,
5004 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5005 getIdentifierCString());
5006 result
= kOSKextReturnInUse
;
5011 if (hasOSMetaClassInstances()) {
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
;
5024 result
= kOSReturnSuccess
;
5028 if (isKernelComponent()) {
5029 result
= kOSKextReturnInvalidArgument
;
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
5038 flags
.unloading
= 1;
5042 if (result
!= KERN_SUCCESS
) {
5044 kOSKextLogErrorLevel
|
5046 "Kext %s can't unload - module stop returned 0x%x.",
5047 getIdentifierCString(), (unsigned)result
);
5048 result
= kOSKextReturnStartStopError
;
5054 kOSKextLogProgressLevel
|
5056 "Kext %s unloading.",
5057 getIdentifierCString());
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.
5065 metaClasses
->flushCollection();
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).
5072 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
5073 if (index
!= (unsigned int)-1) {
5075 sLoadedKexts
->removeObject(index
);
5077 OSKext
* nextKext
= OSDynamicCast(OSKext
,
5078 sLoadedKexts
->getObject(index
));
5082 OSKext
* gapKext
= OSDynamicCast(OSKext
,
5083 sLoadedKexts
->getObject(index
- 1));
5085 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
5087 } else /* index == 0 */ {
5088 nextKext
->kmod_info
->next
= NULL
;
5092 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5093 if (lastKext
&& lastKext
!= sKernelKext
) {
5094 kmod
= lastKext
->kmod_info
;
5096 kmod
= NULL
; // clear the global kmod variable
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.
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
--;
5110 kfree(kmod_info
->reference_list
,
5111 num_kmod_refs
* sizeof(kmod_reference_t
));
5114 /* If we have a linked executable, release & clear it, and then
5115 * unwire & deallocate the buffer the OSData wrapped.
5117 if (linkedExecutable
) {
5120 /* linkedExecutable is just a wrapper for the executable and doesn't
5123 linkedExecutable
->release();
5124 linkedExecutable
= NULL
;
5127 kOSKextLogProgressLevel
|
5129 "Kext %s unwiring and unmapping linked executable.",
5130 getIdentifierCString());
5132 kext_map
= kext_get_vm_map(kmod_info
);
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
);
5145 /* An interface kext has a fake kmod_info that was allocated,
5146 * so we have to free it.
5148 if (isInterface()) {
5149 kfree(kmod_info
, sizeof(kmod_info_t
));
5154 flags
.loaded
= false;
5155 flushDependencies();
5158 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5159 "Kext %s unloaded.", getIdentifierCString());
5162 OSKext::saveLoadedKextPanicList();
5164 flags
.unloading
= 0;
5168 /*********************************************************************
5169 *********************************************************************/
5171 _OSKextConsiderDestroyingLinkContext(
5172 __unused thread_call_param_t p0
,
5173 __unused thread_call_param_t p1
)
5175 /* Once both recursive locks are taken in correct order, we shouldn't
5176 * have to worry about further recursive lock takes.
5178 IORecursiveLockLock(sKextLock
);
5179 IORecursiveLockLock(sKextInnerLock
);
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.
5186 if (sConsiderUnloadsCalled
&& sKxldContext
) {
5187 kxld_destroy_context(sKxldContext
);
5188 sKxldContext
= NULL
;
5191 /* Free the thread_call that was allocated to execute this function.
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.");
5200 sDestroyLinkContextThread
= 0;
5203 IORecursiveLockUnlock(sKextInnerLock
);
5204 IORecursiveLockUnlock(sKextLock
);
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.
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 *********************************************************************/
5221 OSKext::considerDestroyingLinkContext(void)
5223 IORecursiveLockLock(sKextInnerLock
);
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.
5228 if (sDestroyLinkContextThread
) {
5232 /* The function to be invoked in the thread will deallocate
5233 * this thread_call, so don't share it around.
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.");
5244 thread_call_enter(sDestroyLinkContextThread
);
5247 IORecursiveLockUnlock(sKextInnerLock
);
5251 /*********************************************************************
5252 *********************************************************************/
5254 OSKext::getKernelLinkState()
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
;
5263 if (sKernelKext
&& sKernelKext
->linkState
) {
5267 kernel
= (u_char
*)&_mh_execute_header
;
5268 kernelLength
= getlastaddr() - (vm_offset_t
)kernel
;
5270 kxldResult
= kxld_link_file(sKxldContext
,
5273 kOSKextKernelIdentifier
,
5274 /* callbackData */ NULL
,
5275 /* dependencies */ NULL
,
5276 /* numDependencies */ 0,
5277 /* linkedObjectOut */ NULL
,
5278 /* kmod_info_kern out */ NULL
,
5281 /* symbolFile */ NULL
,
5282 /* symbolFileSize */ NULL
);
5284 panic("Can't generate kernel link state; no kexts can be loaded.");
5288 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
5289 linkState
->setDeallocFunction(&osdata_kmem_free
);
5290 sKernelKext
->linkState
= linkState
;
5293 return sKernelKext
->linkState
;
5297 #pragma mark Autounload
5299 /*********************************************************************
5300 * This is a static method because the kext will be deallocated if it
5302 *********************************************************************/
5304 OSKext::autounloadKext(OSKext
* aKext
)
5306 OSReturn result
= kOSKextReturnInUse
;
5308 /* Check for external references to this kext (usu. dependents),
5309 * instances of defined classes (or classes derived from them),
5310 * outstanding requests.
5312 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
5313 !aKext
->flags
.autounloadEnabled
||
5314 aKext
->isKernelComponent()) {
5319 /* Skip a delay-autounload kext, once.
5321 if (aKext
->flags
.delayAutounload
) {
5323 kOSKextLogProgressLevel
|
5324 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5325 "Kext %s has delayed autounload set; skipping and clearing flag.",
5326 aKext
->getIdentifierCString());
5327 aKext
->flags
.delayAutounload
= 0;
5331 if (aKext
->hasOSMetaClassInstances() ||
5332 aKext
->countRequestCallbacks()) {
5336 result
= OSKext::removeKext(aKext
);
5343 /*********************************************************************
5344 *********************************************************************/
5346 _OSKextConsiderUnloads(
5347 __unused thread_call_param_t p0
,
5348 __unused thread_call_param_t p1
)
5350 bool didUnload
= false;
5351 unsigned int count
, i
;
5353 /* Once both recursive locks are taken in correct order, we shouldn't
5354 * have to worry about further recursive lock takes.
5356 IORecursiveLockLock(sKextLock
);
5357 IORecursiveLockLock(sKextInnerLock
);
5359 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
5361 /* If the system is powering down, don't try to unload anything.
5367 OSKextLog(/* kext */ NULL
,
5368 kOSKextLogProgressLevel
|
5370 "Checking for unused kexts to autounload.");
5373 * Remove any request callbacks marked as stale,
5374 * and mark as stale any currently in flight.
5376 count
= sRequestCallbackRecords
->getCount();
5380 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
5381 sRequestCallbackRecords
->getObject(i
));
5382 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
5383 callbackRecord
->getObject(kKextRequestStaleKey
));
5385 if (stale
&& stale
->isTrue()) {
5386 OSKext::invokeRequestCallback(callbackRecord
,
5387 kOSKextReturnTimeout
);
5389 callbackRecord
->setObject(kKextRequestStaleKey
,
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....
5407 count
= sLoadedKexts
->getCount();
5411 OSKext
* thisKext
= OSDynamicCast(OSKext
,
5412 sLoadedKexts
->getObject(i
));
5413 didUnload
= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
5416 } while (didUnload
);
5419 sConsiderUnloadsPending
= false;
5420 sConsiderUnloadsExecuted
= true;
5422 (void) OSKext::considerRebuildOfPrelinkedKernel();
5424 IORecursiveLockUnlock(sKextInnerLock
);
5425 IORecursiveLockUnlock(sKextLock
);
5430 /*********************************************************************
5431 * Do not call any function that takes sKextLock here!
5432 *********************************************************************/
5433 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
5437 IORecursiveLockLock(sKextInnerLock
);
5439 if (!sUnloadCallout
) {
5440 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, 0);
5443 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
5447 thread_call_cancel(sUnloadCallout
);
5448 if (OSKext::getAutounloadEnabled() && !sSystemSleep
) {
5449 clock_interval_to_deadline(sConsiderUnloadDelay
,
5450 1000 * 1000 * 1000, &when
);
5452 OSKextLog(/* kext */ NULL
,
5453 kOSKextLogProgressLevel
|
5455 "%scheduling %sscan for unused kexts in %lu seconds.",
5456 sConsiderUnloadsPending
? "Res" : "S",
5457 sConsiderUnloadsCalled
? "" : "initial ",
5458 (unsigned long)sConsiderUnloadDelay
);
5460 sConsiderUnloadsPending
= true;
5461 thread_call_enter_delayed(sUnloadCallout
, when
);
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.
5470 if (!sConsiderUnloadsCalled
) {
5471 sConsiderUnloadsCalled
= true;
5472 OSKext::considerDestroyingLinkContext();
5475 IORecursiveLockUnlock(sKextInnerLock
);
5479 /*********************************************************************
5480 * Do not call any function that takes sKextLock here!
5481 *********************************************************************/
5484 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
)
5486 IORecursiveLockLock(sKextInnerLock
);
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.
5494 if (messageType
== kIOMessageSystemWillSleep
) {
5495 if (sUnloadCallout
) {
5496 thread_call_cancel(sUnloadCallout
);
5498 sSystemSleep
= true;
5499 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
5500 sSystemSleep
= false;
5502 IORecursiveLockUnlock(sKextInnerLock
);
5504 return kIOReturnSuccess
;
5511 #pragma mark Prelinked Kernel
5513 /*********************************************************************
5514 * Do not access sConsiderUnloads... variables other than
5515 * sConsiderUnloadsExecuted in this function. They are guarded by a
5517 *********************************************************************/
5520 OSKext::considerRebuildOfPrelinkedKernel(void)
5522 OSReturn checkResult
= kOSReturnError
;
5523 static bool requestedPrelink
= false;
5524 OSDictionary
* prelinkRequest
= NULL
; // must release
5526 IORecursiveLockLock(sKextLock
);
5528 if (!sDeferredLoadSucceeded
|| !sConsiderUnloadsExecuted
||
5529 sSafeBoot
|| requestedPrelink
)
5534 OSKextLog(/* kext */ NULL
,
5535 kOSKextLogProgressLevel
|
5536 kOSKextLogArchiveFlag
,
5537 "Requesting build of prelinked kernel.");
5539 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
5541 if (checkResult
!= kOSReturnSuccess
) {
5545 if (!sKernelRequests
->setObject(prelinkRequest
)) {
5550 requestedPrelink
= true;
5553 IORecursiveLockUnlock(sKextLock
);
5554 OSSafeRelease(prelinkRequest
);
5559 #pragma mark Dependencies
5561 /*********************************************************************
5562 *********************************************************************/
5564 OSKext::resolveDependencies(
5565 OSArray
* loopStack
)
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;
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).
5586 if (flags
.hasAllDependencies
) {
5591 /* Check for loops in the dependency graph.
5594 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
5596 kOSKextLogErrorLevel
|
5597 kOSKextLogDependenciesFlag
,
5598 "Kext %s has a dependency loop; can't resolve dependencies.",
5599 getIdentifierCString());
5604 kOSKextLogStepLevel
|
5605 kOSKextLogDependenciesFlag
,
5606 "Kext %s resolving dependencies.",
5607 getIdentifierCString());
5609 loopStack
= OSArray::withCapacity(6); // any small capacity will do
5612 kOSKextLogErrorLevel
|
5613 kOSKextLogDependenciesFlag
,
5614 "Kext %s can't create bookkeeping stack to resolve dependencies.",
5615 getIdentifierCString());
5618 localLoopStack
= loopStack
;
5620 if (!loopStack
->setObject(this)) {
5622 kOSKextLogErrorLevel
|
5623 kOSKextLogDependenciesFlag
,
5624 "Kext %s - internal error resolving dependencies.",
5625 getIdentifierCString());
5628 addedToLoopStack
= true;
5630 /* Purge any existing kexts in the dependency list and start over.
5632 flushDependencies();
5635 kOSKextLogErrorLevel
|
5636 kOSKextLogDependenciesFlag
,
5637 "Kext %s - internal error resolving dependencies.",
5638 getIdentifierCString());
5641 libraries
= OSDynamicCast(OSDictionary
,
5642 getPropertyForHostArch(kOSBundleLibrariesKey
));
5643 if (libraries
== NULL
|| libraries
->getCount() == 0) {
5645 kOSKextLogErrorLevel
|
5646 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5647 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
5648 getIdentifierCString(), kOSBundleLibrariesKey
);
5652 /* Make a new array to hold the dependencies (flush freed the old one).
5654 dependencies
= OSArray::withCapacity(libraries
->getCount());
5655 if (!dependencies
) {
5657 kOSKextLogErrorLevel
|
5658 kOSKextLogDependenciesFlag
,
5659 "Kext %s - can't allocate dependencies array.",
5660 getIdentifierCString());
5664 // xxx - compat: We used to add an implicit dependency on kernel 6.0
5665 // xxx - compat: if none were declared.
5667 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
5668 if (!libraryIterator
) {
5670 kOSKextLogErrorLevel
|
5671 kOSKextLogDependenciesFlag
,
5672 "Kext %s - can't allocate dependencies iterator.",
5673 getIdentifierCString());
5677 while ((libraryID
= OSDynamicCast(OSString
,
5678 libraryIterator
->getNextObject()))) {
5680 const char * library_id
= libraryID
->getCStringNoCopy();
5682 OSString
* libraryVersion
= OSDynamicCast(OSString
,
5683 libraries
->getObject(libraryID
));
5684 if (libraryVersion
== NULL
) {
5686 kOSKextLogErrorLevel
|
5687 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5688 "Kext %s - illegal type in OSBundleLibraries.",
5689 getIdentifierCString());
5693 OSKextVersion libraryVers
=
5694 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
5695 if (libraryVers
== -1) {
5697 kOSKextLogErrorLevel
|
5698 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5699 "Kext %s - invalid library version %s.",
5700 getIdentifierCString(),
5701 libraryVersion
->getCStringNoCopy());
5705 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
5706 if (libraryKext
== NULL
) {
5708 kOSKextLogErrorLevel
|
5709 kOSKextLogDependenciesFlag
,
5710 "Kext %s - library kext %s not found.",
5711 getIdentifierCString(), library_id
);
5715 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
5717 kOSKextLogErrorLevel
|
5718 kOSKextLogDependenciesFlag
,
5719 "Kext %s - library kext %s not compatible "
5720 "with requested version %s.",
5721 getIdentifierCString(), library_id
,
5722 libraryVersion
->getCStringNoCopy());
5726 if (!libraryKext
->resolveDependencies(loopStack
)) {
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.
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()) {
5740 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
5741 dependencies
->setObject(libraryKext
);
5744 kOSKextLogDetailLevel
|
5745 kOSKextLogDependenciesFlag
,
5746 "Kext %s added dependency %s.",
5747 getIdentifierCString(),
5748 libraryKext
->getIdentifierCString());
5751 int numLibDependencies
= libraryKext
->getNumDependencies();
5752 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
5755 if (numLibDependencies
) {
5756 // xxx - this msg level should be 1 lower than the per-kext one
5758 kOSKextLogDetailLevel
|
5759 kOSKextLogDependenciesFlag
,
5760 "Kext %s pulling %d dependencies from codeless library %s.",
5761 getIdentifierCString(),
5763 libraryKext
->getIdentifierCString());
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
);
5771 kOSKextLogDetailLevel
|
5772 kOSKextLogDependenciesFlag
,
5773 "Kext %s added dependency %s from codeless library %s.",
5774 getIdentifierCString(),
5775 thisLibDependency
->getIdentifierCString(),
5776 libraryKext
->getIdentifierCString());
5781 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
5782 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
)-1)) {
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;
5796 if (hasRawKernelDependency
|| hasKernelDependency
) {
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
);
5805 if (!hasKPIDependency
) {
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
);
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.*"?
5818 if (hasRawKernelDependency
&& hasKernelDependency
) {
5820 kOSKextLogErrorLevel
|
5821 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5822 "Error - kext %s declares dependencies on both "
5824 getIdentifierCString(), KERNEL_LIB
, KERNEL6_LIB
);
5828 if ((hasRawKernelDependency
|| hasKernelDependency
) && hasKPIDependency
) {
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
);
5837 if (!hasRawKernelDependency
&& !hasKernelDependency
&& !hasKPIDependency
) {
5838 // xxx - do we want to use validation flag for these too?
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
));
5847 dependencies
->setObject(kernelKext
);
5850 kOSKextLogErrorLevel
|
5851 kOSKextLogDependenciesFlag
,
5852 "Error - Library %s not found for %s.",
5853 KERNEL6_LIB
, getIdentifierCString());
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.
5861 if (!hasRawKernelDependency
&& !hasKPIDependency
) {
5864 count
= getNumDependencies();
5866 /* We add to the dependencies array in this loop, but do not iterate
5867 * past its original count.
5869 for (i
= 0; i
< count
; i
++) {
5870 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
5871 dependencies
->getObject(i
));
5872 dependencyKext
->addBleedthroughDependencies(dependencies
);
5875 #endif /* __LP64__ */
5877 if (hasPrivateKPIDependency
) {
5878 bool hasApplePrefix
= false;
5879 bool infoCopyrightIsValid
= false;
5880 bool readableCopyrightIsValid
= false;
5882 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
5885 infoString
= OSDynamicCast(OSString
,
5886 getPropertyForHostArch("CFBundleGetInfoString"));
5888 infoCopyrightIsValid
=
5889 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
5892 readableString
= OSDynamicCast(OSString
,
5893 getPropertyForHostArch("NSHumanReadableCopyright"));
5894 if (readableString
) {
5895 readableCopyrightIsValid
=
5896 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
5899 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
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
);
5911 flags
.hasAllDependencies
= 1;
5915 if (addedToLoopStack
) {
5916 count
= loopStack
->getCount();
5917 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
5918 loopStack
->removeObject(count
- 1);
5921 kOSKextLogErrorLevel
|
5922 kOSKextLogDependenciesFlag
,
5923 "Kext %s - internal error resolving dependencies.",
5924 getIdentifierCString());
5928 if (result
&& localLoopStack
) {
5930 kOSKextLogStepLevel
|
5931 kOSKextLogDependenciesFlag
,
5932 "Kext %s successfully resolved dependencies.",
5933 getIdentifierCString());
5936 OSSafeRelease(localLoopStack
);
5937 OSSafeRelease(libraryIterator
);
5942 /*********************************************************************
5943 *********************************************************************/
5945 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
5947 bool result
= false;
5948 unsigned int dependencyIndex
, dependencyCount
;
5950 dependencyCount
= getNumDependencies();
5952 for (dependencyIndex
= 0;
5953 dependencyIndex
< dependencyCount
;
5954 dependencyIndex
++) {
5956 OSKext
* dependency
= OSDynamicCast(OSKext
,
5957 dependencies
->getObject(dependencyIndex
));
5960 kOSKextLogErrorLevel
|
5961 kOSKextLogDependenciesFlag
,
5962 "Kext %s - internal error propagating compatibility dependencies.",
5963 getIdentifierCString());
5966 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
5967 anArray
->setObject(dependency
);
5969 dependency
->addBleedthroughDependencies(anArray
);
5978 /*********************************************************************
5979 *********************************************************************/
5981 OSKext::flushDependencies(bool forceFlag
)
5983 bool result
= false;
5985 /* Only clear the dependencies if the kext isn't loaded;
5986 * we need the info for loaded kexts to track references.
5988 if (!isLoaded() || forceFlag
) {
5990 // xxx - check level
5992 kOSKextLogProgressLevel
|
5993 kOSKextLogDependenciesFlag
,
5994 "Kext %s flushing dependencies.",
5995 getIdentifierCString());
5996 OSSafeReleaseNULL(dependencies
);
5999 if (!isKernelComponent()) {
6000 flags
.hasAllDependencies
= 0;
6008 /*********************************************************************
6009 *********************************************************************/
6011 OSKext::getNumDependencies(void)
6013 if (!dependencies
) {
6016 return dependencies
->getCount();
6019 /*********************************************************************
6020 *********************************************************************/
6022 OSKext::getDependencies(void)
6024 return dependencies
;
6028 #pragma mark OSMetaClass Support
6030 /*********************************************************************
6031 *********************************************************************/
6034 OSMetaClass
* aClass
,
6035 uint32_t numClasses
)
6037 OSReturn result
= kOSMetaClassNoInsKModSet
;
6040 metaClasses
= OSSet::withCapacity(numClasses
);
6046 if (metaClasses
->containsObject(aClass
)) {
6048 kOSKextLogWarningLevel
|
6050 "Notice - kext %s has already registered class %s.",
6051 getIdentifierCString(),
6052 aClass
->getClassName());
6053 result
= kOSReturnSuccess
;
6057 if (!metaClasses
->setObject(aClass
)) {
6061 kOSKextLogDetailLevel
|
6063 "Kext %s registered class %s.",
6064 getIdentifierCString(),
6065 aClass
->getClassName());
6068 if (!flags
.autounloadEnabled
) {
6069 const OSMetaClass
* metaScan
= NULL
; // do not release
6071 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
6072 if (metaScan
== OSTypeID(IOService
)) {
6075 kOSKextLogProgressLevel
|
6077 "Kext %s has IOService subclass %s; enabling autounload.",
6078 getIdentifierCString(),
6079 aClass
->getClassName());
6081 flags
.autounloadEnabled
= 1;
6087 result
= kOSReturnSuccess
;
6090 if (result
!= kOSReturnSuccess
) {
6092 kOSKextLogErrorLevel
|
6094 "Kext %s failed to register class %s.",
6095 getIdentifierCString(),
6096 aClass
->getClassName());
6102 /*********************************************************************
6103 *********************************************************************/
6105 OSKext::removeClass(
6106 OSMetaClass
* aClass
)
6108 OSReturn result
= kOSMetaClassNoKModSet
;
6114 if (!metaClasses
->containsObject(aClass
)) {
6116 kOSKextLogWarningLevel
|
6118 "Notice - kext %s asked to unregister unknown class %s.",
6119 getIdentifierCString(),
6120 aClass
->getClassName());
6121 result
= kOSReturnSuccess
;
6126 kOSKextLogDetailLevel
|
6128 "Kext %s unregistering class %s.",
6129 getIdentifierCString(),
6130 aClass
->getClassName());
6132 metaClasses
->removeObject(aClass
);
6134 result
= kOSReturnSuccess
;
6137 if (result
!= kOSReturnSuccess
) {
6139 kOSKextLogErrorLevel
|
6141 "Failed to unregister kext %s class %s.",
6142 getIdentifierCString(),
6143 aClass
->getClassName());
6148 /*********************************************************************
6149 *********************************************************************/
6151 OSKext::getMetaClasses(void)
6156 /*********************************************************************
6157 *********************************************************************/
6159 OSKext::hasOSMetaClassInstances(void)
6161 bool result
= false;
6162 OSCollectionIterator
* classIterator
= NULL
; // must release
6163 OSMetaClass
* checkClass
= NULL
; // do not release
6169 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6170 if (!classIterator
) {
6171 // xxx - log alloc failure?
6174 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6175 if (checkClass
->getInstanceCount()) {
6183 OSSafeRelease(classIterator
);
6187 /*********************************************************************
6188 *********************************************************************/
6191 OSKext::reportOSMetaClassInstances(
6192 const char * kextIdentifier
,
6193 OSKextLogSpec msgLogSpec
)
6195 OSKext
* theKext
= NULL
; // must release
6197 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
6202 theKext
->reportOSMetaClassInstances(msgLogSpec
);
6204 OSSafeRelease(theKext
);
6208 /*********************************************************************
6209 *********************************************************************/
6211 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
6213 OSCollectionIterator
* classIterator
= NULL
; // must release
6214 OSMetaClass
* checkClass
= NULL
; // do not release
6220 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6221 if (!classIterator
) {
6224 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6225 if (checkClass
->getInstanceCount()) {
6228 " Kext %s class %s has %d instance%s.",
6229 getIdentifierCString(),
6230 checkClass
->getClassName(),
6231 checkClass
->getInstanceCount(),
6232 checkClass
->getInstanceCount() == 1 ? "" : "s");
6237 OSSafeRelease(classIterator
);
6242 #pragma mark User-Space Requests
6244 /*********************************************************************
6245 * XXX - this function is a big ugly mess
6246 *********************************************************************/
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
,
6257 uint32_t * logInfoLengthOut
)
6259 OSReturn result
= kOSReturnError
;
6260 kern_return_t kmem_result
= KERN_FAILURE
;
6262 char * response
= NULL
; // returned by reference
6263 uint32_t responseLength
= 0;
6265 OSObject
* parsedXML
= NULL
; // must release
6266 OSDictionary
* requestDict
= NULL
; // do not release
6267 OSString
* errorString
= NULL
; // must release
6269 OSData
* responseData
= NULL
; // must release
6270 OSObject
* responseObject
= NULL
; // must release
6272 OSSerialize
* serializer
= NULL
; // must release
6274 OSArray
* logInfoArray
= NULL
; // must release
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
6282 IORecursiveLockLock(sKextLock
);
6285 *responseOut
= NULL
;
6286 *responseLengthOut
= 0;
6290 *logInfoLengthOut
= 0;
6293 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
6295 /* XML must be nul-terminated.
6297 if (requestBuffer
[requestLength
- 1] != '\0') {
6298 OSKextLog(/* kext */ NULL
,
6299 kOSKextLogErrorLevel
|
6301 "Invalid request from user space (not nul-terminated).");
6302 result
= kOSKextReturnBadData
;
6305 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, &errorString
);
6307 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
);
6310 const char * errorCString
= "(unknown error)";
6312 if (errorString
&& errorString
->getCStringNoCopy()) {
6313 errorCString
= errorString
->getCStringNoCopy();
6314 } else if (parsedXML
) {
6315 errorCString
= "not a dictionary";
6317 OSKextLog(/* kext */ NULL
,
6318 kOSKextLogErrorLevel
|
6320 "Error unserializing request from user space: %s.",
6322 result
= kOSKextReturnSerialization
;
6326 predicate
= _OSKextGetRequestPredicate(requestDict
);
6328 OSKextLog(/* kext */ NULL
,
6329 kOSKextLogErrorLevel
|
6331 "Recieved kext request from user space with no predicate.");
6332 result
= kOSKextReturnInvalidArgument
;
6336 OSKextLog(/* kext */ NULL
,
6337 kOSKextLogDebugLevel
|
6339 "Received '%s' request from user space.",
6340 predicate
->getCStringNoCopy());
6342 result
= kOSKextReturnNotPrivileged
;
6343 if (hostPriv
== HOST_PRIV_NULL
) {
6344 if (!predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) &&
6345 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
) &&
6346 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6352 /* Get common args in anticipation of use.
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
));
6361 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
6362 requestDict
, kKextRequestArgumentValueKey
));
6364 result
= kOSKextReturnInvalidArgument
;
6366 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
6367 if (!kextIdentifier
) {
6368 OSKextLog(/* kext */ NULL
,
6369 kOSKextLogErrorLevel
|
6371 "Invalid arguments to kext start request.");
6372 } else if (!theKext
) {
6373 OSKextLog(/* kext */ NULL
,
6374 kOSKextLogErrorLevel
|
6376 "Kext %s not found for start request.",
6377 kextIdentifier
->getCStringNoCopy());
6378 result
= kOSKextReturnNotFound
;
6380 result
= theKext
->start();
6383 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
6384 if (!kextIdentifier
) {
6385 OSKextLog(/* kext */ NULL
,
6386 kOSKextLogErrorLevel
|
6388 "Invalid arguments to kext stop request.");
6389 } else if (!theKext
) {
6390 OSKextLog(/* kext */ NULL
,
6391 kOSKextLogErrorLevel
|
6393 "Kext %s not found for stop request.",
6394 kextIdentifier
->getCStringNoCopy());
6395 result
= kOSKextReturnNotFound
;
6397 result
= theKext
->stop();
6400 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
6401 if (!kextIdentifier
) {
6402 OSKextLog(/* kext */ NULL
,
6403 kOSKextLogErrorLevel
|
6405 "Invalid arguments to kext unload request.");
6406 } else if (!theKext
) {
6407 OSKextLog(/* kext */ NULL
,
6408 kOSKextLogErrorLevel
|
6410 "Kext %s not found for unload request.",
6411 kextIdentifier
->getCStringNoCopy());
6412 result
= kOSKextReturnNotFound
;
6414 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
6415 _OSKextGetRequestArgument(requestDict
,
6416 kKextRequestArgumentTerminateIOServicesKey
));
6417 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
6420 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
6421 result
= OSKext::dispatchResource(requestDict
);
6423 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
6424 OSBoolean
* delayAutounloadBool
= NULL
;
6426 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
6427 _OSKextGetRequestArgument(requestDict
,
6428 kKextRequestArgumentDelayAutounloadKey
));
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.
6433 if (delayAutounloadBool
== kOSBooleanTrue
) {
6434 OSKext::considerUnloads(/* rescheduleOnly? */ true);
6437 responseObject
= OSDynamicCast(OSObject
,
6438 OSKext::copyLoadedKextInfo(kextIdentifiers
));
6439 if (!responseObject
) {
6440 result
= kOSKextReturnInternalError
;
6442 OSKextLog(/* kext */ NULL
,
6443 kOSKextLogDebugLevel
|
6445 "Returning loaded kext info.");
6446 result
= kOSReturnSuccess
;
6449 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6450 OSNumber
* addressNum
= NULL
; // released as responseObject
6451 kernel_segment_command_t
* textseg
= getsegbyname("__TEXT");
6454 OSKextLog(/* kext */ NULL
,
6455 kOSKextLogErrorLevel
|
6456 kOSKextLogGeneralFlag
| kOSKextLogIPCFlag
,
6457 "Can't find text segment for kernel load address.");
6458 result
= kOSReturnError
;
6462 OSKextLog(/* kext */ NULL
,
6463 kOSKextLogDebugLevel
|
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
;
6472 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
)) {
6473 OSKextLog(/* kext */ NULL
,
6474 kOSKextLogDebugLevel
|
6476 "Returning kernel link state.");
6477 responseData
= sKernelKext
->linkState
;
6478 responseData
->retain();
6479 result
= kOSReturnSuccess
;
6481 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
6483 /* Hand the current sKernelRequests array to the caller
6484 * (who must release it), and make a new one.
6486 responseObject
= OSDynamicCast(OSObject
, sKernelRequests
);
6487 sKernelRequests
= OSArray::withCapacity(0);
6488 sPostedKextLoadIdentifiers
->flushCollection();
6489 OSKextLog(/* kext */ NULL
,
6490 kOSKextLogDebugLevel
|
6492 "Returning kernel requests.");
6493 result
= kOSReturnSuccess
;
6495 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
6497 /* Return the set of all requested bundle identifiers */
6498 responseObject
= OSDynamicCast(OSObject
, sAllKextLoadIdentifiers
);
6499 responseObject
->retain();
6500 OSKextLog(/* kext */ NULL
,
6501 kOSKextLogDebugLevel
|
6503 "Returning load requests.");
6504 result
= kOSReturnSuccess
;
6508 * Now we have handle the request, or not. Gather up the response & logging
6509 * info to ship to user space.
6512 /* Note: Nothing in OSKext is supposed to retain requestDict,
6513 * but you never know....
6515 if (requestDict
->getRetainCount() > 1) {
6516 OSKextLog(/* kext */ NULL
,
6517 kOSKextLogWarningLevel
|
6519 "Request from user space still retained by a kext; "
6520 "probable memory leak.");
6523 if (responseData
&& responseObject
) {
6524 OSKextLog(/* kext */ NULL
,
6525 kOSKextLogErrorLevel
|
6527 "Mistakenly generated both data & plist responses to user request "
6528 "(returning only data).");
6531 if (responseData
&& responseData
->getLength() && responseOut
) {
6533 response
= (char *)responseData
->getBytesNoCopy();
6534 responseLength
= responseData
->getLength();
6535 } else if (responseOut
&& responseObject
) {
6536 serializer
= OSSerialize::withCapacity(0);
6538 result
= kOSKextReturnNoMemory
;
6542 if (!responseObject
->serialize(serializer
)) {
6543 OSKextLog(/* kext */ NULL
,
6544 kOSKextLogErrorLevel
|
6546 "Failed to serialize response to request from user space.");
6547 result
= kOSKextReturnSerialization
;
6551 response
= (char *)serializer
->text();
6552 responseLength
= serializer
->getLength();
6555 if (responseOut
&& response
) {
6558 /* This kmem_alloc sets the return value of the function.
6560 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
6562 if (kmem_result
!= KERN_SUCCESS
) {
6563 OSKextLog(/* kext */ NULL
,
6564 kOSKextLogErrorLevel
|
6566 "Failed to copy response to request from user space.");
6567 result
= kmem_result
;
6570 memcpy(buffer
, response
, responseLength
);
6571 *responseOut
= buffer
;
6572 *responseLengthOut
= responseLength
;
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.
6584 logInfoArray
= OSKext::clearUserSpaceLogFilter();
6586 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
6587 (void)OSKext::serializeLogInfo(logInfoArray
,
6588 logInfoOut
, logInfoLengthOut
);
6591 IORecursiveLockUnlock(sKextLock
);
6593 OSSafeRelease(requestDict
);
6594 OSSafeRelease(errorString
);
6595 OSSafeRelease(responseData
);
6596 OSSafeRelease(responseObject
);
6597 OSSafeRelease(serializer
);
6598 OSSafeRelease(logInfoArray
);
6603 /*********************************************************************
6604 *********************************************************************/
6607 OSKext::copyLoadedKextInfo(OSArray
* kextIdentifiers
)
6609 OSArray
* result
= NULL
;
6610 OSDictionary
* kextInfo
= NULL
; // must release
6612 uint32_t idCount
= 0;
6613 uint32_t idIndex
= 0;
6615 IORecursiveLockLock(sKextLock
);
6617 /* Empty list of bundle ids is equivalent to no list (get all).
6619 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
6620 kextIdentifiers
= NULL
;
6621 } else if (kextIdentifiers
) {
6622 idCount
= kextIdentifiers
->getCount();
6625 count
= sLoadedKexts
->getCount();
6626 result
= OSArray::withCapacity(count
);
6630 for (i
= 0; i
< count
; i
++) {
6631 OSKext
* thisKext
= NULL
; // do not release
6632 Boolean includeThis
= true;
6635 kextInfo
->release();
6638 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6643 /* Skip current kext if we have a list of bundle IDs and
6644 * it isn't in the list.
6646 if (kextIdentifiers
) {
6647 const OSString
* thisKextID
= thisKext
->getIdentifier();
6649 includeThis
= false;
6651 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
6652 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
6653 kextIdentifiers
->getObject(idIndex
));
6654 if (thisKextID
->isEqualTo(thisRequestID
)) {
6665 kextInfo
= thisKext
->copyInfo();
6666 result
->setObject(kextInfo
);
6670 IORecursiveLockUnlock(sKextLock
);
6672 if (kextInfo
) kextInfo
->release();
6677 /*********************************************************************
6686 Dependency Load Tags
6687 # Dependent References
6690 *********************************************************************/
6691 #define _OSKextLoadInfoDictCapacity (12)
6694 OSKext::copyInfo(void)
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
6712 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
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.
6722 if (linkedExecutable
|| (this == sKernelKext
)) {
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
);
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
);
6742 /* CFBundleIdentifier.
6744 result
->setObject(kCFBundleIdentifierKey
, bundleID
);
6748 versionString
= OSDynamicCast(OSString
,
6749 getPropertyForHostArch(kCFBundleVersionKey
));
6750 if (versionString
) {
6751 result
->setObject(kCFBundleVersionKey
, versionString
);
6754 /* OSBundleCompatibleVersion.
6756 versionString
= OSDynamicCast(OSString
,
6757 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
6758 if (versionString
) {
6759 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
6765 result
->setObject(kOSBundlePathKey
, path
);
6772 result
->setObject(kOSBundleUUIDKey
, uuid
);
6776 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
6778 result
->setObject(kOSKernelResourceKey
,
6779 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
6781 result
->setObject(kOSBundleIsInterfaceKey
,
6782 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
6784 result
->setObject(kOSBundlePrelinkedKey
,
6785 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
6787 result
->setObject(kOSBundleStartedKey
,
6788 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
6792 scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
6793 /* numBits */ 8 * sizeof(loadTag
));
6794 if (scratchNumber
) {
6795 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
);
6796 OSSafeReleaseNULL(scratchNumber
);
6799 /* LoadAddress, LoadSize.
6801 if (isInterface() || linkedExecutable
) {
6802 /* These go to userspace via serialization, so we don't want any doubts
6805 uint64_t loadAddress
= 0;
6806 uint32_t loadSize
= 0;
6807 uint32_t wiredSize
= 0;
6809 /* Interfaces always report 0 load address & size.
6810 * Just the way they roll.
6812 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
6813 * xxx - shouldn't have one!
6815 if (linkedExecutable
/* && !isInterface() */) {
6816 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
6817 loadSize
= linkedExecutable
->getLength();
6819 /* If we have a kmod_info struct, calculated the wired size
6820 * from that. Otherwise it's the full load size.
6823 wiredSize
= loadSize
- kmod_info
->hdr_size
;
6825 wiredSize
= loadSize
;
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
);
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
);
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
);
6852 /* OSBundleDependencies. In descending order for
6853 * easy compatibility with kextstat(8).
6855 if ((count
= getNumDependencies())) {
6856 dependencyLoadTags
= OSArray::withCapacity(count
);
6857 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
);
6861 OSKext
* dependency
= OSDynamicCast(OSKext
,
6862 dependencies
->getObject(i
));
6864 OSSafeReleaseNULL(scratchNumber
);
6869 scratchNumber
= OSNumber::withNumber(
6870 (unsigned long long)dependency
->getLoadTag(),
6871 /* numBits*/ 8 * sizeof(loadTag
));
6872 if (scratchNumber
) {
6873 dependencyLoadTags
->setObject(scratchNumber
);
6878 OSSafeReleaseNULL(scratchNumber
);
6880 /* OSBundleMetaClasses.
6882 if (metaClasses
&& metaClasses
->getCount()) {
6883 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
);
6884 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
6885 if (!metaClassIterator
|| !metaClassInfo
) {
6888 result
->setObject(kOSBundleClassesKey
, metaClassInfo
);
6890 while ( (thisMetaClass
= OSDynamicCast(OSMetaClass
,
6891 metaClassIterator
->getNextObject())) ) {
6893 OSSafeReleaseNULL(metaClassDict
);
6894 OSSafeReleaseNULL(metaClassName
);
6895 OSSafeReleaseNULL(superclassName
);
6896 OSSafeReleaseNULL(scratchNumber
);
6898 metaClassDict
= OSDictionary::withCapacity(3);
6899 if (!metaClassDict
) {
6903 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
6904 if (thisMetaClass
->getSuperClass()) {
6905 superclassName
= OSString::withCString(
6906 thisMetaClass
->getSuperClass()->getClassName());
6908 scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
6909 8 * sizeof(unsigned int));
6910 if (!metaClassDict
|| !metaClassName
|| !superclassName
||
6916 metaClassInfo
->setObject(metaClassDict
);
6917 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
);
6918 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
);
6919 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
);
6923 /* OSBundleRetainCount.
6925 OSSafeReleaseNULL(scratchNumber
);
6927 int extRetainCount
= getRetainCount() - 1;
6931 scratchNumber
= OSNumber::withNumber(
6932 (int)extRetainCount
,
6933 /* numBits*/ 8 * sizeof(int));
6934 if (scratchNumber
) {
6935 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
);
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
);
6952 OSSafeReleaseNULL(result
);
6957 /*********************************************************************
6958 *********************************************************************/
6961 OSKext::requestResource(
6962 const char * kextIdentifierCString
,
6963 const char * resourceNameCString
,
6964 OSKextRequestResourceCallback callback
,
6966 OSKextRequestTag
* requestTagOut
)
6968 OSReturn result
= kOSReturnError
;
6969 OSKext
* callbackKext
= NULL
; // must release (looked up)
6971 OSKextRequestTag requestTag
= -1;
6972 OSNumber
* requestTagNum
= NULL
; // must release
6974 OSDictionary
* requestDict
= NULL
; // must release
6975 OSString
* kextIdentifier
= NULL
; // must release
6976 OSString
* resourceName
= NULL
; // must release
6978 OSDictionary
* callbackRecord
= NULL
; // must release
6979 OSData
* callbackWrapper
= NULL
; // must release
6981 OSData
* contextWrapper
= NULL
; // must release
6983 IORecursiveLockLock(sKextLock
);
6985 if (requestTagOut
) {
6986 *requestTagOut
= kOSKextRequestTagInvalid
;
6989 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
6990 result
= kOSKextReturnInvalidArgument
;
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
;
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
;
7010 /* Do not allow any new requests to be made on a kext that is unloading.
7012 if (callbackKext
->flags
.stopping
) {
7013 result
= kOSKextReturnStopping
;
7017 /* If we're wrapped the next available request tag around to the negative
7018 * numbers, we can't service any more requests.
7020 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
7021 OSKextLog(/* kext */ NULL
,
7022 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7023 "No more request tags available; restart required.");
7024 result
= kOSKextReturnNoResources
;
7027 requestTag
= sNextRequestTag
++;
7029 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
7031 if (result
!= kOSReturnSuccess
) {
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
||
7042 !_OSKextSetRequestArgument(requestDict
,
7043 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
7044 !_OSKextSetRequestArgument(requestDict
,
7045 kKextRequestArgumentNameKey
, resourceName
) ||
7046 !_OSKextSetRequestArgument(requestDict
,
7047 kKextRequestArgumentRequestTagKey
, requestTagNum
)) {
7049 result
= kOSKextReturnNoMemory
;
7053 callbackRecord
= OSDynamicCast(OSDictionary
, requestDict
->copyCollection());
7054 if (!callbackRecord
) {
7055 result
= kOSKextReturnNoMemory
;
7058 // we validate callback address at call time
7059 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
7061 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
7063 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7064 kKextRequestArgumentCallbackKey
, callbackWrapper
)) {
7066 result
= kOSKextReturnNoMemory
;
7071 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7072 kKextRequestArgumentContextKey
, contextWrapper
)) {
7074 result
= kOSKextReturnNoMemory
;
7079 /* Only post the requests after all the other potential failure points
7082 if (!sKernelRequests
->setObject(requestDict
) ||
7083 !sRequestCallbackRecords
->setObject(callbackRecord
)) {
7085 result
= kOSKextReturnNoMemory
;
7091 result
= kOSReturnSuccess
;
7092 if (requestTagOut
) {
7093 *requestTagOut
= requestTag
;
7098 /* If we didn't succeed, yank the request & callback
7099 * from their holding arrays.
7101 if (result
!= kOSReturnSuccess
) {
7104 index
= sKernelRequests
->getNextIndexOfObject(requestDict
, 0);
7105 if (index
!= (unsigned int)-1) {
7106 sKernelRequests
->removeObject(index
);
7108 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
, 0);
7109 if (index
!= (unsigned int)-1) {
7110 sRequestCallbackRecords
->removeObject(index
);
7114 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7116 IORecursiveLockUnlock(sKextLock
);
7118 if (callbackKext
) callbackKext
->release();
7119 if (requestTagNum
) requestTagNum
->release();
7121 if (requestDict
) requestDict
->release();
7122 if (kextIdentifier
) kextIdentifier
->release();
7123 if (resourceName
) resourceName
->release();
7125 if (callbackRecord
) callbackRecord
->release();
7126 if (callbackWrapper
) callbackWrapper
->release();
7127 if (contextWrapper
) contextWrapper
->release();
7132 /*********************************************************************
7133 *********************************************************************/
7136 OSKext::dequeueCallbackForRequestTag(
7137 OSKextRequestTag requestTag
,
7138 OSDictionary
** callbackRecordOut
)
7140 OSReturn result
= kOSReturnError
;
7141 OSNumber
* requestTagNum
= NULL
; // must release
7143 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
7144 8 * sizeof(requestTag
));
7145 if (!requestTagNum
) {
7149 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
,
7153 OSSafeRelease(requestTagNum
);
7158 /*********************************************************************
7159 *********************************************************************/
7162 OSKext::dequeueCallbackForRequestTag(
7163 OSNumber
* requestTagNum
,
7164 OSDictionary
** callbackRecordOut
)
7166 OSReturn result
= kOSKextReturnInvalidArgument
;
7167 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
7168 OSNumber
* callbackTagNum
= NULL
; // do not release
7169 unsigned int count
, i
;
7171 IORecursiveLockLock(sKextLock
);
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
) {
7182 /* If we don't find a tag, we basically have a leak here. Maybe
7183 * we should just remove it.
7185 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
7186 callbackRecord
, kKextRequestArgumentRequestTagKey
));
7187 if (!callbackTagNum
) {
7191 /* We could be even more paranoid and check that all the incoming
7192 * args match what's in the callback record.
7194 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
7195 if (callbackRecordOut
) {
7196 *callbackRecordOut
= callbackRecord
;
7197 callbackRecord
->retain();
7199 sRequestCallbackRecords
->removeObject(i
);
7200 result
= kOSReturnSuccess
;
7204 result
= kOSKextReturnNotFound
;
7207 IORecursiveLockUnlock(sKextLock
);
7211 /*********************************************************************
7212 *********************************************************************/
7215 OSKext::dispatchResource(OSDictionary
* requestDict
)
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)
7230 IORecursiveLockLock(sKextLock
);
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.
7235 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7236 kKextRequestArgumentRequestTagKey
));
7237 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7238 kKextRequestArgumentResultKey
));
7239 if (!requestTag
|| !requestResult
) {
7240 result
= kOSKextReturnInvalidArgument
;
7244 /* Look for a callback record matching this request's tag.
7246 result
= dequeueCallbackForRequestTag(requestTag
, &callbackRecord
);
7247 if (result
!= kOSReturnSuccess
) {
7252 * Get the context pointer of the callback record (if there is one).
7254 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
,
7255 kKextRequestArgumentContextKey
));
7256 context
= _OSKextExtractPointer(contextWrapper
);
7257 if (contextWrapper
&& !context
) {
7261 callbackWrapper
= OSDynamicCast(OSData
,
7262 _OSKextGetRequestArgument(callbackRecord
,
7263 kKextRequestArgumentCallbackKey
));
7264 callback
= (OSKextRequestResourceCallback
)
7265 _OSKextExtractPointer(callbackWrapper
);
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.
7274 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
7275 kKextRequestArgumentValueKey
));
7277 dataPtr
= dataObj
->getBytesNoCopy();
7278 dataLength
= dataObj
->getLength();
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.",
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.",
7299 (void)callback(requestTag
->unsigned32BitValue(),
7300 (OSReturn
)requestResult
->unsigned32BitValue(),
7301 dataPtr
, dataLength
, context
);
7303 result
= kOSReturnSuccess
;
7306 if (callbackKext
) callbackKext
->release();
7307 if (callbackRecord
) callbackRecord
->release();
7309 IORecursiveLockUnlock(sKextLock
);
7313 /*********************************************************************
7314 *********************************************************************/
7317 OSKext::invokeRequestCallback(
7318 OSDictionary
* callbackRecord
,
7319 OSReturn callbackResult
)
7321 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
7322 OSNumber
* resultNum
= NULL
; // must release
7328 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
7329 8 * sizeof(callbackResult
));
7334 /* Insert the result into the callback record and dispatch it as if it
7335 * were the reply coming down from user space.
7337 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
7340 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
7341 /* This removes the pending callback record.
7343 OSKext::dispatchResource(callbackRecord
);
7347 if (resultNum
) resultNum
->release();
7351 /*********************************************************************
7352 *********************************************************************/
7355 OSKext::cancelRequest(
7356 OSKextRequestTag requestTag
,
7359 OSReturn result
= kOSKextReturnNoMemory
;
7360 OSDictionary
* callbackRecord
= NULL
; // must release
7361 OSData
* contextWrapper
= NULL
; // do not release
7363 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
7366 if (result
== kOSReturnSuccess
&& contextOut
) {
7367 contextWrapper
= OSDynamicCast(OSData
,
7368 _OSKextGetRequestArgument(callbackRecord
,
7369 kKextRequestArgumentContextKey
));
7370 *contextOut
= _OSKextExtractPointer(contextWrapper
);
7373 if (callbackRecord
) callbackRecord
->release();
7378 /*********************************************************************
7379 *********************************************************************/
7381 OSKext::invokeOrCancelRequestCallbacks(
7382 OSReturn callbackResult
,
7385 unsigned int count
, i
;
7387 IORecursiveLockLock(sKextLock
);
7389 count
= sRequestCallbackRecords
->getCount();
7396 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7397 sRequestCallbackRecords
->getObject(i
));
7402 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7403 _OSKextGetRequestArgument(request
,
7404 kKextRequestArgumentCallbackKey
));
7406 if (!callbackWrapper
) {
7407 sRequestCallbackRecords
->removeObject(i
);
7411 vm_address_t callbackAddress
= (vm_address_t
)
7412 _OSKextExtractPointer(callbackWrapper
);
7414 if ((kmod_info
->address
<= callbackAddress
) &&
7415 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7418 /* This removes the callback record.
7420 invokeRequestCallback(request
, callbackResult
);
7422 sRequestCallbackRecords
->removeObject(i
);
7428 IORecursiveLockUnlock(sKextLock
);
7432 /*********************************************************************
7433 *********************************************************************/
7435 OSKext::countRequestCallbacks(void)
7437 uint32_t result
= 0;
7438 unsigned int count
, i
;
7440 IORecursiveLockLock(sKextLock
);
7442 count
= sRequestCallbackRecords
->getCount();
7449 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7450 sRequestCallbackRecords
->getObject(i
));
7455 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7456 _OSKextGetRequestArgument(request
,
7457 kKextRequestArgumentCallbackKey
));
7459 if (!callbackWrapper
) {
7463 vm_address_t callbackAddress
= (vm_address_t
)
7464 _OSKextExtractPointer(callbackWrapper
);
7466 if ((kmod_info
->address
<= callbackAddress
) &&
7467 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7474 IORecursiveLockUnlock(sKextLock
);
7478 /*********************************************************************
7479 *********************************************************************/
7480 static OSReturn
_OSKextCreateRequest(
7481 const char * predicate
,
7482 OSDictionary
** requestP
)
7484 OSReturn result
= kOSKextReturnNoMemory
;
7485 OSDictionary
* request
= NULL
; // must release on error
7486 OSDictionary
* args
= NULL
; // must release
7488 request
= OSDictionary::withCapacity(2);
7492 result
= _OSDictionarySetCStringValue(request
,
7493 kKextRequestPredicateKey
, predicate
);
7494 if (result
!= kOSReturnSuccess
) {
7497 result
= kOSReturnSuccess
;
7500 if (result
!= kOSReturnSuccess
) {
7501 if (request
) request
->release();
7503 *requestP
= request
;
7505 if (args
) args
->release();
7510 /*********************************************************************
7511 *********************************************************************/
7512 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
7514 return OSDynamicCast(OSString
,
7515 requestDict
->getObject(kKextRequestPredicateKey
));
7518 /*********************************************************************
7519 *********************************************************************/
7520 static OSObject
* _OSKextGetRequestArgument(
7521 OSDictionary
* requestDict
,
7522 const char * argName
)
7524 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7525 requestDict
->getObject(kKextRequestArgumentsKey
));
7527 return args
->getObject(argName
);
7532 /*********************************************************************
7533 *********************************************************************/
7534 static bool _OSKextSetRequestArgument(
7535 OSDictionary
* requestDict
,
7536 const char * argName
,
7539 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7540 requestDict
->getObject(kKextRequestArgumentsKey
));
7542 args
= OSDictionary::withCapacity(2);
7546 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
7550 return args
->setObject(argName
, value
);
7556 /*********************************************************************
7557 *********************************************************************/
7558 static void * _OSKextExtractPointer(OSData
* wrapper
)
7560 void * result
= NULL
;
7561 const void * resultPtr
= NULL
;
7566 resultPtr
= wrapper
->getBytesNoCopy();
7567 result
= *(void **)resultPtr
;
7572 /*********************************************************************
7573 *********************************************************************/
7574 static OSReturn
_OSDictionarySetCStringValue(
7575 OSDictionary
* dict
,
7577 const char * cValue
)
7579 OSReturn result
= kOSKextReturnNoMemory
;
7580 const OSSymbol
* key
= NULL
; // must release
7581 OSString
* value
= NULL
; // must release
7583 key
= OSSymbol::withCString(cKey
);
7584 value
= OSString::withCString(cValue
);
7585 if (!key
|| !value
) {
7588 if (dict
->setObject(key
, value
)) {
7589 result
= kOSReturnSuccess
;
7593 if (key
) key
->release();
7594 if (value
) value
->release();
7600 #pragma mark Personalities (IOKit Drivers)
7602 /*********************************************************************
7603 *********************************************************************/
7606 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
7608 OSArray
* result
= NULL
; // returned
7609 OSCollectionIterator
* kextIterator
= NULL
; // must release
7610 OSArray
* personalities
= NULL
; // must release
7611 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7613 OSString
* kextID
= NULL
; // do not release
7614 OSKext
* theKext
= NULL
; // do not release
7616 IORecursiveLockLock(sKextLock
);
7618 /* Let's conservatively guess that any given kext has around 3
7619 * personalities for now.
7621 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
7626 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
7627 if (!kextIterator
) {
7631 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
7632 if (personalitiesIterator
) {
7633 personalitiesIterator
->release();
7634 personalitiesIterator
= NULL
;
7636 if (personalities
) {
7637 personalities
->release();
7638 personalities
= NULL
;
7641 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
7642 if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
7643 personalities
= theKext
->copyPersonalitiesArray();
7644 if (!personalities
) {
7647 result
->merge(personalities
);
7649 // xxx - check for better place to put this log msg
7651 kOSKextLogWarningLevel
|
7653 "Kext %s is not loadable during safe boot; "
7654 "omitting its personalities.",
7655 theKext
->getIdentifierCString());
7661 IORecursiveLockUnlock(sKextLock
);
7663 if (kextIterator
) kextIterator
->release();
7664 if (personalitiesIterator
) personalitiesIterator
->release();
7665 if (personalities
) personalities
->release();
7670 /*********************************************************************
7671 *********************************************************************/
7674 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
7676 int numPersonalities
= 0;
7678 OSKextLog(/* kext */ NULL
,
7679 kOSKextLogStepLevel
|
7681 "Sending all eligible registered kexts' personalities "
7682 "to the IOCatalogue %s.",
7683 startMatching
? "and starting matching" : "but not starting matching");
7685 OSArray
* personalities
= OSKext::copyAllKextPersonalities(
7686 /* filterSafeBootFlag */ true);
7688 if (personalities
) {
7689 gIOCatalogue
->addDrivers(personalities
, startMatching
);
7690 numPersonalities
= personalities
->getCount();
7691 personalities
->release();
7694 OSKextLog(/* kext */ NULL
,
7695 kOSKextLogStepLevel
|
7697 "%d kext personalit%s sent to the IOCatalogue; %s.",
7698 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
7699 startMatching
? "matching started" : "matching not started");
7703 /*********************************************************************
7704 * Do not make a deep copy, just convert the IOKitPersonalities dict
7705 * to an array for sending to the IOCatalogue.
7706 *********************************************************************/
7708 OSKext::copyPersonalitiesArray(void)
7710 OSArray
* result
= NULL
;
7711 OSDictionary
* personalities
= NULL
; // do not release
7712 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7714 OSString
* personalityName
= NULL
; // do not release
7715 OSString
* personalityBundleIdentifier
= NULL
; // do not release
7717 personalities
= OSDynamicCast(OSDictionary
,
7718 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7719 if (!personalities
) {
7723 result
= OSArray::withCapacity(personalities
->getCount());
7728 personalitiesIterator
=
7729 OSCollectionIterator::withCollection(personalities
);
7730 if (!personalitiesIterator
) {
7733 while ((personalityName
= OSDynamicCast(OSString
,
7734 personalitiesIterator
->getNextObject()))) {
7736 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7737 personalities
->getObject(personalityName
));
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
7745 personalityBundleIdentifier
= OSDynamicCast(OSString
,
7746 personality
->getObject(kCFBundleIdentifierKey
));
7748 if (!personalityBundleIdentifier
) {
7749 personality
->setObject(kCFBundleIdentifierKey
, bundleID
);
7750 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
)) {
7751 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
);
7754 result
->setObject(personality
);
7758 if (personalitiesIterator
) personalitiesIterator
->release();
7763 /*********************************************************************
7764 Might want to change this to a bool return?
7765 *********************************************************************/
7767 OSKext::sendPersonalitiesToCatalog(
7769 OSArray
* personalityNames
)
7771 OSArray
* personalitiesToSend
= NULL
; // must release
7772 OSDictionary
* kextPersonalities
= NULL
; // do not release
7775 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
7777 kOSKextLogErrorLevel
|
7779 "Kext %s is not loadable during safe boot; "
7780 "not sending personalities to the IOCatalogue.",
7781 getIdentifierCString());
7785 if (!personalityNames
|| !personalityNames
->getCount()) {
7786 personalitiesToSend
= copyPersonalitiesArray();
7788 kextPersonalities
= OSDynamicCast(OSDictionary
,
7789 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7790 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
7793 personalitiesToSend
= OSArray::withCapacity(0);
7794 if (!personalitiesToSend
) {
7797 count
= personalityNames
->getCount();
7798 for (i
= 0; i
< count
; i
++) {
7799 OSString
* name
= OSDynamicCast(OSString
,
7800 personalityNames
->getObject(i
));
7804 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7805 kextPersonalities
->getObject(name
));
7807 personalitiesToSend
->setObject(personality
);
7811 if (personalitiesToSend
) {
7812 unsigned numPersonalities
= personalitiesToSend
->getCount();
7814 kOSKextLogStepLevel
|
7816 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
7817 getIdentifierCString(),
7819 numPersonalities
> 1 ? "ies" : "y",
7820 startMatching
? " and starting matching" : " but not starting matching");
7821 gIOCatalogue
->addDrivers(personalitiesToSend
, startMatching
);
7824 if (personalitiesToSend
) {
7825 personalitiesToSend
->release();
7830 /*********************************************************************
7831 *********************************************************************/
7833 OSKext::removePersonalitiesFromCatalog(void)
7835 OSDictionary
* personality
= NULL
; // do not release
7837 personality
= OSDictionary::withCapacity(1);
7841 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
7844 kOSKextLogStepLevel
|
7846 "Kext %s removing all personalities naming it from the IOCatalogue.",
7847 getIdentifierCString());
7849 /* Have the IOCatalog remove all personalities matching this kext's
7850 * bundle ID and trigger matching anew.
7852 gIOCatalogue
->removeDrivers(personality
, /* startMatching */ true);
7855 if (personality
) personality
->release();
7862 #pragma mark Logging
7864 /*********************************************************************
7865 * Do not call any function that takes sKextLock here!
7866 *********************************************************************/
7869 OSKext::setUserSpaceLogFilter(
7870 OSKextLogSpec userLogFilter
,
7873 OSKextLogSpec result
;
7875 IORecursiveLockLock(sKextInnerLock
);
7877 result
= sUserSpaceKextLogFilter
;
7878 sUserSpaceKextLogFilter
= userLogFilter
;
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.
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
);
7892 if (userLogFilter
&& captureFlag
&&
7893 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
7895 // xxx - do some measurements for a good initial capacity?
7896 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
7897 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
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
);
7909 IORecursiveLockUnlock(sKextInnerLock
);
7914 /*********************************************************************
7915 * Do not call any function that takes sKextLock here!
7916 *********************************************************************/
7919 OSKext::clearUserSpaceLogFilter(void)
7921 OSArray
* result
= NULL
;
7922 OSKextLogSpec oldLogFilter
;
7924 IORecursiveLockLock(sKextInnerLock
);
7926 result
= OSArray::withCapacity(2);
7928 result
->setObject(sUserSpaceLogSpecArray
);
7929 result
->setObject(sUserSpaceLogMessageArray
);
7931 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
7932 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
7934 oldLogFilter
= sUserSpaceKextLogFilter
;
7935 sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
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.
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
);
7949 IORecursiveLockUnlock(sKextInnerLock
);
7954 /*********************************************************************
7955 * Do not call any function that takes sKextLock here!
7956 *********************************************************************/
7959 OSKext::getUserSpaceLogFilter(void)
7961 OSKextLogSpec result
;
7963 IORecursiveLockLock(sKextInnerLock
);
7964 result
= sUserSpaceKextLogFilter
;
7965 IORecursiveLockUnlock(sKextInnerLock
);
7970 /*********************************************************************
7971 * This function is called by OSMetaClass during kernel C++ setup.
7972 * Be careful what you access here; assume only OSKext::initialize()
7975 * Do not call any function that takes sKextLock here!
7976 *********************************************************************/
7977 #define VTRESET "\033[0m"
7979 #define VTBOLD "\033[1m"
7980 #define VTUNDER "\033[4m"
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"
7989 inline const char * colorForFlags(OSKextLogSpec flags
)
7991 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
7994 case kOSKextLogErrorLevel
:
7995 return VTRED VTBOLD
;
7997 case kOSKextLogWarningLevel
:
8000 case kOSKextLogBasicLevel
:
8001 return VTYELLOW VTUNDER
;
8003 case kOSKextLogProgressLevel
:
8006 case kOSKextLogStepLevel
:
8009 case kOSKextLogDetailLevel
:
8012 case kOSKextLogDebugLevel
:
8022 inline bool logSpecMatch(
8023 OSKextLogSpec msgLogSpec
,
8024 OSKextLogSpec logFilter
)
8026 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
8027 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
8028 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
8030 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
8031 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
8032 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
8034 /* Explicit messages always get logged.
8036 if (msgLevel
== kOSKextLogExplicitLevel
) {
8040 /* Warnings and errors are logged regardless of the flags.
8042 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
8046 /* A verbose message that isn't for a logging-enabled kext and isn't global
8047 * does *not* get logged.
8049 if (!msgKextGlobal
&& !filterKextGlobal
) {
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.
8058 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
8069 OSKextLogSpec msgLogSpec
,
8070 const char * format
, ...)
8074 va_start(argList
, format
);
8075 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
8082 OSKextLogSpec msgLogSpec
,
8083 const char * format
,
8086 extern int disableConsoleOutput
;
8088 bool logForKernel
= false;
8089 bool logForUser
= false;
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
8098 IORecursiveLockLock(sKextInnerLock
);
8100 /* Set the kext/global bit in the message spec if we have no
8101 * kext or if the kext requests logging.
8103 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
8104 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
8107 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
8108 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
8109 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
8112 if (! (logForKernel
|| logForUser
) ) {
8116 /* No goto from here until past va_end()!
8118 va_copy(argList
, srcArgList
);
8119 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
8122 if (length
+ 1 >= sizeof(stackBuffer
)) {
8123 allocBuffer
= (char *)kalloc((length
+ 1) * sizeof(char));
8128 /* No goto from here until past va_end()!
8130 va_copy(argList
, srcArgList
);
8131 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
8134 buffer
= allocBuffer
;
8137 /* If user space wants the log message, queue it up.
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
);
8148 /* Always log messages from the kernel according to the kernel's
8153 /* If we are in console mode and have a custom log filter,
8154 * colorize the log message.
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
: "");
8162 printf("%s\n", buffer
);
8168 kfree(allocBuffer
, (length
+ 1) * sizeof(char));
8170 OSSafeRelease(logString
);
8171 OSSafeRelease(logSpecNum
);
8172 IORecursiveLockUnlock(sKextInnerLock
);
8179 #pragma mark Backtrace Dump & kmod_get_info() support
8181 /*********************************************************************
8182 *********************************************************************/
8185 OSKext::printKextsInBacktrace(
8188 int (* printf_func
)(const char *fmt
, ...),
8191 vm_offset_t
* kscan_addr
= NULL
;
8192 kmod_info_t
* k
= NULL
;
8193 kmod_reference_t
* r
= NULL
;
8198 IORecursiveLockLock(sKextLock
);
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
);
8208 continue; // skip fake entries for built-in kernel components
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
))) {
8215 (*printf_func
)(" Kernel Extensions in backtrace "
8216 "(with dependencies):\n");
8219 (*printf_func
)(" %s(%s)@%p->%p\n",
8220 k
->name
, k
->version
, k
->address
, k
->address
+ k
->size
- 1);
8222 for (r
= k
->reference_list
; r
; r
= r
->next
) {
8223 kmod_info_t
* rinfo
;
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
);
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
);
8239 if (!rinfo
->address
) {
8240 continue; // skip fake entries for built-ins
8243 (*printf_func
)(" dependency: %s(%s)@%p\n",
8244 rinfo
->name
, rinfo
->version
, rinfo
->address
);
8247 break; // only report this kmod for one backtrace address
8253 IORecursiveLockUnlock(sKextLock
);
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
,
8268 uint32_t * to_index
,
8269 uint32_t * from_index
,
8270 const char * substring
,
8274 /* string_out must be at least KMOD_MAX_NAME bytes.
8278 const char * scan_string
,
8280 uint32_t * to_index
,
8281 uint32_t * from_index
,
8282 const char * substring
,
8286 uint32_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
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.
8293 if (!strncmp(scan_string
, substring
, substring_length
)) {
8295 string_out
[(*to_index
)++] = marker
;
8297 string_out
[(*to_index
)++] = substitution
;
8298 (*from_index
) += substring_length
;
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
);
8316 const char * identifier
,
8317 char * identifier_out
,
8318 char ** identifier_out_end
)
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
;
8326 from_index
= to_index
= 0;
8327 identifier_out
[0] = '\0';
8329 /* Replace certain identifier prefixes with shorter @+character sequences.
8330 * Check the return value of substitute() so we only replace the prefix.
8332 for (subs_entry
= &kext_identifier_prefix_subs
[0];
8333 subs_entry
->substring
&& !did_sub
;
8336 did_sub
= substitute(identifier
, identifier_out
,
8337 &scan_to_index
, &scan_from_index
,
8338 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
8342 /* Now scan through the identifier looking for the common substrings
8343 * and replacing them with shorter !+character sequences via substitute().
8345 for (/* see above */;
8346 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
8349 const char * scan_string
= &identifier
[scan_from_index
];
8353 if (scan_from_index
) {
8354 for (subs_entry
= &kext_identifier_substring_subs
[0];
8355 subs_entry
->substring
&& !did_sub
;
8358 did_sub
= substitute(scan_string
, identifier_out
,
8359 &scan_to_index
, &scan_from_index
,
8360 subs_entry
->substring
, '!', subs_entry
->substitute
);
8364 /* If we didn't substitute, copy the input character to the output.
8367 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
8371 identifier_out
[scan_to_index
] = '\0';
8372 if (identifier_out_end
) {
8373 *identifier_out_end
= &identifier_out
[scan_to_index
];
8379 /*******************************************************************************
8380 * assemble_identifier_and_version() adds to a string buffer a compacted
8381 * bundle identifier followed by a version string.
8382 *******************************************************************************/
8384 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
8386 static int assemble_identifier_and_version(
8387 kmod_info_t
* kmod_info
,
8388 char * identPlusVers
);
8390 assemble_identifier_and_version(
8391 kmod_info_t
* kmod_info
,
8392 char * identPlusVers
)
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
);
8405 /*******************************************************************************
8406 *******************************************************************************/
8407 #define LAST_LOADED " - last loaded "
8408 #define LAST_LOADED_TS_WIDTH (16)
8412 OSKext::saveLoadedKextPanicListTyped(
8413 const char * prefix
,
8418 uint32_t * list_length_ptr
)
8420 uint32_t result
= 0;
8422 unsigned int count
, i
;
8424 count
= sLoadedKexts
->getCount();
8431 OSKext
* theKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
8432 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
8434 char identPlusVers
[2*KMOD_MAX_NAME
];
8435 uint32_t identPlusVersLength
;
8436 char timestampBuffer
[17]; // enough for a uint64_t
8438 /* Skip all built-in kexts.
8440 if (theKext
->isKernelComponent()) {
8444 /* Filter for kmod name (bundle identifier).
8446 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
8447 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
8451 /* Filter for libraries (kexts that have a compatible version).
8453 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
8454 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
8460 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
8462 printf("kext scan stopped due to missing kmod_info page: %p\n",
8468 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
8470 if (!identPlusVersLength
) {
8471 printf("error saving loaded kext info\n");
8475 /* We're going to note the last-loaded kext in the list.
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
));
8484 /* Adding 1 for the newline.
8486 if (*list_length_ptr
+ identPlusVersLength
+ 1 >= list_size
) {
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
);
8495 *list_length_ptr
= strlcat(paniclist
, "\n", list_size
);
8501 if (*list_length_ptr
+ 1 <= list_size
) {
8502 result
= list_size
- (*list_length_ptr
+ 1);
8509 /*********************************************************************
8510 *********************************************************************/
8513 OSKext::saveLoadedKextPanicList(void)
8515 char * newlist
= NULL
;
8516 uint32_t newlist_size
= 0;
8517 uint32_t newlist_length
= 0;
8519 IORecursiveLockLock(sKextLock
);
8522 newlist_size
= KEXT_PANICLIST_SIZE
;
8523 newlist
= (char *)kalloc(newlist_size
);
8526 OSKextLog(/* kext */ NULL
,
8527 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
8528 "Couldn't allocate kext panic log buffer.");
8534 // non-"com.apple." kexts
8535 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
8536 /* libs? */ -1, newlist
, newlist_size
, &newlist_length
)) {
8540 // "com.apple." nonlibrary kexts
8541 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8542 /* libs? */ 0, newlist
, newlist_size
, &newlist_length
)) {
8546 // "com.apple." library kexts
8547 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8548 /* libs? */ 1, newlist
, newlist_size
, &newlist_length
)) {
8553 if (loaded_kext_paniclist
) {
8554 kfree(loaded_kext_paniclist
, loaded_kext_paniclist_size
);
8556 loaded_kext_paniclist
= newlist
;
8557 loaded_kext_paniclist_size
= newlist_size
;
8558 loaded_kext_paniclist_length
= newlist_length
;
8561 IORecursiveLockUnlock(sKextLock
);
8565 /*********************************************************************
8566 *********************************************************************/
8569 OSKext::saveUnloadedKextPanicList(OSKext
* aKext
)
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
;
8577 if (!aKext
->kmod_info
) {
8578 return; // do not goto finish here b/c of lock
8581 IORecursiveLockLock(sKextLock
);
8583 clock_get_uptime(&last_unloaded_timestamp
);
8584 last_unloaded_address
= (void *)aKext
->kmod_info
->address
;
8585 last_unloaded_size
= aKext
->kmod_info
->size
;
8588 identPlusVersLength
= assemble_identifier_and_version(aKext
->kmod_info
,
8590 if (!identPlusVersLength
) {
8591 printf("error saving unloaded kext info\n");
8595 newlist_length
= identPlusVersLength
;
8596 newlist_size
= newlist_length
+ 1;
8597 newlist
= (char *)kalloc(newlist_size
);
8600 printf("couldn't allocate kext panic log buffer\n");
8606 strlcpy(newlist
, identPlusVers
, newlist_size
);
8608 if (unloaded_kext_paniclist
) {
8609 kfree(unloaded_kext_paniclist
, unloaded_kext_paniclist_size
);
8611 unloaded_kext_paniclist
= newlist
;
8612 unloaded_kext_paniclist_size
= newlist_size
;
8613 unloaded_kext_paniclist_length
= newlist_length
;
8616 IORecursiveLockUnlock(sKextLock
);
8620 /*********************************************************************
8621 *********************************************************************/
8623 #define __kLoadSizeEscape "0x%lld"
8625 #define __kLoadSizeEscape "0x%ld"
8626 #endif /* __LP64__ */
8630 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
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]) {
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
));
8643 printf_func("(none)\n");
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]) {
8650 printf_func("%.*s", loaded_kext_paniclist_length
, loaded_kext_paniclist
);
8652 printf_func("(none)\n");
8657 /*********************************************************************
8658 *********************************************************************/
8659 #if __ppc__ || __i386__
8662 OSKext::getKmodInfo(
8663 kmod_info_array_t
* kmodList
,
8664 mach_msg_type_number_t
* kmodCount
)
8666 kern_return_t result
= KERN_FAILURE
;
8668 kmod_info_t
* k
, * kmod_info_scan_ptr
;
8669 kmod_reference_t
* r
, * ref_scan_ptr
;
8673 *kmodList
= (kmod_info_t
*)0;
8676 IORecursiveLockLock(sKextLock
);
8680 size
+= sizeof(kmod_info_t
);
8681 r
= k
->reference_list
;
8683 size
+=sizeof(kmod_reference_t
);
8689 result
= KERN_SUCCESS
;
8693 result
= kmem_alloc(kernel_map
, &data
, size
);
8694 if (result
!= KERN_SUCCESS
) {
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.
8704 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8706 *kmod_info_scan_ptr
= *k
;
8708 kmod_info_scan_ptr
->next
= k
;
8710 kmod_info_scan_ptr
++;
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.
8719 ref_scan_ptr
= (kmod_reference_t
*)kmod_info_scan_ptr
;
8720 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8722 r
= k
->reference_list
;
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.
8734 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
8735 * struct for the client to interpret.
8737 kmod_info_scan_ptr
->reference_list
= (kmod_reference_t
*)(long)ref_count
;
8738 kmod_info_scan_ptr
++;
8742 result
= vm_map_copyin(kernel_map
, data
, size
, TRUE
, (vm_map_copy_t
*)kmodList
);
8743 if (result
!= KERN_SUCCESS
) {
8748 result
= KERN_SUCCESS
;
8751 IORecursiveLockUnlock(sKextLock
);
8753 if (result
!= KERN_SUCCESS
&& data
) {
8754 kmem_free(kernel_map
, data
, size
);
8755 *kmodList
= (kmod_info_t
*)0;
8760 #endif /* __ppc__ || __i386__ */
8762 #pragma mark MAC Framework Support
8764 /*********************************************************************
8765 *********************************************************************/
8766 #if CONFIG_MACF_KEXT
8767 /* MAC Framework support */
8770 * define IOC_DEBUG to display run-time debugging information
8771 * #define IOC_DEBUG 1
8775 #define DPRINTF(x) printf x
8781 /*********************************************************************
8782 *********************************************************************/
8784 MACFObjectIsPrimitiveType(OSObject
* obj
)
8786 const OSMetaClass
* typeID
= NULL
; // do not release
8788 typeID
= OSTypeIDInst(obj
);
8789 if (typeID
== OSTypeID(OSString
) || typeID
== OSTypeID(OSNumber
) ||
8790 typeID
== OSTypeID(OSBoolean
) || typeID
== OSTypeID(OSData
)) {
8797 /*********************************************************************
8798 *********************************************************************/
8800 MACFLengthForObject(OSObject
* obj
)
8802 const OSMetaClass
* typeID
= NULL
; // do not release
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();
8823 /*********************************************************************
8824 *********************************************************************/
8826 MACFInitElementFromObject(
8827 struct mac_module_data_element
* element
,
8830 const OSMetaClass
* typeID
= NULL
; // do not release
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;
8853 strcpy(element
->value
, "false");
8854 element
->value_size
= 6;
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
);
8867 /*********************************************************************
8868 * This function takes an OSDictionary and returns a struct mac_module_data
8870 *********************************************************************/
8871 static struct mac_module_data
*
8872 MACFEncodeOSDictionary(OSDictionary
* dict
)
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;
8889 keyIterator
= OSCollectionIterator::withCollection(dict
);
8894 /* Iterate over OSModuleData to figure out total size */
8895 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
8897 // Get the key's value and determine its type
8898 OSObject
* value
= dict
->getObject(key
);
8903 typeID
= OSTypeIDInst(value
);
8904 if (MACFObjectIsPrimitiveType(value
)) {
8905 strtabsize
+= MACFLengthForObject(value
);
8907 else if (typeID
== OSTypeID(OSArray
)) {
8908 unsigned int k
, cnt
, nents
;
8909 OSArray
* arrayObj
= OSDynamicCast(OSArray
, value
);
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
);
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
8926 dictObj
= OSDynamicCast(OSDictionary
, value
);
8927 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
8928 if (!dictIterator
) {
8931 while ((dictkey
= OSDynamicCast(OSString
,
8932 dictIterator
->getNextObject()))) {
8934 OSObject
* dictvalue
= NULL
; // do not release
8936 dictvalue
= dictObj
->getObject(dictkey
);
8940 if (MACFObjectIsPrimitiveType(dictvalue
)) {
8941 strtabsize
+= MACFLengthForObject(dictvalue
);
8943 continue; /* Only handle primitive types here. */
8946 * Allow for the "arraynnn/" prefix in the key length.
8948 strtabsize
+= dictkey
->getLength() + 1;
8951 dictIterator
->release();
8953 dicttabsize
+= sizeof(struct mac_module_data_list
) +
8954 dents
* sizeof(struct mac_module_data_element
);
8959 continue; /* Skip everything else. */
8965 listtabsize
+= sizeof(struct mac_module_data_list
) +
8966 (nents
- 1) * sizeof(struct mac_module_data_element
);
8968 continue; /* skip anything else */
8970 strtabsize
+= key
->getLength() + 1;
8978 * Allocate and fill in the module data structures.
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
) {
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
));
8998 keyIterator
->reset();
9000 element
= &result
->data
[0];
9001 DPRINTF(("osdict: element %p\n", element
));
9002 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
9004 // Get the key's value and determine its type
9005 OSObject
* value
= dict
->getObject(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
);
9018 typeID
= OSTypeIDInst(value
);
9019 if (MACFObjectIsPrimitiveType(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
;
9029 struct mac_module_data_list
*arrayhd
;
9030 struct mac_module_data_element
*ele
;
9031 OSArray
*arrayObj
= OSDynamicCast(OSArray
, value
);
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
;
9038 DPRINTF(("osdict: arrayhd %p\n", arrayhd
));
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
));
9048 typeID
= OSTypeIDInst(value
);
9049 if (MACFObjectIsPrimitiveType(value
)) {
9050 if (arrayhd
->type
!= 0 &&
9051 arrayhd
->type
!= MAC_DATA_TYPE_PRIMITIVE
) {
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
)) {
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
9069 if (arrayhd
->type
!= 0 &&
9070 arrayhd
->type
!= MAC_DATA_TYPE_DICT
) {
9074 dictObj
= OSDynamicCast(OSDictionary
, value
);
9075 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
9076 if (!dictIterator
) {
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
));
9086 while ((dictkey
= OSDynamicCast(OSString
,
9087 dictIterator
->getNextObject()))) {
9089 OSObject
* dictvalue
= NULL
; // do not release
9091 dictvalue
= dictObj
->getObject(dictkey
);
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(),
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
));
9109 continue; /* Only handle primitive types here. */
9113 dictIterator
->release();
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
;
9126 continue; /* Skip everything else. */
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
;
9140 DPRINTF(("osdict: new strtab %p\n", strtab
));
9142 continue; /* skip anything else */
9146 DPRINTF(("result list @%p, key %p value %p\n",
9147 result
, result
->data
[0].key
, result
->data
[0].value
));
9149 if (keyIterator
) keyIterator
->release();
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
9157 *********************************************************************/
9159 MACFCopyModuleDataForKext(
9161 mach_msg_type_number_t
* datalen
)
9164 struct mac_module_data
* result
= NULL
;
9165 OSDictionary
* kextModuleData
= NULL
; // do not release
9166 vm_map_copy_t copy
= 0;
9168 kextModuleData
= OSDynamicCast(OSDictionary
,
9169 theKext
->getPropertyForHostArch("OSModuleData"));
9170 if (!kextModuleData
) {
9174 result
= MACFEncodeOSDictionary(kextModuleData
);
9178 *datalen
= module_data
->size
;
9181 return (void *)result
;
9183 #endif /* CONFIG_MACF_KEXT */