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
;
3953 alreadyLoaded
= true;
3954 result
= kOSReturnSuccess
;
3957 kOSKextLogDebugLevel
|
3958 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3959 "Kext %s is already loaded.",
3960 getIdentifierCString());
3964 if (!sLoadEnabled
) {
3966 kOSKextLogErrorLevel
|
3968 "Kext loading is disabled (attempt to load kext %s).",
3969 getIdentifierCString());
3970 result
= kOSKextReturnDisabled
;
3974 /* If we've pushed the next available load tag to the invalid value,
3975 * we can't load any more kexts.
3977 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
3979 kOSKextLogErrorLevel
|
3981 "Can't load kext %s - no more load tags to assign.",
3982 getIdentifierCString());
3983 result
= kOSKextReturnNoResources
;
3987 /* This is a bit of a hack, because we shouldn't be handling
3988 * personalities within the load function.
3990 if (!declaresExecutable()) {
3991 result
= kOSReturnSuccess
;
3995 /* Are we in safe boot?
3997 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
3999 kOSKextLogErrorLevel
|
4001 "Can't load kext %s - not loadable during safe boot.",
4002 getIdentifierCString());
4003 result
= kOSKextReturnBootLevel
;
4008 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
4010 getIdentifierCString());
4013 if (!sKxldContext
) {
4014 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
4015 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
4016 /* cputype */ 0, /* cpusubtype */ 0);
4019 kOSKextLogErrorLevel
|
4020 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4021 "Can't load kext %s - failed to create link context.",
4022 getIdentifierCString());
4023 result
= kOSKextReturnNoMemory
;
4028 /* We only need to resolve dependencies once for the whole graph, but
4029 * resolveDependencies will just return if there's no work to do, so it's
4030 * safe to call it more than once.
4032 if (!resolveDependencies()) {
4033 // xxx - check resolveDependencies() for log msg
4035 kOSKextLogErrorLevel
|
4036 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4037 "Can't load kext %s - failed to resolve library dependencies.",
4038 getIdentifierCString());
4039 result
= kOSKextReturnDependencies
;
4043 /* If we are excluding just the kext being loaded now (and not its
4044 * dependencies), drop the exclusion level to none so dependencies
4045 * start and/or add their personalities.
4047 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
4048 dependenciesStartOpt
= kOSKextExcludeNone
;
4051 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
4052 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
4055 /* Load the dependencies, recursively.
4057 count
= getNumDependencies();
4058 for (i
= 0; i
< count
; i
++) {
4059 OSKext
* dependency
= OSDynamicCast(OSKext
,
4060 dependencies
->getObject(i
));
4061 if (dependency
== NULL
) {
4063 kOSKextLogErrorLevel
|
4064 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4065 "Internal error loading kext %s; dependency disappeared.",
4066 getIdentifierCString());
4067 result
= kOSKextReturnInternalError
;
4071 /* Dependencies must be started accorting to the opt,
4072 * but not given the personality names of the main kext.
4074 result
= dependency
->load(dependenciesStartOpt
,
4075 dependenciesStartMatchingOpt
,
4076 /* personalityNames */ NULL
);
4077 if (result
!= KERN_SUCCESS
) {
4079 kOSKextLogErrorLevel
|
4080 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4081 "Dependency %s of kext %s failed to load.",
4082 dependency
->getIdentifierCString(),
4083 getIdentifierCString());
4085 OSKext::removeKext(dependency
,
4086 /* terminateService/removePersonalities */ true);
4087 result
= kOSKextReturnDependencyLoadError
;
4093 result
= loadExecutable();
4094 if (result
!= KERN_SUCCESS
) {
4098 flags
.loaded
= true;
4100 /* Add the kext to the list of loaded kexts and update the kmod_info
4101 * struct to point to that of the last loaded kext (which is the way
4102 * it's always been done, though I'd rather do them in order now).
4104 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
4105 sLoadedKexts
->setObject(this);
4107 /* Keep the kernel itself out of the kmod list.
4109 if (lastLoadedKext
== sKernelKext
) {
4110 lastLoadedKext
= NULL
;
4113 if (lastLoadedKext
) {
4114 kmod_info
->next
= lastLoadedKext
->kmod_info
;
4117 /* Make the global kmod list point at the just-loaded kext. Note that the
4118 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4119 * although we do report it in kextstat these days by using the newer
4120 * OSArray of loaded kexts, which does contain it.
4122 * (The OSKext object representing the kernel doesn't even have a kmod_info
4123 * struct, though I suppose we could stick a pointer to it from the
4124 * static struct in OSRuntime.cpp.)
4128 /* Save the list of loaded kexts in case we panic.
4130 clock_get_uptime(&last_loaded_timestamp
);
4131 OSKext::saveLoadedKextPanicList();
4135 if (declaresExecutable() && (startOpt
== kOSKextExcludeNone
)) {
4137 if (result
!= kOSReturnSuccess
) {
4139 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
4140 "Kext %s start failed (result 0x%x).",
4141 getIdentifierCString(), result
);
4142 result
= kOSKextReturnStartStopError
;
4146 /* If not excluding matching, send the personalities to the kernel.
4147 * This never affects the result of the load operation.
4148 * This is a bit of a hack, because we shouldn't be handling
4149 * personalities within the load function.
4151 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
4152 result
= sendPersonalitiesToCatalog(true, personalityNames
);
4156 /* More hack! If the kext doesn't declare an executable, even if we
4157 * "loaded" it, we have to remove any personalities naming it, or we'll
4158 * never see the registry go quiet. Errors here do not count for the
4159 * load operation itself.
4161 * Note that in every other regard it's perfectly ok for a kext to
4162 * not declare an executable and serve only as a package for personalities
4163 * naming another kext, so we do have to allow such kexts to be "loaded"
4164 * so that those other personalities get added & matched.
4166 if (!declaresExecutable()) {
4168 kOSKextLogStepLevel
| kOSKextLogLoadFlag
,
4169 "Kext %s has no executable; removing any personalities naming it.",
4170 getIdentifierCString());
4171 removePersonalitiesFromCatalog();
4174 if (result
!= kOSReturnSuccess
) {
4176 kOSKextLogErrorLevel
|
4178 "Kext %s failed to load (0x%x).",
4179 getIdentifierCString(), (int)result
);
4180 } else if (!alreadyLoaded
) {
4182 kOSKextLogProgressLevel
|
4185 getIdentifierCString());
4190 /*********************************************************************
4191 * called only by load()
4192 *********************************************************************/
4194 OSKext::loadExecutable()
4196 OSReturn result
= kOSReturnError
;
4197 kern_return_t kxldResult
;
4198 u_char
** kxlddeps
= NULL
; // must kfree
4199 uint32_t num_kxlddeps
= 0;
4200 uint32_t num_kmod_refs
= 0;
4201 u_char
* linkStateBytes
= NULL
; // do not free
4202 u_long linkStateLength
= 0;
4203 u_char
** linkStateBytesPtr
= NULL
; // do not free
4204 u_long
* linkStateLengthPtr
= NULL
; // do not free
4205 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
4206 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
4207 OSData
* theExecutable
= NULL
; // do not release
4208 OSString
* versString
= NULL
; // do not release
4209 const char * versCString
= NULL
; // do not free
4210 const char * string
= NULL
; // do not free
4213 /* We need the version string for a variety of bits below.
4215 versString
= OSDynamicCast(OSString
,
4216 getPropertyForHostArch(kCFBundleVersionKey
));
4220 versCString
= versString
->getCStringNoCopy();
4222 if (isKernelComponent()) {
4223 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
4224 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
4226 kOSKextLogErrorLevel
|
4228 "Kernel component %s has incorrect version %s; "
4230 getIdentifierCString(),
4231 versCString
, KERNEL6_VERSION
);
4232 result
= kOSKextReturnInternalError
;
4234 } else if (strcmp(versCString
, osrelease
)) {
4236 kOSKextLogErrorLevel
|
4238 "Kernel component %s has incorrect version %s; "
4240 getIdentifierCString(),
4241 versCString
, osrelease
);
4242 result
= kOSKextReturnInternalError
;
4248 if (isPrelinked()) {
4252 theExecutable
= getExecutable();
4253 if (!theExecutable
) {
4254 if (declaresExecutable()) {
4256 kOSKextLogErrorLevel
|
4258 "Can't load kext %s - executable is missing.",
4259 getIdentifierCString());
4260 result
= kOSKextReturnValidation
;
4266 if (isKernelComponent()) {
4267 num_kxlddeps
= 1; // the kernel itself
4269 num_kxlddeps
= getNumDependencies();
4271 if (!num_kxlddeps
) {
4273 kOSKextLogErrorLevel
|
4274 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4275 "Can't load kext %s - it has no library dependencies.",
4276 getIdentifierCString());
4279 kxlddeps
= (u_char
**)kalloc(num_kxlddeps
* sizeof(*kxlddeps
));
4282 kOSKextLogErrorLevel
|
4283 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4284 "Can't allocate link context to load kext %s.",
4285 getIdentifierCString());
4289 if (isKernelComponent()) {
4290 OSData
* kernelLinkState
= OSKext::getKernelLinkState();
4291 kxlddeps
[0] = (u_char
*)kernelLinkState
->getBytesNoCopy();
4292 } else for (i
= 0; i
< num_kxlddeps
; i
++) {
4293 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
4294 if (!dependency
->linkState
) {
4295 // xxx - maybe we should panic here
4297 kOSKextLogErrorLevel
|
4298 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4299 "Can't load kext %s - link state missing.",
4300 getIdentifierCString());
4303 kxlddeps
[i
] = (u_char
*)dependency
->linkState
->getBytesNoCopy();
4304 assert(kxlddeps
[i
]);
4307 /* We only need link state for a library kext.
4309 if (compatibleVersion
> -1 && (declaresExecutable() || isKernelComponent())) {
4310 linkStateBytesPtr
= &linkStateBytes
;
4311 linkStateLengthPtr
= &linkStateLength
;
4314 /* We only need the linked executable for a real kext.
4316 if (!isInterface()) {
4317 kxldHeaderPtr
= &kxld_header
;
4322 kOSKextLogExplicitLevel
|
4323 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4324 "Kext %s - calling kxld_link_file:\n"
4325 " kxld_context: %p\n"
4326 " executable: %p executable_length: %d\n"
4328 " kxld_dependencies: %p num_dependencies: %d\n"
4329 " kxld_header_ptr: %p kmod_info_ptr: %p\n"
4330 " link_state_ptr: %p link_state_length_ptr: %p",
4331 getIdentifierCString(), kxldContext
,
4332 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
4333 this, kxlddeps
, num_kxlddeps
,
4334 kxldHeaderPtr
, kernelKmodInfoPtr
,
4335 linkStateBytesPtr
, linkStateLengthPtr
);
4338 /* After this call, the linkedExecutable instance variable
4341 kxldResult
= kxld_link_file(sKxldContext
,
4342 (u_char
*)theExecutable
->getBytesNoCopy(),
4343 theExecutable
->getLength(),
4344 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
4345 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
,
4346 linkStateBytesPtr
, linkStateLengthPtr
,
4347 /* symbolFile */ NULL
, /* symbolFileSize */ NULL
);
4349 if (kxldResult
!= KERN_SUCCESS
) {
4350 // xxx - add kxldResult here?
4352 kOSKextLogErrorLevel
|
4354 "Can't load kext %s - link failed.",
4355 getIdentifierCString());
4356 result
= kOSKextReturnLinkError
;
4360 /* If we got a link state, wrap it in an OSData and keep it
4361 * around for later use linking other kexts that depend on this kext.
4363 if (linkStateBytes
&& linkStateLength
> 0) {
4364 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
4366 linkState
->setDeallocFunction(&osdata_kmem_free
);
4369 /* If this isn't an interface, We've written data & instructions into kernel
4370 * memory, so flush the data cache and invalidate the instruction cache.
4372 if (!isInterface()) {
4373 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
4374 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
4379 if (isInterface()) {
4381 /* Whip up a fake kmod_info entry for the interface kext.
4383 kmod_info
= (kmod_info_t
*)kalloc(sizeof(kmod_info_t
));
4385 result
= KERN_MEMORY_ERROR
;
4389 /* A pseudokext has almost nothing in its kmod_info struct.
4391 bzero(kmod_info
, sizeof(kmod_info_t
));
4393 kmod_info
->info_version
= KMOD_INFO_VERSION
;
4395 /* An interface kext doesn't have a linkedExecutable, so save a
4396 * copy of the UUID out of the original executable via copyUUID()
4397 * while we still have the original executable.
4399 interfaceUUID
= copyUUID();
4402 kmod_info
->id
= loadTag
= sNextLoadTag
++;
4403 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
4405 /* Stamp the bundle ID and version from the OSKext over anything
4406 * resident inside the kmod_info.
4408 string
= getIdentifierCString();
4409 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
4411 string
= versCString
;
4412 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
4414 /* Add the dependencies' kmod_info structs as kmod_references.
4416 num_kmod_refs
= getNumDependencies();
4417 if (num_kmod_refs
) {
4418 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc(
4419 num_kmod_refs
* sizeof(kmod_reference_t
));
4420 if (!kmod_info
->reference_list
) {
4421 result
= KERN_MEMORY_ERROR
;
4424 bzero(kmod_info
->reference_list
,
4425 num_kmod_refs
* sizeof(kmod_reference_t
));
4426 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
4427 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
4428 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
4429 ref
->info
= refKext
->kmod_info
;
4430 ref
->info
->reference_count
++;
4432 if (refIndex
+ 1 < num_kmod_refs
) {
4433 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
4438 if (!isInterface() && linkedExecutable
) {
4440 kOSKextLogProgressLevel
|
4442 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4444 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
4445 (unsigned long)kmod_info
->address
,
4446 (unsigned)kmod_info
->id
);
4449 result
= setVMProtections();
4450 if (result
!= KERN_SUCCESS
) {
4454 result
= kOSReturnSuccess
;
4457 if (kxlddeps
) kfree(kxlddeps
, (num_kxlddeps
* sizeof(void *)));
4459 /* We no longer need the unrelocated executable (which the linker
4460 * has altered anyhow).
4462 setExecutable(NULL
);
4464 if (result
!= kOSReturnSuccess
) {
4466 kOSKextLogErrorLevel
|
4468 "Failed to load executable for kext %s.",
4469 getIdentifierCString());
4471 if (kmod_info
&& kmod_info
->reference_list
) {
4472 kfree(kmod_info
->reference_list
,
4473 num_kmod_refs
* sizeof(kmod_reference_t
));
4475 if (isInterface()) {
4476 kfree(kmod_info
, sizeof(kmod_info_t
));
4479 if (linkedExecutable
) {
4480 linkedExecutable
->release();
4481 linkedExecutable
= NULL
;
4488 /*********************************************************************
4489 * xxx - initWithPrelinkedInfoDict doesn't use this
4490 *********************************************************************/
4492 OSKext::setLinkedExecutable(OSData
* anExecutable
)
4494 if (linkedExecutable
) {
4495 panic("Attempt to set linked executable on kext "
4496 "that already has one (%s).\n",
4497 getIdentifierCString());
4499 linkedExecutable
= anExecutable
;
4500 linkedExecutable
->retain();
4504 /*********************************************************************
4505 * called only by loadExecutable()
4506 *********************************************************************/
4508 OSKext::setVMProtections(void)
4510 vm_map_t kext_map
= NULL
;
4511 kernel_segment_command_t
* seg
= NULL
;
4512 vm_map_offset_t start
= 0;
4513 vm_map_offset_t end
= 0;
4514 OSReturn result
= kOSReturnError
;
4516 if (!kmod_info
->address
&& !kmod_info
->size
) {
4517 result
= kOSReturnSuccess
;
4521 /* Get the kext's vm map */
4522 kext_map
= kext_get_vm_map(kmod_info
);
4524 result
= KERN_MEMORY_ERROR
;
4528 /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
4529 * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
4530 * so the vm_map_protect calls below fail
4531 * I believe this happens in the call to vm_map_enter in kmem_init but I
4534 /* Protect the headers as read-only; they do not need to be wired */
4535 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4536 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
4537 if (result
!= KERN_SUCCESS
) {
4541 /* Set the VM protections and wire down each of the segments */
4542 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
4544 start
= round_page(seg
->vmaddr
);
4545 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
4547 result
= vm_map_protect(kext_map
, start
, end
, seg
->maxprot
, TRUE
);
4548 if (result
!= KERN_SUCCESS
) {
4550 kOSKextLogErrorLevel
|
4552 "Kext %s failed to set maximum VM protections "
4553 "for segment %s - 0x%x.",
4554 getIdentifierCString(), seg
->segname
, (int)result
);
4558 result
= vm_map_protect(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4559 if (result
!= KERN_SUCCESS
) {
4561 kOSKextLogErrorLevel
|
4563 "Kext %s failed to set initial VM protections "
4564 "for segment %s - 0x%x.",
4565 getIdentifierCString(), seg
->segname
, (int)result
);
4569 result
= vm_map_wire(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4570 if (result
!= KERN_SUCCESS
) {
4574 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
4581 /*********************************************************************
4582 *********************************************************************/
4584 OSKext::validateKextMapping(bool startFlag
)
4586 OSReturn result
= kOSReturnError
;
4587 const char * whichOp
= startFlag
? "start" : "stop";
4588 kern_return_t kern_result
= 0;
4589 vm_map_t kext_map
= NULL
;
4590 mach_vm_address_t address
= 0;
4591 mach_vm_size_t size
= 0;
4593 mach_msg_type_number_t count
;
4594 vm_region_submap_short_info_data_64_t info
;
4596 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
4597 bzero(&info
, sizeof(info
));
4599 // xxx - do we need a distinct OSReturn value for these or is "bad data"
4600 // xxx - sufficient?
4602 /* Verify that the kmod_info and start/stop pointers are non-NULL.
4606 kOSKextLogErrorLevel
|
4608 "Kext %s - NULL kmod_info pointer.",
4609 getIdentifierCString());
4610 result
= kOSKextReturnBadData
;
4615 address
= (mach_vm_address_t
)kmod_info
->start
;
4617 address
= (mach_vm_address_t
)kmod_info
->stop
;
4622 kOSKextLogErrorLevel
|
4624 "Kext %s - NULL module %s pointer.",
4625 getIdentifierCString(), whichOp
);
4626 result
= kOSKextReturnBadData
;
4630 kext_map
= kext_get_vm_map(kmod_info
);
4631 depth
= (kernel_map
== kext_map
) ? 1 : 2;
4633 /* Verify that the start/stop function lies within the kext's address range.
4635 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
4636 kmod_info
->address
+ kmod_info
->size
<= address
)
4639 kOSKextLogErrorLevel
|
4641 "Kext %s module %s pointer is outside of kext range "
4642 "(%s %p - kext at %p-%p)..",
4643 getIdentifierCString(),
4647 (void *)kmod_info
->address
,
4648 (void *)(kmod_info
->address
+ kmod_info
->size
));
4649 result
= kOSKextReturnBadData
;
4653 /* Only do these checks before calling the start function;
4654 * If anything goes wrong with the mapping while the kext is running,
4655 * we'll likely have panicked well before any attempt to stop the kext.
4659 /* Verify that the start/stop function is executable.
4661 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
4662 (vm_region_recurse_info_t
)&info
, &count
);
4663 if (kern_result
!= KERN_SUCCESS
) {
4665 kOSKextLogErrorLevel
|
4667 "Kext %s - bad %s pointer %p.",
4668 getIdentifierCString(),
4669 whichOp
, (void *)address
);
4670 result
= kOSKextReturnBadData
;
4674 if (!(info
.protection
& VM_PROT_EXECUTE
)) {
4676 kOSKextLogErrorLevel
|
4678 "Kext %s - memory region containing module %s function "
4679 "is not executable.",
4680 getIdentifierCString(), whichOp
);
4681 result
= kOSKextReturnBadData
;
4685 /* Verify that the kext is backed by physical memory.
4687 for (address
= kmod_info
->address
;
4688 address
< round_page(kmod_info
->address
+ kmod_info
->size
);
4689 address
+= PAGE_SIZE
)
4691 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
4693 kOSKextLogErrorLevel
|
4695 "Kext %s - page %p is not backed by physical memory.",
4696 getIdentifierCString(),
4698 result
= kOSKextReturnBadData
;
4704 result
= kOSReturnSuccess
;
4709 /*********************************************************************
4710 *********************************************************************/
4712 OSKext::start(bool startDependenciesFlag
)
4714 OSReturn result
= kOSReturnError
;
4715 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
4716 unsigned int i
, count
;
4717 void * kmodStartData
= NULL
; // special handling needed
4718 #if CONFIG_MACF_KEXT
4719 mach_msg_type_number_t kmodStartDataCount
= 0;
4720 #endif /* CONFIG_MACF_KEXT */
4722 if (isStarted() || isInterface() || isKernelComponent()) {
4723 result
= kOSReturnSuccess
;
4729 kOSKextLogErrorLevel
|
4731 "Attempt to start nonloaded kext %s.",
4732 getIdentifierCString());
4733 result
= kOSKextReturnInvalidArgument
;
4737 if (!sLoadEnabled
) {
4739 kOSKextLogErrorLevel
|
4741 "Kext loading is disabled (attempt to start kext %s).",
4742 getIdentifierCString());
4743 result
= kOSKextReturnDisabled
;
4747 result
= validateKextMapping(/* start? */ true);
4748 if (result
!= kOSReturnSuccess
) {
4752 startfunc
= kmod_info
->start
;
4754 count
= getNumDependencies();
4755 for (i
= 0; i
< count
; i
++) {
4756 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
4757 if (dependency
== NULL
) {
4759 kOSKextLogErrorLevel
|
4761 "Kext %s start - internal error, dependency disappeared.",
4762 getIdentifierCString());
4765 if (!dependency
->isStarted()) {
4766 if (startDependenciesFlag
) {
4767 OSReturn dependencyResult
=
4768 dependency
->start(startDependenciesFlag
);
4769 if (dependencyResult
!= KERN_SUCCESS
) {
4771 kOSKextLogErrorLevel
|
4773 "Kext %s start - dependency %s failed to start (error 0x%x).",
4774 getIdentifierCString(),
4775 dependency
->getIdentifierCString(),
4781 kOSKextLogErrorLevel
|
4783 "Not starting %s - dependency %s not started yet.",
4784 getIdentifierCString(),
4785 dependency
->getIdentifierCString());
4786 result
= kOSKextReturnStartStopError
; // xxx - make new return?
4792 #if CONFIG_MACF_KEXT
4793 /* See if the kext has any MAC framework module data in its plist.
4794 * This is passed in as arg #2 of the kext's start routine,
4795 * which is otherwise reserved for any other kext.
4797 kmodStartData
= MACFCopyModuleDataForKext(this, &kmodStartDataCount
);
4798 #endif /* CONFIG_MACF_KEXT */
4801 kOSKextLogDetailLevel
|
4803 "Kext %s calling module start function.",
4804 getIdentifierCString());
4808 #if !__i386__ && !__ppc__
4809 result
= OSRuntimeInitializeCPP(kmod_info
, NULL
);
4810 if (result
== KERN_SUCCESS
) {
4813 result
= startfunc(kmod_info
, kmodStartData
);
4815 #if !__i386__ && !__ppc__
4816 if (result
!= KERN_SUCCESS
) {
4817 (void) OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4824 /* On success overlap the setting of started/starting. On failure just
4827 if (result
== KERN_SUCCESS
) {
4830 // xxx - log start error from kernel?
4832 kOSKextLogProgressLevel
|
4834 "Kext %s is now started.",
4835 getIdentifierCString());
4837 invokeOrCancelRequestCallbacks(
4838 /* result not actually used */ kOSKextReturnStartStopError
,
4839 /* invokeFlag */ false);
4841 kOSKextLogProgressLevel
|
4843 "Kext %s did not start (return code 0x%x).",
4844 getIdentifierCString(), result
);
4848 #if CONFIG_MACF_KEXT
4849 /* Free the module data for a MAC framework kext. When we start using
4850 * param #2 we'll have to distinguish and free/release appropriately.
4852 * xxx - I'm pretty sure the old codepath freed the data and that it's
4853 * xxx - up to the kext to copy it.
4855 if (kmodStartData
) {
4856 kmem_free(kernel_map
, (vm_offset_t
)kmodStartData
, kmodStartDataCount
);
4858 #endif /* CONFIG_MACF_KEXT */
4863 /*********************************************************************
4864 *********************************************************************/
4866 bool OSKext::canUnloadKextWithIdentifier(
4867 OSString
* kextIdentifier
,
4868 bool checkClassesFlag
)
4870 bool result
= false;
4871 OSKext
* aKext
= NULL
; // do not release
4873 IORecursiveLockLock(sKextLock
);
4875 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4878 goto finish
; // can't unload what's not loaded
4881 if (aKext
->isLoaded()) {
4882 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
4885 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
4893 IORecursiveLockUnlock(sKextLock
);
4897 /*********************************************************************
4898 *********************************************************************/
4902 OSReturn result
= kOSReturnError
;
4903 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
4905 if (!isStarted() || isInterface()) {
4906 result
= kOSReturnSuccess
;
4912 kOSKextLogErrorLevel
|
4914 "Attempt to stop nonloaded kext %s.",
4915 getIdentifierCString());
4916 result
= kOSKextReturnInvalidArgument
;
4920 /* Refuse to stop if we have clients or instances. It is up to
4921 * the caller to make sure those aren't true.
4923 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4925 kOSKextLogErrorLevel
|
4927 "Kext %s - C++ instances; can't stop.",
4928 getIdentifierCString());
4929 result
= kOSKextReturnInUse
;
4933 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4936 kOSKextLogErrorLevel
|
4938 "Kext %s - has references (linkage or tracking object); "
4940 getIdentifierCString());
4941 result
= kOSKextReturnInUse
;
4945 /* Note: If validateKextMapping fails on the stop & unload path,
4946 * we are in serious trouble and a kernel panic is likely whether
4947 * we stop & unload the kext or not.
4949 result
= validateKextMapping(/* start? */ false);
4950 if (result
!= kOSReturnSuccess
) {
4954 /* Save the list of loaded kexts in case we panic.
4956 OSKext::saveUnloadedKextPanicList(this);
4958 stopfunc
= kmod_info
->stop
;
4961 kOSKextLogDetailLevel
|
4963 "Kext %s calling module stop function.",
4964 getIdentifierCString());
4968 result
= stopfunc(kmod_info
, /* userData */ NULL
);
4969 #if !__i386__ && !__ppc__
4970 if (result
== KERN_SUCCESS
) {
4971 result
= OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4977 if (result
== KERN_SUCCESS
) {
4981 kOSKextLogDetailLevel
|
4983 "Kext %s is now stopped and ready to unload.",
4984 getIdentifierCString());
4987 kOSKextLogErrorLevel
|
4989 "Kext %s did not stop (return code 0x%x).",
4990 getIdentifierCString(), result
);
4991 result
= kOSKextReturnStartStopError
;
4999 /*********************************************************************
5000 *********************************************************************/
5002 OSKext::unload(void)
5004 OSReturn result
= kOSReturnError
;
5006 uint32_t num_kmod_refs
= 0;
5008 if (!sUnloadEnabled
) {
5010 kOSKextLogErrorLevel
|
5012 "Kext unloading is disabled (%s).",
5013 this->getIdentifierCString());
5015 result
= kOSKextReturnDisabled
;
5019 /* Refuse to unload if we have clients or instances. It is up to
5020 * the caller to make sure those aren't true.
5022 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5023 // xxx - Don't log under errors? this is more of an info thing
5025 kOSKextLogErrorLevel
|
5026 kOSKextLogKextBookkeepingFlag
,
5027 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5028 getIdentifierCString());
5029 result
= kOSKextReturnInUse
;
5034 if (hasOSMetaClassInstances()) {
5036 kOSKextLogErrorLevel
|
5037 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5038 "Can't unload kext %s; classes have instances:",
5039 getIdentifierCString());
5040 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
5041 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
5042 result
= kOSKextReturnInUse
;
5047 result
= kOSReturnSuccess
;
5051 if (isKernelComponent()) {
5052 result
= kOSKextReturnInvalidArgument
;
5056 /* Note that the kext is unloading before running any code that
5057 * might be in the kext (request callbacks, module stop function).
5058 * We will deny certain requests made against a kext in the process
5061 flags
.unloading
= 1;
5065 if (result
!= KERN_SUCCESS
) {
5067 kOSKextLogErrorLevel
|
5069 "Kext %s can't unload - module stop returned 0x%x.",
5070 getIdentifierCString(), (unsigned)result
);
5071 result
= kOSKextReturnStartStopError
;
5077 kOSKextLogProgressLevel
|
5079 "Kext %s unloading.",
5080 getIdentifierCString());
5082 /* Even if we don't call the stop function, we want to be sure we
5083 * have no OSMetaClass references before unloading the kext executable
5084 * from memory. OSMetaClasses may have pointers into the kext executable
5085 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5088 metaClasses
->flushCollection();
5091 /* Remove the kext from the list of loaded kexts, patch the gap
5092 * in the kmod_info_t linked list, and reset "kmod" to point to the
5093 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5095 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
5096 if (index
!= (unsigned int)-1) {
5098 sLoadedKexts
->removeObject(index
);
5100 OSKext
* nextKext
= OSDynamicCast(OSKext
,
5101 sLoadedKexts
->getObject(index
));
5105 OSKext
* gapKext
= OSDynamicCast(OSKext
,
5106 sLoadedKexts
->getObject(index
- 1));
5108 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
5110 } else /* index == 0 */ {
5111 nextKext
->kmod_info
->next
= NULL
;
5115 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5116 if (lastKext
&& lastKext
!= sKernelKext
) {
5117 kmod
= lastKext
->kmod_info
;
5119 kmod
= NULL
; // clear the global kmod variable
5123 /* Clear out the kmod references that we're keeping for compatibility
5124 * with current panic backtrace code & kgmacros.
5125 * xxx - will want to update those bits sometime and remove this.
5127 num_kmod_refs
= getNumDependencies();
5128 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
5129 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
5130 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
5131 ref
->info
->reference_count
--;
5133 kfree(kmod_info
->reference_list
,
5134 num_kmod_refs
* sizeof(kmod_reference_t
));
5137 /* If we have a linked executable, release & clear it, and then
5138 * unwire & deallocate the buffer the OSData wrapped.
5140 if (linkedExecutable
) {
5143 /* linkedExecutable is just a wrapper for the executable and doesn't
5146 linkedExecutable
->release();
5147 linkedExecutable
= NULL
;
5150 kOSKextLogProgressLevel
|
5152 "Kext %s unwiring and unmapping linked executable.",
5153 getIdentifierCString());
5155 kext_map
= kext_get_vm_map(kmod_info
);
5157 // xxx - do we have to do this before freeing? Why can't we just free it?
5158 // xxx - we should be able to set a dealloc func on the linkedExecutable
5159 result
= vm_map_unwire(kext_map
,
5160 kmod_info
->address
+ kmod_info
->hdr_size
,
5161 kmod_info
->address
+ kmod_info
->size
, FALSE
);
5162 if (result
== KERN_SUCCESS
) {
5163 kext_free(kmod_info
->address
, kmod_info
->size
);
5168 /* An interface kext has a fake kmod_info that was allocated,
5169 * so we have to free it.
5171 if (isInterface()) {
5172 kfree(kmod_info
, sizeof(kmod_info_t
));
5177 flags
.loaded
= false;
5178 flushDependencies();
5181 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5182 "Kext %s unloaded.", getIdentifierCString());
5185 OSKext::saveLoadedKextPanicList();
5187 flags
.unloading
= 0;
5191 /*********************************************************************
5192 *********************************************************************/
5194 _OSKextConsiderDestroyingLinkContext(
5195 __unused thread_call_param_t p0
,
5196 __unused thread_call_param_t p1
)
5198 /* Once both recursive locks are taken in correct order, we shouldn't
5199 * have to worry about further recursive lock takes.
5201 IORecursiveLockLock(sKextLock
);
5202 IORecursiveLockLock(sKextInnerLock
);
5204 /* The first time we destroy the kxldContext is in the first
5205 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5206 * before calling this function. Thereafter any call to this function
5207 * will actually destroy the context.
5209 if (sConsiderUnloadsCalled
&& sKxldContext
) {
5210 kxld_destroy_context(sKxldContext
);
5211 sKxldContext
= NULL
;
5214 /* Free the thread_call that was allocated to execute this function.
5216 if (sDestroyLinkContextThread
) {
5217 if (!thread_call_free(sDestroyLinkContextThread
)) {
5218 OSKextLog(/* kext */ NULL
,
5219 kOSKextLogErrorLevel
|
5220 kOSKextLogGeneralFlag
,
5221 "thread_call_free() failed for kext link context.");
5223 sDestroyLinkContextThread
= 0;
5226 IORecursiveLockUnlock(sKextInnerLock
);
5227 IORecursiveLockUnlock(sKextLock
);
5232 /*********************************************************************
5233 * Destroying the kxldContext requires checking variables under both
5234 * sKextInnerLock and sKextLock, so we do it on a separate thread
5235 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5236 * call relationship.
5238 * Do not call any function that takes sKextLock here! This function
5239 * can be invoked with sKextInnerLock, and the two must always
5240 * be taken in the order: sKextLock -> sKextInnerLock.
5241 *********************************************************************/
5244 OSKext::considerDestroyingLinkContext(void)
5246 IORecursiveLockLock(sKextInnerLock
);
5248 /* If we have already queued a thread to destroy the link context,
5249 * don't bother resetting; that thread will take care of it.
5251 if (sDestroyLinkContextThread
) {
5255 /* The function to be invoked in the thread will deallocate
5256 * this thread_call, so don't share it around.
5258 sDestroyLinkContextThread
= thread_call_allocate(
5259 &_OSKextConsiderDestroyingLinkContext
, 0);
5260 if (!sDestroyLinkContextThread
) {
5261 OSKextLog(/* kext */ NULL
,
5262 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
5263 "Can't create thread to destroy kext link context.");
5267 thread_call_enter(sDestroyLinkContextThread
);
5270 IORecursiveLockUnlock(sKextInnerLock
);
5274 /*********************************************************************
5275 *********************************************************************/
5277 OSKext::getKernelLinkState()
5279 kern_return_t kxldResult
;
5280 u_char
* kernel
= NULL
;
5281 size_t kernelLength
;
5282 u_char
* linkStateBytes
= NULL
;
5283 u_long linkStateLength
;
5284 OSData
* linkState
= NULL
;
5286 if (sKernelKext
&& sKernelKext
->linkState
) {
5290 kernel
= (u_char
*)&_mh_execute_header
;
5291 kernelLength
= getlastaddr() - (vm_offset_t
)kernel
;
5293 kxldResult
= kxld_link_file(sKxldContext
,
5296 kOSKextKernelIdentifier
,
5297 /* callbackData */ NULL
,
5298 /* dependencies */ NULL
,
5299 /* numDependencies */ 0,
5300 /* linkedObjectOut */ NULL
,
5301 /* kmod_info_kern out */ NULL
,
5304 /* symbolFile */ NULL
,
5305 /* symbolFileSize */ NULL
);
5307 panic("Can't generate kernel link state; no kexts can be loaded.");
5311 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
5312 linkState
->setDeallocFunction(&osdata_kmem_free
);
5313 sKernelKext
->linkState
= linkState
;
5316 return sKernelKext
->linkState
;
5320 #pragma mark Autounload
5322 /*********************************************************************
5323 * This is a static method because the kext will be deallocated if it
5325 *********************************************************************/
5327 OSKext::autounloadKext(OSKext
* aKext
)
5329 OSReturn result
= kOSKextReturnInUse
;
5331 /* Check for external references to this kext (usu. dependents),
5332 * instances of defined classes (or classes derived from them),
5333 * outstanding requests.
5335 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
5336 !aKext
->flags
.autounloadEnabled
||
5337 aKext
->isKernelComponent()) {
5342 /* Skip a delay-autounload kext, once.
5344 if (aKext
->flags
.delayAutounload
) {
5346 kOSKextLogProgressLevel
|
5347 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5348 "Kext %s has delayed autounload set; skipping and clearing flag.",
5349 aKext
->getIdentifierCString());
5350 aKext
->flags
.delayAutounload
= 0;
5354 if (aKext
->hasOSMetaClassInstances() ||
5355 aKext
->countRequestCallbacks()) {
5359 result
= OSKext::removeKext(aKext
);
5366 /*********************************************************************
5367 *********************************************************************/
5369 _OSKextConsiderUnloads(
5370 __unused thread_call_param_t p0
,
5371 __unused thread_call_param_t p1
)
5373 bool didUnload
= false;
5374 unsigned int count
, i
;
5376 /* Once both recursive locks are taken in correct order, we shouldn't
5377 * have to worry about further recursive lock takes.
5379 IORecursiveLockLock(sKextLock
);
5380 IORecursiveLockLock(sKextInnerLock
);
5382 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
5384 /* If the system is powering down, don't try to unload anything.
5390 OSKextLog(/* kext */ NULL
,
5391 kOSKextLogProgressLevel
|
5393 "Checking for unused kexts to autounload.");
5396 * Remove any request callbacks marked as stale,
5397 * and mark as stale any currently in flight.
5399 count
= sRequestCallbackRecords
->getCount();
5403 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
5404 sRequestCallbackRecords
->getObject(i
));
5405 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
5406 callbackRecord
->getObject(kKextRequestStaleKey
));
5408 if (stale
&& stale
->isTrue()) {
5409 OSKext::invokeRequestCallback(callbackRecord
,
5410 kOSKextReturnTimeout
);
5412 callbackRecord
->setObject(kKextRequestStaleKey
,
5419 * Make multiple passes through the array of loaded kexts until
5420 * we don't unload any. This handles unwinding of dependency
5421 * chains. We have to go *backwards* through the array because
5422 * kexts are removed from it when unloaded, and we cannot make
5423 * a copy or we'll mess up the retain counts we rely on to
5424 * check whether a kext will unload. If only we could have
5425 * nonretaining collections like CF has....
5430 count
= sLoadedKexts
->getCount();
5434 OSKext
* thisKext
= OSDynamicCast(OSKext
,
5435 sLoadedKexts
->getObject(i
));
5436 didUnload
= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
5439 } while (didUnload
);
5442 sConsiderUnloadsPending
= false;
5443 sConsiderUnloadsExecuted
= true;
5445 (void) OSKext::considerRebuildOfPrelinkedKernel();
5447 IORecursiveLockUnlock(sKextInnerLock
);
5448 IORecursiveLockUnlock(sKextLock
);
5453 /*********************************************************************
5454 * Do not call any function that takes sKextLock here!
5455 *********************************************************************/
5456 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
5460 IORecursiveLockLock(sKextInnerLock
);
5462 if (!sUnloadCallout
) {
5463 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, 0);
5466 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
5470 thread_call_cancel(sUnloadCallout
);
5471 if (OSKext::getAutounloadEnabled() && !sSystemSleep
) {
5472 clock_interval_to_deadline(sConsiderUnloadDelay
,
5473 1000 * 1000 * 1000, &when
);
5475 OSKextLog(/* kext */ NULL
,
5476 kOSKextLogProgressLevel
|
5478 "%scheduling %sscan for unused kexts in %lu seconds.",
5479 sConsiderUnloadsPending
? "Res" : "S",
5480 sConsiderUnloadsCalled
? "" : "initial ",
5481 (unsigned long)sConsiderUnloadDelay
);
5483 sConsiderUnloadsPending
= true;
5484 thread_call_enter_delayed(sUnloadCallout
, when
);
5488 /* The kxld context should be reused throughout boot. We mark the end of
5489 * period as the first time considerUnloads() is called, and we destroy
5490 * the first kxld context in that function. Afterwards, it will be
5491 * destroyed in flushNonloadedKexts.
5493 if (!sConsiderUnloadsCalled
) {
5494 sConsiderUnloadsCalled
= true;
5495 OSKext::considerDestroyingLinkContext();
5498 IORecursiveLockUnlock(sKextInnerLock
);
5502 /*********************************************************************
5503 * Do not call any function that takes sKextLock here!
5504 *********************************************************************/
5507 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
)
5509 IORecursiveLockLock(sKextInnerLock
);
5511 /* If the system is going to sleep, cancel the reaper thread timer,
5512 * and note that we're in a sleep state in case it just fired but hasn't
5513 * taken the lock yet. If we are coming back from sleep, just
5514 * clear the sleep flag; IOService's normal operation will cause
5515 * unloads to be considered soon enough.
5517 if (messageType
== kIOMessageSystemWillSleep
) {
5518 if (sUnloadCallout
) {
5519 thread_call_cancel(sUnloadCallout
);
5521 sSystemSleep
= true;
5522 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
5523 sSystemSleep
= false;
5525 IORecursiveLockUnlock(sKextInnerLock
);
5527 return kIOReturnSuccess
;
5534 #pragma mark Prelinked Kernel
5536 /*********************************************************************
5537 * Do not access sConsiderUnloads... variables other than
5538 * sConsiderUnloadsExecuted in this function. They are guarded by a
5540 *********************************************************************/
5543 OSKext::considerRebuildOfPrelinkedKernel(void)
5545 OSReturn checkResult
= kOSReturnError
;
5546 static bool requestedPrelink
= false;
5547 OSDictionary
* prelinkRequest
= NULL
; // must release
5549 IORecursiveLockLock(sKextLock
);
5551 if (!sDeferredLoadSucceeded
|| !sConsiderUnloadsExecuted
||
5552 sSafeBoot
|| requestedPrelink
)
5557 OSKextLog(/* kext */ NULL
,
5558 kOSKextLogProgressLevel
|
5559 kOSKextLogArchiveFlag
,
5560 "Requesting build of prelinked kernel.");
5562 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
5564 if (checkResult
!= kOSReturnSuccess
) {
5568 if (!sKernelRequests
->setObject(prelinkRequest
)) {
5573 requestedPrelink
= true;
5576 IORecursiveLockUnlock(sKextLock
);
5577 OSSafeRelease(prelinkRequest
);
5582 #pragma mark Dependencies
5584 /*********************************************************************
5585 *********************************************************************/
5587 OSKext::resolveDependencies(
5588 OSArray
* loopStack
)
5590 bool result
= false;
5591 OSArray
* localLoopStack
= NULL
; // must release
5592 bool addedToLoopStack
= false;
5593 OSDictionary
* libraries
= NULL
; // do not release
5594 OSCollectionIterator
* libraryIterator
= NULL
; // must release
5595 OSString
* libraryID
= NULL
; // do not release
5596 OSString
* infoString
= NULL
; // do not release
5597 OSString
* readableString
= NULL
; // do not release
5598 OSKext
* libraryKext
= NULL
; // do not release
5599 bool hasRawKernelDependency
= false;
5600 bool hasKernelDependency
= false;
5601 bool hasKPIDependency
= false;
5602 bool hasPrivateKPIDependency
= false;
5605 /* A kernel component will automatically have this flag set,
5606 * and a loaded kext should also have it set (as should all its
5607 * loaded dependencies).
5609 if (flags
.hasAllDependencies
) {
5614 /* Check for loops in the dependency graph.
5617 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
5619 kOSKextLogErrorLevel
|
5620 kOSKextLogDependenciesFlag
,
5621 "Kext %s has a dependency loop; can't resolve dependencies.",
5622 getIdentifierCString());
5627 kOSKextLogStepLevel
|
5628 kOSKextLogDependenciesFlag
,
5629 "Kext %s resolving dependencies.",
5630 getIdentifierCString());
5632 loopStack
= OSArray::withCapacity(6); // any small capacity will do
5635 kOSKextLogErrorLevel
|
5636 kOSKextLogDependenciesFlag
,
5637 "Kext %s can't create bookkeeping stack to resolve dependencies.",
5638 getIdentifierCString());
5641 localLoopStack
= loopStack
;
5643 if (!loopStack
->setObject(this)) {
5645 kOSKextLogErrorLevel
|
5646 kOSKextLogDependenciesFlag
,
5647 "Kext %s - internal error resolving dependencies.",
5648 getIdentifierCString());
5651 addedToLoopStack
= true;
5653 /* Purge any existing kexts in the dependency list and start over.
5655 flushDependencies();
5658 kOSKextLogErrorLevel
|
5659 kOSKextLogDependenciesFlag
,
5660 "Kext %s - internal error resolving dependencies.",
5661 getIdentifierCString());
5664 libraries
= OSDynamicCast(OSDictionary
,
5665 getPropertyForHostArch(kOSBundleLibrariesKey
));
5666 if (libraries
== NULL
|| libraries
->getCount() == 0) {
5668 kOSKextLogErrorLevel
|
5669 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5670 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
5671 getIdentifierCString(), kOSBundleLibrariesKey
);
5675 /* Make a new array to hold the dependencies (flush freed the old one).
5677 dependencies
= OSArray::withCapacity(libraries
->getCount());
5678 if (!dependencies
) {
5680 kOSKextLogErrorLevel
|
5681 kOSKextLogDependenciesFlag
,
5682 "Kext %s - can't allocate dependencies array.",
5683 getIdentifierCString());
5687 // xxx - compat: We used to add an implicit dependency on kernel 6.0
5688 // xxx - compat: if none were declared.
5690 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
5691 if (!libraryIterator
) {
5693 kOSKextLogErrorLevel
|
5694 kOSKextLogDependenciesFlag
,
5695 "Kext %s - can't allocate dependencies iterator.",
5696 getIdentifierCString());
5700 while ((libraryID
= OSDynamicCast(OSString
,
5701 libraryIterator
->getNextObject()))) {
5703 const char * library_id
= libraryID
->getCStringNoCopy();
5705 OSString
* libraryVersion
= OSDynamicCast(OSString
,
5706 libraries
->getObject(libraryID
));
5707 if (libraryVersion
== NULL
) {
5709 kOSKextLogErrorLevel
|
5710 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5711 "Kext %s - illegal type in OSBundleLibraries.",
5712 getIdentifierCString());
5716 OSKextVersion libraryVers
=
5717 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
5718 if (libraryVers
== -1) {
5720 kOSKextLogErrorLevel
|
5721 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5722 "Kext %s - invalid library version %s.",
5723 getIdentifierCString(),
5724 libraryVersion
->getCStringNoCopy());
5728 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
5729 if (libraryKext
== NULL
) {
5731 kOSKextLogErrorLevel
|
5732 kOSKextLogDependenciesFlag
,
5733 "Kext %s - library kext %s not found.",
5734 getIdentifierCString(), library_id
);
5738 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
5740 kOSKextLogErrorLevel
|
5741 kOSKextLogDependenciesFlag
,
5742 "Kext %s - library kext %s not compatible "
5743 "with requested version %s.",
5744 getIdentifierCString(), library_id
,
5745 libraryVersion
->getCStringNoCopy());
5749 if (!libraryKext
->resolveDependencies(loopStack
)) {
5753 /* Add the library directly only if it has an executable to link.
5754 * Otherwise it's just used to collect other dependencies, so put
5755 * *its* dependencies on the list for this kext.
5757 // xxx - We are losing info here; would like to make fake entries or
5758 // xxx - keep these in the dependency graph for loaded kexts.
5759 // xxx - I really want to make kernel components not a special case!
5760 if (libraryKext
->declaresExecutable() ||
5761 libraryKext
->isInterface()) {
5763 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
5764 dependencies
->setObject(libraryKext
);
5767 kOSKextLogDetailLevel
|
5768 kOSKextLogDependenciesFlag
,
5769 "Kext %s added dependency %s.",
5770 getIdentifierCString(),
5771 libraryKext
->getIdentifierCString());
5774 int numLibDependencies
= libraryKext
->getNumDependencies();
5775 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
5778 if (numLibDependencies
) {
5779 // xxx - this msg level should be 1 lower than the per-kext one
5781 kOSKextLogDetailLevel
|
5782 kOSKextLogDependenciesFlag
,
5783 "Kext %s pulling %d dependencies from codeless library %s.",
5784 getIdentifierCString(),
5786 libraryKext
->getIdentifierCString());
5788 for (index
= 0; index
< numLibDependencies
; index
++) {
5789 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
5790 libraryDependencies
->getObject(index
));
5791 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
5792 dependencies
->setObject(thisLibDependency
);
5794 kOSKextLogDetailLevel
|
5795 kOSKextLogDependenciesFlag
,
5796 "Kext %s added dependency %s from codeless library %s.",
5797 getIdentifierCString(),
5798 thisLibDependency
->getIdentifierCString(),
5799 libraryKext
->getIdentifierCString());
5804 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
5805 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
)-1)) {
5807 hasRawKernelDependency
= true;
5808 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
5809 hasKernelDependency
= true;
5810 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
5811 hasKPIDependency
= true;
5812 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
)-1)) {
5813 hasPrivateKPIDependency
= true;
5819 if (hasRawKernelDependency
|| hasKernelDependency
) {
5821 kOSKextLogErrorLevel
|
5822 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5823 "Error - kext %s declares %s dependencies. "
5824 "Only %s* dependencies are supported for 64-bit kexts.",
5825 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
5828 if (!hasKPIDependency
) {
5830 kOSKextLogWarningLevel
|
5831 kOSKextLogDependenciesFlag
,
5832 "Warning - kext %s declares no %s* dependencies. "
5833 "If it uses any KPIs, the link may fail with undefined symbols.",
5834 getIdentifierCString(), KPI_LIB_PREFIX
);
5836 #else /* __LP64__ */
5837 // xxx - will change to flatly disallow "kernel" dependencies at some point
5838 // xxx - is it invalid to do both "com.apple.kernel" and any
5839 // xxx - "com.apple.kernel.*"?
5841 if (hasRawKernelDependency
&& hasKernelDependency
) {
5843 kOSKextLogErrorLevel
|
5844 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5845 "Error - kext %s declares dependencies on both "
5847 getIdentifierCString(), KERNEL_LIB
, KERNEL6_LIB
);
5851 if ((hasRawKernelDependency
|| hasKernelDependency
) && hasKPIDependency
) {
5853 kOSKextLogWarningLevel
|
5854 kOSKextLogDependenciesFlag
,
5855 "Warning - kext %s has immediate dependencies on both "
5856 "%s* and %s* components; use only one style.",
5857 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
5860 if (!hasRawKernelDependency
&& !hasKernelDependency
&& !hasKPIDependency
) {
5861 // xxx - do we want to use validation flag for these too?
5863 kOSKextLogWarningLevel
|
5864 kOSKextLogDependenciesFlag
,
5865 "Warning - %s declares no kernel dependencies; using %s.",
5866 getIdentifierCString(), KERNEL6_LIB
);
5867 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
5868 sKextsByID
->getObject(KERNEL6_LIB
));
5870 dependencies
->setObject(kernelKext
);
5873 kOSKextLogErrorLevel
|
5874 kOSKextLogDependenciesFlag
,
5875 "Error - Library %s not found for %s.",
5876 KERNEL6_LIB
, getIdentifierCString());
5880 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
5881 * its indirect dependencies to simulate old-style linking. XXX - Should
5882 * check for duplicates.
5884 if (!hasRawKernelDependency
&& !hasKPIDependency
) {
5887 count
= getNumDependencies();
5889 /* We add to the dependencies array in this loop, but do not iterate
5890 * past its original count.
5892 for (i
= 0; i
< count
; i
++) {
5893 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
5894 dependencies
->getObject(i
));
5895 dependencyKext
->addBleedthroughDependencies(dependencies
);
5898 #endif /* __LP64__ */
5900 if (hasPrivateKPIDependency
) {
5901 bool hasApplePrefix
= false;
5902 bool infoCopyrightIsValid
= false;
5903 bool readableCopyrightIsValid
= false;
5905 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
5908 infoString
= OSDynamicCast(OSString
,
5909 getPropertyForHostArch("CFBundleGetInfoString"));
5911 infoCopyrightIsValid
=
5912 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
5915 readableString
= OSDynamicCast(OSString
,
5916 getPropertyForHostArch("NSHumanReadableCopyright"));
5917 if (readableString
) {
5918 readableCopyrightIsValid
=
5919 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
5922 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
5924 kOSKextLogErrorLevel
|
5925 kOSKextLogDependenciesFlag
,
5926 "Error - kext %s declares a dependency on %s. "
5927 "Only Apple kexts may declare a dependency on %s.",
5928 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
5934 flags
.hasAllDependencies
= 1;
5938 if (addedToLoopStack
) {
5939 count
= loopStack
->getCount();
5940 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
5941 loopStack
->removeObject(count
- 1);
5944 kOSKextLogErrorLevel
|
5945 kOSKextLogDependenciesFlag
,
5946 "Kext %s - internal error resolving dependencies.",
5947 getIdentifierCString());
5951 if (result
&& localLoopStack
) {
5953 kOSKextLogStepLevel
|
5954 kOSKextLogDependenciesFlag
,
5955 "Kext %s successfully resolved dependencies.",
5956 getIdentifierCString());
5959 OSSafeRelease(localLoopStack
);
5960 OSSafeRelease(libraryIterator
);
5965 /*********************************************************************
5966 *********************************************************************/
5968 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
5970 bool result
= false;
5971 unsigned int dependencyIndex
, dependencyCount
;
5973 dependencyCount
= getNumDependencies();
5975 for (dependencyIndex
= 0;
5976 dependencyIndex
< dependencyCount
;
5977 dependencyIndex
++) {
5979 OSKext
* dependency
= OSDynamicCast(OSKext
,
5980 dependencies
->getObject(dependencyIndex
));
5983 kOSKextLogErrorLevel
|
5984 kOSKextLogDependenciesFlag
,
5985 "Kext %s - internal error propagating compatibility dependencies.",
5986 getIdentifierCString());
5989 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
5990 anArray
->setObject(dependency
);
5992 dependency
->addBleedthroughDependencies(anArray
);
6001 /*********************************************************************
6002 *********************************************************************/
6004 OSKext::flushDependencies(bool forceFlag
)
6006 bool result
= false;
6008 /* Only clear the dependencies if the kext isn't loaded;
6009 * we need the info for loaded kexts to track references.
6011 if (!isLoaded() || forceFlag
) {
6013 // xxx - check level
6015 kOSKextLogProgressLevel
|
6016 kOSKextLogDependenciesFlag
,
6017 "Kext %s flushing dependencies.",
6018 getIdentifierCString());
6019 OSSafeReleaseNULL(dependencies
);
6022 if (!isKernelComponent()) {
6023 flags
.hasAllDependencies
= 0;
6031 /*********************************************************************
6032 *********************************************************************/
6034 OSKext::getNumDependencies(void)
6036 if (!dependencies
) {
6039 return dependencies
->getCount();
6042 /*********************************************************************
6043 *********************************************************************/
6045 OSKext::getDependencies(void)
6047 return dependencies
;
6051 #pragma mark OSMetaClass Support
6053 /*********************************************************************
6054 *********************************************************************/
6057 OSMetaClass
* aClass
,
6058 uint32_t numClasses
)
6060 OSReturn result
= kOSMetaClassNoInsKModSet
;
6063 metaClasses
= OSSet::withCapacity(numClasses
);
6069 if (metaClasses
->containsObject(aClass
)) {
6071 kOSKextLogWarningLevel
|
6073 "Notice - kext %s has already registered class %s.",
6074 getIdentifierCString(),
6075 aClass
->getClassName());
6076 result
= kOSReturnSuccess
;
6080 if (!metaClasses
->setObject(aClass
)) {
6084 kOSKextLogDetailLevel
|
6086 "Kext %s registered class %s.",
6087 getIdentifierCString(),
6088 aClass
->getClassName());
6091 if (!flags
.autounloadEnabled
) {
6092 const OSMetaClass
* metaScan
= NULL
; // do not release
6094 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
6095 if (metaScan
== OSTypeID(IOService
)) {
6098 kOSKextLogProgressLevel
|
6100 "Kext %s has IOService subclass %s; enabling autounload.",
6101 getIdentifierCString(),
6102 aClass
->getClassName());
6104 flags
.autounloadEnabled
= 1;
6110 result
= kOSReturnSuccess
;
6113 if (result
!= kOSReturnSuccess
) {
6115 kOSKextLogErrorLevel
|
6117 "Kext %s failed to register class %s.",
6118 getIdentifierCString(),
6119 aClass
->getClassName());
6125 /*********************************************************************
6126 *********************************************************************/
6128 OSKext::removeClass(
6129 OSMetaClass
* aClass
)
6131 OSReturn result
= kOSMetaClassNoKModSet
;
6137 if (!metaClasses
->containsObject(aClass
)) {
6139 kOSKextLogWarningLevel
|
6141 "Notice - kext %s asked to unregister unknown class %s.",
6142 getIdentifierCString(),
6143 aClass
->getClassName());
6144 result
= kOSReturnSuccess
;
6149 kOSKextLogDetailLevel
|
6151 "Kext %s unregistering class %s.",
6152 getIdentifierCString(),
6153 aClass
->getClassName());
6155 metaClasses
->removeObject(aClass
);
6157 result
= kOSReturnSuccess
;
6160 if (result
!= kOSReturnSuccess
) {
6162 kOSKextLogErrorLevel
|
6164 "Failed to unregister kext %s class %s.",
6165 getIdentifierCString(),
6166 aClass
->getClassName());
6171 /*********************************************************************
6172 *********************************************************************/
6174 OSKext::getMetaClasses(void)
6179 /*********************************************************************
6180 *********************************************************************/
6182 OSKext::hasOSMetaClassInstances(void)
6184 bool result
= false;
6185 OSCollectionIterator
* classIterator
= NULL
; // must release
6186 OSMetaClass
* checkClass
= NULL
; // do not release
6192 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6193 if (!classIterator
) {
6194 // xxx - log alloc failure?
6197 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6198 if (checkClass
->getInstanceCount()) {
6206 OSSafeRelease(classIterator
);
6210 /*********************************************************************
6211 *********************************************************************/
6214 OSKext::reportOSMetaClassInstances(
6215 const char * kextIdentifier
,
6216 OSKextLogSpec msgLogSpec
)
6218 OSKext
* theKext
= NULL
; // must release
6220 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
6225 theKext
->reportOSMetaClassInstances(msgLogSpec
);
6227 OSSafeRelease(theKext
);
6231 /*********************************************************************
6232 *********************************************************************/
6234 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
6236 OSCollectionIterator
* classIterator
= NULL
; // must release
6237 OSMetaClass
* checkClass
= NULL
; // do not release
6243 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6244 if (!classIterator
) {
6247 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6248 if (checkClass
->getInstanceCount()) {
6251 " Kext %s class %s has %d instance%s.",
6252 getIdentifierCString(),
6253 checkClass
->getClassName(),
6254 checkClass
->getInstanceCount(),
6255 checkClass
->getInstanceCount() == 1 ? "" : "s");
6260 OSSafeRelease(classIterator
);
6265 #pragma mark User-Space Requests
6267 /*********************************************************************
6268 * XXX - this function is a big ugly mess
6269 *********************************************************************/
6272 OSKext::handleRequest(
6273 host_priv_t hostPriv
,
6274 OSKextLogSpec clientLogFilter
,
6275 char * requestBuffer
,
6276 uint32_t requestLength
,
6277 char ** responseOut
,
6278 uint32_t * responseLengthOut
,
6280 uint32_t * logInfoLengthOut
)
6282 OSReturn result
= kOSReturnError
;
6283 kern_return_t kmem_result
= KERN_FAILURE
;
6285 char * response
= NULL
; // returned by reference
6286 uint32_t responseLength
= 0;
6288 OSObject
* parsedXML
= NULL
; // must release
6289 OSDictionary
* requestDict
= NULL
; // do not release
6290 OSString
* errorString
= NULL
; // must release
6292 OSData
* responseData
= NULL
; // must release
6293 OSObject
* responseObject
= NULL
; // must release
6295 OSSerialize
* serializer
= NULL
; // must release
6297 OSArray
* logInfoArray
= NULL
; // must release
6299 OSString
* predicate
= NULL
; // do not release
6300 OSString
* kextIdentifier
= NULL
; // do not release
6301 OSArray
* kextIdentifiers
= NULL
; // do not release
6302 OSKext
* theKext
= NULL
; // do not release
6303 OSBoolean
* boolArg
= NULL
; // do not release
6305 IORecursiveLockLock(sKextLock
);
6308 *responseOut
= NULL
;
6309 *responseLengthOut
= 0;
6313 *logInfoLengthOut
= 0;
6316 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
6318 /* XML must be nul-terminated.
6320 if (requestBuffer
[requestLength
- 1] != '\0') {
6321 OSKextLog(/* kext */ NULL
,
6322 kOSKextLogErrorLevel
|
6324 "Invalid request from user space (not nul-terminated).");
6325 result
= kOSKextReturnBadData
;
6328 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, &errorString
);
6330 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
);
6333 const char * errorCString
= "(unknown error)";
6335 if (errorString
&& errorString
->getCStringNoCopy()) {
6336 errorCString
= errorString
->getCStringNoCopy();
6337 } else if (parsedXML
) {
6338 errorCString
= "not a dictionary";
6340 OSKextLog(/* kext */ NULL
,
6341 kOSKextLogErrorLevel
|
6343 "Error unserializing request from user space: %s.",
6345 result
= kOSKextReturnSerialization
;
6349 predicate
= _OSKextGetRequestPredicate(requestDict
);
6351 OSKextLog(/* kext */ NULL
,
6352 kOSKextLogErrorLevel
|
6354 "Recieved kext request from user space with no predicate.");
6355 result
= kOSKextReturnInvalidArgument
;
6359 OSKextLog(/* kext */ NULL
,
6360 kOSKextLogDebugLevel
|
6362 "Received '%s' request from user space.",
6363 predicate
->getCStringNoCopy());
6365 result
= kOSKextReturnNotPrivileged
;
6366 if (hostPriv
== HOST_PRIV_NULL
) {
6367 if (!predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) &&
6368 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
) &&
6369 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6375 /* Get common args in anticipation of use.
6377 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
6378 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
6379 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
6380 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
6381 if (kextIdentifier
) {
6382 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
6384 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
6385 requestDict
, kKextRequestArgumentValueKey
));
6387 result
= kOSKextReturnInvalidArgument
;
6389 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
6390 if (!kextIdentifier
) {
6391 OSKextLog(/* kext */ NULL
,
6392 kOSKextLogErrorLevel
|
6394 "Invalid arguments to kext start request.");
6395 } else if (!theKext
) {
6396 OSKextLog(/* kext */ NULL
,
6397 kOSKextLogErrorLevel
|
6399 "Kext %s not found for start request.",
6400 kextIdentifier
->getCStringNoCopy());
6401 result
= kOSKextReturnNotFound
;
6403 result
= theKext
->start();
6406 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
6407 if (!kextIdentifier
) {
6408 OSKextLog(/* kext */ NULL
,
6409 kOSKextLogErrorLevel
|
6411 "Invalid arguments to kext stop request.");
6412 } else if (!theKext
) {
6413 OSKextLog(/* kext */ NULL
,
6414 kOSKextLogErrorLevel
|
6416 "Kext %s not found for stop request.",
6417 kextIdentifier
->getCStringNoCopy());
6418 result
= kOSKextReturnNotFound
;
6420 result
= theKext
->stop();
6423 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
6424 if (!kextIdentifier
) {
6425 OSKextLog(/* kext */ NULL
,
6426 kOSKextLogErrorLevel
|
6428 "Invalid arguments to kext unload request.");
6429 } else if (!theKext
) {
6430 OSKextLog(/* kext */ NULL
,
6431 kOSKextLogErrorLevel
|
6433 "Kext %s not found for unload request.",
6434 kextIdentifier
->getCStringNoCopy());
6435 result
= kOSKextReturnNotFound
;
6437 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
6438 _OSKextGetRequestArgument(requestDict
,
6439 kKextRequestArgumentTerminateIOServicesKey
));
6440 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
6443 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
6444 result
= OSKext::dispatchResource(requestDict
);
6446 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
6447 OSBoolean
* delayAutounloadBool
= NULL
;
6449 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
6450 _OSKextGetRequestArgument(requestDict
,
6451 kKextRequestArgumentDelayAutounloadKey
));
6453 /* If asked to delay autounload, reset the timer if it's currently set.
6454 * (That is, don't schedule an unload if one isn't already pending.
6456 if (delayAutounloadBool
== kOSBooleanTrue
) {
6457 OSKext::considerUnloads(/* rescheduleOnly? */ true);
6460 responseObject
= OSDynamicCast(OSObject
,
6461 OSKext::copyLoadedKextInfo(kextIdentifiers
));
6462 if (!responseObject
) {
6463 result
= kOSKextReturnInternalError
;
6465 OSKextLog(/* kext */ NULL
,
6466 kOSKextLogDebugLevel
|
6468 "Returning loaded kext info.");
6469 result
= kOSReturnSuccess
;
6472 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6473 OSNumber
* addressNum
= NULL
; // released as responseObject
6474 kernel_segment_command_t
* textseg
= getsegbyname("__TEXT");
6477 OSKextLog(/* kext */ NULL
,
6478 kOSKextLogErrorLevel
|
6479 kOSKextLogGeneralFlag
| kOSKextLogIPCFlag
,
6480 "Can't find text segment for kernel load address.");
6481 result
= kOSReturnError
;
6485 OSKextLog(/* kext */ NULL
,
6486 kOSKextLogDebugLevel
|
6488 "Returning kernel load address 0x%llx.",
6489 (unsigned long long)textseg
->vmaddr
);
6490 addressNum
= OSNumber::withNumber((long long unsigned int)textseg
->vmaddr
,
6491 8 * sizeof(long long unsigned int));
6492 responseObject
= OSDynamicCast(OSObject
, addressNum
);
6493 result
= kOSReturnSuccess
;
6495 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
)) {
6496 OSKextLog(/* kext */ NULL
,
6497 kOSKextLogDebugLevel
|
6499 "Returning kernel link state.");
6500 responseData
= sKernelKext
->linkState
;
6501 responseData
->retain();
6502 result
= kOSReturnSuccess
;
6504 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
6506 /* Hand the current sKernelRequests array to the caller
6507 * (who must release it), and make a new one.
6509 responseObject
= OSDynamicCast(OSObject
, sKernelRequests
);
6510 sKernelRequests
= OSArray::withCapacity(0);
6511 sPostedKextLoadIdentifiers
->flushCollection();
6512 OSKextLog(/* kext */ NULL
,
6513 kOSKextLogDebugLevel
|
6515 "Returning kernel requests.");
6516 result
= kOSReturnSuccess
;
6518 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
6520 /* Return the set of all requested bundle identifiers */
6521 responseObject
= OSDynamicCast(OSObject
, sAllKextLoadIdentifiers
);
6522 responseObject
->retain();
6523 OSKextLog(/* kext */ NULL
,
6524 kOSKextLogDebugLevel
|
6526 "Returning load requests.");
6527 result
= kOSReturnSuccess
;
6531 * Now we have handle the request, or not. Gather up the response & logging
6532 * info to ship to user space.
6535 /* Note: Nothing in OSKext is supposed to retain requestDict,
6536 * but you never know....
6538 if (requestDict
->getRetainCount() > 1) {
6539 OSKextLog(/* kext */ NULL
,
6540 kOSKextLogWarningLevel
|
6542 "Request from user space still retained by a kext; "
6543 "probable memory leak.");
6546 if (responseData
&& responseObject
) {
6547 OSKextLog(/* kext */ NULL
,
6548 kOSKextLogErrorLevel
|
6550 "Mistakenly generated both data & plist responses to user request "
6551 "(returning only data).");
6554 if (responseData
&& responseData
->getLength() && responseOut
) {
6556 response
= (char *)responseData
->getBytesNoCopy();
6557 responseLength
= responseData
->getLength();
6558 } else if (responseOut
&& responseObject
) {
6559 serializer
= OSSerialize::withCapacity(0);
6561 result
= kOSKextReturnNoMemory
;
6565 if (!responseObject
->serialize(serializer
)) {
6566 OSKextLog(/* kext */ NULL
,
6567 kOSKextLogErrorLevel
|
6569 "Failed to serialize response to request from user space.");
6570 result
= kOSKextReturnSerialization
;
6574 response
= (char *)serializer
->text();
6575 responseLength
= serializer
->getLength();
6578 if (responseOut
&& response
) {
6581 /* This kmem_alloc sets the return value of the function.
6583 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
6585 if (kmem_result
!= KERN_SUCCESS
) {
6586 OSKextLog(/* kext */ NULL
,
6587 kOSKextLogErrorLevel
|
6589 "Failed to copy response to request from user space.");
6590 result
= kmem_result
;
6593 memcpy(buffer
, response
, responseLength
);
6594 *responseOut
= buffer
;
6595 *responseLengthOut
= responseLength
;
6601 /* Gather up the collected log messages for user space. Any messages
6602 * messages past this call will not make it up as log messages but
6603 * will be in the system log. Note that we ignore the return of the
6604 * serialize; it has no bearing on the operation at hand even if we
6605 * fail to get the log messages.
6607 logInfoArray
= OSKext::clearUserSpaceLogFilter();
6609 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
6610 (void)OSKext::serializeLogInfo(logInfoArray
,
6611 logInfoOut
, logInfoLengthOut
);
6614 IORecursiveLockUnlock(sKextLock
);
6616 OSSafeRelease(requestDict
);
6617 OSSafeRelease(errorString
);
6618 OSSafeRelease(responseData
);
6619 OSSafeRelease(responseObject
);
6620 OSSafeRelease(serializer
);
6621 OSSafeRelease(logInfoArray
);
6626 /*********************************************************************
6627 *********************************************************************/
6630 OSKext::copyLoadedKextInfo(OSArray
* kextIdentifiers
)
6632 OSArray
* result
= NULL
;
6633 OSDictionary
* kextInfo
= NULL
; // must release
6635 uint32_t idCount
= 0;
6636 uint32_t idIndex
= 0;
6638 IORecursiveLockLock(sKextLock
);
6640 /* Empty list of bundle ids is equivalent to no list (get all).
6642 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
6643 kextIdentifiers
= NULL
;
6644 } else if (kextIdentifiers
) {
6645 idCount
= kextIdentifiers
->getCount();
6648 count
= sLoadedKexts
->getCount();
6649 result
= OSArray::withCapacity(count
);
6653 for (i
= 0; i
< count
; i
++) {
6654 OSKext
* thisKext
= NULL
; // do not release
6655 Boolean includeThis
= true;
6658 kextInfo
->release();
6661 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6666 /* Skip current kext if we have a list of bundle IDs and
6667 * it isn't in the list.
6669 if (kextIdentifiers
) {
6670 const OSString
* thisKextID
= thisKext
->getIdentifier();
6672 includeThis
= false;
6674 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
6675 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
6676 kextIdentifiers
->getObject(idIndex
));
6677 if (thisKextID
->isEqualTo(thisRequestID
)) {
6688 kextInfo
= thisKext
->copyInfo();
6689 result
->setObject(kextInfo
);
6693 IORecursiveLockUnlock(sKextLock
);
6695 if (kextInfo
) kextInfo
->release();
6700 /*********************************************************************
6709 Dependency Load Tags
6710 # Dependent References
6713 *********************************************************************/
6714 #define _OSKextLoadInfoDictCapacity (12)
6717 OSKext::copyInfo(void)
6719 OSDictionary
* result
= NULL
;
6720 bool success
= false;
6721 OSNumber
* cpuTypeNumber
= NULL
; // must release
6722 OSNumber
* cpuSubtypeNumber
= NULL
; // must release
6723 OSString
* versionString
= NULL
; // do not release
6724 OSData
* uuid
= NULL
; // must release
6725 OSNumber
* scratchNumber
= NULL
; // must release
6726 OSArray
* dependencyLoadTags
= NULL
; // must release
6727 OSCollectionIterator
* metaClassIterator
= NULL
; // must release
6728 OSArray
* metaClassInfo
= NULL
; // must release
6729 OSDictionary
* metaClassDict
= NULL
; // must release
6730 OSMetaClass
* thisMetaClass
= NULL
; // do not release
6731 OSString
* metaClassName
= NULL
; // must release
6732 OSString
* superclassName
= NULL
; // must release
6735 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
6740 /* CPU Type & Subtype.
6741 * Use the CPU type of the kernel for all (loaded) kexts.
6742 * xxx - should we not include this for the kernel components,
6743 * xxx - or for any interface? they have mach-o files, they're just weird.
6745 if (linkedExecutable
|| (this == sKernelKext
)) {
6747 cpuTypeNumber
= OSNumber::withNumber(
6748 (long long unsigned int)_mh_execute_header
.cputype
,
6749 8 * sizeof(_mh_execute_header
.cputype
));
6750 if (cpuTypeNumber
) {
6751 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
);
6755 // I don't want to rely on a mach header for nonkernel kexts, yet
6756 if (this == sKernelKext
) {
6757 cpuSubtypeNumber
= OSNumber::withNumber(
6758 (long long unsigned int)_mh_execute_header
.cputype
,
6759 8 * sizeof(_mh_execute_header
.cputype
));
6760 if (cpuSubtypeNumber
) {
6761 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
);
6765 /* CFBundleIdentifier.
6767 result
->setObject(kCFBundleIdentifierKey
, bundleID
);
6771 versionString
= OSDynamicCast(OSString
,
6772 getPropertyForHostArch(kCFBundleVersionKey
));
6773 if (versionString
) {
6774 result
->setObject(kCFBundleVersionKey
, versionString
);
6777 /* OSBundleCompatibleVersion.
6779 versionString
= OSDynamicCast(OSString
,
6780 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
6781 if (versionString
) {
6782 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
6788 result
->setObject(kOSBundlePathKey
, path
);
6795 result
->setObject(kOSBundleUUIDKey
, uuid
);
6799 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
6801 result
->setObject(kOSKernelResourceKey
,
6802 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
6804 result
->setObject(kOSBundleIsInterfaceKey
,
6805 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
6807 result
->setObject(kOSBundlePrelinkedKey
,
6808 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
6810 result
->setObject(kOSBundleStartedKey
,
6811 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
6815 scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
6816 /* numBits */ 8 * sizeof(loadTag
));
6817 if (scratchNumber
) {
6818 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
);
6819 OSSafeReleaseNULL(scratchNumber
);
6822 /* LoadAddress, LoadSize.
6824 if (isInterface() || linkedExecutable
) {
6825 /* These go to userspace via serialization, so we don't want any doubts
6828 uint64_t loadAddress
= 0;
6829 uint32_t loadSize
= 0;
6830 uint32_t wiredSize
= 0;
6832 /* Interfaces always report 0 load address & size.
6833 * Just the way they roll.
6835 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
6836 * xxx - shouldn't have one!
6838 if (linkedExecutable
/* && !isInterface() */) {
6839 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
6840 loadSize
= linkedExecutable
->getLength();
6842 /* If we have a kmod_info struct, calculated the wired size
6843 * from that. Otherwise it's the full load size.
6846 wiredSize
= loadSize
- kmod_info
->hdr_size
;
6848 wiredSize
= loadSize
;
6852 scratchNumber
= OSNumber::withNumber(
6853 (unsigned long long)(loadAddress
),
6854 /* numBits */ 8 * sizeof(loadAddress
));
6855 if (scratchNumber
) {
6856 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
);
6857 OSSafeReleaseNULL(scratchNumber
);
6859 scratchNumber
= OSNumber::withNumber(
6860 (unsigned long long)(loadSize
),
6861 /* numBits */ 8 * sizeof(loadSize
));
6862 if (scratchNumber
) {
6863 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
);
6864 OSSafeReleaseNULL(scratchNumber
);
6866 scratchNumber
= OSNumber::withNumber(
6867 (unsigned long long)(wiredSize
),
6868 /* numBits */ 8 * sizeof(wiredSize
));
6869 if (scratchNumber
) {
6870 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
);
6871 OSSafeReleaseNULL(scratchNumber
);
6875 /* OSBundleDependencies. In descending order for
6876 * easy compatibility with kextstat(8).
6878 if ((count
= getNumDependencies())) {
6879 dependencyLoadTags
= OSArray::withCapacity(count
);
6880 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
);
6884 OSKext
* dependency
= OSDynamicCast(OSKext
,
6885 dependencies
->getObject(i
));
6887 OSSafeReleaseNULL(scratchNumber
);
6892 scratchNumber
= OSNumber::withNumber(
6893 (unsigned long long)dependency
->getLoadTag(),
6894 /* numBits*/ 8 * sizeof(loadTag
));
6895 if (scratchNumber
) {
6896 dependencyLoadTags
->setObject(scratchNumber
);
6901 OSSafeReleaseNULL(scratchNumber
);
6903 /* OSBundleMetaClasses.
6905 if (metaClasses
&& metaClasses
->getCount()) {
6906 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
);
6907 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
6908 if (!metaClassIterator
|| !metaClassInfo
) {
6911 result
->setObject(kOSBundleClassesKey
, metaClassInfo
);
6913 while ( (thisMetaClass
= OSDynamicCast(OSMetaClass
,
6914 metaClassIterator
->getNextObject())) ) {
6916 OSSafeReleaseNULL(metaClassDict
);
6917 OSSafeReleaseNULL(metaClassName
);
6918 OSSafeReleaseNULL(superclassName
);
6919 OSSafeReleaseNULL(scratchNumber
);
6921 metaClassDict
= OSDictionary::withCapacity(3);
6922 if (!metaClassDict
) {
6926 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
6927 if (thisMetaClass
->getSuperClass()) {
6928 superclassName
= OSString::withCString(
6929 thisMetaClass
->getSuperClass()->getClassName());
6931 scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
6932 8 * sizeof(unsigned int));
6933 if (!metaClassDict
|| !metaClassName
|| !superclassName
||
6939 metaClassInfo
->setObject(metaClassDict
);
6940 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
);
6941 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
);
6942 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
);
6946 /* OSBundleRetainCount.
6948 OSSafeReleaseNULL(scratchNumber
);
6950 int extRetainCount
= getRetainCount() - 1;
6954 scratchNumber
= OSNumber::withNumber(
6955 (int)extRetainCount
,
6956 /* numBits*/ 8 * sizeof(int));
6957 if (scratchNumber
) {
6958 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
);
6964 OSSafeRelease(cpuTypeNumber
);
6965 OSSafeRelease(cpuSubtypeNumber
);
6966 OSSafeRelease(uuid
);
6967 OSSafeRelease(scratchNumber
);
6968 OSSafeRelease(dependencyLoadTags
);
6969 OSSafeRelease(metaClassIterator
);
6970 OSSafeRelease(metaClassInfo
);
6971 OSSafeRelease(metaClassDict
);
6972 OSSafeRelease(metaClassName
);
6973 OSSafeRelease(superclassName
);
6975 OSSafeReleaseNULL(result
);
6980 /*********************************************************************
6981 *********************************************************************/
6984 OSKext::requestResource(
6985 const char * kextIdentifierCString
,
6986 const char * resourceNameCString
,
6987 OSKextRequestResourceCallback callback
,
6989 OSKextRequestTag
* requestTagOut
)
6991 OSReturn result
= kOSReturnError
;
6992 OSKext
* callbackKext
= NULL
; // must release (looked up)
6994 OSKextRequestTag requestTag
= -1;
6995 OSNumber
* requestTagNum
= NULL
; // must release
6997 OSDictionary
* requestDict
= NULL
; // must release
6998 OSString
* kextIdentifier
= NULL
; // must release
6999 OSString
* resourceName
= NULL
; // must release
7001 OSDictionary
* callbackRecord
= NULL
; // must release
7002 OSData
* callbackWrapper
= NULL
; // must release
7004 OSData
* contextWrapper
= NULL
; // must release
7006 IORecursiveLockLock(sKextLock
);
7008 if (requestTagOut
) {
7009 *requestTagOut
= kOSKextRequestTagInvalid
;
7012 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
7013 result
= kOSKextReturnInvalidArgument
;
7017 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
7018 if (!callbackKext
) {
7019 OSKextLog(/* kext */ NULL
,
7020 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7021 "Resource request has bad callback address.");
7022 result
= kOSKextReturnInvalidArgument
;
7025 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
7026 OSKextLog(/* kext */ NULL
,
7027 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7028 "Resource request callback is in a kext that is not started.");
7029 result
= kOSKextReturnInvalidArgument
;
7033 /* Do not allow any new requests to be made on a kext that is unloading.
7035 if (callbackKext
->flags
.stopping
) {
7036 result
= kOSKextReturnStopping
;
7040 /* If we're wrapped the next available request tag around to the negative
7041 * numbers, we can't service any more requests.
7043 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
7044 OSKextLog(/* kext */ NULL
,
7045 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7046 "No more request tags available; restart required.");
7047 result
= kOSKextReturnNoResources
;
7050 requestTag
= sNextRequestTag
++;
7052 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
7054 if (result
!= kOSReturnSuccess
) {
7058 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
7059 resourceName
= OSString::withCString(resourceNameCString
);
7060 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
7061 8 * sizeof(requestTag
));
7062 if (!kextIdentifier
||
7065 !_OSKextSetRequestArgument(requestDict
,
7066 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
7067 !_OSKextSetRequestArgument(requestDict
,
7068 kKextRequestArgumentNameKey
, resourceName
) ||
7069 !_OSKextSetRequestArgument(requestDict
,
7070 kKextRequestArgumentRequestTagKey
, requestTagNum
)) {
7072 result
= kOSKextReturnNoMemory
;
7076 callbackRecord
= OSDynamicCast(OSDictionary
, requestDict
->copyCollection());
7077 if (!callbackRecord
) {
7078 result
= kOSKextReturnNoMemory
;
7081 // we validate callback address at call time
7082 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
7084 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
7086 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7087 kKextRequestArgumentCallbackKey
, callbackWrapper
)) {
7089 result
= kOSKextReturnNoMemory
;
7094 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7095 kKextRequestArgumentContextKey
, contextWrapper
)) {
7097 result
= kOSKextReturnNoMemory
;
7102 /* Only post the requests after all the other potential failure points
7105 if (!sKernelRequests
->setObject(requestDict
) ||
7106 !sRequestCallbackRecords
->setObject(callbackRecord
)) {
7108 result
= kOSKextReturnNoMemory
;
7114 result
= kOSReturnSuccess
;
7115 if (requestTagOut
) {
7116 *requestTagOut
= requestTag
;
7121 /* If we didn't succeed, yank the request & callback
7122 * from their holding arrays.
7124 if (result
!= kOSReturnSuccess
) {
7127 index
= sKernelRequests
->getNextIndexOfObject(requestDict
, 0);
7128 if (index
!= (unsigned int)-1) {
7129 sKernelRequests
->removeObject(index
);
7131 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
, 0);
7132 if (index
!= (unsigned int)-1) {
7133 sRequestCallbackRecords
->removeObject(index
);
7137 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7139 IORecursiveLockUnlock(sKextLock
);
7141 if (callbackKext
) callbackKext
->release();
7142 if (requestTagNum
) requestTagNum
->release();
7144 if (requestDict
) requestDict
->release();
7145 if (kextIdentifier
) kextIdentifier
->release();
7146 if (resourceName
) resourceName
->release();
7148 if (callbackRecord
) callbackRecord
->release();
7149 if (callbackWrapper
) callbackWrapper
->release();
7150 if (contextWrapper
) contextWrapper
->release();
7155 /*********************************************************************
7156 *********************************************************************/
7159 OSKext::dequeueCallbackForRequestTag(
7160 OSKextRequestTag requestTag
,
7161 OSDictionary
** callbackRecordOut
)
7163 OSReturn result
= kOSReturnError
;
7164 OSNumber
* requestTagNum
= NULL
; // must release
7166 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
7167 8 * sizeof(requestTag
));
7168 if (!requestTagNum
) {
7172 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
,
7176 OSSafeRelease(requestTagNum
);
7181 /*********************************************************************
7182 *********************************************************************/
7185 OSKext::dequeueCallbackForRequestTag(
7186 OSNumber
* requestTagNum
,
7187 OSDictionary
** callbackRecordOut
)
7189 OSReturn result
= kOSKextReturnInvalidArgument
;
7190 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
7191 OSNumber
* callbackTagNum
= NULL
; // do not release
7192 unsigned int count
, i
;
7194 IORecursiveLockLock(sKextLock
);
7196 result
= kOSReturnError
;
7197 count
= sRequestCallbackRecords
->getCount();
7198 for (i
= 0; i
< count
; i
++) {
7199 callbackRecord
= OSDynamicCast(OSDictionary
,
7200 sRequestCallbackRecords
->getObject(i
));
7201 if (!callbackRecord
) {
7205 /* If we don't find a tag, we basically have a leak here. Maybe
7206 * we should just remove it.
7208 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
7209 callbackRecord
, kKextRequestArgumentRequestTagKey
));
7210 if (!callbackTagNum
) {
7214 /* We could be even more paranoid and check that all the incoming
7215 * args match what's in the callback record.
7217 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
7218 if (callbackRecordOut
) {
7219 *callbackRecordOut
= callbackRecord
;
7220 callbackRecord
->retain();
7222 sRequestCallbackRecords
->removeObject(i
);
7223 result
= kOSReturnSuccess
;
7227 result
= kOSKextReturnNotFound
;
7230 IORecursiveLockUnlock(sKextLock
);
7234 /*********************************************************************
7235 *********************************************************************/
7238 OSKext::dispatchResource(OSDictionary
* requestDict
)
7240 OSReturn result
= kOSReturnError
;
7241 OSDictionary
* callbackRecord
= NULL
; // must release
7242 OSNumber
* requestTag
= NULL
; // do not release
7243 OSNumber
* requestResult
= NULL
; // do not release
7244 OSData
* dataObj
= NULL
; // do not release
7245 uint32_t dataLength
= 0;
7246 const void * dataPtr
= NULL
; // do not free
7247 OSData
* callbackWrapper
= NULL
; // do not release
7248 OSKextRequestResourceCallback callback
= NULL
;
7249 OSData
* contextWrapper
= NULL
; // do not release
7250 void * context
= NULL
; // do not free
7251 OSKext
* callbackKext
= NULL
; // must release (looked up)
7253 IORecursiveLockLock(sKextLock
);
7255 /* Get the args from the request. Right now we need the tag
7256 * to look up the callback record, and the result for invoking the callback.
7258 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7259 kKextRequestArgumentRequestTagKey
));
7260 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7261 kKextRequestArgumentResultKey
));
7262 if (!requestTag
|| !requestResult
) {
7263 result
= kOSKextReturnInvalidArgument
;
7267 /* Look for a callback record matching this request's tag.
7269 result
= dequeueCallbackForRequestTag(requestTag
, &callbackRecord
);
7270 if (result
!= kOSReturnSuccess
) {
7275 * Get the context pointer of the callback record (if there is one).
7277 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
,
7278 kKextRequestArgumentContextKey
));
7279 context
= _OSKextExtractPointer(contextWrapper
);
7280 if (contextWrapper
&& !context
) {
7284 callbackWrapper
= OSDynamicCast(OSData
,
7285 _OSKextGetRequestArgument(callbackRecord
,
7286 kKextRequestArgumentCallbackKey
));
7287 callback
= (OSKextRequestResourceCallback
)
7288 _OSKextExtractPointer(callbackWrapper
);
7293 /* Check for a data obj. We might not have one and that's ok, that means
7294 * we didn't find the requested resource, and we still have to tell the
7295 * caller that via the callback.
7297 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
7298 kKextRequestArgumentValueKey
));
7300 dataPtr
= dataObj
->getBytesNoCopy();
7301 dataLength
= dataObj
->getLength();
7304 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
7305 if (!callbackKext
) {
7306 OSKextLog(/* kext */ NULL
,
7307 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7308 "Can't invoke callback for resource request; "
7309 "no kext loaded at callback address %p.",
7313 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
7314 OSKextLog(/* kext */ NULL
,
7315 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7316 "Can't invoke kext resource callback; "
7317 "kext at callback address %p is not running.",
7322 (void)callback(requestTag
->unsigned32BitValue(),
7323 (OSReturn
)requestResult
->unsigned32BitValue(),
7324 dataPtr
, dataLength
, context
);
7326 result
= kOSReturnSuccess
;
7329 if (callbackKext
) callbackKext
->release();
7330 if (callbackRecord
) callbackRecord
->release();
7332 IORecursiveLockUnlock(sKextLock
);
7336 /*********************************************************************
7337 *********************************************************************/
7340 OSKext::invokeRequestCallback(
7341 OSDictionary
* callbackRecord
,
7342 OSReturn callbackResult
)
7344 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
7345 OSNumber
* resultNum
= NULL
; // must release
7351 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
7352 8 * sizeof(callbackResult
));
7357 /* Insert the result into the callback record and dispatch it as if it
7358 * were the reply coming down from user space.
7360 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
7363 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
7364 /* This removes the pending callback record.
7366 OSKext::dispatchResource(callbackRecord
);
7370 if (resultNum
) resultNum
->release();
7374 /*********************************************************************
7375 *********************************************************************/
7378 OSKext::cancelRequest(
7379 OSKextRequestTag requestTag
,
7382 OSReturn result
= kOSKextReturnNoMemory
;
7383 OSDictionary
* callbackRecord
= NULL
; // must release
7384 OSData
* contextWrapper
= NULL
; // do not release
7386 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
7389 if (result
== kOSReturnSuccess
&& contextOut
) {
7390 contextWrapper
= OSDynamicCast(OSData
,
7391 _OSKextGetRequestArgument(callbackRecord
,
7392 kKextRequestArgumentContextKey
));
7393 *contextOut
= _OSKextExtractPointer(contextWrapper
);
7396 if (callbackRecord
) callbackRecord
->release();
7401 /*********************************************************************
7402 *********************************************************************/
7404 OSKext::invokeOrCancelRequestCallbacks(
7405 OSReturn callbackResult
,
7408 unsigned int count
, i
;
7410 IORecursiveLockLock(sKextLock
);
7412 count
= sRequestCallbackRecords
->getCount();
7419 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7420 sRequestCallbackRecords
->getObject(i
));
7425 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7426 _OSKextGetRequestArgument(request
,
7427 kKextRequestArgumentCallbackKey
));
7429 if (!callbackWrapper
) {
7430 sRequestCallbackRecords
->removeObject(i
);
7434 vm_address_t callbackAddress
= (vm_address_t
)
7435 _OSKextExtractPointer(callbackWrapper
);
7437 if ((kmod_info
->address
<= callbackAddress
) &&
7438 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7441 /* This removes the callback record.
7443 invokeRequestCallback(request
, callbackResult
);
7445 sRequestCallbackRecords
->removeObject(i
);
7451 IORecursiveLockUnlock(sKextLock
);
7455 /*********************************************************************
7456 *********************************************************************/
7458 OSKext::countRequestCallbacks(void)
7460 uint32_t result
= 0;
7461 unsigned int count
, i
;
7463 IORecursiveLockLock(sKextLock
);
7465 count
= sRequestCallbackRecords
->getCount();
7472 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7473 sRequestCallbackRecords
->getObject(i
));
7478 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7479 _OSKextGetRequestArgument(request
,
7480 kKextRequestArgumentCallbackKey
));
7482 if (!callbackWrapper
) {
7486 vm_address_t callbackAddress
= (vm_address_t
)
7487 _OSKextExtractPointer(callbackWrapper
);
7489 if ((kmod_info
->address
<= callbackAddress
) &&
7490 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7497 IORecursiveLockUnlock(sKextLock
);
7501 /*********************************************************************
7502 *********************************************************************/
7503 static OSReturn
_OSKextCreateRequest(
7504 const char * predicate
,
7505 OSDictionary
** requestP
)
7507 OSReturn result
= kOSKextReturnNoMemory
;
7508 OSDictionary
* request
= NULL
; // must release on error
7509 OSDictionary
* args
= NULL
; // must release
7511 request
= OSDictionary::withCapacity(2);
7515 result
= _OSDictionarySetCStringValue(request
,
7516 kKextRequestPredicateKey
, predicate
);
7517 if (result
!= kOSReturnSuccess
) {
7520 result
= kOSReturnSuccess
;
7523 if (result
!= kOSReturnSuccess
) {
7524 if (request
) request
->release();
7526 *requestP
= request
;
7528 if (args
) args
->release();
7533 /*********************************************************************
7534 *********************************************************************/
7535 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
7537 return OSDynamicCast(OSString
,
7538 requestDict
->getObject(kKextRequestPredicateKey
));
7541 /*********************************************************************
7542 *********************************************************************/
7543 static OSObject
* _OSKextGetRequestArgument(
7544 OSDictionary
* requestDict
,
7545 const char * argName
)
7547 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7548 requestDict
->getObject(kKextRequestArgumentsKey
));
7550 return args
->getObject(argName
);
7555 /*********************************************************************
7556 *********************************************************************/
7557 static bool _OSKextSetRequestArgument(
7558 OSDictionary
* requestDict
,
7559 const char * argName
,
7562 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7563 requestDict
->getObject(kKextRequestArgumentsKey
));
7565 args
= OSDictionary::withCapacity(2);
7569 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
7573 return args
->setObject(argName
, value
);
7579 /*********************************************************************
7580 *********************************************************************/
7581 static void * _OSKextExtractPointer(OSData
* wrapper
)
7583 void * result
= NULL
;
7584 const void * resultPtr
= NULL
;
7589 resultPtr
= wrapper
->getBytesNoCopy();
7590 result
= *(void **)resultPtr
;
7595 /*********************************************************************
7596 *********************************************************************/
7597 static OSReturn
_OSDictionarySetCStringValue(
7598 OSDictionary
* dict
,
7600 const char * cValue
)
7602 OSReturn result
= kOSKextReturnNoMemory
;
7603 const OSSymbol
* key
= NULL
; // must release
7604 OSString
* value
= NULL
; // must release
7606 key
= OSSymbol::withCString(cKey
);
7607 value
= OSString::withCString(cValue
);
7608 if (!key
|| !value
) {
7611 if (dict
->setObject(key
, value
)) {
7612 result
= kOSReturnSuccess
;
7616 if (key
) key
->release();
7617 if (value
) value
->release();
7623 #pragma mark Personalities (IOKit Drivers)
7625 /*********************************************************************
7626 *********************************************************************/
7629 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
7631 OSArray
* result
= NULL
; // returned
7632 OSCollectionIterator
* kextIterator
= NULL
; // must release
7633 OSArray
* personalities
= NULL
; // must release
7634 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7636 OSString
* kextID
= NULL
; // do not release
7637 OSKext
* theKext
= NULL
; // do not release
7639 IORecursiveLockLock(sKextLock
);
7641 /* Let's conservatively guess that any given kext has around 3
7642 * personalities for now.
7644 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
7649 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
7650 if (!kextIterator
) {
7654 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
7655 if (personalitiesIterator
) {
7656 personalitiesIterator
->release();
7657 personalitiesIterator
= NULL
;
7659 if (personalities
) {
7660 personalities
->release();
7661 personalities
= NULL
;
7664 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
7665 if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
7666 personalities
= theKext
->copyPersonalitiesArray();
7667 if (!personalities
) {
7670 result
->merge(personalities
);
7672 // xxx - check for better place to put this log msg
7674 kOSKextLogWarningLevel
|
7676 "Kext %s is not loadable during safe boot; "
7677 "omitting its personalities.",
7678 theKext
->getIdentifierCString());
7684 IORecursiveLockUnlock(sKextLock
);
7686 if (kextIterator
) kextIterator
->release();
7687 if (personalitiesIterator
) personalitiesIterator
->release();
7688 if (personalities
) personalities
->release();
7693 /*********************************************************************
7694 *********************************************************************/
7697 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
7699 int numPersonalities
= 0;
7701 OSKextLog(/* kext */ NULL
,
7702 kOSKextLogStepLevel
|
7704 "Sending all eligible registered kexts' personalities "
7705 "to the IOCatalogue %s.",
7706 startMatching
? "and starting matching" : "but not starting matching");
7708 OSArray
* personalities
= OSKext::copyAllKextPersonalities(
7709 /* filterSafeBootFlag */ true);
7711 if (personalities
) {
7712 gIOCatalogue
->addDrivers(personalities
, startMatching
);
7713 numPersonalities
= personalities
->getCount();
7714 personalities
->release();
7717 OSKextLog(/* kext */ NULL
,
7718 kOSKextLogStepLevel
|
7720 "%d kext personalit%s sent to the IOCatalogue; %s.",
7721 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
7722 startMatching
? "matching started" : "matching not started");
7726 /*********************************************************************
7727 * Do not make a deep copy, just convert the IOKitPersonalities dict
7728 * to an array for sending to the IOCatalogue.
7729 *********************************************************************/
7731 OSKext::copyPersonalitiesArray(void)
7733 OSArray
* result
= NULL
;
7734 OSDictionary
* personalities
= NULL
; // do not release
7735 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7737 OSString
* personalityName
= NULL
; // do not release
7738 OSString
* personalityBundleIdentifier
= NULL
; // do not release
7740 personalities
= OSDynamicCast(OSDictionary
,
7741 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7742 if (!personalities
) {
7746 result
= OSArray::withCapacity(personalities
->getCount());
7751 personalitiesIterator
=
7752 OSCollectionIterator::withCollection(personalities
);
7753 if (!personalitiesIterator
) {
7756 while ((personalityName
= OSDynamicCast(OSString
,
7757 personalitiesIterator
->getNextObject()))) {
7759 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7760 personalities
->getObject(personalityName
));
7763 * If the personality doesn't have a CFBundleIdentifier, or if it
7764 * differs from the kext's, insert the kext's ID so we can find it.
7765 * The publisher ID is used to remove personalities from bundles
7768 personalityBundleIdentifier
= OSDynamicCast(OSString
,
7769 personality
->getObject(kCFBundleIdentifierKey
));
7771 if (!personalityBundleIdentifier
) {
7772 personality
->setObject(kCFBundleIdentifierKey
, bundleID
);
7773 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
)) {
7774 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
);
7777 result
->setObject(personality
);
7781 if (personalitiesIterator
) personalitiesIterator
->release();
7786 /*********************************************************************
7787 Might want to change this to a bool return?
7788 *********************************************************************/
7790 OSKext::sendPersonalitiesToCatalog(
7792 OSArray
* personalityNames
)
7794 OSReturn result
= kOSReturnSuccess
;
7795 OSArray
* personalitiesToSend
= NULL
; // must release
7796 OSDictionary
* kextPersonalities
= NULL
; // do not release
7799 if (!sLoadEnabled
) {
7801 kOSKextLogErrorLevel
|
7803 "Kext loading is disabled (attempt to start matching for kext %s).",
7804 getIdentifierCString());
7805 result
= kOSKextReturnDisabled
;
7809 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
7811 kOSKextLogErrorLevel
|
7813 "Kext %s is not loadable during safe boot; "
7814 "not sending personalities to the IOCatalogue.",
7815 getIdentifierCString());
7816 result
= kOSKextReturnNotLoadable
;
7820 if (!personalityNames
|| !personalityNames
->getCount()) {
7821 personalitiesToSend
= copyPersonalitiesArray();
7823 kextPersonalities
= OSDynamicCast(OSDictionary
,
7824 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7825 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
7829 personalitiesToSend
= OSArray::withCapacity(0);
7830 if (!personalitiesToSend
) {
7831 result
= kOSKextReturnNoMemory
;
7834 count
= personalityNames
->getCount();
7835 for (i
= 0; i
< count
; i
++) {
7836 OSString
* name
= OSDynamicCast(OSString
,
7837 personalityNames
->getObject(i
));
7841 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7842 kextPersonalities
->getObject(name
));
7844 personalitiesToSend
->setObject(personality
);
7848 if (personalitiesToSend
) {
7849 unsigned numPersonalities
= personalitiesToSend
->getCount();
7851 kOSKextLogStepLevel
|
7853 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
7854 getIdentifierCString(),
7856 numPersonalities
> 1 ? "ies" : "y",
7857 startMatching
? " and starting matching" : " but not starting matching");
7858 gIOCatalogue
->addDrivers(personalitiesToSend
, startMatching
);
7861 if (personalitiesToSend
) {
7862 personalitiesToSend
->release();
7867 /*********************************************************************
7868 * xxx - We should allow removing the kext's declared personalities,
7869 * xxx - even with other bundle identifiers.
7870 *********************************************************************/
7872 OSKext::removePersonalitiesFromCatalog(void)
7874 OSDictionary
* personality
= NULL
; // do not release
7876 personality
= OSDictionary::withCapacity(1);
7880 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
7883 kOSKextLogStepLevel
|
7885 "Kext %s removing all personalities naming it from the IOCatalogue.",
7886 getIdentifierCString());
7888 /* Have the IOCatalog remove all personalities matching this kext's
7889 * bundle ID and trigger matching anew.
7891 gIOCatalogue
->removeDrivers(personality
, /* startMatching */ true);
7894 if (personality
) personality
->release();
7901 #pragma mark Logging
7903 /*********************************************************************
7904 * Do not call any function that takes sKextLock here!
7905 *********************************************************************/
7908 OSKext::setUserSpaceLogFilter(
7909 OSKextLogSpec userLogFilter
,
7912 OSKextLogSpec result
;
7914 IORecursiveLockLock(sKextInnerLock
);
7916 result
= sUserSpaceKextLogFilter
;
7917 sUserSpaceKextLogFilter
= userLogFilter
;
7919 /* If the config flag itself is changing, log the state change
7920 * going both ways, before setting up the user-space log arrays,
7921 * so that this is only logged in the kernel.
7923 if (sUserSpaceKextLogFilter
!= result
) {
7924 OSKextLog(/* kext */ NULL
,
7925 kOSKextLogDebugLevel
|
7926 kOSKextLogGeneralFlag
,
7927 "User-space log flags changed from 0x%x to 0x%x.",
7928 result
, sUserSpaceKextLogFilter
);
7931 if (userLogFilter
&& captureFlag
&&
7932 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
7934 // xxx - do some measurements for a good initial capacity?
7935 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
7936 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
7938 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
7939 OSKextLog(/* kext */ NULL
,
7940 kOSKextLogErrorLevel
|
7941 kOSKextLogGeneralFlag
,
7942 "Failed to allocate user-space log message arrays.");
7943 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
7944 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
7948 IORecursiveLockUnlock(sKextInnerLock
);
7953 /*********************************************************************
7954 * Do not call any function that takes sKextLock here!
7955 *********************************************************************/
7958 OSKext::clearUserSpaceLogFilter(void)
7960 OSArray
* result
= NULL
;
7961 OSKextLogSpec oldLogFilter
;
7963 IORecursiveLockLock(sKextInnerLock
);
7965 result
= OSArray::withCapacity(2);
7967 result
->setObject(sUserSpaceLogSpecArray
);
7968 result
->setObject(sUserSpaceLogMessageArray
);
7970 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
7971 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
7973 oldLogFilter
= sUserSpaceKextLogFilter
;
7974 sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
7976 /* If the config flag itself is changing, log the state change
7977 * going both ways, after tearing down the user-space log
7978 * arrays, so this is only logged within the kernel.
7980 if (oldLogFilter
!= sUserSpaceKextLogFilter
) {
7981 OSKextLog(/* kext */ NULL
,
7982 kOSKextLogDebugLevel
|
7983 kOSKextLogGeneralFlag
,
7984 "User-space log flags changed from 0x%x to 0x%x.",
7985 oldLogFilter
, sUserSpaceKextLogFilter
);
7988 IORecursiveLockUnlock(sKextInnerLock
);
7993 /*********************************************************************
7994 * Do not call any function that takes sKextLock here!
7995 *********************************************************************/
7998 OSKext::getUserSpaceLogFilter(void)
8000 OSKextLogSpec result
;
8002 IORecursiveLockLock(sKextInnerLock
);
8003 result
= sUserSpaceKextLogFilter
;
8004 IORecursiveLockUnlock(sKextInnerLock
);
8009 /*********************************************************************
8010 * This function is called by OSMetaClass during kernel C++ setup.
8011 * Be careful what you access here; assume only OSKext::initialize()
8014 * Do not call any function that takes sKextLock here!
8015 *********************************************************************/
8016 #define VTRESET "\033[0m"
8018 #define VTBOLD "\033[1m"
8019 #define VTUNDER "\033[4m"
8021 #define VTRED "\033[31m"
8022 #define VTGREEN "\033[32m"
8023 #define VTYELLOW "\033[33m"
8024 #define VTBLUE "\033[34m"
8025 #define VTMAGENTA "\033[35m"
8026 #define VTCYAN "\033[36m"
8028 inline const char * colorForFlags(OSKextLogSpec flags
)
8030 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
8033 case kOSKextLogErrorLevel
:
8034 return VTRED VTBOLD
;
8036 case kOSKextLogWarningLevel
:
8039 case kOSKextLogBasicLevel
:
8040 return VTYELLOW VTUNDER
;
8042 case kOSKextLogProgressLevel
:
8045 case kOSKextLogStepLevel
:
8048 case kOSKextLogDetailLevel
:
8051 case kOSKextLogDebugLevel
:
8061 inline bool logSpecMatch(
8062 OSKextLogSpec msgLogSpec
,
8063 OSKextLogSpec logFilter
)
8065 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
8066 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
8067 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
8069 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
8070 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
8071 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
8073 /* Explicit messages always get logged.
8075 if (msgLevel
== kOSKextLogExplicitLevel
) {
8079 /* Warnings and errors are logged regardless of the flags.
8081 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
8085 /* A verbose message that isn't for a logging-enabled kext and isn't global
8086 * does *not* get logged.
8088 if (!msgKextGlobal
&& !filterKextGlobal
) {
8092 /* Warnings and errors are logged regardless of the flags.
8093 * All other messages must fit the flags and
8094 * have a level at or below the filter.
8097 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
8108 OSKextLogSpec msgLogSpec
,
8109 const char * format
, ...)
8113 va_start(argList
, format
);
8114 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
8121 OSKextLogSpec msgLogSpec
,
8122 const char * format
,
8125 extern int disableConsoleOutput
;
8127 bool logForKernel
= false;
8128 bool logForUser
= false;
8130 char stackBuffer
[120];
8131 uint32_t length
= 0;
8132 char * allocBuffer
= NULL
; // must kfree
8133 OSNumber
* logSpecNum
= NULL
; // must release
8134 OSString
* logString
= NULL
; // must release
8135 char * buffer
= stackBuffer
; // do not free
8137 IORecursiveLockLock(sKextInnerLock
);
8139 /* Set the kext/global bit in the message spec if we have no
8140 * kext or if the kext requests logging.
8142 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
8143 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
8146 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
8147 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
8148 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
8151 if (! (logForKernel
|| logForUser
) ) {
8155 /* No goto from here until past va_end()!
8157 va_copy(argList
, srcArgList
);
8158 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
8161 if (length
+ 1 >= sizeof(stackBuffer
)) {
8162 allocBuffer
= (char *)kalloc((length
+ 1) * sizeof(char));
8167 /* No goto from here until past va_end()!
8169 va_copy(argList
, srcArgList
);
8170 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
8173 buffer
= allocBuffer
;
8176 /* If user space wants the log message, queue it up.
8178 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
8179 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
8180 logString
= OSString::withCString(buffer
);
8181 if (logSpecNum
&& logString
) {
8182 sUserSpaceLogSpecArray
->setObject(logSpecNum
);
8183 sUserSpaceLogMessageArray
->setObject(logString
);
8187 /* Always log messages from the kernel according to the kernel's
8192 /* If we are in console mode and have a custom log filter,
8193 * colorize the log message.
8195 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
8196 const char * color
= ""; // do not free
8197 color
= colorForFlags(msgLogSpec
);
8198 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
8199 buffer
, color
[0] ? VTRESET
: "");
8201 printf("%s\n", buffer
);
8207 kfree(allocBuffer
, (length
+ 1) * sizeof(char));
8209 OSSafeRelease(logString
);
8210 OSSafeRelease(logSpecNum
);
8211 IORecursiveLockUnlock(sKextInnerLock
);
8218 #pragma mark Backtrace Dump & kmod_get_info() support
8220 /*********************************************************************
8221 *********************************************************************/
8224 OSKext::printKextsInBacktrace(
8227 int (* printf_func
)(const char *fmt
, ...),
8230 vm_offset_t
* kscan_addr
= NULL
;
8231 kmod_info_t
* k
= NULL
;
8232 kmod_reference_t
* r
= NULL
;
8237 IORecursiveLockLock(sKextLock
);
8240 for (k
= kmod
; k
; k
= k
->next
) {
8241 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)k
)) == 0) {
8242 (*printf_func
)(" kmod scan stopped due to missing "
8243 "kmod page: %p\n", k
);
8247 continue; // skip fake entries for built-in kernel components
8249 for (i
= 0, kscan_addr
= addr
; i
< cnt
; i
++, kscan_addr
++) {
8250 if ((*kscan_addr
>= k
->address
) &&
8251 (*kscan_addr
< (k
->address
+ k
->size
))) {
8254 (*printf_func
)(" Kernel Extensions in backtrace "
8255 "(with dependencies):\n");
8258 (*printf_func
)(" %s(%s)@%p->%p\n",
8259 k
->name
, k
->version
, k
->address
, k
->address
+ k
->size
- 1);
8261 for (r
= k
->reference_list
; r
; r
= r
->next
) {
8262 kmod_info_t
* rinfo
;
8264 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)r
)) == 0) {
8265 (*printf_func
)(" kmod dependency scan stopped "
8266 "due to missing dependency page: %p\n", r
);
8272 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
8273 (*printf_func
)(" kmod dependency scan stopped "
8274 "due to missing kmod page: %p\n", rinfo
);
8278 if (!rinfo
->address
) {
8279 continue; // skip fake entries for built-ins
8282 (*printf_func
)(" dependency: %s(%s)@%p\n",
8283 rinfo
->name
, rinfo
->version
, rinfo
->address
);
8286 break; // only report this kmod for one backtrace address
8292 IORecursiveLockUnlock(sKextLock
);
8298 /*******************************************************************************
8299 * substitute() looks at an input string (a pointer within a larger buffer)
8300 * for a match to a substring, and on match it writes the marker & substitution
8301 * character to an output string, updating the scan (from) and
8302 * output (to) indexes as appropriate.
8303 *******************************************************************************/
8304 static int substitute(
8305 const char * scan_string
,
8307 uint32_t * to_index
,
8308 uint32_t * from_index
,
8309 const char * substring
,
8313 /* string_out must be at least KMOD_MAX_NAME bytes.
8317 const char * scan_string
,
8319 uint32_t * to_index
,
8320 uint32_t * from_index
,
8321 const char * substring
,
8325 uint32_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
8327 /* On a substring match, append the marker (if there is one) and then
8328 * the substitution character, updating the output (to) index accordingly.
8329 * Then update the input (from) length by the length of the substring
8330 * that got replaced.
8332 if (!strncmp(scan_string
, substring
, substring_length
)) {
8334 string_out
[(*to_index
)++] = marker
;
8336 string_out
[(*to_index
)++] = substitution
;
8337 (*from_index
) += substring_length
;
8343 /*******************************************************************************
8344 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
8345 * KMOD_MAX_NAME characters and performs various substitutions of common
8346 * prefixes & substrings as defined by tables in kext_panic_report.h.
8347 *******************************************************************************/
8348 static void compactIdentifier(
8349 const char * identifier
,
8350 char * identifier_out
,
8351 char ** identifier_out_end
);
8355 const char * identifier
,
8356 char * identifier_out
,
8357 char ** identifier_out_end
)
8359 uint32_t from_index
, to_index
;
8360 uint32_t scan_from_index
= 0;
8361 uint32_t scan_to_index
= 0;
8362 subs_entry_t
* subs_entry
= NULL
;
8365 from_index
= to_index
= 0;
8366 identifier_out
[0] = '\0';
8368 /* Replace certain identifier prefixes with shorter @+character sequences.
8369 * Check the return value of substitute() so we only replace the prefix.
8371 for (subs_entry
= &kext_identifier_prefix_subs
[0];
8372 subs_entry
->substring
&& !did_sub
;
8375 did_sub
= substitute(identifier
, identifier_out
,
8376 &scan_to_index
, &scan_from_index
,
8377 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
8381 /* Now scan through the identifier looking for the common substrings
8382 * and replacing them with shorter !+character sequences via substitute().
8384 for (/* see above */;
8385 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
8388 const char * scan_string
= &identifier
[scan_from_index
];
8392 if (scan_from_index
) {
8393 for (subs_entry
= &kext_identifier_substring_subs
[0];
8394 subs_entry
->substring
&& !did_sub
;
8397 did_sub
= substitute(scan_string
, identifier_out
,
8398 &scan_to_index
, &scan_from_index
,
8399 subs_entry
->substring
, '!', subs_entry
->substitute
);
8403 /* If we didn't substitute, copy the input character to the output.
8406 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
8410 identifier_out
[scan_to_index
] = '\0';
8411 if (identifier_out_end
) {
8412 *identifier_out_end
= &identifier_out
[scan_to_index
];
8418 /*******************************************************************************
8419 * assemble_identifier_and_version() adds to a string buffer a compacted
8420 * bundle identifier followed by a version string.
8421 *******************************************************************************/
8423 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
8425 static int assemble_identifier_and_version(
8426 kmod_info_t
* kmod_info
,
8427 char * identPlusVers
);
8429 assemble_identifier_and_version(
8430 kmod_info_t
* kmod_info
,
8431 char * identPlusVers
)
8435 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
8436 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
8437 identPlusVers
[result
++] = '\t'; // increment for real char
8438 identPlusVers
[result
] = '\0'; // don't increment for nul char
8439 result
= strlcat(identPlusVers
, kmod_info
->version
, KMOD_MAX_NAME
);
8444 /*******************************************************************************
8445 *******************************************************************************/
8446 #define LAST_LOADED " - last loaded "
8447 #define LAST_LOADED_TS_WIDTH (16)
8451 OSKext::saveLoadedKextPanicListTyped(
8452 const char * prefix
,
8457 uint32_t * list_length_ptr
)
8459 uint32_t result
= 0;
8461 unsigned int count
, i
;
8463 count
= sLoadedKexts
->getCount();
8470 OSKext
* theKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
8471 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
8473 char identPlusVers
[2*KMOD_MAX_NAME
];
8474 uint32_t identPlusVersLength
;
8475 char timestampBuffer
[17]; // enough for a uint64_t
8477 /* Skip all built-in kexts.
8479 if (theKext
->isKernelComponent()) {
8483 /* Filter for kmod name (bundle identifier).
8485 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
8486 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
8490 /* Filter for libraries (kexts that have a compatible version).
8492 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
8493 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
8499 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
8501 printf("kext scan stopped due to missing kmod_info page: %p\n",
8507 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
8509 if (!identPlusVersLength
) {
8510 printf("error saving loaded kext info\n");
8514 /* We're going to note the last-loaded kext in the list.
8516 if (i
+ 1 == count
) {
8517 snprintf(timestampBuffer
, sizeof(timestampBuffer
), "%llu",
8518 AbsoluteTime_to_scalar(&last_loaded_timestamp
));
8519 identPlusVersLength
+= sizeof(LAST_LOADED
) - 1 +
8520 strnlen(timestampBuffer
, sizeof(timestampBuffer
));
8523 /* Adding 1 for the newline.
8525 if (*list_length_ptr
+ identPlusVersLength
+ 1 >= list_size
) {
8529 *list_length_ptr
= strlcat(paniclist
, identPlusVers
, list_size
);
8530 if (i
+ 1 == count
) {
8531 *list_length_ptr
= strlcat(paniclist
, LAST_LOADED
, list_size
);
8532 *list_length_ptr
= strlcat(paniclist
, timestampBuffer
, list_size
);
8534 *list_length_ptr
= strlcat(paniclist
, "\n", list_size
);
8540 if (*list_length_ptr
+ 1 <= list_size
) {
8541 result
= list_size
- (*list_length_ptr
+ 1);
8548 /*********************************************************************
8549 *********************************************************************/
8552 OSKext::saveLoadedKextPanicList(void)
8554 char * newlist
= NULL
;
8555 uint32_t newlist_size
= 0;
8556 uint32_t newlist_length
= 0;
8558 IORecursiveLockLock(sKextLock
);
8561 newlist_size
= KEXT_PANICLIST_SIZE
;
8562 newlist
= (char *)kalloc(newlist_size
);
8565 OSKextLog(/* kext */ NULL
,
8566 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
8567 "Couldn't allocate kext panic log buffer.");
8573 // non-"com.apple." kexts
8574 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
8575 /* libs? */ -1, newlist
, newlist_size
, &newlist_length
)) {
8579 // "com.apple." nonlibrary kexts
8580 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8581 /* libs? */ 0, newlist
, newlist_size
, &newlist_length
)) {
8585 // "com.apple." library kexts
8586 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8587 /* libs? */ 1, newlist
, newlist_size
, &newlist_length
)) {
8592 if (loaded_kext_paniclist
) {
8593 kfree(loaded_kext_paniclist
, loaded_kext_paniclist_size
);
8595 loaded_kext_paniclist
= newlist
;
8596 loaded_kext_paniclist_size
= newlist_size
;
8597 loaded_kext_paniclist_length
= newlist_length
;
8600 IORecursiveLockUnlock(sKextLock
);
8604 /*********************************************************************
8605 *********************************************************************/
8608 OSKext::saveUnloadedKextPanicList(OSKext
* aKext
)
8610 char * newlist
= NULL
;
8611 uint32_t newlist_size
= 0;
8612 uint32_t newlist_length
= 0;
8613 char identPlusVers
[2*KMOD_MAX_NAME
];
8614 uint32_t identPlusVersLength
;
8616 if (!aKext
->kmod_info
) {
8617 return; // do not goto finish here b/c of lock
8620 IORecursiveLockLock(sKextLock
);
8622 clock_get_uptime(&last_unloaded_timestamp
);
8623 last_unloaded_address
= (void *)aKext
->kmod_info
->address
;
8624 last_unloaded_size
= aKext
->kmod_info
->size
;
8627 identPlusVersLength
= assemble_identifier_and_version(aKext
->kmod_info
,
8629 if (!identPlusVersLength
) {
8630 printf("error saving unloaded kext info\n");
8634 newlist_length
= identPlusVersLength
;
8635 newlist_size
= newlist_length
+ 1;
8636 newlist
= (char *)kalloc(newlist_size
);
8639 printf("couldn't allocate kext panic log buffer\n");
8645 strlcpy(newlist
, identPlusVers
, newlist_size
);
8647 if (unloaded_kext_paniclist
) {
8648 kfree(unloaded_kext_paniclist
, unloaded_kext_paniclist_size
);
8650 unloaded_kext_paniclist
= newlist
;
8651 unloaded_kext_paniclist_size
= newlist_size
;
8652 unloaded_kext_paniclist_length
= newlist_length
;
8655 IORecursiveLockUnlock(sKextLock
);
8659 /*********************************************************************
8660 *********************************************************************/
8662 #define __kLoadSizeEscape "0x%lld"
8664 #define __kLoadSizeEscape "0x%ld"
8665 #endif /* __LP64__ */
8669 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
8671 printf_func("unloaded kexts:\n");
8672 if (unloaded_kext_paniclist
&&
8673 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) unloaded_kext_paniclist
) &&
8674 unloaded_kext_paniclist
[0]) {
8677 "%.*s (addr %p, size " __kLoadSizeEscape
") - last unloaded %llu\n",
8678 unloaded_kext_paniclist_length
, unloaded_kext_paniclist
,
8679 last_unloaded_address
, last_unloaded_size
,
8680 AbsoluteTime_to_scalar(&last_unloaded_timestamp
));
8682 printf_func("(none)\n");
8684 printf_func("loaded kexts:\n");
8685 if (loaded_kext_paniclist
&&
8686 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
8687 loaded_kext_paniclist
[0]) {
8689 printf_func("%.*s", loaded_kext_paniclist_length
, loaded_kext_paniclist
);
8691 printf_func("(none)\n");
8696 /*********************************************************************
8697 *********************************************************************/
8698 #if __ppc__ || __i386__
8701 OSKext::getKmodInfo(
8702 kmod_info_array_t
* kmodList
,
8703 mach_msg_type_number_t
* kmodCount
)
8705 kern_return_t result
= KERN_FAILURE
;
8707 kmod_info_t
* k
, * kmod_info_scan_ptr
;
8708 kmod_reference_t
* r
, * ref_scan_ptr
;
8712 *kmodList
= (kmod_info_t
*)0;
8715 IORecursiveLockLock(sKextLock
);
8719 size
+= sizeof(kmod_info_t
);
8720 r
= k
->reference_list
;
8722 size
+=sizeof(kmod_reference_t
);
8728 result
= KERN_SUCCESS
;
8732 result
= kmem_alloc(kernel_map
, &data
, size
);
8733 if (result
!= KERN_SUCCESS
) {
8737 /* Copy each kmod_info struct sequentially into the data buffer.
8738 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
8739 * the kernel space address is used to match refs, and a zero 'next' flags
8740 * the end of kmod_infos in the data buffer and the beginning of references.
8743 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8745 *kmod_info_scan_ptr
= *k
;
8747 kmod_info_scan_ptr
->next
= k
;
8749 kmod_info_scan_ptr
++;
8753 /* Now add references after the kmod_info structs in the same buffer.
8754 * Update each kmod_info with the ref_count so we can associate
8755 * references with kmod_info structs.
8758 ref_scan_ptr
= (kmod_reference_t
*)kmod_info_scan_ptr
;
8759 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8761 r
= k
->reference_list
;
8764 /* Note the last kmod_info in the data buffer has its next == 0.
8765 * Since there can only be one like that,
8766 * this case is handled by the caller.
8773 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
8774 * struct for the client to interpret.
8776 kmod_info_scan_ptr
->reference_list
= (kmod_reference_t
*)(long)ref_count
;
8777 kmod_info_scan_ptr
++;
8781 result
= vm_map_copyin(kernel_map
, data
, size
, TRUE
, (vm_map_copy_t
*)kmodList
);
8782 if (result
!= KERN_SUCCESS
) {
8787 result
= KERN_SUCCESS
;
8790 IORecursiveLockUnlock(sKextLock
);
8792 if (result
!= KERN_SUCCESS
&& data
) {
8793 kmem_free(kernel_map
, data
, size
);
8794 *kmodList
= (kmod_info_t
*)0;
8799 #endif /* __ppc__ || __i386__ */
8801 #pragma mark MAC Framework Support
8803 /*********************************************************************
8804 *********************************************************************/
8805 #if CONFIG_MACF_KEXT
8806 /* MAC Framework support */
8809 * define IOC_DEBUG to display run-time debugging information
8810 * #define IOC_DEBUG 1
8814 #define DPRINTF(x) printf x
8820 /*********************************************************************
8821 *********************************************************************/
8823 MACFObjectIsPrimitiveType(OSObject
* obj
)
8825 const OSMetaClass
* typeID
= NULL
; // do not release
8827 typeID
= OSTypeIDInst(obj
);
8828 if (typeID
== OSTypeID(OSString
) || typeID
== OSTypeID(OSNumber
) ||
8829 typeID
== OSTypeID(OSBoolean
) || typeID
== OSTypeID(OSData
)) {
8836 /*********************************************************************
8837 *********************************************************************/
8839 MACFLengthForObject(OSObject
* obj
)
8841 const OSMetaClass
* typeID
= NULL
; // do not release
8844 typeID
= OSTypeIDInst(obj
);
8845 if (typeID
== OSTypeID(OSString
)) {
8846 OSString
* stringObj
= OSDynamicCast(OSString
, obj
);
8847 len
= stringObj
->getLength() + 1;
8848 } else if (typeID
== OSTypeID(OSNumber
)) {
8849 len
= sizeof("4294967295"); /* UINT32_MAX */
8850 } else if (typeID
== OSTypeID(OSBoolean
)) {
8851 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, obj
);
8852 len
= boolObj
->isTrue() ? sizeof("true") : sizeof("false");
8853 } else if (typeID
== OSTypeID(OSData
)) {
8854 OSData
* dataObj
= OSDynamicCast(OSData
, obj
);
8855 len
= dataObj
->getLength();
8862 /*********************************************************************
8863 *********************************************************************/
8865 MACFInitElementFromObject(
8866 struct mac_module_data_element
* element
,
8869 const OSMetaClass
* typeID
= NULL
; // do not release
8871 typeID
= OSTypeIDInst(value
);
8872 if (typeID
== OSTypeID(OSString
)) {
8873 OSString
* stringObj
= OSDynamicCast(OSString
, value
);
8874 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8875 element
->value_size
= stringObj
->getLength() + 1;
8876 DPRINTF(("osdict: string %s size %d\n",
8877 stringObj
->getCStringNoCopy(), element
->value_size
));
8878 memcpy(element
->value
, stringObj
->getCStringNoCopy(),
8879 element
->value_size
);
8880 } else if (typeID
== OSTypeID(OSNumber
)) {
8881 OSNumber
* numberObj
= OSDynamicCast(OSNumber
, value
);
8882 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8883 element
->value_size
= sprintf(element
->value
, "%u",
8884 numberObj
->unsigned32BitValue()) + 1;
8885 } else if (typeID
== OSTypeID(OSBoolean
)) {
8886 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, value
);
8887 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8888 if (boolObj
->isTrue()) {
8889 strcpy(element
->value
, "true");
8890 element
->value_size
= 5;
8892 strcpy(element
->value
, "false");
8893 element
->value_size
= 6;
8895 } else if (typeID
== OSTypeID(OSData
)) {
8896 OSData
* dataObj
= OSDynamicCast(OSData
, value
);
8897 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8898 element
->value_size
= dataObj
->getLength();
8899 DPRINTF(("osdict: data size %d\n", dataObj
->getLength()));
8900 memcpy(element
->value
, dataObj
->getBytesNoCopy(),
8901 element
->value_size
);
8906 /*********************************************************************
8907 * This function takes an OSDictionary and returns a struct mac_module_data
8909 *********************************************************************/
8910 static struct mac_module_data
*
8911 MACFEncodeOSDictionary(OSDictionary
* dict
)
8913 struct mac_module_data
* result
= NULL
; // do not free
8914 const OSMetaClass
* typeID
= NULL
; // do not release
8915 OSString
* key
= NULL
; // do not release
8916 OSCollectionIterator
* keyIterator
= NULL
; // must release
8917 struct mac_module_data_element
* element
= NULL
; // do not free
8918 unsigned int strtabsize
= 0;
8919 unsigned int listtabsize
= 0;
8920 unsigned int dicttabsize
= 0;
8921 unsigned int nkeys
= 0;
8922 unsigned int datalen
= 0;
8923 char * strtab
= NULL
; // do not free
8924 char * listtab
= NULL
; // do not free
8925 char * dicttab
= NULL
; // do not free
8926 vm_offset_t data_addr
= 0;
8928 keyIterator
= OSCollectionIterator::withCollection(dict
);
8933 /* Iterate over OSModuleData to figure out total size */
8934 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
8936 // Get the key's value and determine its type
8937 OSObject
* value
= dict
->getObject(key
);
8942 typeID
= OSTypeIDInst(value
);
8943 if (MACFObjectIsPrimitiveType(value
)) {
8944 strtabsize
+= MACFLengthForObject(value
);
8946 else if (typeID
== OSTypeID(OSArray
)) {
8947 unsigned int k
, cnt
, nents
;
8948 OSArray
* arrayObj
= OSDynamicCast(OSArray
, value
);
8951 cnt
= arrayObj
->getCount();
8952 for (k
= 0; k
< cnt
; k
++) {
8953 value
= arrayObj
->getObject(k
);
8954 typeID
= OSTypeIDInst(value
);
8955 if (MACFObjectIsPrimitiveType(value
)) {
8956 listtabsize
+= MACFLengthForObject(value
);
8959 else if (typeID
== OSTypeID(OSDictionary
)) {
8960 unsigned int dents
= 0;
8961 OSDictionary
* dictObj
= NULL
; // do not release
8962 OSString
* dictkey
= NULL
; // do not release
8963 OSCollectionIterator
* dictIterator
= NULL
; // must release
8965 dictObj
= OSDynamicCast(OSDictionary
, value
);
8966 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
8967 if (!dictIterator
) {
8970 while ((dictkey
= OSDynamicCast(OSString
,
8971 dictIterator
->getNextObject()))) {
8973 OSObject
* dictvalue
= NULL
; // do not release
8975 dictvalue
= dictObj
->getObject(dictkey
);
8979 if (MACFObjectIsPrimitiveType(dictvalue
)) {
8980 strtabsize
+= MACFLengthForObject(dictvalue
);
8982 continue; /* Only handle primitive types here. */
8985 * Allow for the "arraynnn/" prefix in the key length.
8987 strtabsize
+= dictkey
->getLength() + 1;
8990 dictIterator
->release();
8992 dicttabsize
+= sizeof(struct mac_module_data_list
) +
8993 dents
* sizeof(struct mac_module_data_element
);
8998 continue; /* Skip everything else. */
9004 listtabsize
+= sizeof(struct mac_module_data_list
) +
9005 (nents
- 1) * sizeof(struct mac_module_data_element
);
9007 continue; /* skip anything else */
9009 strtabsize
+= key
->getLength() + 1;
9017 * Allocate and fill in the module data structures.
9019 datalen
= sizeof(struct mac_module_data
) +
9020 sizeof(mac_module_data_element
) * (nkeys
- 1) +
9021 strtabsize
+ listtabsize
+ dicttabsize
;
9022 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
9023 datalen
, strtabsize
, listtabsize
, dicttabsize
));
9024 if (kmem_alloc(kernel_map
, &data_addr
, datalen
) != KERN_SUCCESS
) {
9027 result
= (mac_module_data
*)data_addr
;
9028 result
->base_addr
= data_addr
;
9029 result
->size
= datalen
;
9030 result
->count
= nkeys
;
9031 strtab
= (char *)&result
->data
[nkeys
];
9032 listtab
= strtab
+ strtabsize
;
9033 dicttab
= listtab
+ listtabsize
;
9034 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
9035 data_addr
, strtab
, listtab
, dicttab
, data_addr
+ datalen
));
9037 keyIterator
->reset();
9039 element
= &result
->data
[0];
9040 DPRINTF(("osdict: element %p\n", element
));
9041 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
9043 // Get the key's value and determine its type
9044 OSObject
* value
= dict
->getObject(key
);
9050 DPRINTF(("osdict: element @%p\n", element
));
9051 element
->key
= strtab
;
9052 element
->key_size
= key
->getLength() + 1;
9053 DPRINTF(("osdict: key %s size %d @%p\n", key
->getCStringNoCopy(),
9054 element
->key_size
, strtab
));
9055 memcpy(element
->key
, key
->getCStringNoCopy(), element
->key_size
);
9057 typeID
= OSTypeIDInst(value
);
9058 if (MACFObjectIsPrimitiveType(value
)) {
9060 element
->value
= element
->key
+ element
->key_size
;
9061 DPRINTF(("osdict: primitive element value %p\n", element
->value
));
9062 MACFInitElementFromObject(element
, value
);
9063 strtab
+= element
->key_size
+ element
->value_size
;
9064 DPRINTF(("osdict: new strtab %p\n", strtab
));
9065 } else if (typeID
== OSTypeID(OSArray
)) {
9066 unsigned int k
, cnt
, nents
;
9068 struct mac_module_data_list
*arrayhd
;
9069 struct mac_module_data_element
*ele
;
9070 OSArray
*arrayObj
= OSDynamicCast(OSArray
, value
);
9072 element
->value
= listtab
;
9073 DPRINTF(("osdict: array element value %p\n", element
->value
));
9074 element
->value_type
= MAC_DATA_TYPE_ARRAY
;
9075 arrayhd
= (struct mac_module_data_list
*)element
->value
;
9077 DPRINTF(("osdict: arrayhd %p\n", arrayhd
));
9079 astrtab
= strtab
+ element
->key_size
;
9080 ele
= &(arrayhd
->list
[0]);
9081 cnt
= arrayObj
->getCount();
9082 for (k
= 0; k
< cnt
; k
++) {
9083 value
= arrayObj
->getObject(k
);
9084 DPRINTF(("osdict: array ele %d @%p\n", nents
, ele
));
9087 typeID
= OSTypeIDInst(value
);
9088 if (MACFObjectIsPrimitiveType(value
)) {
9089 if (arrayhd
->type
!= 0 &&
9090 arrayhd
->type
!= MAC_DATA_TYPE_PRIMITIVE
) {
9094 arrayhd
->type
= MAC_DATA_TYPE_PRIMITIVE
;
9095 ele
->value
= astrtab
;
9096 MACFInitElementFromObject(ele
, value
);
9097 astrtab
+= ele
->value_size
;
9098 DPRINTF(("osdict: array new astrtab %p\n", astrtab
));
9099 } else if (typeID
== OSTypeID(OSDictionary
)) {
9101 char * dstrtab
= NULL
; // do not free
9102 OSDictionary
* dictObj
= NULL
; // do not release
9103 OSString
* dictkey
= NULL
; // do not release
9104 OSCollectionIterator
* dictIterator
= NULL
; // must release
9105 struct mac_module_data_list
* dicthd
= NULL
; // do not free
9106 struct mac_module_data_element
* dele
= NULL
; // do not free
9108 if (arrayhd
->type
!= 0 &&
9109 arrayhd
->type
!= MAC_DATA_TYPE_DICT
) {
9113 dictObj
= OSDynamicCast(OSDictionary
, value
);
9114 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
9115 if (!dictIterator
) {
9118 DPRINTF(("osdict: dict\n"));
9119 ele
->value
= dicttab
;
9120 ele
->value_type
= MAC_DATA_TYPE_DICT
;
9121 dicthd
= (struct mac_module_data_list
*)ele
->value
;
9122 DPRINTF(("osdict: dicthd %p\n", dicthd
));
9125 while ((dictkey
= OSDynamicCast(OSString
,
9126 dictIterator
->getNextObject()))) {
9128 OSObject
* dictvalue
= NULL
; // do not release
9130 dictvalue
= dictObj
->getObject(dictkey
);
9134 dele
= &(dicthd
->list
[dents
]);
9135 DPRINTF(("osdict: dict ele %d @%p\n", dents
, dele
));
9136 if (MACFObjectIsPrimitiveType(dictvalue
)) {
9137 dele
->key
= dstrtab
;
9138 dele
->key_size
= dictkey
->getLength() + 1;
9139 DPRINTF(("osdict: dictkey %s size %d @%p\n",
9140 dictkey
->getCStringNoCopy(), dictkey
->getLength(), dstrtab
));
9141 memcpy(dele
->key
, dictkey
->getCStringNoCopy(),
9143 dele
->value
= dele
->key
+ dele
->key_size
;
9144 MACFInitElementFromObject(dele
, dictvalue
);
9145 dstrtab
+= dele
->key_size
+ dele
->value_size
;
9146 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab
));
9148 continue; /* Only handle primitive types here. */
9152 dictIterator
->release();
9156 arrayhd
->type
= MAC_DATA_TYPE_DICT
;
9157 ele
->value_size
= sizeof(struct mac_module_data_list
) +
9158 (dents
- 1) * sizeof(struct mac_module_data_element
);
9159 DPRINTF(("osdict: dict ele size %d ents %d\n", ele
->value_size
, dents
));
9160 dicttab
+= ele
->value_size
;
9161 DPRINTF(("osdict: new dicttab %p\n", dicttab
));
9162 dicthd
->count
= dents
;
9165 continue; /* Skip everything else. */
9173 element
->value_size
= sizeof(struct mac_module_data_list
) +
9174 (nents
- 1) * sizeof(struct mac_module_data_element
);
9175 listtab
+= element
->value_size
;
9176 DPRINTF(("osdict: new listtab %p\n", listtab
));
9177 arrayhd
->count
= nents
;
9179 DPRINTF(("osdict: new strtab %p\n", strtab
));
9181 continue; /* skip anything else */
9185 DPRINTF(("result list @%p, key %p value %p\n",
9186 result
, result
->data
[0].key
, result
->data
[0].value
));
9188 if (keyIterator
) keyIterator
->release();
9192 /*********************************************************************
9193 * This function takes a plist and looks for an OSModuleData dictionary.
9194 * If it is found, an encoded copy is returned. The value must be
9196 *********************************************************************/
9198 MACFCopyModuleDataForKext(
9200 mach_msg_type_number_t
* datalen
)
9203 struct mac_module_data
* result
= NULL
;
9204 OSDictionary
* kextModuleData
= NULL
; // do not release
9205 vm_map_copy_t copy
= 0;
9207 kextModuleData
= OSDynamicCast(OSDictionary
,
9208 theKext
->getPropertyForHostArch("OSModuleData"));
9209 if (!kextModuleData
) {
9213 result
= MACFEncodeOSDictionary(kextModuleData
);
9217 *datalen
= module_data
->size
;
9220 return (void *)result
;
9222 #endif /* CONFIG_MACF_KEXT */