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 static OSArray
* sPrelinkedPersonalities
= NULL
;
195 // Requests to kextd waiting to be picked up.
196 static OSArray
* sKernelRequests
= NULL
;
197 // Identifier of kext load requests in sKernelRequests
198 static OSSet
* sPostedKextLoadIdentifiers
= NULL
;
199 static OSArray
* sRequestCallbackRecords
= NULL
;
201 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
202 static OSSet
* sAllKextLoadIdentifiers
= NULL
;
203 static KXLDContext
* sKxldContext
= NULL
;
204 static uint32_t sNextLoadTag
= 0;
205 static uint32_t sNextRequestTag
= 0;
207 static bool sUserLoadsActive
= false;
208 static bool sKextdActive
= false;
209 static bool sDeferredLoadSucceeded
= false;
210 static bool sConsiderUnloadsExecuted
= false;
212 static bool sKernelRequestsEnabled
= true;
213 static bool sLoadEnabled
= true;
214 static bool sUnloadEnabled
= true;
216 /*********************************************************************
217 * Stuff for the OSKext representing the kernel itself.
219 static OSKext
* sKernelKext
= NULL
;
221 /* Set up a fake kmod_info struct for the kernel.
222 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
223 * before OSKext is initialized; that call only needs the name
224 * and address to be set correctly.
226 * We don't do much else with the kerne's kmod_info; we never
227 * put it into the kmod list, never adjust the reference count,
228 * and never have kernel components reference it.
229 * For that matter, we don't do much with kmod_info structs
230 * at all anymore! We just keep them filled in for gdb and
231 * binary compability.
233 kmod_info_t g_kernel_kmod_info
= {
235 /* info_version */ KMOD_INFO_VERSION
,
236 /* id */ 0, // loadTag: kernel is always 0
237 /* name */ kOSKextKernelIdentifier
, // bundle identifier
238 /* version */ "0", // filled in in OSKext::initialize()
239 /* reference_count */ -1, // never adjusted; kernel never unloads
240 /* reference_list */ NULL
,
241 /* address */ (vm_address_t
)&_mh_execute_header
,
242 /* size */ 0, // filled in in OSKext::initialize()
249 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
250 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
251 // misc_protos.h, db_low_trace.c, kgmacros
252 // 'kmod' is a holdover from the old kmod system, we can't rename it.
253 kmod_info_t
* kmod
= NULL
;
255 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
257 static char * unloaded_kext_paniclist
= NULL
;
258 static uint32_t unloaded_kext_paniclist_size
= 0;
259 static uint32_t unloaded_kext_paniclist_length
= 0;
260 AbsoluteTime last_loaded_timestamp
;
262 static char * loaded_kext_paniclist
= NULL
;
263 static uint32_t loaded_kext_paniclist_size
= 0;
264 static uint32_t loaded_kext_paniclist_length
= 0;
265 AbsoluteTime last_unloaded_timestamp
;
266 static void * last_unloaded_address
= NULL
;
268 static uint64_t last_unloaded_size
= 0;
270 static uint32_t last_unloaded_size
= 0;
271 #endif /* __LP64__ */
275 /*********************************************************************
276 * Because we can start IOService matching from OSKext (via IOCatalogue)
277 * and IOService can call into OSKext, there is potential for cross-lock
278 * contention, so OSKext needs two locks. The regular sKextLock above
279 * guards most OSKext class/static variables, and sKextInnerLock guards
280 * variables that can be accessed on in-calls from IOService, currently:
282 * * OSKext::considerUnloads()
284 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
286 * When both sKextLock and sKextInnerLock need to be taken,
287 * always lock sKextLock first and unlock it second. Never take both
288 * locks in an entry point to OSKext; if you need to do so, you must
289 * spawn an independent thread to avoid potential deadlocks for threads
290 * calling into OSKext.
292 * All static variables from here to the closing comment block fall
293 * under sKextInnerLock.
295 static IORecursiveLock
* sKextInnerLock
= NULL
;
297 static bool sAutounloadEnabled
= true;
298 static bool sConsiderUnloadsCalled
= false;
299 static bool sConsiderUnloadsPending
= false;
301 static unsigned int sConsiderUnloadDelay
= 60; // seconds
302 static thread_call_t sUnloadCallout
= 0;
303 static thread_call_t sDestroyLinkContextThread
= 0; // one-shot, one-at-a-time thread
304 static bool sSystemSleep
= false; // true when system going to sleep
306 static const OSKextLogSpec kDefaultKernelLogFilter
= kOSKextLogBasicLevel
|
307 kOSKextLogVerboseFlagsMask
;
308 static OSKextLogSpec sKernelLogFilter
= kDefaultKernelLogFilter
;
309 static bool sBootArgLogFilterFound
= false;
310 SYSCTL_INT(_debug
, OID_AUTO
, kextlog
, CTLFLAG_RW
, &sKernelLogFilter
,
311 sKernelLogFilter
, "kernel kext logging");
313 static OSKextLogSpec sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
314 static OSArray
* sUserSpaceLogSpecArray
= NULL
;
315 static OSArray
* sUserSpaceLogMessageArray
= NULL
;
318 * End scope for sKextInnerLock-protected variables.
319 *********************************************************************/
322 #pragma mark OSData callbacks (need to move to OSData)
324 /*********************************************************************
325 * C functions used for callbacks.
326 *********************************************************************/
328 void osdata_kmem_free(void * ptr
, unsigned int length
) {
329 kmem_free(kernel_map
, (vm_address_t
)ptr
, length
);
333 void osdata_phys_free(void * ptr
, unsigned int length
) {
334 ml_static_mfree((vm_offset_t
)ptr
, length
);
338 void osdata_vm_deallocate(void * ptr
, unsigned int length
)
340 (void)vm_deallocate(kernel_map
, (vm_offset_t
)ptr
, length
);
346 #pragma mark KXLD Allocation Callback
348 /*********************************************************************
349 * KXLD Allocation Callback
350 *********************************************************************/
354 KXLDAllocateFlags
* flags
,
357 vm_address_t result
= 0; // returned
358 kern_return_t mach_result
= KERN_FAILURE
;
359 bool success
= false;
360 OSKext
* theKext
= (OSKext
*)user_data
;
361 u_long roundSize
= round_page(size
);
362 OSData
* linkBuffer
= NULL
; // must release
364 mach_result
= kext_alloc(&result
, roundSize
, /* fixed */ FALSE
);
365 if (mach_result
!= KERN_SUCCESS
) {
367 kOSKextLogErrorLevel
|
368 kOSKextLogGeneralFlag
,
369 "Can't allocate kernel memory to link %s.",
370 theKext
->getIdentifierCString());
374 /* Create an OSData wrapper for the allocated buffer.
375 * Note that we do not set a dealloc function on it here.
376 * We have to call vm_map_unwire() on it in OSKext::unload()
377 * and an OSData dealloc function can't take all those parameters.
379 linkBuffer
= OSData::withBytesNoCopy((void *)result
, roundSize
);
382 kOSKextLogErrorLevel
|
383 kOSKextLogGeneralFlag
,
384 "Can't allocate linked executable wrapper for %s.",
385 theKext
->getIdentifierCString());
390 kOSKextLogProgressLevel
|
391 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
392 "Allocated link buffer for kext %s at %p (%lu bytes).",
393 theKext
->getIdentifierCString(),
394 (void *)result
, (unsigned long)roundSize
);
396 theKext
->setLinkedExecutable(linkBuffer
);
398 *flags
= kKxldAllocateWritable
;
402 if (!success
&& result
) {
403 kext_free(result
, roundSize
);
407 OSSafeRelease(linkBuffer
);
409 return (kxld_addr_t
)result
;
412 /*********************************************************************
413 *********************************************************************/
416 KXLDLogSubsystem subsystem
,
422 OSKext
*theKext
= (OSKext
*) user_data
;
423 OSKextLogSpec logSpec
= 0;
426 case kKxldLogLinking
:
427 logSpec
|= kOSKextLogLinkFlag
;
429 case kKxldLogPatching
:
430 logSpec
|= kOSKextLogPatchFlag
;
435 case kKxldLogExplicit
:
436 logSpec
|= kOSKextLogExplicitLevel
;
439 logSpec
|= kOSKextLogErrorLevel
;
442 logSpec
|= kOSKextLogWarningLevel
;
445 logSpec
|= kOSKextLogProgressLevel
;
448 logSpec
|= kOSKextLogDetailLevel
;
451 logSpec
|= kOSKextLogDebugLevel
;
455 OSKextVLog(theKext
, logSpec
, format
, argList
);
459 #pragma mark Module Config (Startup & Shutdown)
461 /*********************************************************************
462 * Module Config (Class Definition & Class Methods)
463 *********************************************************************/
464 #define super OSObject
465 OSDefineMetaClassAndStructors(OSKext
, OSObject
)
467 /*********************************************************************
468 *********************************************************************/
471 OSKext::initialize(void)
473 OSData
* kernelExecutable
= NULL
; // do not release
474 u_char
* kernelStart
= NULL
; // do not free
475 size_t kernelLength
= 0;
476 OSString
* scratchString
= NULL
; // must release
477 IORegistryEntry
* registryRoot
= NULL
; // do not release
478 OSNumber
* kernelCPUType
= NULL
; // must release
479 OSNumber
* kernelCPUSubtype
= NULL
; // must release
480 OSKextLogSpec bootLogFilter
= kOSKextLogSilentFilter
;
481 bool setResult
= false;
482 uint64_t * timestamp
= 0;
483 char bootArgBuffer
[16]; // for PE_parse_boot_argn w/strings
485 /* This must be the first thing allocated. Everything else grabs this lock.
487 sKextLock
= IORecursiveLockAlloc();
488 sKextInnerLock
= IORecursiveLockAlloc();
490 assert(sKextInnerLock
);
492 sKextsByID
= OSDictionary::withCapacity(kOSKextTypicalLoadCount
);
493 sLoadedKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
);
494 sKernelRequests
= OSArray::withCapacity(0);
495 sPostedKextLoadIdentifiers
= OSSet::withCapacity(0);
496 sAllKextLoadIdentifiers
= OSSet::withCapacity(kOSKextTypicalLoadCount
);
497 sRequestCallbackRecords
= OSArray::withCapacity(0);
498 assert(sKextsByID
&& sLoadedKexts
&& sKernelRequests
&&
499 sPostedKextLoadIdentifiers
&& sAllKextLoadIdentifiers
&&
500 sRequestCallbackRecords
);
502 /* Read the log flag boot-args and set the log flags.
504 if (PE_parse_boot_argn("kextlog", &bootLogFilter
, sizeof("kextlog=0x00000000 "))) {
505 sBootArgLogFilterFound
= true;
506 sKernelLogFilter
= bootLogFilter
;
507 // log this if any flags are set
508 OSKextLog(/* kext */ NULL
,
509 kOSKextLogBasicLevel
|
511 "Kernel kext log filter 0x%x per kextlog boot arg.",
512 (unsigned)sKernelLogFilter
);
515 sSafeBoot
= PE_parse_boot_argn("-x", bootArgBuffer
,
516 sizeof(bootArgBuffer
)) ? true : false;
519 OSKextLog(/* kext */ NULL
,
520 kOSKextLogWarningLevel
|
521 kOSKextLogGeneralFlag
,
522 "SAFE BOOT DETECTED - "
523 "only valid OSBundleRequired kexts will be loaded.");
526 /* Set up an OSKext instance to represent the kernel itself.
528 sKernelKext
= new OSKext
;
531 kernelStart
= (u_char
*)&_mh_execute_header
;
532 kernelLength
= getlastaddr() - (vm_offset_t
)kernelStart
;
533 kernelExecutable
= OSData::withBytesNoCopy(
534 kernelStart
, kernelLength
);
535 assert(kernelExecutable
);
537 sKernelKext
->loadTag
= sNextLoadTag
++; // the kernel is load tag 0
538 sKernelKext
->bundleID
= OSSymbol::withCString(kOSKextKernelIdentifier
);
540 sKernelKext
->version
= OSKextParseVersionString(osrelease
);
541 sKernelKext
->compatibleVersion
= sKernelKext
->version
;
542 sKernelKext
->linkedExecutable
= kernelExecutable
;
543 // linkState will be set first time we do a link
545 sKernelKext
->flags
.hasAllDependencies
= 1;
546 sKernelKext
->flags
.kernelComponent
= 1;
547 sKernelKext
->flags
.prelinked
= 0;
548 sKernelKext
->flags
.loaded
= 1;
549 sKernelKext
->flags
.started
= 1;
550 sKernelKext
->flags
.CPPInitialized
= 0;
552 sKernelKext
->kmod_info
= &g_kernel_kmod_info
;
553 strlcpy(g_kernel_kmod_info
.version
, osrelease
,
554 sizeof(g_kernel_kmod_info
.version
));
555 g_kernel_kmod_info
.size
= kernelLength
;
556 g_kernel_kmod_info
.id
= sKernelKext
->loadTag
;
558 /* Cons up an info dict, so we don't have to have special-case
561 sKernelKext
->infoDict
= OSDictionary::withCapacity(5);
562 assert(sKernelKext
->infoDict
);
563 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleIdentifierKey
,
564 sKernelKext
->bundleID
);
566 setResult
= sKernelKext
->infoDict
->setObject(kOSKernelResourceKey
,
570 scratchString
= OSString::withCStringNoCopy(osrelease
);
571 assert(scratchString
);
572 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleVersionKey
,
575 OSSafeReleaseNULL(scratchString
);
577 scratchString
= OSString::withCStringNoCopy("mach_kernel");
578 assert(scratchString
);
579 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleNameKey
,
582 OSSafeReleaseNULL(scratchString
);
584 /* Add the kernel kext to the bookkeeping dictionaries. Note that
585 * the kernel kext doesn't have a kmod_info struct. copyInfo()
586 * gathers info from other places anyhow.
588 setResult
= sKextsByID
->setObject(sKernelKext
->bundleID
, sKernelKext
);
590 setResult
= sLoadedKexts
->setObject(sKernelKext
);
592 sKernelKext
->release();
594 registryRoot
= IORegistryEntry::getRegistryRoot();
595 kernelCPUType
= OSNumber::withNumber(
596 (long long unsigned int)_mh_execute_header
.cputype
,
597 8 * sizeof(_mh_execute_header
.cputype
));
598 kernelCPUSubtype
= OSNumber::withNumber(
599 (long long unsigned int)_mh_execute_header
.cpusubtype
,
600 8 * sizeof(_mh_execute_header
.cpusubtype
));
601 assert(registryRoot
&& kernelCPUSubtype
&& kernelCPUType
);
603 registryRoot
->setProperty(kOSKernelCPUTypeKey
, kernelCPUType
);
604 registryRoot
->setProperty(kOSKernelCPUSubtypeKey
, kernelCPUSubtype
);
606 OSSafeRelease(kernelCPUType
);
607 OSSafeRelease(kernelCPUSubtype
);
609 timestamp
= __OSAbsoluteTimePtr(&last_loaded_timestamp
);
611 timestamp
= __OSAbsoluteTimePtr(&last_unloaded_timestamp
);
614 OSKextLog(/* kext */ NULL
,
615 kOSKextLogProgressLevel
|
616 kOSKextLogGeneralFlag
,
617 "Kext system initialized.");
622 /*********************************************************************
623 * This could be in OSKextLib.cpp but we need to hold a lock
624 * while removing all the segments and sKextLock will do.
625 *********************************************************************/
628 OSKext::removeKextBootstrap(void)
630 OSReturn result
= kOSReturnError
;
632 static bool alreadyDone
= false;
633 boolean_t keepsyms
= FALSE
;
635 const char * dt_kernel_header_name
= "Kernel-__HEADER";
636 const char * dt_kernel_symtab_name
= "Kernel-__SYMTAB";
637 kernel_mach_header_t
* dt_mach_header
= NULL
;
638 int dt_mach_header_size
= 0;
639 struct symtab_command
* dt_symtab
= NULL
;
640 int dt_symtab_size
= 0;
643 kernel_segment_command_t
* seg_to_remove
= NULL
;
644 #if __ppc__ || __arm__
645 const char * dt_segment_name
= NULL
;
646 void * segment_paddress
= NULL
;
647 int segment_size
= 0;
650 /* This must be the very first thing done by this function.
652 IORecursiveLockLock(sKextLock
);
654 /* If we already did this, it's a success.
657 result
= kOSReturnSuccess
;
661 OSKextLog(/* kext */ NULL
,
662 kOSKextLogProgressLevel
|
663 kOSKextLogGeneralFlag
,
664 "Jettisoning kext bootstrap segments.");
666 PE_parse_boot_argn("keepsyms", &keepsyms
, sizeof(keepsyms
));
669 * Dispose of unnecessary stuff that the booter didn't need to load.
671 dt_result
= IODTGetLoaderInfo(dt_kernel_header_name
,
672 (void **)&dt_mach_header
, &dt_mach_header_size
);
673 if (dt_result
== 0 && dt_mach_header
) {
674 IODTFreeLoaderInfo(dt_kernel_header_name
, (void *)dt_mach_header
,
675 round_page_32(dt_mach_header_size
));
677 dt_result
= IODTGetLoaderInfo(dt_kernel_symtab_name
,
678 (void **)&dt_symtab
, &dt_symtab_size
);
679 if (dt_result
== 0 && dt_symtab
) {
680 IODTFreeLoaderInfo(dt_kernel_symtab_name
, (void *)dt_symtab
,
681 round_page_32(dt_symtab_size
));
685 * KLD bootstrap segment.
687 // xxx - should rename KLD segment
688 seg_to_remove
= getsegbyname("__KLD");
690 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
693 #if __ppc__ || __arm__
694 /* Free the memory that was set up by bootx.
696 dt_segment_name
= "Kernel-__KLD";
697 if (0 == IODTGetLoaderInfo(dt_segment_name
, &segment_paddress
, &segment_size
)) {
698 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
701 #elif __i386__ || __x86_64__
702 /* On x86, use the mapping data from the segment load command to
703 * unload KLD directly.
704 * This may invalidate any assumptions about "avail_start"
705 * defining the lower bound for valid physical addresses.
707 if (seg_to_remove
&& seg_to_remove
->vmaddr
&& seg_to_remove
->vmsize
) {
708 ml_static_mfree(seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
714 seg_to_remove
= NULL
;
717 * Prelinked kernel's symtab (if there is one).
719 kernel_section_t
* sect
;
720 sect
= getsectbyname("__PRELINK", "__symtab");
721 if (sect
&& sect
->addr
&& sect
->size
) {
722 ml_static_mfree(sect
->addr
, sect
->size
);
726 * Dump the LINKEDIT segment, unless keepsyms is set.
729 seg_to_remove
= (kernel_segment_command_t
*)getsegbyname("__LINKEDIT");
731 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
734 #if __ppc__ || __arm__
735 dt_segment_name
= "Kernel-__LINKEDIT";
736 if (0 == IODTGetLoaderInfo(dt_segment_name
,
737 &segment_paddress
, &segment_size
)) {
739 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
742 #elif __i386__ || __x86_64__
743 if (seg_to_remove
&& seg_to_remove
->vmaddr
&& seg_to_remove
->vmsize
) {
744 ml_static_mfree(seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
750 OSKextLog(/* kext */ NULL
,
751 kOSKextLogBasicLevel
|
752 kOSKextLogGeneralFlag
,
753 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
756 seg_to_remove
= NULL
;
759 result
= kOSReturnSuccess
;
763 /* This must be the very last thing done before returning.
765 IORecursiveLockUnlock(sKextLock
);
770 /*********************************************************************
771 *********************************************************************/
773 OSKext::flushNonloadedKexts(
774 Boolean flushPrelinkedKexts
)
776 OSSet
* prelinkedKexts
= NULL
; // must release
777 OSCollectionIterator
* kextIterator
= NULL
; // must release
778 OSCollectionIterator
* prelinkIterator
= NULL
; // must release
779 const OSSymbol
* thisID
= NULL
; // do not release
780 OSKext
* thisKext
= NULL
; // do not release
783 IORecursiveLockLock(sKextLock
);
785 OSKextLog(/* kext */ NULL
,
786 kOSKextLogProgressLevel
|
787 kOSKextLogKextBookkeepingFlag
,
788 "Flushing nonloaded kexts and other unused data.");
790 OSKext::considerDestroyingLinkContext();
792 /* If we aren't flushing unused prelinked kexts, we have to put them
793 * aside while we flush everything else so make a container for them.
795 if (!flushPrelinkedKexts
) {
796 prelinkedKexts
= OSSet::withCapacity(0);
797 if (!prelinkedKexts
) {
802 /* Set aside prelinked kexts (in-use or not) and break
803 * any lingering inter-kext references for nonloaded kexts
804 * so they have min. retain counts.
806 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
811 while ((thisID
= OSDynamicCast(OSSymbol
,
812 kextIterator
->getNextObject()))) {
814 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
817 if (prelinkedKexts
&& thisKext
->isPrelinked()) {
818 prelinkedKexts
->setObject(thisKext
);
820 thisKext
->flushDependencies(/* forceIfLoaded */ false);
824 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
826 sKextsByID
->flushCollection();
828 /* Now put the loaded kexts back into the ID dictionary.
830 count
= sLoadedKexts
->getCount();
831 for (i
= 0; i
< count
; i
++) {
832 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
833 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
836 /* Finally, put back the prelinked kexts if we saved any.
838 if (prelinkedKexts
) {
839 prelinkIterator
= OSCollectionIterator::withCollection(prelinkedKexts
);
840 if (!prelinkIterator
) {
844 while ((thisKext
= OSDynamicCast(OSKext
,
845 prelinkIterator
->getNextObject()))) {
847 sKextsByID
->setObject(thisKext
->getIdentifierCString(),
853 IORecursiveLockUnlock(sKextLock
);
855 OSSafeRelease(prelinkedKexts
);
856 OSSafeRelease(kextIterator
);
857 OSSafeRelease(prelinkIterator
);
862 /*********************************************************************
863 *********************************************************************/
866 OSKext::setKextdActive(Boolean active
)
868 IORecursiveLockLock(sKextLock
);
869 sKextdActive
= active
;
870 if (sPrelinkedPersonalities
) {
871 gIOCatalogue
->removePersonalities(sPrelinkedPersonalities
);
872 OSSafeReleaseNULL(sPrelinkedPersonalities
);
874 IORecursiveLockUnlock(sKextLock
);
879 /*********************************************************************
880 *********************************************************************/
883 OSKext::setDeferredLoadSucceeded(Boolean succeeded
)
885 IORecursiveLockLock(sKextLock
);
886 sDeferredLoadSucceeded
= succeeded
;
887 IORecursiveLockUnlock(sKextLock
);
892 /*********************************************************************
893 * Called from IOSystemShutdownNotification.
894 *********************************************************************/
897 OSKext::willShutdown(void)
899 OSReturn checkResult
= kOSReturnError
;
900 OSDictionary
* exitRequest
= NULL
; // must release
902 IORecursiveLockLock(sKextLock
);
904 OSKext::setLoadEnabled(false);
905 OSKext::setUnloadEnabled(false);
906 OSKext::setAutounloadsEnabled(false);
907 OSKext::setKernelRequestsEnabled(false);
909 OSKextLog(/* kext */ NULL
,
910 kOSKextLogProgressLevel
|
911 kOSKextLogGeneralFlag
,
912 "System shutdown; requesting immediate kextd exit.");
914 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit
,
916 if (checkResult
!= kOSReturnSuccess
) {
919 if (!sKernelRequests
->setObject(exitRequest
)) {
926 IORecursiveLockUnlock(sKextLock
);
928 OSSafeRelease(exitRequest
);
932 /*********************************************************************
933 *********************************************************************/
936 OSKext::getLoadEnabled(void)
940 IORecursiveLockLock(sKextLock
);
941 result
= sLoadEnabled
;
942 IORecursiveLockUnlock(sKextLock
);
946 /*********************************************************************
947 *********************************************************************/
950 OSKext::setLoadEnabled(bool flag
)
954 IORecursiveLockLock(sKextLock
);
955 result
= sLoadEnabled
;
956 sLoadEnabled
= (flag
? true : false);
958 if (sLoadEnabled
!= result
) {
959 OSKextLog(/* kext */ NULL
,
960 kOSKextLogBasicLevel
|
962 "Kext loading now %sabled.", sLoadEnabled
? "en" : "dis");
965 IORecursiveLockUnlock(sKextLock
);
970 /*********************************************************************
971 *********************************************************************/
974 OSKext::getUnloadEnabled(void)
978 IORecursiveLockLock(sKextLock
);
979 result
= sUnloadEnabled
;
980 IORecursiveLockUnlock(sKextLock
);
984 /*********************************************************************
985 *********************************************************************/
988 OSKext::setUnloadEnabled(bool flag
)
992 IORecursiveLockLock(sKextLock
);
993 result
= sUnloadEnabled
;
994 sUnloadEnabled
= (flag
? true : false);
995 IORecursiveLockUnlock(sKextLock
);
997 if (sUnloadEnabled
!= result
) {
998 OSKextLog(/* kext */ NULL
,
999 kOSKextLogBasicLevel
|
1000 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1001 "Kext unloading now %sabled.", sUnloadEnabled
? "en" : "dis");
1007 /*********************************************************************
1008 * Do not call any function that takes sKextLock here!
1009 *********************************************************************/
1012 OSKext::getAutounloadEnabled(void)
1016 IORecursiveLockLock(sKextInnerLock
);
1017 result
= sAutounloadEnabled
? true : false;
1018 IORecursiveLockUnlock(sKextInnerLock
);
1022 /*********************************************************************
1023 * Do not call any function that takes sKextLock here!
1024 *********************************************************************/
1027 OSKext::setAutounloadsEnabled(bool flag
)
1031 IORecursiveLockLock(sKextInnerLock
);
1033 result
= sAutounloadEnabled
;
1034 sAutounloadEnabled
= (flag
? true : false);
1035 if (!sAutounloadEnabled
&& sUnloadCallout
) {
1036 thread_call_cancel(sUnloadCallout
);
1039 if (sAutounloadEnabled
!= result
) {
1040 OSKextLog(/* kext */ NULL
,
1041 kOSKextLogBasicLevel
|
1042 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1043 "Kext autounloading now %sabled.",
1044 sAutounloadEnabled
? "en" : "dis");
1047 IORecursiveLockUnlock(sKextInnerLock
);
1052 /*********************************************************************
1053 *********************************************************************/
1054 /* instance method operating on OSKext field */
1056 OSKext::setAutounloadEnabled(bool flag
)
1058 bool result
= flags
.autounloadEnabled
? true : false;
1059 flags
.autounloadEnabled
= flag
? 1 : 0;
1061 if (result
!= (flag
? true : false)) {
1063 kOSKextLogProgressLevel
|
1064 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
1065 "Autounloading for kext %s now %sabled.",
1066 getIdentifierCString(),
1067 flags
.autounloadEnabled
? "en" : "dis");
1072 /*********************************************************************
1073 *********************************************************************/
1076 OSKext::setKernelRequestsEnabled(bool flag
)
1080 IORecursiveLockLock(sKextLock
);
1081 result
= sKernelRequestsEnabled
;
1082 sKernelRequestsEnabled
= flag
? true : false;
1084 if (sKernelRequestsEnabled
!= result
) {
1085 OSKextLog(/* kext */ NULL
,
1086 kOSKextLogBasicLevel
|
1087 kOSKextLogGeneralFlag
,
1088 "Kernel requests now %sabled.",
1089 sKernelRequestsEnabled
? "en" : "dis");
1091 IORecursiveLockUnlock(sKextLock
);
1095 /*********************************************************************
1096 *********************************************************************/
1099 OSKext::getKernelRequestsEnabled(void)
1103 IORecursiveLockLock(sKextLock
);
1104 result
= sKernelRequestsEnabled
;
1105 IORecursiveLockUnlock(sKextLock
);
1110 #pragma mark Kext Life Cycle
1112 /*********************************************************************
1113 *********************************************************************/
1115 OSKext::withPrelinkedInfoDict(
1116 OSDictionary
* anInfoDict
)
1118 OSKext
* newKext
= new OSKext
;
1120 if (newKext
&& !newKext
->initWithPrelinkedInfoDict(anInfoDict
)) {
1128 /*********************************************************************
1129 *********************************************************************/
1131 OSKext::initWithPrelinkedInfoDict(
1132 OSDictionary
* anInfoDict
)
1134 bool result
= false;
1135 kern_return_t alloc_result
= KERN_SUCCESS
;
1136 OSString
* kextPath
= NULL
; // do not release
1137 OSNumber
* addressNum
= NULL
; // reused; do not release
1138 OSNumber
* lengthNum
= NULL
; // reused; do not release
1139 void * data
= NULL
; // do not free
1140 void * srcData
= NULL
; // do not free
1141 OSData
* prelinkedExecutable
= NULL
; // must release
1142 void * linkStateCopy
= NULL
; // kmem_free on error
1143 uint32_t linkStateLength
= 0;
1144 uint32_t length
= 0; // reused
1146 if (!super::init()) {
1150 /* Get the path. Don't look for an arch-specific path property.
1152 kextPath
= OSDynamicCast(OSString
,
1153 anInfoDict
->getObject(kPrelinkBundlePathKey
));
1155 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
1159 /* Don't need the path to be in the info dictionary any more.
1161 anInfoDict
->removeObject(kPrelinkBundlePathKey
);
1163 /* If we have a link state, create an OSData wrapper for it.
1165 addressNum
= OSDynamicCast(OSNumber
,
1166 anInfoDict
->getObject(kPrelinkLinkStateKey
));
1168 lengthNum
= OSDynamicCast(OSNumber
,
1169 anInfoDict
->getObject(kPrelinkLinkStateSizeKey
));
1172 kOSKextLogErrorLevel
|
1173 kOSKextLogArchiveFlag
,
1174 "Kext %s can't find prelinked kext link state size.",
1175 getIdentifierCString());
1179 data
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1180 linkStateLength
= (uint32_t) (lengthNum
->unsigned32BitValue());
1182 anInfoDict
->removeObject(kPrelinkLinkStateKey
);
1183 anInfoDict
->removeObject(kPrelinkLinkStateSizeKey
);
1185 /* Copy the link state out of the booter-provided memory so it is in
1186 * the VM system and we can page it out.
1188 alloc_result
= kmem_alloc_pageable(kernel_map
,
1189 (vm_offset_t
*)&linkStateCopy
, linkStateLength
);
1190 if (alloc_result
!= KERN_SUCCESS
) {
1192 kOSKextLogErrorLevel
|
1193 kOSKextLogArchiveFlag
,
1194 "Kext %s failed to copy prelinked link state.",
1195 getIdentifierCString());
1198 memcpy(linkStateCopy
, data
, linkStateLength
);
1200 linkState
= OSData::withBytesNoCopy(linkStateCopy
, linkStateLength
);
1203 kOSKextLogErrorLevel
|
1204 kOSKextLogArchiveFlag
,
1205 "Kext %s failed to create link state wrapper.",
1206 getIdentifierCString());
1209 linkState
->setDeallocFunction(osdata_kmem_free
);
1211 /* Clear linkStateCopy; the OSData owns it now so we mustn't free it.
1213 linkStateCopy
= NULL
;
1216 /* Create an OSData wrapper around the linked executable.
1218 addressNum
= OSDynamicCast(OSNumber
,
1219 anInfoDict
->getObject(kPrelinkExecutableLoadKey
));
1221 lengthNum
= OSDynamicCast(OSNumber
,
1222 anInfoDict
->getObject(kPrelinkExecutableSizeKey
));
1225 kOSKextLogErrorLevel
|
1226 kOSKextLogArchiveFlag
,
1227 "Kext %s can't find prelinked kext executable size.",
1228 getIdentifierCString());
1232 data
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1233 length
= (uint32_t) (lengthNum
->unsigned32BitValue());
1235 anInfoDict
->removeObject(kPrelinkExecutableLoadKey
);
1236 anInfoDict
->removeObject(kPrelinkExecutableSizeKey
);
1238 /* If the kext's load address differs from its source address, allocate
1239 * space in the kext map at the load address and copy the kext over.
1241 addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject(kPrelinkExecutableSourceKey
));
1243 srcData
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1245 if (data
!= srcData
) {
1247 alloc_result
= kext_alloc((vm_offset_t
*)&data
, length
, /* fixed */ TRUE
);
1248 if (alloc_result
!= KERN_SUCCESS
) {
1250 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1251 "Failed to allocate space for prelinked kext %s.",
1252 getIdentifierCString());
1255 memcpy(data
, srcData
, length
);
1258 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1259 "Error: prelinked kext %s - source and load addresses "
1260 "differ on ILP32 architecture.",
1261 getIdentifierCString());
1263 #endif /* __LP64__ */
1266 anInfoDict
->removeObject(kPrelinkExecutableSourceKey
);
1269 /* We don't need to set a dealloc function for the linked executable
1270 * because it is freed separately in OSKext::unload(), which must unwire
1271 * part of the memory.
1272 * xxx - do we *have* to do it that way?
1274 prelinkedExecutable
= OSData::withBytesNoCopy(data
, length
);
1275 if (!prelinkedExecutable
) {
1277 kOSKextLogErrorLevel
|
1278 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1279 "Kext %s failed to create executable wrapper.",
1280 getIdentifierCString());
1283 setLinkedExecutable(prelinkedExecutable
);
1285 addressNum
= OSDynamicCast(OSNumber
,
1286 anInfoDict
->getObject(kPrelinkKmodInfoKey
));
1289 kOSKextLogErrorLevel
|
1290 kOSKextLogArchiveFlag
,
1291 "Kext %s can't find prelinked kext kmod_info address.",
1292 getIdentifierCString());
1296 kmod_info
= (kmod_info_t
*) (intptr_t) (addressNum
->unsigned64BitValue());
1298 anInfoDict
->removeObject(kPrelinkKmodInfoKey
);
1301 /* If the plist has a UUID for an interface, save that off.
1303 if (isInterface()) {
1304 interfaceUUID
= OSDynamicCast(OSData
,
1305 anInfoDict
->getObject(kPrelinkInterfaceUUIDKey
));
1306 if (interfaceUUID
) {
1307 interfaceUUID
->retain();
1308 anInfoDict
->removeObject(kPrelinkInterfaceUUIDKey
);
1312 flags
.prelinked
= true;
1314 /* If we created a kext from prelink info,
1315 * we must be booting from a prelinked kernel.
1317 sPrelinkBoot
= true;
1319 result
= registerIdentifier();
1323 /* If we didn't hand linkStateCopy off to an OSData, free it.
1325 if (linkStateCopy
) {
1326 kmem_free(kernel_map
, (vm_offset_t
)linkStateCopy
, linkStateLength
);
1329 OSSafeRelease(prelinkedExecutable
);
1334 /*********************************************************************
1335 *********************************************************************/
1337 OSKext::withBooterData(
1338 OSString
* deviceTreeName
,
1339 OSData
* booterData
)
1341 OSKext
* newKext
= new OSKext
;
1343 if (newKext
&& !newKext
->initWithBooterData(deviceTreeName
, booterData
)) {
1351 /*********************************************************************
1352 *********************************************************************/
1353 typedef struct _BooterKextFileInfo
{
1354 uint32_t infoDictPhysAddr
;
1355 uint32_t infoDictLength
;
1356 uint32_t executablePhysAddr
;
1357 uint32_t executableLength
;
1358 uint32_t bundlePathPhysAddr
;
1359 uint32_t bundlePathLength
;
1360 } _BooterKextFileInfo
;
1363 OSKext::initWithBooterData(
1364 OSString
* deviceTreeName
,
1365 OSData
* booterData
)
1367 bool result
= false;
1368 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not free
1369 char * infoDictAddr
= NULL
; // do not free
1370 void * executableAddr
= NULL
; // do not free
1371 char * bundlePathAddr
= NULL
; // do not free
1373 OSObject
* parsedXML
= NULL
; // must release
1374 OSDictionary
* theInfoDict
= NULL
; // do not release
1375 OSString
* kextPath
= NULL
; // must release
1376 OSString
* errorString
= NULL
; // must release
1377 OSData
* executable
= NULL
; // must release
1379 if (!super::init()) {
1383 kextFileInfo
= (_BooterKextFileInfo
*)booterData
->getBytesNoCopy();
1384 if (!kextFileInfo
) {
1386 kOSKextLogErrorLevel
|
1387 kOSKextLogGeneralFlag
,
1388 "No booter-provided data for kext device tree entry %s.",
1389 deviceTreeName
->getCStringNoCopy());
1393 /* The info plist must exist or we can't read the kext.
1395 if (!kextFileInfo
->infoDictPhysAddr
|| !kextFileInfo
->infoDictLength
) {
1397 kOSKextLogErrorLevel
|
1398 kOSKextLogGeneralFlag
,
1399 "No kext info dictionary for booter device tree entry %s.",
1400 deviceTreeName
->getCStringNoCopy());
1404 infoDictAddr
= (char *)ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
1405 if (!infoDictAddr
) {
1407 kOSKextLogErrorLevel
|
1408 kOSKextLogGeneralFlag
,
1409 "Can't translate physical address 0x%x of kext info dictionary "
1410 "for device tree entry %s.",
1411 (int)kextFileInfo
->infoDictPhysAddr
,
1412 deviceTreeName
->getCStringNoCopy());
1416 parsedXML
= OSUnserializeXML(infoDictAddr
, &errorString
);
1418 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
1421 const char * errorCString
= "(unknown error)";
1423 if (errorString
&& errorString
->getCStringNoCopy()) {
1424 errorCString
= errorString
->getCStringNoCopy();
1425 } else if (parsedXML
) {
1426 errorCString
= "not a dictionary";
1429 kOSKextLogErrorLevel
|
1430 kOSKextLogGeneralFlag
,
1431 "Error unserializing info dictionary for device tree entry %s: %s.",
1432 deviceTreeName
->getCStringNoCopy(), errorCString
);
1436 /* A bundle path is not mandatory.
1438 if (kextFileInfo
->bundlePathPhysAddr
&& kextFileInfo
->bundlePathLength
) {
1439 bundlePathAddr
= (char *)ml_static_ptovirt(kextFileInfo
->bundlePathPhysAddr
);
1440 if (!bundlePathAddr
) {
1442 kOSKextLogErrorLevel
|
1443 kOSKextLogGeneralFlag
,
1444 "Can't translate physical address 0x%x of kext bundle path "
1445 "for device tree entry %s.",
1446 (int)kextFileInfo
->bundlePathPhysAddr
,
1447 deviceTreeName
->getCStringNoCopy());
1450 bundlePathAddr
[kextFileInfo
->bundlePathLength
-1] = '\0'; // just in case!
1452 kextPath
= OSString::withCString(bundlePathAddr
);
1455 kOSKextLogErrorLevel
|
1456 kOSKextLogGeneralFlag
,
1457 "Failed to create wrapper for device tree entry %s kext path %s.",
1458 deviceTreeName
->getCStringNoCopy(), bundlePathAddr
);
1463 if (!setInfoDictionaryAndPath(theInfoDict
, kextPath
)) {
1467 /* An executable is not mandatory.
1469 if (kextFileInfo
->executablePhysAddr
&& kextFileInfo
->executableLength
) {
1470 executableAddr
= (void *)ml_static_ptovirt(kextFileInfo
->executablePhysAddr
);
1471 if (!executableAddr
) {
1473 kOSKextLogErrorLevel
|
1474 kOSKextLogGeneralFlag
,
1475 "Can't translate physical address 0x%x of kext executable "
1476 "for device tree entry %s.",
1477 (int)kextFileInfo
->executablePhysAddr
,
1478 deviceTreeName
->getCStringNoCopy());
1482 executable
= OSData::withBytesNoCopy(executableAddr
,
1483 kextFileInfo
->executableLength
);
1486 kOSKextLogErrorLevel
|
1487 kOSKextLogGeneralFlag
,
1488 "Failed to create executable wrapper for device tree entry %s.",
1489 deviceTreeName
->getCStringNoCopy());
1493 /* A kext with an executable needs to retain the whole booterData
1494 * object to keep the executable in memory.
1496 if (!setExecutable(executable
, booterData
)) {
1498 kOSKextLogErrorLevel
|
1499 kOSKextLogGeneralFlag
,
1500 "Failed to set kext executable for device tree entry %s.",
1501 deviceTreeName
->getCStringNoCopy());
1506 result
= registerIdentifier();
1509 OSSafeRelease(parsedXML
);
1510 OSSafeRelease(kextPath
);
1511 OSSafeRelease(errorString
);
1512 OSSafeRelease(executable
);
1517 /*********************************************************************
1518 *********************************************************************/
1520 OSKext::registerIdentifier(void)
1522 bool result
= false;
1523 OSKext
* existingKext
= NULL
; // do not release
1524 bool existingIsLoaded
= false;
1525 bool existingIsPrelinked
= false;
1526 OSKextVersion newVersion
= -1;
1527 OSKextVersion existingVersion
= -1;
1528 char newVersionCString
[kOSKextVersionMaxLength
];
1529 char existingVersionCString
[kOSKextVersionMaxLength
];
1530 OSData
* newUUID
= NULL
; // must release
1531 OSData
* existingUUID
= NULL
; // must release
1533 /* Get the new kext's version for checks & log messages.
1535 newVersion
= getVersion();
1536 OSKextVersionGetString(newVersion
, newVersionCString
,
1537 kOSKextVersionMaxLength
);
1539 /* If we don't have an existing kext with this identifier,
1540 * just record the new kext and we're done!
1542 existingKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
));
1543 if (!existingKext
) {
1544 sKextsByID
->setObject(bundleID
, this);
1549 /* Get the existing kext's version for checks & log messages.
1551 existingVersion
= existingKext
->getVersion();
1552 OSKextVersionGetString(existingVersion
,
1553 existingVersionCString
, kOSKextVersionMaxLength
);
1555 existingIsLoaded
= existingKext
->isLoaded();
1556 existingIsPrelinked
= existingKext
->isPrelinked();
1558 /* If we have a kext with this identifier that's already loaded/prelinked,
1559 * we can't use the new one, but let's be really thorough and check how
1560 * the two are related for a precise diagnostic log message.
1562 * Note that user space can't find out about nonloaded prelinked kexts,
1563 * so in this case we log a message when new & existing are equivalent
1564 * at the step rather than warning level, because we are always going
1565 * be getting a copy of the kext in the user load request mkext.
1567 if (existingIsLoaded
|| existingIsPrelinked
) {
1568 bool sameVersion
= (newVersion
== existingVersion
);
1569 bool sameExecutable
= true; // assume true unless we have UUIDs
1571 /* Only get the UUID if the existing kext is loaded. Doing so
1572 * might have to uncompress an mkext executable and we shouldn't
1573 * take that hit when neither kext is loaded.
1575 newUUID
= copyUUID();
1576 existingUUID
= existingKext
->copyUUID();
1578 /* I'm entirely too paranoid about checking equivalence of executables,
1579 * but I remember nasty problems with it in the past.
1581 * - If we have UUIDs for both kexts, compare them.
1582 * - If only one kext has a UUID, they're definitely different.
1584 if (newUUID
&& existingUUID
) {
1585 sameExecutable
= newUUID
->isEqualTo(existingUUID
);
1586 } else if (newUUID
|| existingUUID
) {
1587 sameExecutable
= false;
1590 if (!newUUID
&& !existingUUID
) {
1592 /* If there are no UUIDs, we can't really tell that the executables
1593 * are *different* without a lot of work; the loaded kext's
1594 * unrelocated executable is no longer around (and we never had it
1595 * in-kernel for a prelinked kext). We certainly don't want to do
1596 * a whole fake link for the new kext just to compare, either.
1599 OSKextVersionGetString(version
, newVersionCString
,
1600 sizeof(newVersionCString
));
1602 kOSKextLogWarningLevel
|
1603 kOSKextLogKextBookkeepingFlag
,
1604 "Notice - new kext %s, v%s matches %s kext "
1605 "but can't determine if executables are the same (no UUIDs).",
1606 getIdentifierCString(),
1608 (existingIsLoaded
? "loaded" : "prelinked"));
1611 if (sameVersion
&& sameExecutable
) {
1613 (existingIsLoaded
? kOSKextLogWarningLevel
: kOSKextLogStepLevel
) |
1614 kOSKextLogKextBookkeepingFlag
,
1615 "Refusing new kext %s, v%s: a %s copy is already present "
1616 "(same version and executable).",
1617 getIdentifierCString(), newVersionCString
,
1618 (existingIsLoaded
? "loaded" : "prelinked"));
1621 /* This condition is significant so log it under warnings.
1624 kOSKextLogWarningLevel
|
1625 kOSKextLogKextBookkeepingFlag
,
1626 "Refusing new kext %s, v%s: already have %s v%s.",
1627 getIdentifierCString(),
1629 (existingIsLoaded
? "loaded" : "prelinked"),
1630 existingVersionCString
);
1632 /* This condition is significant so log it under warnings.
1635 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
1636 "Refusing new kext %s, v%s: a %s copy with a different "
1637 "executable UUID is already present.",
1638 getIdentifierCString(), newVersionCString
,
1639 (existingIsLoaded
? "loaded" : "prelinked"));
1643 } /* if (existingIsLoaded || existingIsPrelinked) */
1645 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
1646 * user loads are happening or if we're still in early boot. User agents are
1647 * supposed to resolve dependencies topside and include only the exact
1648 * kexts needed; so we always accept the new kext (in fact we should never
1649 * see an older unloaded copy hanging around).
1651 if (sUserLoadsActive
) {
1652 sKextsByID
->setObject(bundleID
, this);
1656 kOSKextLogStepLevel
|
1657 kOSKextLogKextBookkeepingFlag
,
1658 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
1659 getIdentifierCString(),
1660 existingVersionCString
,
1666 /* During early boot, the kext with the highest version always wins out.
1667 * Prelinked kernels will never hit this, but mkexts and booter-read
1668 * kexts might have duplicates.
1670 if (newVersion
> existingVersion
) {
1671 sKextsByID
->setObject(bundleID
, this);
1675 kOSKextLogStepLevel
|
1676 kOSKextLogKextBookkeepingFlag
,
1677 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
1678 existingVersionCString
,
1679 getIdentifierCString(),
1684 kOSKextLogStepLevel
|
1685 kOSKextLogKextBookkeepingFlag
,
1686 "Kext %s is already registered with a higher/same version (v%s); "
1687 "dropping newly-added (v%s).",
1688 getIdentifierCString(),
1689 existingVersionCString
,
1693 /* result has been set appropriately by now. */
1699 kOSKextLogStepLevel
|
1700 kOSKextLogKextBookkeepingFlag
,
1701 "Kext %s, v%s registered and available for loading.",
1702 getIdentifierCString(), newVersionCString
);
1705 OSSafeRelease(newUUID
);
1706 OSSafeRelease(existingUUID
);
1711 /*********************************************************************
1712 * Does the bare minimum validation to look up a kext.
1713 * All other validation is done on the spot as needed.
1715 * No need for lock, only called from init
1716 **********************************************************************/
1718 OSKext::setInfoDictionaryAndPath(
1719 OSDictionary
* aDictionary
,
1722 bool result
= false;
1723 OSString
* bundleIDString
= NULL
; // do not release
1724 OSString
* versionString
= NULL
; // do not release
1725 OSString
* compatibleVersionString
= NULL
; // do not release
1726 const char * versionCString
= NULL
; // do not free
1727 const char * compatibleVersionCString
= NULL
; // do not free
1728 OSBoolean
* scratchBool
= NULL
; // do not release
1731 panic("Attempt to set info dictionary on a kext "
1732 "that already has one (%s).",
1733 getIdentifierCString());
1736 if (!aDictionary
|| !OSDynamicCast(OSDictionary
, aDictionary
)) {
1740 infoDict
= aDictionary
;
1743 /* Check right away if the info dictionary has any log flags.
1745 scratchBool
= OSDynamicCast(OSBoolean
,
1746 getPropertyForHostArch(kOSBundleEnableKextLoggingKey
));
1747 if (scratchBool
== kOSBooleanTrue
) {
1748 flags
.loggingEnabled
= 1;
1751 /* The very next thing to get is the bundle identifier. Unlike
1752 * in user space, a kext with no bundle identifier gets axed
1755 bundleIDString
= OSDynamicCast(OSString
,
1756 getPropertyForHostArch(kCFBundleIdentifierKey
));
1757 if (!bundleIDString
) {
1759 kOSKextLogErrorLevel
|
1760 kOSKextLogValidationFlag
,
1761 "CFBundleIdentifier missing/invalid type in kext %s.",
1762 aPath
? aPath
->getCStringNoCopy() : "(unknown)");
1765 bundleID
= OSSymbol::withString(bundleIDString
);
1768 kOSKextLogErrorLevel
|
1769 kOSKextLogValidationFlag
,
1770 "Can't copy bundle identifier as symbol for kext %s.",
1771 bundleIDString
->getCStringNoCopy());
1775 /* Save the path if we got one (it should always be available but it's
1776 * just something nice to have for bookkeeping).
1784 * Minimal validation to initialize. We'll do other validation on the spot.
1786 if (bundleID
->getLength() >= KMOD_MAX_NAME
) {
1788 kOSKextLogErrorLevel
|
1789 kOSKextLogValidationFlag
,
1790 "Kext %s error - CFBundleIdentifier over max length %d.",
1791 getIdentifierCString(), KMOD_MAX_NAME
- 1);
1795 version
= compatibleVersion
= -1;
1797 versionString
= OSDynamicCast(OSString
,
1798 getPropertyForHostArch(kCFBundleVersionKey
));
1799 if (!versionString
) {
1801 kOSKextLogErrorLevel
|
1802 kOSKextLogValidationFlag
,
1803 "Kext %s error - CFBundleVersion missing/invalid type.",
1804 getIdentifierCString());
1807 versionCString
= versionString
->getCStringNoCopy();
1808 version
= OSKextParseVersionString(versionCString
);
1811 kOSKextLogErrorLevel
|
1812 kOSKextLogValidationFlag
,
1813 "Kext %s error - CFBundleVersion bad value '%s'.",
1814 getIdentifierCString(), versionCString
);
1818 compatibleVersion
= -1; // set to illegal value for kexts that don't have
1820 compatibleVersionString
= OSDynamicCast(OSString
,
1821 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
1822 if (compatibleVersionString
) {
1823 compatibleVersionCString
= compatibleVersionString
->getCStringNoCopy();
1824 compatibleVersion
= OSKextParseVersionString(compatibleVersionCString
);
1825 if (compatibleVersion
< 0) {
1827 kOSKextLogErrorLevel
|
1828 kOSKextLogValidationFlag
,
1829 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
1830 getIdentifierCString(), compatibleVersionCString
);
1834 if (compatibleVersion
> version
) {
1836 kOSKextLogErrorLevel
|
1837 kOSKextLogValidationFlag
,
1838 "Kext %s error - %s %s > %s %s (must be <=).",
1839 getIdentifierCString(),
1840 kOSBundleCompatibleVersionKey
, compatibleVersionCString
,
1841 kCFBundleVersionKey
, versionCString
);
1846 /* Set flags for later use if the infoDict gets flushed. We only
1847 * check for true values, not false ones(!)
1849 scratchBool
= OSDynamicCast(OSBoolean
,
1850 getPropertyForHostArch(kOSBundleIsInterfaceKey
));
1851 if (scratchBool
&& scratchBool
->isTrue()) {
1852 flags
.interface
= 1;
1855 scratchBool
= OSDynamicCast(OSBoolean
,
1856 getPropertyForHostArch(kOSKernelResourceKey
));
1857 if (scratchBool
&& scratchBool
->isTrue()) {
1858 flags
.kernelComponent
= 1;
1859 flags
.interface
= 1; // xxx - hm. the kernel itself isn't an interface...
1862 /* A kernel component has one implicit dependency on the kernel.
1864 flags
.hasAllDependencies
= 1;
1874 /*********************************************************************
1875 * Not used for prelinked kernel boot as there is no unrelocated
1877 *********************************************************************/
1879 OSKext::setExecutable(
1880 OSData
* anExecutable
,
1881 OSData
* externalData
,
1882 bool externalDataIsMkext
)
1884 bool result
= false;
1885 const char * executableKey
= NULL
; // do not free
1887 if (!anExecutable
) {
1888 infoDict
->removeObject(_kOSKextExecutableKey
);
1889 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
1890 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
1895 if (infoDict
->getObject(_kOSKextExecutableKey
) ||
1896 infoDict
->getObject(_kOSKextMkextExecutableReferenceKey
)) {
1898 panic("Attempt to set an executable on a kext "
1899 "that already has one (%s).",
1900 getIdentifierCString());
1904 if (externalDataIsMkext
) {
1905 executableKey
= _kOSKextMkextExecutableReferenceKey
;
1907 executableKey
= _kOSKextExecutableKey
;
1911 infoDict
->setObject(executableKey
, anExecutable
);
1913 infoDict
->setObject(_kOSKextExecutableExternalDataKey
, externalData
);
1923 /*********************************************************************
1924 *********************************************************************/
1929 panic("Attempt to free loaded kext %s.", getIdentifierCString());
1932 OSSafeRelease(infoDict
);
1933 OSSafeRelease(bundleID
);
1934 OSSafeRelease(path
);
1935 OSSafeRelease(dependencies
);
1936 OSSafeRelease(linkState
);
1937 OSSafeRelease(linkedExecutable
);
1938 OSSafeRelease(metaClasses
);
1939 OSSafeRelease(interfaceUUID
);
1941 if (isInterface() && kmod_info
) {
1942 kfree(kmod_info
, sizeof(kmod_info_t
));
1950 #pragma mark Mkext files
1952 /*********************************************************************
1953 *********************************************************************/
1955 OSKext::readMkextArchive(OSData
* mkextData
,
1956 uint32_t * checksumPtr
)
1958 OSReturn result
= kOSKextReturnBadData
;
1959 uint32_t mkextLength
= 0;
1960 mkext_header
* mkextHeader
= 0; // do not free
1961 uint32_t mkextVersion
= 0;
1963 /* Note default return of kOSKextReturnBadData above.
1965 mkextLength
= mkextData
->getLength();
1966 if (mkextLength
< sizeof(mkext_basic_header
)) {
1967 OSKextLog(/* kext */ NULL
,
1968 kOSKextLogErrorLevel
|
1969 kOSKextLogArchiveFlag
,
1970 "Mkext archive too small to be valid.");
1974 mkextHeader
= (mkext_header
*)mkextData
->getBytesNoCopy();
1976 if (MKEXT_GET_MAGIC(mkextHeader
) != MKEXT_MAGIC
||
1977 MKEXT_GET_SIGNATURE(mkextHeader
) != MKEXT_SIGN
) {
1978 OSKextLog(/* kext */ NULL
,
1979 kOSKextLogErrorLevel
|
1980 kOSKextLogArchiveFlag
,
1981 "Mkext archive has invalid magic or signature.");
1985 if (MKEXT_GET_LENGTH(mkextHeader
) != mkextLength
) {
1986 OSKextLog(/* kext */ NULL
,
1987 kOSKextLogErrorLevel
|
1988 kOSKextLogArchiveFlag
,
1989 "Mkext archive recorded length doesn't match actual file length.");
1993 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
1995 if (mkextVersion
== MKEXT_VERS_2
) {
1996 result
= OSKext::readMkext2Archive(mkextData
, NULL
, checksumPtr
);
1997 } else if (mkextVersion
== MKEXT_VERS_1
) {
1998 result
= OSKext::readMkext1Archive(mkextData
, checksumPtr
);
2000 OSKextLog(/* kext */ NULL
,
2001 kOSKextLogErrorLevel
|
2002 kOSKextLogArchiveFlag
,
2003 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion
);
2004 result
= kOSKextReturnUnsupported
;
2011 /*********************************************************************
2012 * Assumes magic, signature, version, length have been checked.
2014 * Doesn't do as much bounds-checking as it should, but we're dropping
2015 * mkext1 support from the kernel for SnowLeopard soon.
2017 * Should keep track of all kexts created so far, and if we hit a
2018 * fatal error halfway through, remove those kexts. If we've dropped
2019 * an older version that had already been read, whoops! Might want to
2020 * add a level of buffering?
2021 *********************************************************************/
2024 OSKext::readMkext1Archive(
2026 uint32_t * checksumPtr
)
2028 OSReturn result
= kOSReturnError
;
2029 uint32_t mkextLength
;
2030 mkext1_header
* mkextHeader
= 0; // do not free
2031 void * mkextEnd
= 0; // do not free
2032 uint32_t mkextVersion
;
2033 uint8_t * crc_address
= 0;
2035 uint32_t numKexts
= 0;
2037 OSData
* infoDictDataObject
= NULL
; // must release
2038 OSObject
* parsedXML
= NULL
; // must release
2039 OSDictionary
* infoDict
= NULL
; // do not release
2040 OSString
* errorString
= NULL
; // must release
2041 OSData
* mkextExecutableInfo
= NULL
; // must release
2042 OSKext
* theKext
= NULL
; // must release
2044 mkextLength
= mkextData
->getLength();
2045 mkextHeader
= (mkext1_header
*)mkextData
->getBytesNoCopy();
2046 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2047 mkextVersion
= OSSwapBigToHostInt32(mkextHeader
->version
);
2049 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
2050 checksum
= mkext_adler32(crc_address
,
2051 (uintptr_t)mkextHeader
+
2052 OSSwapBigToHostInt32(mkextHeader
->length
) - (uintptr_t)crc_address
);
2054 if (OSSwapBigToHostInt32(mkextHeader
->adler32
) != checksum
) {
2055 OSKextLog(/* kext */ NULL
,
2056 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2057 "Kext archive has a bad checksum.");
2058 result
= kOSKextReturnBadData
;
2063 *checksumPtr
= checksum
;
2066 /* Check that the CPU type & subtype match that of the running kernel. */
2067 if (OSSwapBigToHostInt32(mkextHeader
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
2068 if ((UInt32
)_mh_execute_header
.cputype
!=
2069 OSSwapBigToHostInt32(mkextHeader
->cputype
)) {
2071 OSKextLog(/* kext */ NULL
,
2072 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2073 "Kext archive doesn't contain software "
2074 "for this computer's CPU type.");
2075 result
= kOSKextReturnArchNotFound
;
2080 numKexts
= OSSwapBigToHostInt32(mkextHeader
->numkexts
);
2082 for (uint32_t i
= 0; i
< numKexts
; i
++) {
2084 OSSafeReleaseNULL(infoDictDataObject
);
2085 OSSafeReleaseNULL(infoDict
);
2086 OSSafeReleaseNULL(mkextExecutableInfo
);
2087 OSSafeReleaseNULL(errorString
);
2088 OSSafeReleaseNULL(theKext
);
2090 mkext_kext
* kextEntry
= &mkextHeader
->kext
[i
];
2091 mkext_file
* infoDictPtr
= &kextEntry
->plist
;
2092 mkext_file
* executablePtr
= &kextEntry
->module;
2093 if (kextEntry
>= mkextEnd
) {
2094 OSKextLog(/* kext */ NULL
,
2095 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2096 "Mkext file overrun.");
2097 result
= kOSKextReturnBadData
;
2101 /* Note that we're pretty tolerant of errors in individual entries.
2102 * As long as we can keep processing, we do.
2104 infoDictDataObject
= OSKext::extractMkext1Entry(
2105 mkextHeader
, infoDictPtr
);
2106 if (!infoDictDataObject
) {
2107 OSKextLog(/* kext */ NULL
,
2108 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2109 "Can't uncompress info dictionary "
2110 "from mkext archive entry %d.", i
);
2114 parsedXML
= OSUnserializeXML(
2115 (const char *)infoDictDataObject
->getBytesNoCopy(),
2118 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
2121 const char * errorCString
= "(unknown error)";
2123 if (errorString
&& errorString
->getCStringNoCopy()) {
2124 errorCString
= errorString
->getCStringNoCopy();
2125 } else if (parsedXML
) {
2126 errorCString
= "not a dictionary";
2128 OSKextLog(/* kext */ NULL
,
2129 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2130 "Error: Can't read XML property list "
2131 "for mkext archive entry %d: %s.", i
, errorCString
);
2135 theKext
= new OSKext
;
2137 OSKextLog(/* kext */ NULL
,
2138 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2139 "Kext allocation failure.");
2144 * Prepare an entry to hold the mkext entry info for the
2145 * compressed binary module, if there is one. If all four fields
2146 * of the module entry are zero, there isn't one.
2148 if ((OSSwapBigToHostInt32(executablePtr
->offset
) ||
2149 OSSwapBigToHostInt32(executablePtr
->compsize
) ||
2150 OSSwapBigToHostInt32(executablePtr
->realsize
) ||
2151 OSSwapBigToHostInt32(executablePtr
->modifiedsecs
))) {
2153 MkextEntryRef entryRef
;
2155 mkextExecutableInfo
= OSData::withCapacity(sizeof(entryRef
));
2156 if (!mkextExecutableInfo
) {
2157 panic("Error: Couldn't allocate data object "
2158 "for mkext archive entry %d.\n", i
);
2161 entryRef
.mkext
= (mkext_basic_header
*)mkextHeader
;
2162 entryRef
.fileinfo
= (uint8_t *)executablePtr
;
2163 if (!mkextExecutableInfo
->appendBytes(&entryRef
,
2164 sizeof(entryRef
))) {
2166 OSKextLog(/* kext */ NULL
,
2167 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2168 "Couldn't record executable info "
2169 "for mkext archive entry %d.", i
);
2170 // we might hit a load error later but oh well
2171 // xxx - should probably remove theKext
2177 /* Init can fail because of a data/runtime error, or because the
2178 * kext is a dup. Either way, we don't care here.
2180 if (!theKext
->initWithMkext1Info(infoDict
, mkextExecutableInfo
,
2183 // theKext is released at the top of the loop or in the finish block
2187 /* If we got even one kext out of the mkext archive,
2188 * we have successfully read the archive, in that we
2189 * have data references into its mapped memory.
2191 result
= kOSReturnSuccess
;
2196 OSSafeRelease(infoDictDataObject
);
2197 OSSafeRelease(parsedXML
);
2198 OSSafeRelease(errorString
);
2199 OSSafeRelease(mkextExecutableInfo
);
2200 OSSafeRelease(theKext
);
2205 /*********************************************************************
2206 *********************************************************************/
2208 OSKext::initWithMkext1Info(
2209 OSDictionary
* anInfoDict
,
2210 OSData
* executableWrapper
,
2213 bool result
= false;
2215 // mkext1 doesn't allow for path (might stuff in info dict)
2216 if (!setInfoDictionaryAndPath(anInfoDict
, /* path */ NULL
)) {
2220 if (!registerIdentifier()) {
2224 if (!setExecutable(executableWrapper
, mkextData
, true)) {
2232 /* If we can't init, remove the kext from the lookup dictionary.
2233 * This is safe to call in init because there's an implicit retain.
2236 OSKext::removeKext(this, /* removePersonalities? */ false);
2242 /*********************************************************************
2243 * xxx - this should take the input data length
2244 *********************************************************************/
2247 OSKext::extractMkext1Entry(
2248 const void * mkextFileBase
,
2251 OSData
* result
= NULL
;
2252 OSData
* uncompressedData
= NULL
; // release on error
2253 const char * errmsg
= NULL
;
2255 mkext_file
* fileinfo
;
2256 uint8_t * uncompressedDataBuffer
= 0; // do not free (panic on alloc. fail)
2257 size_t uncompressed_size
= 0;
2258 kern_return_t kern_result
;
2260 fileinfo
= (mkext_file
*)entry
;
2262 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
2263 size_t compressed_size
= OSSwapBigToHostInt32(fileinfo
->compsize
);
2264 size_t expected_size
= OSSwapBigToHostInt32(fileinfo
->realsize
);
2266 // Add 1 for '\0' to terminate XML string (for plists)
2267 // (we really should have the archive format include that).
2268 size_t alloc_size
= expected_size
+ 1;
2269 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
2271 /* If these four fields are zero there's no file, but it's up to
2272 * the calling context to decide if that's an error.
2274 if (offset
== 0 && compressed_size
== 0 &&
2275 expected_size
== 0 && modifiedsecs
== 0) {
2279 kern_result
= kmem_alloc(kernel_map
,
2280 (vm_offset_t
*)&uncompressedDataBuffer
,
2282 if (kern_result
!= KERN_SUCCESS
) {
2287 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
,
2289 if (uncompressedData
== NULL
) {
2290 /* No need to free uncompressedDataBuffer here, either. */
2294 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
2296 /* Do the decompression if necessary. Note that even if the file isn't
2297 * compressed, we want to make a copy so that we don't have the tie to
2298 * the larger mkext file buffer any more.
2299 * xxx - need to detect decompression overflow too
2301 if (compressed_size
!= 0) {
2302 errmsg
= "OSKext::uncompressMkext - "
2303 "uncompressed file shorter than expected";
2304 uncompressed_size
= decompress_lzss(uncompressedDataBuffer
,
2306 ((uint8_t *)mkextFileBase
) + offset
,
2308 if (uncompressed_size
!= expected_size
) {
2312 memcpy(uncompressedDataBuffer
,
2313 ((uint8_t *)mkextFileBase
) + offset
,
2317 // Add a terminating nul character in case the data is XML.
2318 // (we really should have the archive format include that).
2319 uncompressedDataBuffer
[expected_size
] = '\0';
2321 result
= uncompressedData
;
2326 OSKextLog(/* kext */ NULL
,
2327 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2330 if (uncompressedData
) {
2331 uncompressedData
->release();
2337 /*********************************************************************
2338 * Assumes magic, signature, version, length have been checked.
2339 * xxx - need to add further bounds checking for each file entry
2341 * Should keep track of all kexts created so far, and if we hit a
2342 * fatal error halfway through, remove those kexts. If we've dropped
2343 * an older version that had already been read, whoops! Might want to
2344 * add a level of buffering?
2345 *********************************************************************/
2348 OSKext::readMkext2Archive(
2350 OSDictionary
** mkextPlistOut
,
2351 uint32_t * checksumPtr
)
2353 OSReturn result
= kOSReturnError
;
2354 uint32_t mkextLength
;
2355 mkext2_header
* mkextHeader
= NULL
; // do not free
2356 void * mkextEnd
= NULL
; // do not free
2357 uint32_t mkextVersion
;
2358 uint8_t * crc_address
= NULL
;
2360 uint32_t mkextPlistOffset
;
2361 uint32_t mkextPlistCompressedSize
;
2362 char * mkextPlistEnd
= NULL
; // do not free
2363 uint32_t mkextPlistFullSize
;
2364 OSString
* errorString
= NULL
; // must release
2365 OSData
* mkextPlistUncompressedData
= NULL
; // must release
2366 const char * mkextPlistDataBuffer
= NULL
; // do not free
2367 OSObject
* parsedXML
= NULL
; // must release
2368 OSDictionary
* mkextPlist
= NULL
; // do not release
2369 OSArray
* mkextInfoDictArray
= NULL
; // do not release
2372 mkextLength
= mkextData
->getLength();
2373 mkextHeader
= (mkext2_header
*)mkextData
->getBytesNoCopy();
2374 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2375 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2377 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
2378 checksum
= mkext_adler32(crc_address
,
2379 (uintptr_t)mkextHeader
+
2380 MKEXT_GET_LENGTH(mkextHeader
) - (uintptr_t)crc_address
);
2382 if (MKEXT_GET_CHECKSUM(mkextHeader
) != checksum
) {
2383 OSKextLog(/* kext */ NULL
,
2384 kOSKextLogErrorLevel
|
2385 kOSKextLogArchiveFlag
,
2386 "Mkext archive has bad checksum.");
2387 result
= kOSKextReturnBadData
;
2392 *checksumPtr
= checksum
;
2395 /* Check that the CPU type & subtype match that of the running kernel. */
2396 if (MKEXT_GET_CPUTYPE(mkextHeader
) == (UInt32
)CPU_TYPE_ANY
) {
2397 OSKextLog(/* kext */ NULL
,
2398 kOSKextLogErrorLevel
|
2399 kOSKextLogArchiveFlag
,
2400 "Mkext archive must have a specific CPU type.");
2401 result
= kOSKextReturnBadData
;
2404 if ((UInt32
)_mh_execute_header
.cputype
!=
2405 MKEXT_GET_CPUTYPE(mkextHeader
)) {
2407 OSKextLog(/* kext */ NULL
,
2408 kOSKextLogErrorLevel
|
2409 kOSKextLogArchiveFlag
,
2410 "Mkext archive does not match the running kernel's CPU type.");
2411 result
= kOSKextReturnArchNotFound
;
2416 mkextPlistOffset
= MKEXT2_GET_PLIST(mkextHeader
);
2417 mkextPlistCompressedSize
= MKEXT2_GET_PLIST_COMPSIZE(mkextHeader
);
2418 mkextPlistEnd
= (char *)mkextHeader
+ mkextPlistOffset
+
2419 mkextPlistCompressedSize
;
2420 if (mkextPlistEnd
> mkextEnd
) {
2421 OSKextLog(/* kext */ NULL
,
2422 kOSKextLogErrorLevel
|
2423 kOSKextLogArchiveFlag
,
2424 "Mkext archive file overrun.");
2425 result
= kOSKextReturnBadData
;
2428 mkextPlistFullSize
= MKEXT2_GET_PLIST_FULLSIZE(mkextHeader
);
2429 if (mkextPlistCompressedSize
) {
2430 mkextPlistUncompressedData
= sKernelKext
->extractMkext2FileData(
2431 (UInt8
*)mkextHeader
+ mkextPlistOffset
,
2433 mkextPlistCompressedSize
, mkextPlistFullSize
);
2434 if (!mkextPlistUncompressedData
) {
2437 mkextPlistDataBuffer
= (const char *)
2438 mkextPlistUncompressedData
->getBytesNoCopy();
2440 mkextPlistDataBuffer
= (const char *)mkextHeader
+ mkextPlistOffset
;
2443 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2445 parsedXML
= OSUnserializeXML(mkextPlistDataBuffer
, &errorString
);
2447 mkextPlist
= OSDynamicCast(OSDictionary
, parsedXML
);
2450 const char * errorCString
= "(unknown error)";
2452 if (errorString
&& errorString
->getCStringNoCopy()) {
2453 errorCString
= errorString
->getCStringNoCopy();
2454 } else if (parsedXML
) {
2455 errorCString
= "not a dictionary";
2457 OSKextLog(/* kext */ NULL
,
2458 kOSKextLogErrorLevel
|
2459 kOSKextLogArchiveFlag
,
2460 "Error unserializing mkext plist: %s.", errorCString
);
2464 /* If the caller needs the plist, hand it back and retain it.
2465 * (This function releases it at the end.)
2467 if (mkextPlistOut
) {
2468 *mkextPlistOut
= mkextPlist
;
2469 (*mkextPlistOut
)->retain();
2472 mkextInfoDictArray
= OSDynamicCast(OSArray
,
2473 mkextPlist
->getObject(kMKEXTInfoDictionariesKey
));
2474 if (!mkextInfoDictArray
) {
2475 OSKextLog(/* kext */ NULL
,
2476 kOSKextLogErrorLevel
|
2477 kOSKextLogArchiveFlag
,
2478 "Mkext archive contains no kext info dictionaries.");
2482 count
= mkextInfoDictArray
->getCount();
2483 for (i
= 0; i
< count
; i
++) {
2484 OSDictionary
* infoDict
;
2487 infoDict
= OSDynamicCast(OSDictionary
,
2488 mkextInfoDictArray
->getObject(i
));
2490 /* Create the kext for the entry, then release it, because the
2491 * kext system keeps them around until explicitly removed.
2492 * Any creation/registration failures are already logged for us.
2494 OSKext
* newKext
= OSKext::withMkext2Info(infoDict
, mkextData
);
2495 OSSafeRelease(newKext
);
2498 /* Even if we didn't keep any kexts from the mkext, we may have a load
2499 * request to process, so we are successful (no errors occurred).
2501 result
= kOSReturnSuccess
;
2505 OSSafeRelease(parsedXML
);
2506 OSSafeRelease(mkextPlistUncompressedData
);
2507 OSSafeRelease(errorString
);
2512 /*********************************************************************
2513 *********************************************************************/
2516 OSKext::withMkext2Info(
2517 OSDictionary
* anInfoDict
,
2520 OSKext
* newKext
= new OSKext
;
2522 if (newKext
&& !newKext
->initWithMkext2Info(anInfoDict
, mkextData
)) {
2530 /*********************************************************************
2531 *********************************************************************/
2533 OSKext::initWithMkext2Info(
2534 OSDictionary
* anInfoDict
,
2537 bool result
= false;
2538 OSString
* kextPath
= NULL
; // do not release
2539 OSNumber
* executableOffsetNum
= NULL
; // do not release
2540 OSCollectionIterator
* iterator
= NULL
; // must release
2541 OSData
* executable
= NULL
; // must release
2543 if (!super::init()) {
2547 /* Get the path. Don't look for an arch-specific path property.
2549 kextPath
= OSDynamicCast(OSString
,
2550 anInfoDict
->getObject(kMKEXTBundlePathKey
));
2552 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
2556 /* Don't need the path to be in the info dictionary any more.
2558 anInfoDict
->removeObject(kMKEXTBundlePathKey
);
2560 executableOffsetNum
= OSDynamicCast(OSNumber
,
2561 infoDict
->getObject(kMKEXTExecutableKey
));
2562 if (executableOffsetNum
) {
2563 executable
= createMkext2FileEntry(mkextData
,
2564 executableOffsetNum
, "executable");
2565 infoDict
->removeObject(kMKEXTExecutableKey
);
2569 if (!setExecutable(executable
, mkextData
, true)) {
2574 result
= registerIdentifier();
2578 OSSafeRelease(executable
);
2579 OSSafeRelease(iterator
);
2583 /*********************************************************************
2584 *********************************************************************/
2586 OSKext::createMkext2FileEntry(
2588 OSNumber
* offsetNum
,
2591 OSData
* result
= NULL
;
2592 MkextEntryRef entryRef
;
2593 uint8_t * mkextBuffer
= (uint8_t *)mkextData
->getBytesNoCopy();
2594 uint32_t entryOffset
= offsetNum
->unsigned32BitValue();
2596 result
= OSData::withCapacity(sizeof(entryRef
));
2601 entryRef
.mkext
= (mkext_basic_header
*)mkextBuffer
;
2602 entryRef
.fileinfo
= mkextBuffer
+ entryOffset
;
2603 if (!result
->appendBytes(&entryRef
, sizeof(entryRef
))) {
2604 OSSafeReleaseNULL(result
);
2611 kOSKextLogErrorLevel
|
2612 kOSKextLogArchiveFlag
,
2613 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2614 name
, getIdentifierCString());
2619 /*********************************************************************
2620 *********************************************************************/
2622 static void * z_alloc(void *, u_int items
, u_int size
);
2623 static void z_free(void *, void *ptr
);
2625 typedef struct z_mem
{
2626 uint32_t alloc_size
;
2631 * Space allocation and freeing routines for use by zlib routines.
2634 z_alloc(void * notused __unused
, u_int num_items
, u_int size
)
2636 void * result
= NULL
;
2637 z_mem
* zmem
= NULL
;
2638 uint32_t total
= num_items
* size
;
2639 uint32_t allocSize
= total
+ sizeof(zmem
);
2641 zmem
= (z_mem
*)kalloc(allocSize
);
2645 zmem
->alloc_size
= allocSize
;
2646 result
= (void *)&(zmem
->data
);
2652 z_free(void * notused __unused
, void * ptr
)
2654 uint32_t * skipper
= (uint32_t *)ptr
- 1;
2655 z_mem
* zmem
= (z_mem
*)skipper
;
2656 kfree((void *)zmem
, zmem
->alloc_size
);
2662 OSKext::extractMkext2FileData(
2665 uint32_t compressedSize
,
2668 OSData
* result
= NULL
;
2670 OSData
* uncompressedData
= NULL
; // release on error
2672 uint8_t * uncompressedDataBuffer
= 0; // do not free
2673 unsigned long uncompressedSize
;
2675 bool zstream_inited
= false;
2678 /* If the file isn't compressed, we want to make a copy
2679 * so that we don't have the tie to the larger mkext file buffer any more.
2681 if (!compressedSize
) {
2682 uncompressedData
= OSData::withBytes(data
, fullSize
);
2683 // xxx - no check for failure?
2684 result
= uncompressedData
;
2688 if (KERN_SUCCESS
!= kmem_alloc(kernel_map
,
2689 (vm_offset_t
*)&uncompressedDataBuffer
, fullSize
)) {
2691 /* How's this for cheesy? The kernel is only asked to extract
2692 * kext plists so we tailor the log messages.
2694 if (this == sKernelKext
) {
2696 kOSKextLogErrorLevel
|
2697 kOSKextLogArchiveFlag
,
2698 "Allocation failure extracting %s from mkext.", name
);
2701 kOSKextLogErrorLevel
|
2702 kOSKextLogArchiveFlag
,
2703 "Allocation failure extracting %s from mkext for kext %s.",
2704 name
, getIdentifierCString());
2709 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
, fullSize
);
2710 if (!uncompressedData
) {
2711 if (this == sKernelKext
) {
2713 kOSKextLogErrorLevel
|
2714 kOSKextLogArchiveFlag
,
2715 "Allocation failure extracting %s from mkext.", name
);
2718 kOSKextLogErrorLevel
|
2719 kOSKextLogArchiveFlag
,
2720 "Allocation failure extracting %s from mkext for kext %s.",
2721 name
, getIdentifierCString());
2725 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
2727 if (this == sKernelKext
) {
2729 kOSKextLogDetailLevel
|
2730 kOSKextLogArchiveFlag
,
2731 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2732 name
, compressedSize
, fullSize
);
2735 kOSKextLogDetailLevel
|
2736 kOSKextLogArchiveFlag
,
2737 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2738 getIdentifierCString(), name
, compressedSize
, fullSize
);
2741 bzero(&zstream
, sizeof(zstream
));
2742 zstream
.next_in
= (UInt8
*)data
;
2743 zstream
.avail_in
= compressedSize
;
2745 zstream
.next_out
= uncompressedDataBuffer
;
2746 zstream
.avail_out
= fullSize
;
2748 zstream
.zalloc
= z_alloc
;
2749 zstream
.zfree
= z_free
;
2751 zlib_result
= inflateInit(&zstream
);
2752 if (Z_OK
!= zlib_result
) {
2753 if (this == sKernelKext
) {
2755 kOSKextLogErrorLevel
|
2756 kOSKextLogArchiveFlag
,
2757 "Mkext error; zlib inflateInit failed (%d) for %s.",
2761 kOSKextLogErrorLevel
|
2762 kOSKextLogArchiveFlag
,
2763 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
2764 getIdentifierCString(), zlib_result
, name
);
2768 zstream_inited
= true;
2771 zlib_result
= inflate(&zstream
, Z_FINISH
);
2773 if (zlib_result
== Z_STREAM_END
|| zlib_result
== Z_OK
) {
2774 uncompressedSize
= zstream
.total_out
;
2776 if (this == sKernelKext
) {
2778 kOSKextLogErrorLevel
|
2779 kOSKextLogArchiveFlag
,
2780 "Mkext error; zlib inflate failed (%d) for %s.",
2784 kOSKextLogErrorLevel
|
2785 kOSKextLogArchiveFlag
,
2786 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
2787 getIdentifierCString(), zlib_result
, name
);
2791 kOSKextLogErrorLevel
|
2792 kOSKextLogArchiveFlag
,
2793 "zlib error: %s.", zstream
.msg
);
2798 if (uncompressedSize
!= fullSize
) {
2799 if (this == sKernelKext
) {
2801 kOSKextLogErrorLevel
|
2802 kOSKextLogArchiveFlag
,
2803 "Mkext error; zlib inflate discrepancy for %s, "
2804 "uncompressed size != original size.", name
);
2807 kOSKextLogErrorLevel
|
2808 kOSKextLogArchiveFlag
,
2809 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
2810 "uncompressed size != original size.",
2811 getIdentifierCString(), name
);
2816 result
= uncompressedData
;
2819 /* Don't bother checking return, nothing we can do on fail.
2821 if (zstream_inited
) inflateEnd(&zstream
);
2824 OSSafeRelease(uncompressedData
);
2830 /*********************************************************************
2831 *********************************************************************/
2834 OSKext::loadFromMkext(
2835 OSKextLogSpec clientLogFilter
,
2837 uint32_t mkextBufferLength
,
2839 uint32_t * logInfoLengthOut
)
2841 OSReturn result
= kOSReturnError
;
2842 OSReturn tempResult
= kOSReturnError
;
2844 OSData
* mkextData
= NULL
; // must release
2845 OSDictionary
* mkextPlist
= NULL
; // must release
2847 OSArray
* logInfoArray
= NULL
; // must release
2848 OSSerialize
* serializer
= NULL
; // must release
2850 OSString
* predicate
= NULL
; // do not release
2851 OSDictionary
* requestArgs
= NULL
; // do not release
2853 OSString
* kextIdentifier
= NULL
; // do not release
2854 OSNumber
* startKextExcludeNum
= NULL
; // do not release
2855 OSNumber
* startMatchingExcludeNum
= NULL
; // do not release
2856 OSBoolean
* delayAutounloadBool
= NULL
; // do not release
2857 OSArray
* personalityNames
= NULL
; // do not release
2859 /* Default values for these two options: regular autounload behavior,
2860 * load all kexts, send no personalities.
2862 Boolean delayAutounload
= false;
2863 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
2864 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeAll
;
2866 IORecursiveLockLock(sKextLock
);
2870 *logInfoLengthOut
= 0;
2873 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
2875 OSKextLog(/* kext */ NULL
,
2876 kOSKextLogDebugLevel
|
2878 "Received kext load request from user space.");
2880 /* Regardless of processing, the fact that we have gotten here means some
2881 * user-space program is up and talking to us, so we'll switch our kext
2882 * registration to reflect that.
2884 if (!sUserLoadsActive
) {
2885 OSKextLog(/* kext */ NULL
,
2886 kOSKextLogProgressLevel
|
2887 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
2888 "Switching to late startup (user-space) kext loading policy.");
2890 sUserLoadsActive
= true;
2893 if (!sLoadEnabled
) {
2894 OSKextLog(/* kext */ NULL
,
2895 kOSKextLogErrorLevel
|
2897 "Kext loading is disabled.");
2898 result
= kOSKextReturnDisabled
;
2902 /* Note that we do not set a dealloc function on this OSData
2903 * object! No references to it can remain after the loadFromMkext()
2904 * call since we are in a MIG function, and will vm_deallocate()
2907 mkextData
= OSData::withBytesNoCopy(mkextBuffer
,
2910 OSKextLog(/* kext */ NULL
,
2911 kOSKextLogErrorLevel
|
2912 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
2913 "Failed to create wrapper for kext load request.");
2914 result
= kOSKextReturnNoMemory
;
2918 result
= readMkext2Archive(mkextData
, &mkextPlist
, NULL
);
2919 if (result
!= kOSReturnSuccess
) {
2920 OSKextLog(/* kext */ NULL
,
2921 kOSKextLogErrorLevel
|
2923 "Failed to read kext load request.");
2927 predicate
= _OSKextGetRequestPredicate(mkextPlist
);
2928 if (!predicate
|| !predicate
->isEqualTo(kKextRequestPredicateLoad
)) {
2929 OSKextLog(/* kext */ NULL
,
2930 kOSKextLogErrorLevel
|
2932 "Received kext load request with no predicate; skipping.");
2933 result
= kOSKextReturnInvalidArgument
;
2937 requestArgs
= OSDynamicCast(OSDictionary
,
2938 mkextPlist
->getObject(kKextRequestArgumentsKey
));
2939 if (!requestArgs
|| !requestArgs
->getCount()) {
2940 OSKextLog(/* kext */ NULL
,
2941 kOSKextLogErrorLevel
|
2943 "Received kext load request with no arguments.");
2944 result
= kOSKextReturnInvalidArgument
;
2948 kextIdentifier
= OSDynamicCast(OSString
,
2949 requestArgs
->getObject(kKextRequestArgumentBundleIdentifierKey
));
2950 if (!kextIdentifier
) {
2951 OSKextLog(/* kext */ NULL
,
2952 kOSKextLogErrorLevel
|
2954 "Received kext load request with no kext identifier.");
2955 result
= kOSKextReturnInvalidArgument
;
2959 startKextExcludeNum
= OSDynamicCast(OSNumber
,
2960 requestArgs
->getObject(kKextKextRequestArgumentStartExcludeKey
));
2961 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
2962 requestArgs
->getObject(kKextRequestArgumentStartMatchingExcludeKey
));
2963 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
2964 requestArgs
->getObject(kKextRequestArgumentDelayAutounloadKey
));
2965 personalityNames
= OSDynamicCast(OSArray
,
2966 requestArgs
->getObject(kKextRequestArgumentPersonalityNamesKey
));
2968 if (delayAutounloadBool
) {
2969 delayAutounload
= delayAutounloadBool
->getValue();
2971 if (startKextExcludeNum
) {
2972 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
2974 if (startMatchingExcludeNum
) {
2975 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
2978 OSKextLog(/* kext */ NULL
,
2979 kOSKextLogProgressLevel
|
2981 "Received request from user space to load kext %s.",
2982 kextIdentifier
->getCStringNoCopy());
2984 /* Load the kext, with no deferral, since this is a load from outside
2986 * xxx - Would like a better way to handle the default values for the
2987 * xxx - start/match opt args.
2989 result
= OSKext::loadKextWithIdentifier(
2991 /* allowDefer */ false,
2993 startKextExcludeLevel
,
2994 startMatchingExcludeLevel
,
2996 if (result
!= kOSReturnSuccess
) {
2999 /* If the load came down from kextd, it will shortly inform IOCatalogue
3000 * for matching via a separate IOKit calldown.
3005 /* Gather up the collected log messages for user space. Any
3006 * error messages past this call will not make it up as log messages
3007 * but will be in the system log.
3009 logInfoArray
= OSKext::clearUserSpaceLogFilter();
3011 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
3012 tempResult
= OSKext::serializeLogInfo(logInfoArray
,
3013 logInfoOut
, logInfoLengthOut
);
3014 if (tempResult
!= kOSReturnSuccess
) {
3015 result
= tempResult
;
3019 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3021 /* Note: mkextDataObject will have been retained by every kext w/an
3022 * executable in it. That should all have been flushed out at the
3023 * and of the load operation, but you never know....
3025 if (mkextData
&& mkextData
->getRetainCount() > 1) {
3026 OSKextLog(/* kext */ NULL
,
3027 kOSKextLogErrorLevel
|
3028 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3029 "Kext load request buffer from user space still retained by a kext; "
3030 "probable memory leak.");
3033 IORecursiveLockUnlock(sKextLock
);
3035 OSSafeRelease(mkextData
);
3036 OSSafeRelease(mkextPlist
);
3037 OSSafeRelease(serializer
);
3038 OSSafeRelease(logInfoArray
);
3043 /*********************************************************************
3044 *********************************************************************/
3047 OSKext::serializeLogInfo(
3048 OSArray
* logInfoArray
,
3050 uint32_t * logInfoLengthOut
)
3052 OSReturn result
= kOSReturnError
;
3053 char * buffer
= NULL
;
3054 kern_return_t kmem_result
= KERN_FAILURE
;
3055 OSSerialize
* serializer
= NULL
; // must release; reused
3056 char * logInfo
= NULL
; // returned by reference
3057 uint32_t logInfoLength
= 0;
3059 if (!logInfoArray
|| !logInfoOut
|| !logInfoLengthOut
) {
3060 OSKextLog(/* kext */ NULL
,
3061 kOSKextLogErrorLevel
|
3063 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3064 /* Bad programmer. */
3065 result
= kOSKextReturnInvalidArgument
;
3069 serializer
= OSSerialize::withCapacity(0);
3071 OSKextLog(/* kext */ NULL
,
3072 kOSKextLogErrorLevel
|
3074 "Failed to create serializer on log info for request from user space.");
3075 /* Incidental error; we're going to (try to) allow the request
3076 * itself to succeed. */
3079 if (!logInfoArray
->serialize(serializer
)) {
3080 OSKextLog(/* kext */ NULL
,
3081 kOSKextLogErrorLevel
|
3083 "Failed to serialize log info for request from user space.");
3084 /* Incidental error; we're going to (try to) allow the request
3085 * itself to succeed. */
3087 logInfo
= serializer
->text();
3088 logInfoLength
= serializer
->getLength();
3090 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
, logInfoLength
);
3091 if (kmem_result
!= KERN_SUCCESS
) {
3092 OSKextLog(/* kext */ NULL
,
3093 kOSKextLogErrorLevel
|
3095 "Failed to copy log info for request from user space.");
3096 /* Incidental error; we're going to (try to) allow the request
3099 memcpy(buffer
, logInfo
, logInfoLength
);
3100 *logInfoOut
= buffer
;
3101 *logInfoLengthOut
= logInfoLength
;
3105 result
= kOSReturnSuccess
;
3107 OSSafeRelease(serializer
);
3112 #pragma mark Instance Management Methods
3114 /*********************************************************************
3115 *********************************************************************/
3117 OSKext::lookupKextWithIdentifier(const char * kextIdentifier
)
3119 OSKext
* foundKext
= NULL
;
3121 IORecursiveLockLock(sKextLock
);
3122 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3124 foundKext
->retain();
3126 IORecursiveLockUnlock(sKextLock
);
3131 /*********************************************************************
3132 *********************************************************************/
3134 OSKext::lookupKextWithIdentifier(OSString
* kextIdentifier
)
3136 return OSKext::lookupKextWithIdentifier(kextIdentifier
->getCStringNoCopy());
3139 /*********************************************************************
3140 *********************************************************************/
3142 OSKext::lookupKextWithLoadTag(uint32_t aTag
)
3144 OSKext
* foundKext
= NULL
; // returned
3147 IORecursiveLockLock(sKextLock
);
3149 count
= sLoadedKexts
->getCount();
3150 for (i
= 0; i
< count
; i
++) {
3151 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3152 if (thisKext
->getLoadTag() == aTag
) {
3153 foundKext
= thisKext
;
3154 foundKext
->retain();
3160 IORecursiveLockUnlock(sKextLock
);
3165 /*********************************************************************
3166 *********************************************************************/
3168 OSKext::lookupKextWithAddress(vm_address_t address
)
3170 OSKext
* foundKext
= NULL
; // returned
3173 IORecursiveLockLock(sKextLock
);
3175 count
= sLoadedKexts
->getCount();
3176 for (i
= 0; i
< count
; i
++) {
3177 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3178 if (thisKext
->linkedExecutable
) {
3179 vm_address_t kext_start
=
3180 (vm_address_t
)thisKext
->linkedExecutable
->getBytesNoCopy();
3181 vm_address_t kext_end
= kext_start
+
3182 thisKext
->linkedExecutable
->getLength();
3184 if ((kext_start
<= address
) && (address
< kext_end
)) {
3185 foundKext
= thisKext
;
3186 foundKext
->retain();
3193 IORecursiveLockUnlock(sKextLock
);
3198 /*********************************************************************
3199 *********************************************************************/
3201 bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
3203 bool result
= false;
3204 OSKext
* foundKext
= NULL
; // returned
3206 IORecursiveLockLock(sKextLock
);
3208 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3209 if (foundKext
&& foundKext
->isLoaded()) {
3213 IORecursiveLockUnlock(sKextLock
);
3218 /*********************************************************************
3219 * xxx - should spawn a separate thread so a kext can safely have
3220 * xxx - itself unloaded.
3221 *********************************************************************/
3226 bool terminateServicesAndRemovePersonalitiesFlag
)
3228 OSReturn result
= kOSKextReturnInUse
;
3229 OSKext
* checkKext
= NULL
; // do not release
3231 IORecursiveLockLock(sKextLock
);
3233 /* If the kext has no identifier, it failed to init
3234 * so isn't in sKextsByID and it isn't loaded.
3236 if (!aKext
->getIdentifier()) {
3237 result
= kOSReturnSuccess
;
3241 checkKext
= OSDynamicCast(OSKext
,
3242 sKextsByID
->getObject(aKext
->getIdentifier()));
3243 if (checkKext
!= aKext
) {
3244 result
= kOSKextReturnNotFound
;
3248 if (aKext
->isLoaded()) {
3249 /* If we are terminating, send the request to the IOCatalogue
3250 * (which will actually call us right back but that's ok we have
3251 * a recursive lock don't you know) but do not ask the IOCatalogue
3252 * to call back with an unload, we'll do that right here.
3254 if (terminateServicesAndRemovePersonalitiesFlag
) {
3255 result
= gIOCatalogue
->terminateDriversForModule(
3256 aKext
->getIdentifierCString(), /* unload */ false);
3257 if (result
!= kOSReturnSuccess
) {
3259 kOSKextLogProgressLevel
|
3260 kOSKextLogKextBookkeepingFlag
,
3261 "Can't remove kext %s; services failed to terminate - 0x%x.",
3262 aKext
->getIdentifierCString(), result
);
3267 result
= aKext
->unload();
3268 if (result
!= kOSReturnSuccess
) {
3273 /* Remove personalities as requested. This is a bit redundant for a loaded
3274 * kext as IOCatalogue::terminateDriversForModule() removes driver
3275 * personalities, but it doesn't restart matching, which we always want
3276 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3279 if (terminateServicesAndRemovePersonalitiesFlag
) {
3280 aKext
->removePersonalitiesFromCatalog();
3284 kOSKextLogProgressLevel
|
3285 kOSKextLogKextBookkeepingFlag
,
3286 "Removing kext %s.",
3287 aKext
->getIdentifierCString());
3289 sKextsByID
->removeObject(aKext
->getIdentifier());
3290 result
= kOSReturnSuccess
;
3293 IORecursiveLockUnlock(sKextLock
);
3297 /*********************************************************************
3298 *********************************************************************/
3301 OSKext::removeKextWithIdentifier(
3302 const char * kextIdentifier
,
3303 bool terminateServicesAndRemovePersonalitiesFlag
)
3305 OSReturn result
= kOSReturnError
;
3307 IORecursiveLockLock(sKextLock
);
3309 OSKext
* aKext
= OSDynamicCast(OSKext
,
3310 sKextsByID
->getObject(kextIdentifier
));
3312 result
= kOSKextReturnNotFound
;
3313 OSKextLog(/* kext */ NULL
,
3314 kOSKextLogErrorLevel
|
3315 kOSKextLogKextBookkeepingFlag
,
3316 "Can't remove kext %s - not found.",
3321 result
= OSKext::removeKext(aKext
,
3322 terminateServicesAndRemovePersonalitiesFlag
);
3325 IORecursiveLockUnlock(sKextLock
);
3330 /*********************************************************************
3331 *********************************************************************/
3334 OSKext::removeKextWithLoadTag(
3335 OSKextLoadTag loadTag
,
3336 bool terminateServicesAndRemovePersonalitiesFlag
)
3338 OSReturn result
= kOSReturnError
;
3339 OSKext
* foundKext
= NULL
;
3342 IORecursiveLockLock(sKextLock
);
3344 count
= sLoadedKexts
->getCount();
3345 for (i
= 0; i
< count
; i
++) {
3346 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3347 if (thisKext
->loadTag
== loadTag
) {
3348 foundKext
= thisKext
;
3354 result
= kOSKextReturnNotFound
;
3355 OSKextLog(/* kext */ NULL
,
3356 kOSKextLogErrorLevel
|
3357 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3358 "Can't remove kext with load tag %d - not found.",
3363 result
= OSKext::removeKext(foundKext
,
3364 terminateServicesAndRemovePersonalitiesFlag
);
3367 IORecursiveLockUnlock(sKextLock
);
3372 /*********************************************************************
3373 *********************************************************************/
3375 OSKext::copyKexts(void)
3377 OSDictionary
* result
;
3379 IORecursiveLockLock(sKextLock
);
3380 result
= OSDynamicCast(OSDictionary
, sKextsByID
->copyCollection());
3381 IORecursiveLockUnlock(sKextLock
);
3387 #pragma mark Accessors
3389 /*********************************************************************
3390 *********************************************************************/
3392 OSKext::getIdentifier(void)
3397 /*********************************************************************
3398 * A kext must have a bundle identifier to even survive initialization;
3399 * this is guaranteed to exist past then.
3400 *********************************************************************/
3402 OSKext::getIdentifierCString(void)
3404 return bundleID
->getCStringNoCopy();
3407 /*********************************************************************
3408 *********************************************************************/
3410 OSKext::getVersion(void)
3415 /*********************************************************************
3416 *********************************************************************/
3418 OSKext::getCompatibleVersion(void)
3420 return compatibleVersion
;
3423 /*********************************************************************
3424 *********************************************************************/
3426 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
3428 if ((compatibleVersion
> -1 && version
> -1) &&
3429 (compatibleVersion
<= version
&& aVersion
<= version
)) {
3435 /*********************************************************************
3436 *********************************************************************/
3438 OSKext::declaresExecutable(void)
3440 if (getPropertyForHostArch(kCFBundleExecutableKey
)) {
3446 /*********************************************************************
3447 *********************************************************************/
3449 OSKext::getExecutable(void)
3451 OSData
* result
= NULL
;
3452 OSData
* extractedExecutable
= NULL
; // must release
3453 OSData
* mkextExecutableRef
= NULL
; // do not release
3455 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
3460 mkextExecutableRef
= OSDynamicCast(OSData
,
3461 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
3463 if (mkextExecutableRef
) {
3465 MkextEntryRef
* mkextEntryRef
= (MkextEntryRef
*)
3466 mkextExecutableRef
->getBytesNoCopy();
3467 uint32_t mkextVersion
= MKEXT_GET_VERSION(mkextEntryRef
->mkext
);
3468 if (mkextVersion
== MKEXT_VERS_2
) {
3469 mkext2_file_entry
* fileinfo
=
3470 (mkext2_file_entry
*)mkextEntryRef
->fileinfo
;
3471 uint32_t compressedSize
= MKEXT2_GET_ENTRY_COMPSIZE(fileinfo
);
3472 uint32_t fullSize
= MKEXT2_GET_ENTRY_FULLSIZE(fileinfo
);
3473 extractedExecutable
= extractMkext2FileData(
3474 MKEXT2_GET_ENTRY_DATA(fileinfo
), "executable",
3475 compressedSize
, fullSize
);
3476 } else if (mkextVersion
== MKEXT_VERS_1
) {
3477 extractedExecutable
= extractMkext1Entry(
3478 mkextEntryRef
->mkext
, mkextEntryRef
->fileinfo
);
3480 OSKextLog(this, kOSKextLogErrorLevel
|
3481 kOSKextLogArchiveFlag
,
3482 "Kext %s - unknown mkext version 0x%x for executable.",
3483 getIdentifierCString(), mkextVersion
);
3486 /* Regardless of success, remove the mkext executable,
3487 * and drop one reference on the mkext. (setExecutable() does not
3488 * replace, it removes, or panics if asked to replace.)
3490 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
3491 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
3493 if (extractedExecutable
&& extractedExecutable
->getLength()) {
3494 if (!setExecutable(extractedExecutable
)) {
3497 result
= extractedExecutable
;
3505 OSSafeRelease(extractedExecutable
);
3510 /*********************************************************************
3511 *********************************************************************/
3513 OSKext::isInterface(void)
3515 return flags
.interface
;
3518 /*********************************************************************
3519 *********************************************************************/
3521 OSKext::isKernelComponent(void)
3523 return flags
.kernelComponent
? true : false;
3526 /*********************************************************************
3527 * We might want to check this recursively for all dependencies,
3528 * since a subtree of dependencies could get loaded before we hit
3529 * a dependency that isn't safe-boot-loadable.
3531 * xxx - Might want to return false if OSBundleEnableKextLogging or
3532 * OSBundleDebugLevel
3533 * or IOKitDebug is nonzero too (we used to do that, but I don't see
3534 * the point except it's usually development drivers, which might
3535 * cause panics on startup, that have those properties). Heh; could
3536 * use a "kx" boot-arg!
3537 *********************************************************************/
3539 OSKext::isLoadableInSafeBoot(void)
3541 bool result
= false;
3542 OSString
* required
= NULL
; // do not release
3545 required
= OSDynamicCast(OSString
,
3546 getPropertyForHostArch(kOSBundleRequiredKey
));
3550 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
3551 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
3552 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
3553 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
3554 required
->isEqualTo(kOSBundleRequiredConsole
)) {
3563 /*********************************************************************
3564 *********************************************************************/
3566 OSKext::isPrelinked(void)
3568 return flags
.prelinked
? true : false;
3571 /*********************************************************************
3572 *********************************************************************/
3573 bool OSKext::isLoaded(void)
3575 return flags
.loaded
? true : false;
3578 /*********************************************************************
3579 *********************************************************************/
3581 OSKext::isStarted(void)
3583 return flags
.started
? true : false;
3586 /*********************************************************************
3587 *********************************************************************/
3589 OSKext::isCPPInitialized(void)
3591 return flags
.CPPInitialized
;
3594 /*********************************************************************
3595 *********************************************************************/
3597 OSKext::setCPPInitialized(bool initialized
)
3599 flags
.CPPInitialized
= initialized
;
3602 /*********************************************************************
3603 *********************************************************************/
3605 OSKext::getLoadTag(void)
3610 /*********************************************************************
3611 *********************************************************************/
3613 OSKext::copyUUID(void)
3615 OSData
* result
= NULL
;
3616 OSData
* theExecutable
= NULL
; // do not release
3617 const kernel_mach_header_t
* header
= NULL
;
3618 const struct load_command
* load_cmd
= NULL
;
3619 const struct uuid_command
* uuid_cmd
= NULL
;
3622 /* An interface kext doesn't have a linked executable with an LC_UUID,
3623 * we create one when it's linked.
3625 if (interfaceUUID
) {
3626 result
= interfaceUUID
;
3631 /* For real kexts, try to get the UUID from the linked executable,
3632 * or if is hasn't been linked yet, the unrelocated executable.
3634 theExecutable
= linkedExecutable
;
3635 if (!theExecutable
) {
3636 theExecutable
= getExecutable();
3638 if (!theExecutable
) {
3642 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
3643 load_cmd
= (const struct load_command
*)&header
[1];
3645 for (i
= 0; i
< header
->ncmds
; i
++) {
3646 if (load_cmd
->cmd
== LC_UUID
) {
3647 uuid_cmd
= (struct uuid_command
*)load_cmd
;
3648 result
= OSData::withBytes(uuid_cmd
->uuid
, sizeof(uuid_cmd
->uuid
));
3651 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
3658 /*********************************************************************
3659 *********************************************************************/
3660 #if defined (__ppc__)
3661 #define ARCHNAME "ppc"
3662 #elif defined (__i386__)
3663 #define ARCHNAME "i386"
3664 #elif defined (__x86_64__)
3665 #define ARCHNAME "x86_64"
3667 #error architecture not supported
3670 #define ARCH_SEPARATOR_CHAR '_'
3672 static char * makeHostArchKey(const char * key
, uint32_t * keySizeOut
)
3674 char * result
= NULL
;
3675 uint32_t keyLength
= strlen(key
);
3678 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
3680 keySize
= 1 + 1 + strlen(key
) + strlen(ARCHNAME
);
3681 result
= (char *)kalloc(keySize
);
3685 strlcpy(result
, key
, keySize
);
3686 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
3687 result
[keyLength
] = '\0';
3688 strlcat(result
, ARCHNAME
, keySize
);
3689 *keySizeOut
= keySize
;
3695 /*********************************************************************
3696 *********************************************************************/
3698 OSKext::getPropertyForHostArch(const char * key
)
3700 OSObject
* result
= NULL
; // do not release
3701 uint32_t hostArchKeySize
= 0;
3702 char * hostArchKey
= NULL
; // must kfree
3704 if (!key
|| !infoDict
) {
3708 /* Some properties are not allowed to be arch-variant:
3709 * - Any CFBundle... property.
3710 * - OSBundleIsInterface.
3711 * - OSKernelResource.
3713 if (STRING_HAS_PREFIX(key
, "OS") ||
3714 STRING_HAS_PREFIX(key
, "IO")) {
3716 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
3718 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
3719 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
3720 "Allocation failure.");
3723 result
= infoDict
->getObject(hostArchKey
);
3727 result
= infoDict
->getObject(key
);
3731 if (hostArchKey
) kfree(hostArchKey
, hostArchKeySize
);
3736 #pragma mark Load/Start/Stop/Unload
3738 /*********************************************************************
3739 *********************************************************************/
3741 OSKext::loadKextWithIdentifier(
3742 const char * kextIdentifierCString
,
3743 Boolean allowDeferFlag
,
3744 Boolean delayAutounloadFlag
,
3745 OSKextExcludeLevel startOpt
,
3746 OSKextExcludeLevel startMatchingOpt
,
3747 OSArray
* personalityNames
)
3749 OSReturn result
= kOSReturnError
;
3750 OSString
* kextIdentifier
= NULL
; // must release
3752 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
3753 if (!kextIdentifier
) {
3754 result
= kOSKextReturnNoMemory
;
3757 result
= OSKext::loadKextWithIdentifier(kextIdentifier
,
3758 allowDeferFlag
, delayAutounloadFlag
,
3759 startOpt
, startMatchingOpt
, personalityNames
);
3762 OSSafeRelease(kextIdentifier
);
3767 /*********************************************************************
3768 *********************************************************************/
3770 OSKext::loadKextWithIdentifier(
3771 OSString
* kextIdentifier
,
3772 Boolean allowDeferFlag
,
3773 Boolean delayAutounloadFlag
,
3774 OSKextExcludeLevel startOpt
,
3775 OSKextExcludeLevel startMatchingOpt
,
3776 OSArray
* personalityNames
)
3778 OSReturn result
= kOSReturnError
;
3779 OSKext
* theKext
= NULL
; // do not release
3780 OSDictionary
* loadRequest
= NULL
; // must release
3781 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
3783 IORecursiveLockLock(sKextLock
);
3785 if (!kextIdentifier
) {
3786 result
= kOSKextReturnInvalidArgument
;
3790 OSKext::recordIdentifierRequest(kextIdentifier
);
3792 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3794 if (!allowDeferFlag
) {
3795 OSKextLog(/* kext */ NULL
,
3796 kOSKextLogErrorLevel
|
3798 "Can't load kext %s - not found.",
3799 kextIdentifier
->getCStringNoCopy());
3803 if (!sKernelRequestsEnabled
) {
3805 kOSKextLogErrorLevel
|
3807 "Can't load kext %s - requests to user space are disabled.",
3808 kextIdentifier
->getCStringNoCopy());
3809 result
= kOSKextReturnDisabled
;
3813 /* Create a new request unless one is already sitting
3814 * in sKernelRequests for this bundle identifier
3816 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
3817 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
3818 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
3820 if (result
!= kOSReturnSuccess
) {
3823 if (!_OSKextSetRequestArgument(loadRequest
,
3824 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
3826 result
= kOSKextReturnNoMemory
;
3829 if (!sKernelRequests
->setObject(loadRequest
)) {
3830 result
= kOSKextReturnNoMemory
;
3834 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
3835 result
= kOSKextReturnNoMemory
;
3840 kOSKextLogDebugLevel
|
3842 "Kext %s not found; queued load request to user space.",
3843 kextIdentifier
->getCStringNoCopy());
3849 OSKextLog(/* kext */ NULL
,
3850 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
3852 "Not loading kext %s - not found and kextd not available in early boot.",
3853 kextIdentifier
->getCStringNoCopy());
3856 result
= kOSKextReturnDeferred
;
3860 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
3862 if (result
!= kOSReturnSuccess
) {
3864 kOSKextLogErrorLevel
|
3866 "Failed to load kext %s (error 0x%x).",
3867 kextIdentifier
->getCStringNoCopy(), (int)result
);
3869 OSKext::removeKext(theKext
,
3870 /* terminateService/removePersonalities */ true);
3874 if (delayAutounloadFlag
) {
3876 kOSKextLogProgressLevel
|
3877 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3878 "Setting delayed autounload for %s.",
3879 kextIdentifier
->getCStringNoCopy());
3880 theKext
->flags
.delayAutounload
= 1;
3884 OSSafeRelease(loadRequest
);
3885 OSSafeRelease(kextIdentifierSymbol
);
3887 IORecursiveLockUnlock(sKextLock
);
3892 /*********************************************************************
3893 *********************************************************************/
3896 OSKext::recordIdentifierRequest(
3897 OSString
* kextIdentifier
)
3899 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
3902 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
3906 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
3907 if (!kextIdentifierSymbol
) {
3908 // xxx - this is really a basic alloc failure
3913 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
3914 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
3917 // xxx - need to find a way to associate this whole func w/the kext
3918 OSKextLog(/* kext */ NULL
,
3919 // xxx - check level
3920 kOSKextLogStepLevel
|
3921 kOSKextLogArchiveFlag
,
3922 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
3923 kextIdentifier
->getCStringNoCopy());
3929 OSKextLog(/* kext */ NULL
,
3930 kOSKextLogErrorLevel
|
3931 kOSKextLogArchiveFlag
,
3932 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
3933 kextIdentifier
->getCStringNoCopy());
3935 OSSafeRelease(kextIdentifierSymbol
);
3939 /*********************************************************************
3940 *********************************************************************/
3943 OSKextExcludeLevel startOpt
,
3944 OSKextExcludeLevel startMatchingOpt
,
3945 OSArray
* personalityNames
)
3947 OSReturn result
= kOSReturnError
;
3948 kern_return_t kxldResult
;
3949 OSKextExcludeLevel dependenciesStartOpt
= startOpt
;
3950 OSKextExcludeLevel dependenciesStartMatchingOpt
= startMatchingOpt
;
3951 unsigned int i
, count
;
3952 Boolean alreadyLoaded
= false;
3953 OSKext
* lastLoadedKext
= NULL
;
3955 if (!sLoadEnabled
) {
3956 if (!isLoaded() || (!isStarted() && startOpt
!= kOSKextExcludeNone
) ||
3957 (startMatchingOpt
!= kOSKextExcludeNone
)) {
3960 kOSKextLogErrorLevel
|
3962 "Kext loading is disabled "
3963 "(attempt to load/start/start matching for kext %s).",
3964 getIdentifierCString());
3966 result
= kOSKextReturnDisabled
;
3971 alreadyLoaded
= true;
3972 result
= kOSReturnSuccess
;
3975 kOSKextLogDebugLevel
|
3976 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3977 "Kext %s is already loaded.",
3978 getIdentifierCString());
3982 /* If we've pushed the next available load tag to the invalid value,
3983 * we can't load any more kexts.
3985 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
3987 kOSKextLogErrorLevel
|
3989 "Can't load kext %s - no more load tags to assign.",
3990 getIdentifierCString());
3991 result
= kOSKextReturnNoResources
;
3995 /* This is a bit of a hack, because we shouldn't be handling
3996 * personalities within the load function.
3998 if (!declaresExecutable()) {
3999 result
= kOSReturnSuccess
;
4003 /* Are we in safe boot?
4005 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
4007 kOSKextLogErrorLevel
|
4009 "Can't load kext %s - not loadable during safe boot.",
4010 getIdentifierCString());
4011 result
= kOSKextReturnBootLevel
;
4016 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
4018 getIdentifierCString());
4021 if (!sKxldContext
) {
4022 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
4023 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
4024 /* cputype */ 0, /* cpusubtype */ 0);
4027 kOSKextLogErrorLevel
|
4028 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4029 "Can't load kext %s - failed to create link context.",
4030 getIdentifierCString());
4031 result
= kOSKextReturnNoMemory
;
4036 /* We only need to resolve dependencies once for the whole graph, but
4037 * resolveDependencies will just return if there's no work to do, so it's
4038 * safe to call it more than once.
4040 if (!resolveDependencies()) {
4041 // xxx - check resolveDependencies() for log msg
4043 kOSKextLogErrorLevel
|
4044 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4045 "Can't load kext %s - failed to resolve library dependencies.",
4046 getIdentifierCString());
4047 result
= kOSKextReturnDependencies
;
4051 /* If we are excluding just the kext being loaded now (and not its
4052 * dependencies), drop the exclusion level to none so dependencies
4053 * start and/or add their personalities.
4055 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
4056 dependenciesStartOpt
= kOSKextExcludeNone
;
4059 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
4060 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
4063 /* Load the dependencies, recursively.
4065 count
= getNumDependencies();
4066 for (i
= 0; i
< count
; i
++) {
4067 OSKext
* dependency
= OSDynamicCast(OSKext
,
4068 dependencies
->getObject(i
));
4069 if (dependency
== NULL
) {
4071 kOSKextLogErrorLevel
|
4072 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4073 "Internal error loading kext %s; dependency disappeared.",
4074 getIdentifierCString());
4075 result
= kOSKextReturnInternalError
;
4079 /* Dependencies must be started accorting to the opt,
4080 * but not given the personality names of the main kext.
4082 result
= dependency
->load(dependenciesStartOpt
,
4083 dependenciesStartMatchingOpt
,
4084 /* personalityNames */ NULL
);
4085 if (result
!= KERN_SUCCESS
) {
4087 kOSKextLogErrorLevel
|
4088 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4089 "Dependency %s of kext %s failed to load.",
4090 dependency
->getIdentifierCString(),
4091 getIdentifierCString());
4093 OSKext::removeKext(dependency
,
4094 /* terminateService/removePersonalities */ true);
4095 result
= kOSKextReturnDependencyLoadError
;
4101 result
= loadExecutable();
4102 if (result
!= KERN_SUCCESS
) {
4106 flags
.loaded
= true;
4108 /* Add the kext to the list of loaded kexts and update the kmod_info
4109 * struct to point to that of the last loaded kext (which is the way
4110 * it's always been done, though I'd rather do them in order now).
4112 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
4113 sLoadedKexts
->setObject(this);
4115 /* Keep the kernel itself out of the kmod list.
4117 if (lastLoadedKext
== sKernelKext
) {
4118 lastLoadedKext
= NULL
;
4121 if (lastLoadedKext
) {
4122 kmod_info
->next
= lastLoadedKext
->kmod_info
;
4125 /* Make the global kmod list point at the just-loaded kext. Note that the
4126 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4127 * although we do report it in kextstat these days by using the newer
4128 * OSArray of loaded kexts, which does contain it.
4130 * (The OSKext object representing the kernel doesn't even have a kmod_info
4131 * struct, though I suppose we could stick a pointer to it from the
4132 * static struct in OSRuntime.cpp.)
4136 /* Save the list of loaded kexts in case we panic.
4138 clock_get_uptime(&last_loaded_timestamp
);
4139 OSKext::saveLoadedKextPanicList();
4142 /* This is a bit of a hack, because we shouldn't be handling
4143 * personalities within the load function.
4145 if (declaresExecutable() && (startOpt
== kOSKextExcludeNone
)) {
4147 if (result
!= kOSReturnSuccess
) {
4149 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
4150 "Kext %s start failed (result 0x%x).",
4151 getIdentifierCString(), result
);
4152 result
= kOSKextReturnStartStopError
;
4156 /* If not excluding matching, send the personalities to the kernel.
4157 * This never affects the result of the load operation.
4159 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
4160 sendPersonalitiesToCatalog(true, personalityNames
);
4164 if (result
!= kOSReturnSuccess
) {
4166 kOSKextLogErrorLevel
|
4168 "Kext %s failed to load (0x%x).",
4169 getIdentifierCString(), (int)result
);
4170 } else if (!alreadyLoaded
) {
4172 kOSKextLogProgressLevel
|
4175 getIdentifierCString());
4180 /*********************************************************************
4181 * called only by load()
4182 *********************************************************************/
4184 OSKext::loadExecutable()
4186 OSReturn result
= kOSReturnError
;
4187 kern_return_t kxldResult
;
4188 u_char
** kxlddeps
= NULL
; // must kfree
4189 uint32_t num_kxlddeps
= 0;
4190 uint32_t num_kmod_refs
= 0;
4191 u_char
* linkStateBytes
= NULL
; // do not free
4192 u_long linkStateLength
= 0;
4193 u_char
** linkStateBytesPtr
= NULL
; // do not free
4194 u_long
* linkStateLengthPtr
= NULL
; // do not free
4195 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
4196 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
4197 OSData
* theExecutable
= NULL
; // do not release
4198 OSString
* versString
= NULL
; // do not release
4199 const char * versCString
= NULL
; // do not free
4200 const char * string
= NULL
; // do not free
4203 /* We need the version string for a variety of bits below.
4205 versString
= OSDynamicCast(OSString
,
4206 getPropertyForHostArch(kCFBundleVersionKey
));
4210 versCString
= versString
->getCStringNoCopy();
4212 if (isKernelComponent()) {
4213 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
4214 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
4216 kOSKextLogErrorLevel
|
4218 "Kernel component %s has incorrect version %s; "
4220 getIdentifierCString(),
4221 versCString
, KERNEL6_VERSION
);
4222 result
= kOSKextReturnInternalError
;
4224 } else if (strcmp(versCString
, osrelease
)) {
4226 kOSKextLogErrorLevel
|
4228 "Kernel component %s has incorrect version %s; "
4230 getIdentifierCString(),
4231 versCString
, osrelease
);
4232 result
= kOSKextReturnInternalError
;
4238 if (isPrelinked()) {
4242 theExecutable
= getExecutable();
4243 if (!theExecutable
) {
4244 if (declaresExecutable()) {
4246 kOSKextLogErrorLevel
|
4248 "Can't load kext %s - executable is missing.",
4249 getIdentifierCString());
4250 result
= kOSKextReturnValidation
;
4256 if (isKernelComponent()) {
4257 num_kxlddeps
= 1; // the kernel itself
4259 num_kxlddeps
= getNumDependencies();
4261 if (!num_kxlddeps
) {
4263 kOSKextLogErrorLevel
|
4264 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4265 "Can't load kext %s - it has no library dependencies.",
4266 getIdentifierCString());
4269 kxlddeps
= (u_char
**)kalloc(num_kxlddeps
* sizeof(*kxlddeps
));
4272 kOSKextLogErrorLevel
|
4273 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4274 "Can't allocate link context to load kext %s.",
4275 getIdentifierCString());
4279 if (isKernelComponent()) {
4280 OSData
* kernelLinkState
= OSKext::getKernelLinkState();
4281 kxlddeps
[0] = (u_char
*)kernelLinkState
->getBytesNoCopy();
4282 } else for (i
= 0; i
< num_kxlddeps
; i
++) {
4283 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
4284 if (!dependency
->linkState
) {
4285 // xxx - maybe we should panic here
4287 kOSKextLogErrorLevel
|
4288 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4289 "Can't load kext %s - link state missing.",
4290 getIdentifierCString());
4293 kxlddeps
[i
] = (u_char
*)dependency
->linkState
->getBytesNoCopy();
4294 assert(kxlddeps
[i
]);
4297 /* We only need link state for a library kext.
4299 if (compatibleVersion
> -1 && (declaresExecutable() || isKernelComponent())) {
4300 linkStateBytesPtr
= &linkStateBytes
;
4301 linkStateLengthPtr
= &linkStateLength
;
4304 /* We only need the linked executable for a real kext.
4306 if (!isInterface()) {
4307 kxldHeaderPtr
= &kxld_header
;
4312 kOSKextLogExplicitLevel
|
4313 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4314 "Kext %s - calling kxld_link_file:\n"
4315 " kxld_context: %p\n"
4316 " executable: %p executable_length: %d\n"
4318 " kxld_dependencies: %p num_dependencies: %d\n"
4319 " kxld_header_ptr: %p kmod_info_ptr: %p\n"
4320 " link_state_ptr: %p link_state_length_ptr: %p",
4321 getIdentifierCString(), kxldContext
,
4322 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
4323 this, kxlddeps
, num_kxlddeps
,
4324 kxldHeaderPtr
, kernelKmodInfoPtr
,
4325 linkStateBytesPtr
, linkStateLengthPtr
);
4328 /* After this call, the linkedExecutable instance variable
4331 kxldResult
= kxld_link_file(sKxldContext
,
4332 (u_char
*)theExecutable
->getBytesNoCopy(),
4333 theExecutable
->getLength(),
4334 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
4335 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
,
4336 linkStateBytesPtr
, linkStateLengthPtr
,
4337 /* symbolFile */ NULL
, /* symbolFileSize */ NULL
);
4339 if (kxldResult
!= KERN_SUCCESS
) {
4340 // xxx - add kxldResult here?
4342 kOSKextLogErrorLevel
|
4344 "Can't load kext %s - link failed.",
4345 getIdentifierCString());
4346 result
= kOSKextReturnLinkError
;
4350 /* If we got a link state, wrap it in an OSData and keep it
4351 * around for later use linking other kexts that depend on this kext.
4353 if (linkStateBytes
&& linkStateLength
> 0) {
4354 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
4356 linkState
->setDeallocFunction(&osdata_kmem_free
);
4359 /* If this isn't an interface, We've written data & instructions into kernel
4360 * memory, so flush the data cache and invalidate the instruction cache.
4362 if (!isInterface()) {
4363 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
4364 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
4369 if (isInterface()) {
4371 /* Whip up a fake kmod_info entry for the interface kext.
4373 kmod_info
= (kmod_info_t
*)kalloc(sizeof(kmod_info_t
));
4375 result
= KERN_MEMORY_ERROR
;
4379 /* A pseudokext has almost nothing in its kmod_info struct.
4381 bzero(kmod_info
, sizeof(kmod_info_t
));
4383 kmod_info
->info_version
= KMOD_INFO_VERSION
;
4385 /* An interface kext doesn't have a linkedExecutable, so save a
4386 * copy of the UUID out of the original executable via copyUUID()
4387 * while we still have the original executable.
4389 interfaceUUID
= copyUUID();
4392 kmod_info
->id
= loadTag
= sNextLoadTag
++;
4393 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
4395 /* Stamp the bundle ID and version from the OSKext over anything
4396 * resident inside the kmod_info.
4398 string
= getIdentifierCString();
4399 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
4401 string
= versCString
;
4402 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
4404 /* Add the dependencies' kmod_info structs as kmod_references.
4406 num_kmod_refs
= getNumDependencies();
4407 if (num_kmod_refs
) {
4408 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc(
4409 num_kmod_refs
* sizeof(kmod_reference_t
));
4410 if (!kmod_info
->reference_list
) {
4411 result
= KERN_MEMORY_ERROR
;
4414 bzero(kmod_info
->reference_list
,
4415 num_kmod_refs
* sizeof(kmod_reference_t
));
4416 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
4417 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
4418 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
4419 ref
->info
= refKext
->kmod_info
;
4420 ref
->info
->reference_count
++;
4422 if (refIndex
+ 1 < num_kmod_refs
) {
4423 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
4428 if (!isInterface() && linkedExecutable
) {
4430 kOSKextLogProgressLevel
|
4432 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4434 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
4435 (unsigned long)kmod_info
->address
,
4436 (unsigned)kmod_info
->id
);
4439 result
= setVMProtections();
4440 if (result
!= KERN_SUCCESS
) {
4444 result
= kOSReturnSuccess
;
4447 if (kxlddeps
) kfree(kxlddeps
, (num_kxlddeps
* sizeof(void *)));
4449 /* We no longer need the unrelocated executable (which the linker
4450 * has altered anyhow).
4452 setExecutable(NULL
);
4454 if (result
!= kOSReturnSuccess
) {
4456 kOSKextLogErrorLevel
|
4458 "Failed to load executable for kext %s.",
4459 getIdentifierCString());
4461 if (kmod_info
&& kmod_info
->reference_list
) {
4462 kfree(kmod_info
->reference_list
,
4463 num_kmod_refs
* sizeof(kmod_reference_t
));
4465 if (isInterface()) {
4466 kfree(kmod_info
, sizeof(kmod_info_t
));
4469 if (linkedExecutable
) {
4470 linkedExecutable
->release();
4471 linkedExecutable
= NULL
;
4478 /*********************************************************************
4479 * xxx - initWithPrelinkedInfoDict doesn't use this
4480 *********************************************************************/
4482 OSKext::setLinkedExecutable(OSData
* anExecutable
)
4484 if (linkedExecutable
) {
4485 panic("Attempt to set linked executable on kext "
4486 "that already has one (%s).\n",
4487 getIdentifierCString());
4489 linkedExecutable
= anExecutable
;
4490 linkedExecutable
->retain();
4494 /*********************************************************************
4495 * called only by loadExecutable()
4496 *********************************************************************/
4498 OSKext::setVMProtections(void)
4500 vm_map_t kext_map
= NULL
;
4501 kernel_segment_command_t
* seg
= NULL
;
4502 vm_map_offset_t start
= 0;
4503 vm_map_offset_t end
= 0;
4504 OSReturn result
= kOSReturnError
;
4506 if (!kmod_info
->address
&& !kmod_info
->size
) {
4507 result
= kOSReturnSuccess
;
4511 /* Get the kext's vm map */
4512 kext_map
= kext_get_vm_map(kmod_info
);
4514 result
= KERN_MEMORY_ERROR
;
4518 /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
4519 * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
4520 * so the vm_map_protect calls below fail
4521 * I believe this happens in the call to vm_map_enter in kmem_init but I
4524 /* Protect the headers as read-only; they do not need to be wired */
4525 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4526 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
4527 if (result
!= KERN_SUCCESS
) {
4531 /* Set the VM protections and wire down each of the segments */
4532 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
4534 start
= round_page(seg
->vmaddr
);
4535 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
4537 result
= vm_map_protect(kext_map
, start
, end
, seg
->maxprot
, TRUE
);
4538 if (result
!= KERN_SUCCESS
) {
4540 kOSKextLogErrorLevel
|
4542 "Kext %s failed to set maximum VM protections "
4543 "for segment %s - 0x%x.",
4544 getIdentifierCString(), seg
->segname
, (int)result
);
4548 result
= vm_map_protect(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4549 if (result
!= KERN_SUCCESS
) {
4551 kOSKextLogErrorLevel
|
4553 "Kext %s failed to set initial VM protections "
4554 "for segment %s - 0x%x.",
4555 getIdentifierCString(), seg
->segname
, (int)result
);
4559 result
= vm_map_wire(kext_map
, start
, end
, seg
->initprot
, FALSE
);
4560 if (result
!= KERN_SUCCESS
) {
4564 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
4571 /*********************************************************************
4572 *********************************************************************/
4574 OSKext::validateKextMapping(bool startFlag
)
4576 OSReturn result
= kOSReturnError
;
4577 const char * whichOp
= startFlag
? "start" : "stop";
4578 kern_return_t kern_result
= 0;
4579 vm_map_t kext_map
= NULL
;
4580 mach_vm_address_t address
= 0;
4581 mach_vm_size_t size
= 0;
4583 mach_msg_type_number_t count
;
4584 vm_region_submap_short_info_data_64_t info
;
4586 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
4587 bzero(&info
, sizeof(info
));
4589 // xxx - do we need a distinct OSReturn value for these or is "bad data"
4590 // xxx - sufficient?
4592 /* Verify that the kmod_info and start/stop pointers are non-NULL.
4596 kOSKextLogErrorLevel
|
4598 "Kext %s - NULL kmod_info pointer.",
4599 getIdentifierCString());
4600 result
= kOSKextReturnBadData
;
4605 address
= (mach_vm_address_t
)kmod_info
->start
;
4607 address
= (mach_vm_address_t
)kmod_info
->stop
;
4612 kOSKextLogErrorLevel
|
4614 "Kext %s - NULL module %s pointer.",
4615 getIdentifierCString(), whichOp
);
4616 result
= kOSKextReturnBadData
;
4620 kext_map
= kext_get_vm_map(kmod_info
);
4621 depth
= (kernel_map
== kext_map
) ? 1 : 2;
4623 /* Verify that the start/stop function lies within the kext's address range.
4625 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
4626 kmod_info
->address
+ kmod_info
->size
<= address
)
4629 kOSKextLogErrorLevel
|
4631 "Kext %s module %s pointer is outside of kext range "
4632 "(%s %p - kext at %p-%p)..",
4633 getIdentifierCString(),
4637 (void *)kmod_info
->address
,
4638 (void *)(kmod_info
->address
+ kmod_info
->size
));
4639 result
= kOSKextReturnBadData
;
4643 /* Only do these checks before calling the start function;
4644 * If anything goes wrong with the mapping while the kext is running,
4645 * we'll likely have panicked well before any attempt to stop the kext.
4649 /* Verify that the start/stop function is executable.
4651 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
4652 (vm_region_recurse_info_t
)&info
, &count
);
4653 if (kern_result
!= KERN_SUCCESS
) {
4655 kOSKextLogErrorLevel
|
4657 "Kext %s - bad %s pointer %p.",
4658 getIdentifierCString(),
4659 whichOp
, (void *)address
);
4660 result
= kOSKextReturnBadData
;
4664 if (!(info
.protection
& VM_PROT_EXECUTE
)) {
4666 kOSKextLogErrorLevel
|
4668 "Kext %s - memory region containing module %s function "
4669 "is not executable.",
4670 getIdentifierCString(), whichOp
);
4671 result
= kOSKextReturnBadData
;
4675 /* Verify that the kext is backed by physical memory.
4677 for (address
= kmod_info
->address
;
4678 address
< round_page(kmod_info
->address
+ kmod_info
->size
);
4679 address
+= PAGE_SIZE
)
4681 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
4683 kOSKextLogErrorLevel
|
4685 "Kext %s - page %p is not backed by physical memory.",
4686 getIdentifierCString(),
4688 result
= kOSKextReturnBadData
;
4694 result
= kOSReturnSuccess
;
4699 /*********************************************************************
4700 *********************************************************************/
4702 OSKext::start(bool startDependenciesFlag
)
4704 OSReturn result
= kOSReturnError
;
4705 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
4706 unsigned int i
, count
;
4707 void * kmodStartData
= NULL
; // special handling needed
4708 #if CONFIG_MACF_KEXT
4709 mach_msg_type_number_t kmodStartDataCount
= 0;
4710 #endif /* CONFIG_MACF_KEXT */
4712 if (isStarted() || isInterface() || isKernelComponent()) {
4713 result
= kOSReturnSuccess
;
4719 kOSKextLogErrorLevel
|
4721 "Attempt to start nonloaded kext %s.",
4722 getIdentifierCString());
4723 result
= kOSKextReturnInvalidArgument
;
4727 result
= validateKextMapping(/* start? */ true);
4728 if (result
!= kOSReturnSuccess
) {
4732 startfunc
= kmod_info
->start
;
4734 count
= getNumDependencies();
4735 for (i
= 0; i
< count
; i
++) {
4736 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
4737 if (dependency
== NULL
) {
4739 kOSKextLogErrorLevel
|
4741 "Kext %s start - internal error, dependency disappeared.",
4742 getIdentifierCString());
4745 if (!dependency
->isStarted()) {
4746 if (startDependenciesFlag
) {
4747 OSReturn dependencyResult
=
4748 dependency
->start(startDependenciesFlag
);
4749 if (dependencyResult
!= KERN_SUCCESS
) {
4751 kOSKextLogErrorLevel
|
4753 "Kext %s start - dependency %s failed to start (error 0x%x).",
4754 getIdentifierCString(),
4755 dependency
->getIdentifierCString(),
4761 kOSKextLogErrorLevel
|
4763 "Not starting %s - dependency %s not started yet.",
4764 getIdentifierCString(),
4765 dependency
->getIdentifierCString());
4766 result
= kOSKextReturnStartStopError
; // xxx - make new return?
4772 #if CONFIG_MACF_KEXT
4773 /* See if the kext has any MAC framework module data in its plist.
4774 * This is passed in as arg #2 of the kext's start routine,
4775 * which is otherwise reserved for any other kext.
4777 kmodStartData
= MACFCopyModuleDataForKext(this, &kmodStartDataCount
);
4778 #endif /* CONFIG_MACF_KEXT */
4781 kOSKextLogDetailLevel
|
4783 "Kext %s calling module start function.",
4784 getIdentifierCString());
4788 #if !__i386__ && !__ppc__
4789 result
= OSRuntimeInitializeCPP(kmod_info
, NULL
);
4790 if (result
== KERN_SUCCESS
) {
4793 result
= startfunc(kmod_info
, kmodStartData
);
4795 #if !__i386__ && !__ppc__
4796 if (result
!= KERN_SUCCESS
) {
4797 (void) OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4804 /* On success overlap the setting of started/starting. On failure just
4807 if (result
== KERN_SUCCESS
) {
4810 // xxx - log start error from kernel?
4812 kOSKextLogProgressLevel
|
4814 "Kext %s is now started.",
4815 getIdentifierCString());
4817 invokeOrCancelRequestCallbacks(
4818 /* result not actually used */ kOSKextReturnStartStopError
,
4819 /* invokeFlag */ false);
4821 kOSKextLogProgressLevel
|
4823 "Kext %s did not start (return code 0x%x).",
4824 getIdentifierCString(), result
);
4828 #if CONFIG_MACF_KEXT
4829 /* Free the module data for a MAC framework kext. When we start using
4830 * param #2 we'll have to distinguish and free/release appropriately.
4832 * xxx - I'm pretty sure the old codepath freed the data and that it's
4833 * xxx - up to the kext to copy it.
4835 if (kmodStartData
) {
4836 kmem_free(kernel_map
, (vm_offset_t
)kmodStartData
, kmodStartDataCount
);
4838 #endif /* CONFIG_MACF_KEXT */
4843 /*********************************************************************
4844 *********************************************************************/
4846 bool OSKext::canUnloadKextWithIdentifier(
4847 OSString
* kextIdentifier
,
4848 bool checkClassesFlag
)
4850 bool result
= false;
4851 OSKext
* aKext
= NULL
; // do not release
4853 IORecursiveLockLock(sKextLock
);
4855 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4858 goto finish
; // can't unload what's not loaded
4861 if (aKext
->isLoaded()) {
4862 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
4865 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
4873 IORecursiveLockUnlock(sKextLock
);
4877 /*********************************************************************
4878 *********************************************************************/
4882 OSReturn result
= kOSReturnError
;
4883 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
4885 if (!isStarted() || isInterface()) {
4886 result
= kOSReturnSuccess
;
4892 kOSKextLogErrorLevel
|
4894 "Attempt to stop nonloaded kext %s.",
4895 getIdentifierCString());
4896 result
= kOSKextReturnInvalidArgument
;
4900 /* Refuse to stop if we have clients or instances. It is up to
4901 * the caller to make sure those aren't true.
4903 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4905 kOSKextLogErrorLevel
|
4907 "Kext %s - C++ instances; can't stop.",
4908 getIdentifierCString());
4909 result
= kOSKextReturnInUse
;
4913 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
4916 kOSKextLogErrorLevel
|
4918 "Kext %s - has references (linkage or tracking object); "
4920 getIdentifierCString());
4921 result
= kOSKextReturnInUse
;
4925 /* Note: If validateKextMapping fails on the stop & unload path,
4926 * we are in serious trouble and a kernel panic is likely whether
4927 * we stop & unload the kext or not.
4929 result
= validateKextMapping(/* start? */ false);
4930 if (result
!= kOSReturnSuccess
) {
4934 /* Save the list of loaded kexts in case we panic.
4936 OSKext::saveUnloadedKextPanicList(this);
4938 stopfunc
= kmod_info
->stop
;
4941 kOSKextLogDetailLevel
|
4943 "Kext %s calling module stop function.",
4944 getIdentifierCString());
4948 result
= stopfunc(kmod_info
, /* userData */ NULL
);
4949 #if !__i386__ && !__ppc__
4950 if (result
== KERN_SUCCESS
) {
4951 result
= OSRuntimeFinalizeCPP(kmod_info
, NULL
);
4957 if (result
== KERN_SUCCESS
) {
4961 kOSKextLogDetailLevel
|
4963 "Kext %s is now stopped and ready to unload.",
4964 getIdentifierCString());
4967 kOSKextLogErrorLevel
|
4969 "Kext %s did not stop (return code 0x%x).",
4970 getIdentifierCString(), result
);
4971 result
= kOSKextReturnStartStopError
;
4979 /*********************************************************************
4980 *********************************************************************/
4982 OSKext::unload(void)
4984 OSReturn result
= kOSReturnError
;
4986 uint32_t num_kmod_refs
= 0;
4988 if (!sUnloadEnabled
) {
4990 kOSKextLogErrorLevel
|
4992 "Kext unloading is disabled (%s).",
4993 this->getIdentifierCString());
4995 result
= kOSKextReturnDisabled
;
4999 /* Refuse to unload if we have clients or instances. It is up to
5000 * the caller to make sure those aren't true.
5002 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5003 // xxx - Don't log under errors? this is more of an info thing
5005 kOSKextLogErrorLevel
|
5006 kOSKextLogKextBookkeepingFlag
,
5007 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5008 getIdentifierCString());
5009 result
= kOSKextReturnInUse
;
5014 if (hasOSMetaClassInstances()) {
5016 kOSKextLogErrorLevel
|
5017 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5018 "Can't unload kext %s; classes have instances:",
5019 getIdentifierCString());
5020 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
5021 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
5022 result
= kOSKextReturnInUse
;
5027 result
= kOSReturnSuccess
;
5031 if (isKernelComponent()) {
5032 result
= kOSKextReturnInvalidArgument
;
5036 /* Note that the kext is unloading before running any code that
5037 * might be in the kext (request callbacks, module stop function).
5038 * We will deny certain requests made against a kext in the process
5041 flags
.unloading
= 1;
5045 if (result
!= KERN_SUCCESS
) {
5047 kOSKextLogErrorLevel
|
5049 "Kext %s can't unload - module stop returned 0x%x.",
5050 getIdentifierCString(), (unsigned)result
);
5051 result
= kOSKextReturnStartStopError
;
5057 kOSKextLogProgressLevel
|
5059 "Kext %s unloading.",
5060 getIdentifierCString());
5062 /* Even if we don't call the stop function, we want to be sure we
5063 * have no OSMetaClass references before unloading the kext executable
5064 * from memory. OSMetaClasses may have pointers into the kext executable
5065 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5068 metaClasses
->flushCollection();
5071 /* Remove the kext from the list of loaded kexts, patch the gap
5072 * in the kmod_info_t linked list, and reset "kmod" to point to the
5073 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5075 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
5076 if (index
!= (unsigned int)-1) {
5078 sLoadedKexts
->removeObject(index
);
5080 OSKext
* nextKext
= OSDynamicCast(OSKext
,
5081 sLoadedKexts
->getObject(index
));
5085 OSKext
* gapKext
= OSDynamicCast(OSKext
,
5086 sLoadedKexts
->getObject(index
- 1));
5088 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
5090 } else /* index == 0 */ {
5091 nextKext
->kmod_info
->next
= NULL
;
5095 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5096 if (lastKext
&& lastKext
!= sKernelKext
) {
5097 kmod
= lastKext
->kmod_info
;
5099 kmod
= NULL
; // clear the global kmod variable
5103 /* Clear out the kmod references that we're keeping for compatibility
5104 * with current panic backtrace code & kgmacros.
5105 * xxx - will want to update those bits sometime and remove this.
5107 num_kmod_refs
= getNumDependencies();
5108 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
5109 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
5110 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
5111 ref
->info
->reference_count
--;
5113 kfree(kmod_info
->reference_list
,
5114 num_kmod_refs
* sizeof(kmod_reference_t
));
5117 /* If we have a linked executable, release & clear it, and then
5118 * unwire & deallocate the buffer the OSData wrapped.
5120 if (linkedExecutable
) {
5123 /* linkedExecutable is just a wrapper for the executable and doesn't
5126 linkedExecutable
->release();
5127 linkedExecutable
= NULL
;
5130 kOSKextLogProgressLevel
|
5132 "Kext %s unwiring and unmapping linked executable.",
5133 getIdentifierCString());
5135 kext_map
= kext_get_vm_map(kmod_info
);
5137 // xxx - do we have to do this before freeing? Why can't we just free it?
5138 // xxx - we should be able to set a dealloc func on the linkedExecutable
5139 result
= vm_map_unwire(kext_map
,
5140 kmod_info
->address
+ kmod_info
->hdr_size
,
5141 kmod_info
->address
+ kmod_info
->size
, FALSE
);
5142 if (result
== KERN_SUCCESS
) {
5143 kext_free(kmod_info
->address
, kmod_info
->size
);
5148 /* An interface kext has a fake kmod_info that was allocated,
5149 * so we have to free it.
5151 if (isInterface()) {
5152 kfree(kmod_info
, sizeof(kmod_info_t
));
5157 flags
.loaded
= false;
5158 flushDependencies();
5161 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5162 "Kext %s unloaded.", getIdentifierCString());
5165 OSKext::saveLoadedKextPanicList();
5167 flags
.unloading
= 0;
5171 /*********************************************************************
5172 *********************************************************************/
5174 _OSKextConsiderDestroyingLinkContext(
5175 __unused thread_call_param_t p0
,
5176 __unused thread_call_param_t p1
)
5178 /* Once both recursive locks are taken in correct order, we shouldn't
5179 * have to worry about further recursive lock takes.
5181 IORecursiveLockLock(sKextLock
);
5182 IORecursiveLockLock(sKextInnerLock
);
5184 /* The first time we destroy the kxldContext is in the first
5185 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5186 * before calling this function. Thereafter any call to this function
5187 * will actually destroy the context.
5189 if (sConsiderUnloadsCalled
&& sKxldContext
) {
5190 kxld_destroy_context(sKxldContext
);
5191 sKxldContext
= NULL
;
5194 /* Free the thread_call that was allocated to execute this function.
5196 if (sDestroyLinkContextThread
) {
5197 if (!thread_call_free(sDestroyLinkContextThread
)) {
5198 OSKextLog(/* kext */ NULL
,
5199 kOSKextLogErrorLevel
|
5200 kOSKextLogGeneralFlag
,
5201 "thread_call_free() failed for kext link context.");
5203 sDestroyLinkContextThread
= 0;
5206 IORecursiveLockUnlock(sKextInnerLock
);
5207 IORecursiveLockUnlock(sKextLock
);
5212 /*********************************************************************
5213 * Destroying the kxldContext requires checking variables under both
5214 * sKextInnerLock and sKextLock, so we do it on a separate thread
5215 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5216 * call relationship.
5218 * Do not call any function that takes sKextLock here! This function
5219 * can be invoked with sKextInnerLock, and the two must always
5220 * be taken in the order: sKextLock -> sKextInnerLock.
5221 *********************************************************************/
5224 OSKext::considerDestroyingLinkContext(void)
5226 IORecursiveLockLock(sKextInnerLock
);
5228 /* If we have already queued a thread to destroy the link context,
5229 * don't bother resetting; that thread will take care of it.
5231 if (sDestroyLinkContextThread
) {
5235 /* The function to be invoked in the thread will deallocate
5236 * this thread_call, so don't share it around.
5238 sDestroyLinkContextThread
= thread_call_allocate(
5239 &_OSKextConsiderDestroyingLinkContext
, 0);
5240 if (!sDestroyLinkContextThread
) {
5241 OSKextLog(/* kext */ NULL
,
5242 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
5243 "Can't create thread to destroy kext link context.");
5247 thread_call_enter(sDestroyLinkContextThread
);
5250 IORecursiveLockUnlock(sKextInnerLock
);
5254 /*********************************************************************
5255 *********************************************************************/
5257 OSKext::getKernelLinkState()
5259 kern_return_t kxldResult
;
5260 u_char
* kernel
= NULL
;
5261 size_t kernelLength
;
5262 u_char
* linkStateBytes
= NULL
;
5263 u_long linkStateLength
;
5264 OSData
* linkState
= NULL
;
5266 if (sKernelKext
&& sKernelKext
->linkState
) {
5270 kernel
= (u_char
*)&_mh_execute_header
;
5271 kernelLength
= getlastaddr() - (vm_offset_t
)kernel
;
5273 kxldResult
= kxld_link_file(sKxldContext
,
5276 kOSKextKernelIdentifier
,
5277 /* callbackData */ NULL
,
5278 /* dependencies */ NULL
,
5279 /* numDependencies */ 0,
5280 /* linkedObjectOut */ NULL
,
5281 /* kmod_info_kern out */ NULL
,
5284 /* symbolFile */ NULL
,
5285 /* symbolFileSize */ NULL
);
5287 panic("Can't generate kernel link state; no kexts can be loaded.");
5291 linkState
= OSData::withBytesNoCopy(linkStateBytes
, linkStateLength
);
5292 linkState
->setDeallocFunction(&osdata_kmem_free
);
5293 sKernelKext
->linkState
= linkState
;
5296 return sKernelKext
->linkState
;
5300 #pragma mark Autounload
5302 /*********************************************************************
5303 * This is a static method because the kext will be deallocated if it
5305 *********************************************************************/
5307 OSKext::autounloadKext(OSKext
* aKext
)
5309 OSReturn result
= kOSKextReturnInUse
;
5311 /* Check for external references to this kext (usu. dependents),
5312 * instances of defined classes (or classes derived from them),
5313 * outstanding requests.
5315 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
5316 !aKext
->flags
.autounloadEnabled
||
5317 aKext
->isKernelComponent()) {
5322 /* Skip a delay-autounload kext, once.
5324 if (aKext
->flags
.delayAutounload
) {
5326 kOSKextLogProgressLevel
|
5327 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5328 "Kext %s has delayed autounload set; skipping and clearing flag.",
5329 aKext
->getIdentifierCString());
5330 aKext
->flags
.delayAutounload
= 0;
5334 if (aKext
->hasOSMetaClassInstances() ||
5335 aKext
->countRequestCallbacks()) {
5339 result
= OSKext::removeKext(aKext
);
5346 /*********************************************************************
5347 *********************************************************************/
5349 _OSKextConsiderUnloads(
5350 __unused thread_call_param_t p0
,
5351 __unused thread_call_param_t p1
)
5353 bool didUnload
= false;
5354 unsigned int count
, i
;
5356 /* Once both recursive locks are taken in correct order, we shouldn't
5357 * have to worry about further recursive lock takes.
5359 IORecursiveLockLock(sKextLock
);
5360 IORecursiveLockLock(sKextInnerLock
);
5362 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
5364 /* If the system is powering down, don't try to unload anything.
5370 OSKextLog(/* kext */ NULL
,
5371 kOSKextLogProgressLevel
|
5373 "Checking for unused kexts to autounload.");
5376 * Remove any request callbacks marked as stale,
5377 * and mark as stale any currently in flight.
5379 count
= sRequestCallbackRecords
->getCount();
5383 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
5384 sRequestCallbackRecords
->getObject(i
));
5385 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
5386 callbackRecord
->getObject(kKextRequestStaleKey
));
5388 if (stale
&& stale
->isTrue()) {
5389 OSKext::invokeRequestCallback(callbackRecord
,
5390 kOSKextReturnTimeout
);
5392 callbackRecord
->setObject(kKextRequestStaleKey
,
5399 * Make multiple passes through the array of loaded kexts until
5400 * we don't unload any. This handles unwinding of dependency
5401 * chains. We have to go *backwards* through the array because
5402 * kexts are removed from it when unloaded, and we cannot make
5403 * a copy or we'll mess up the retain counts we rely on to
5404 * check whether a kext will unload. If only we could have
5405 * nonretaining collections like CF has....
5410 count
= sLoadedKexts
->getCount();
5414 OSKext
* thisKext
= OSDynamicCast(OSKext
,
5415 sLoadedKexts
->getObject(i
));
5416 didUnload
= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
5419 } while (didUnload
);
5422 sConsiderUnloadsPending
= false;
5423 sConsiderUnloadsExecuted
= true;
5425 (void) OSKext::considerRebuildOfPrelinkedKernel();
5427 IORecursiveLockUnlock(sKextInnerLock
);
5428 IORecursiveLockUnlock(sKextLock
);
5433 /*********************************************************************
5434 * Do not call any function that takes sKextLock here!
5435 *********************************************************************/
5436 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
5440 IORecursiveLockLock(sKextInnerLock
);
5442 if (!sUnloadCallout
) {
5443 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, 0);
5446 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
5450 thread_call_cancel(sUnloadCallout
);
5451 if (OSKext::getAutounloadEnabled() && !sSystemSleep
) {
5452 clock_interval_to_deadline(sConsiderUnloadDelay
,
5453 1000 * 1000 * 1000, &when
);
5455 OSKextLog(/* kext */ NULL
,
5456 kOSKextLogProgressLevel
|
5458 "%scheduling %sscan for unused kexts in %lu seconds.",
5459 sConsiderUnloadsPending
? "Res" : "S",
5460 sConsiderUnloadsCalled
? "" : "initial ",
5461 (unsigned long)sConsiderUnloadDelay
);
5463 sConsiderUnloadsPending
= true;
5464 thread_call_enter_delayed(sUnloadCallout
, when
);
5468 /* The kxld context should be reused throughout boot. We mark the end of
5469 * period as the first time considerUnloads() is called, and we destroy
5470 * the first kxld context in that function. Afterwards, it will be
5471 * destroyed in flushNonloadedKexts.
5473 if (!sConsiderUnloadsCalled
) {
5474 sConsiderUnloadsCalled
= true;
5475 OSKext::considerDestroyingLinkContext();
5478 IORecursiveLockUnlock(sKextInnerLock
);
5482 /*********************************************************************
5483 * Do not call any function that takes sKextLock here!
5484 *********************************************************************/
5487 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
)
5489 IORecursiveLockLock(sKextInnerLock
);
5491 /* If the system is going to sleep, cancel the reaper thread timer,
5492 * and note that we're in a sleep state in case it just fired but hasn't
5493 * taken the lock yet. If we are coming back from sleep, just
5494 * clear the sleep flag; IOService's normal operation will cause
5495 * unloads to be considered soon enough.
5497 if (messageType
== kIOMessageSystemWillSleep
) {
5498 if (sUnloadCallout
) {
5499 thread_call_cancel(sUnloadCallout
);
5501 sSystemSleep
= true;
5502 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
5503 sSystemSleep
= false;
5505 IORecursiveLockUnlock(sKextInnerLock
);
5507 return kIOReturnSuccess
;
5514 #pragma mark Prelinked Kernel
5516 /*********************************************************************
5517 * Do not access sConsiderUnloads... variables other than
5518 * sConsiderUnloadsExecuted in this function. They are guarded by a
5520 *********************************************************************/
5523 OSKext::considerRebuildOfPrelinkedKernel(void)
5525 OSReturn checkResult
= kOSReturnError
;
5526 static bool requestedPrelink
= false;
5527 OSDictionary
* prelinkRequest
= NULL
; // must release
5529 IORecursiveLockLock(sKextLock
);
5531 if (!sDeferredLoadSucceeded
|| !sConsiderUnloadsExecuted
||
5532 sSafeBoot
|| requestedPrelink
)
5537 OSKextLog(/* kext */ NULL
,
5538 kOSKextLogProgressLevel
|
5539 kOSKextLogArchiveFlag
,
5540 "Requesting build of prelinked kernel.");
5542 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
5544 if (checkResult
!= kOSReturnSuccess
) {
5548 if (!sKernelRequests
->setObject(prelinkRequest
)) {
5553 requestedPrelink
= true;
5556 IORecursiveLockUnlock(sKextLock
);
5557 OSSafeRelease(prelinkRequest
);
5562 #pragma mark Dependencies
5564 /*********************************************************************
5565 *********************************************************************/
5567 OSKext::resolveDependencies(
5568 OSArray
* loopStack
)
5570 bool result
= false;
5571 OSArray
* localLoopStack
= NULL
; // must release
5572 bool addedToLoopStack
= false;
5573 OSDictionary
* libraries
= NULL
; // do not release
5574 OSCollectionIterator
* libraryIterator
= NULL
; // must release
5575 OSString
* libraryID
= NULL
; // do not release
5576 OSString
* infoString
= NULL
; // do not release
5577 OSString
* readableString
= NULL
; // do not release
5578 OSKext
* libraryKext
= NULL
; // do not release
5579 bool hasRawKernelDependency
= false;
5580 bool hasKernelDependency
= false;
5581 bool hasKPIDependency
= false;
5582 bool hasPrivateKPIDependency
= false;
5585 /* A kernel component will automatically have this flag set,
5586 * and a loaded kext should also have it set (as should all its
5587 * loaded dependencies).
5589 if (flags
.hasAllDependencies
) {
5594 /* Check for loops in the dependency graph.
5597 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
5599 kOSKextLogErrorLevel
|
5600 kOSKextLogDependenciesFlag
,
5601 "Kext %s has a dependency loop; can't resolve dependencies.",
5602 getIdentifierCString());
5607 kOSKextLogStepLevel
|
5608 kOSKextLogDependenciesFlag
,
5609 "Kext %s resolving dependencies.",
5610 getIdentifierCString());
5612 loopStack
= OSArray::withCapacity(6); // any small capacity will do
5615 kOSKextLogErrorLevel
|
5616 kOSKextLogDependenciesFlag
,
5617 "Kext %s can't create bookkeeping stack to resolve dependencies.",
5618 getIdentifierCString());
5621 localLoopStack
= loopStack
;
5623 if (!loopStack
->setObject(this)) {
5625 kOSKextLogErrorLevel
|
5626 kOSKextLogDependenciesFlag
,
5627 "Kext %s - internal error resolving dependencies.",
5628 getIdentifierCString());
5631 addedToLoopStack
= true;
5633 /* Purge any existing kexts in the dependency list and start over.
5635 flushDependencies();
5638 kOSKextLogErrorLevel
|
5639 kOSKextLogDependenciesFlag
,
5640 "Kext %s - internal error resolving dependencies.",
5641 getIdentifierCString());
5644 libraries
= OSDynamicCast(OSDictionary
,
5645 getPropertyForHostArch(kOSBundleLibrariesKey
));
5646 if (libraries
== NULL
|| libraries
->getCount() == 0) {
5648 kOSKextLogErrorLevel
|
5649 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5650 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
5651 getIdentifierCString(), kOSBundleLibrariesKey
);
5655 /* Make a new array to hold the dependencies (flush freed the old one).
5657 dependencies
= OSArray::withCapacity(libraries
->getCount());
5658 if (!dependencies
) {
5660 kOSKextLogErrorLevel
|
5661 kOSKextLogDependenciesFlag
,
5662 "Kext %s - can't allocate dependencies array.",
5663 getIdentifierCString());
5667 // xxx - compat: We used to add an implicit dependency on kernel 6.0
5668 // xxx - compat: if none were declared.
5670 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
5671 if (!libraryIterator
) {
5673 kOSKextLogErrorLevel
|
5674 kOSKextLogDependenciesFlag
,
5675 "Kext %s - can't allocate dependencies iterator.",
5676 getIdentifierCString());
5680 while ((libraryID
= OSDynamicCast(OSString
,
5681 libraryIterator
->getNextObject()))) {
5683 const char * library_id
= libraryID
->getCStringNoCopy();
5685 OSString
* libraryVersion
= OSDynamicCast(OSString
,
5686 libraries
->getObject(libraryID
));
5687 if (libraryVersion
== NULL
) {
5689 kOSKextLogErrorLevel
|
5690 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5691 "Kext %s - illegal type in OSBundleLibraries.",
5692 getIdentifierCString());
5696 OSKextVersion libraryVers
=
5697 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
5698 if (libraryVers
== -1) {
5700 kOSKextLogErrorLevel
|
5701 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5702 "Kext %s - invalid library version %s.",
5703 getIdentifierCString(),
5704 libraryVersion
->getCStringNoCopy());
5708 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
5709 if (libraryKext
== NULL
) {
5711 kOSKextLogErrorLevel
|
5712 kOSKextLogDependenciesFlag
,
5713 "Kext %s - library kext %s not found.",
5714 getIdentifierCString(), library_id
);
5718 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
5720 kOSKextLogErrorLevel
|
5721 kOSKextLogDependenciesFlag
,
5722 "Kext %s - library kext %s not compatible "
5723 "with requested version %s.",
5724 getIdentifierCString(), library_id
,
5725 libraryVersion
->getCStringNoCopy());
5729 if (!libraryKext
->resolveDependencies(loopStack
)) {
5733 /* Add the library directly only if it has an executable to link.
5734 * Otherwise it's just used to collect other dependencies, so put
5735 * *its* dependencies on the list for this kext.
5737 // xxx - We are losing info here; would like to make fake entries or
5738 // xxx - keep these in the dependency graph for loaded kexts.
5739 // xxx - I really want to make kernel components not a special case!
5740 if (libraryKext
->declaresExecutable() ||
5741 libraryKext
->isInterface()) {
5743 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
5744 dependencies
->setObject(libraryKext
);
5747 kOSKextLogDetailLevel
|
5748 kOSKextLogDependenciesFlag
,
5749 "Kext %s added dependency %s.",
5750 getIdentifierCString(),
5751 libraryKext
->getIdentifierCString());
5754 int numLibDependencies
= libraryKext
->getNumDependencies();
5755 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
5758 if (numLibDependencies
) {
5759 // xxx - this msg level should be 1 lower than the per-kext one
5761 kOSKextLogDetailLevel
|
5762 kOSKextLogDependenciesFlag
,
5763 "Kext %s pulling %d dependencies from codeless library %s.",
5764 getIdentifierCString(),
5766 libraryKext
->getIdentifierCString());
5768 for (index
= 0; index
< numLibDependencies
; index
++) {
5769 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
5770 libraryDependencies
->getObject(index
));
5771 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
5772 dependencies
->setObject(thisLibDependency
);
5774 kOSKextLogDetailLevel
|
5775 kOSKextLogDependenciesFlag
,
5776 "Kext %s added dependency %s from codeless library %s.",
5777 getIdentifierCString(),
5778 thisLibDependency
->getIdentifierCString(),
5779 libraryKext
->getIdentifierCString());
5784 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
5785 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
)-1)) {
5787 hasRawKernelDependency
= true;
5788 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
5789 hasKernelDependency
= true;
5790 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
5791 hasKPIDependency
= true;
5792 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
)-1)) {
5793 hasPrivateKPIDependency
= true;
5799 if (hasRawKernelDependency
|| hasKernelDependency
) {
5801 kOSKextLogErrorLevel
|
5802 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5803 "Error - kext %s declares %s dependencies. "
5804 "Only %s* dependencies are supported for 64-bit kexts.",
5805 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
5808 if (!hasKPIDependency
) {
5810 kOSKextLogWarningLevel
|
5811 kOSKextLogDependenciesFlag
,
5812 "Warning - kext %s declares no %s* dependencies. "
5813 "If it uses any KPIs, the link may fail with undefined symbols.",
5814 getIdentifierCString(), KPI_LIB_PREFIX
);
5816 #else /* __LP64__ */
5817 // xxx - will change to flatly disallow "kernel" dependencies at some point
5818 // xxx - is it invalid to do both "com.apple.kernel" and any
5819 // xxx - "com.apple.kernel.*"?
5821 if (hasRawKernelDependency
&& hasKernelDependency
) {
5823 kOSKextLogErrorLevel
|
5824 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
5825 "Error - kext %s declares dependencies on both "
5827 getIdentifierCString(), KERNEL_LIB
, KERNEL6_LIB
);
5831 if ((hasRawKernelDependency
|| hasKernelDependency
) && hasKPIDependency
) {
5833 kOSKextLogWarningLevel
|
5834 kOSKextLogDependenciesFlag
,
5835 "Warning - kext %s has immediate dependencies on both "
5836 "%s* and %s* components; use only one style.",
5837 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
5840 if (!hasRawKernelDependency
&& !hasKernelDependency
&& !hasKPIDependency
) {
5841 // xxx - do we want to use validation flag for these too?
5843 kOSKextLogWarningLevel
|
5844 kOSKextLogDependenciesFlag
,
5845 "Warning - %s declares no kernel dependencies; using %s.",
5846 getIdentifierCString(), KERNEL6_LIB
);
5847 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
5848 sKextsByID
->getObject(KERNEL6_LIB
));
5850 dependencies
->setObject(kernelKext
);
5853 kOSKextLogErrorLevel
|
5854 kOSKextLogDependenciesFlag
,
5855 "Error - Library %s not found for %s.",
5856 KERNEL6_LIB
, getIdentifierCString());
5860 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
5861 * its indirect dependencies to simulate old-style linking. XXX - Should
5862 * check for duplicates.
5864 if (!hasRawKernelDependency
&& !hasKPIDependency
) {
5867 count
= getNumDependencies();
5869 /* We add to the dependencies array in this loop, but do not iterate
5870 * past its original count.
5872 for (i
= 0; i
< count
; i
++) {
5873 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
5874 dependencies
->getObject(i
));
5875 dependencyKext
->addBleedthroughDependencies(dependencies
);
5878 #endif /* __LP64__ */
5880 if (hasPrivateKPIDependency
) {
5881 bool hasApplePrefix
= false;
5882 bool infoCopyrightIsValid
= false;
5883 bool readableCopyrightIsValid
= false;
5885 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
5888 infoString
= OSDynamicCast(OSString
,
5889 getPropertyForHostArch("CFBundleGetInfoString"));
5891 infoCopyrightIsValid
=
5892 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
5895 readableString
= OSDynamicCast(OSString
,
5896 getPropertyForHostArch("NSHumanReadableCopyright"));
5897 if (readableString
) {
5898 readableCopyrightIsValid
=
5899 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
5902 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
5904 kOSKextLogErrorLevel
|
5905 kOSKextLogDependenciesFlag
,
5906 "Error - kext %s declares a dependency on %s. "
5907 "Only Apple kexts may declare a dependency on %s.",
5908 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
5914 flags
.hasAllDependencies
= 1;
5918 if (addedToLoopStack
) {
5919 count
= loopStack
->getCount();
5920 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
5921 loopStack
->removeObject(count
- 1);
5924 kOSKextLogErrorLevel
|
5925 kOSKextLogDependenciesFlag
,
5926 "Kext %s - internal error resolving dependencies.",
5927 getIdentifierCString());
5931 if (result
&& localLoopStack
) {
5933 kOSKextLogStepLevel
|
5934 kOSKextLogDependenciesFlag
,
5935 "Kext %s successfully resolved dependencies.",
5936 getIdentifierCString());
5939 OSSafeRelease(localLoopStack
);
5940 OSSafeRelease(libraryIterator
);
5945 /*********************************************************************
5946 *********************************************************************/
5948 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
5950 bool result
= false;
5951 unsigned int dependencyIndex
, dependencyCount
;
5953 dependencyCount
= getNumDependencies();
5955 for (dependencyIndex
= 0;
5956 dependencyIndex
< dependencyCount
;
5957 dependencyIndex
++) {
5959 OSKext
* dependency
= OSDynamicCast(OSKext
,
5960 dependencies
->getObject(dependencyIndex
));
5963 kOSKextLogErrorLevel
|
5964 kOSKextLogDependenciesFlag
,
5965 "Kext %s - internal error propagating compatibility dependencies.",
5966 getIdentifierCString());
5969 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
5970 anArray
->setObject(dependency
);
5972 dependency
->addBleedthroughDependencies(anArray
);
5981 /*********************************************************************
5982 *********************************************************************/
5984 OSKext::flushDependencies(bool forceFlag
)
5986 bool result
= false;
5988 /* Only clear the dependencies if the kext isn't loaded;
5989 * we need the info for loaded kexts to track references.
5991 if (!isLoaded() || forceFlag
) {
5993 // xxx - check level
5995 kOSKextLogProgressLevel
|
5996 kOSKextLogDependenciesFlag
,
5997 "Kext %s flushing dependencies.",
5998 getIdentifierCString());
5999 OSSafeReleaseNULL(dependencies
);
6002 if (!isKernelComponent()) {
6003 flags
.hasAllDependencies
= 0;
6011 /*********************************************************************
6012 *********************************************************************/
6014 OSKext::getNumDependencies(void)
6016 if (!dependencies
) {
6019 return dependencies
->getCount();
6022 /*********************************************************************
6023 *********************************************************************/
6025 OSKext::getDependencies(void)
6027 return dependencies
;
6031 #pragma mark OSMetaClass Support
6033 /*********************************************************************
6034 *********************************************************************/
6037 OSMetaClass
* aClass
,
6038 uint32_t numClasses
)
6040 OSReturn result
= kOSMetaClassNoInsKModSet
;
6043 metaClasses
= OSSet::withCapacity(numClasses
);
6049 if (metaClasses
->containsObject(aClass
)) {
6051 kOSKextLogWarningLevel
|
6053 "Notice - kext %s has already registered class %s.",
6054 getIdentifierCString(),
6055 aClass
->getClassName());
6056 result
= kOSReturnSuccess
;
6060 if (!metaClasses
->setObject(aClass
)) {
6064 kOSKextLogDetailLevel
|
6066 "Kext %s registered class %s.",
6067 getIdentifierCString(),
6068 aClass
->getClassName());
6071 if (!flags
.autounloadEnabled
) {
6072 const OSMetaClass
* metaScan
= NULL
; // do not release
6074 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
6075 if (metaScan
== OSTypeID(IOService
)) {
6078 kOSKextLogProgressLevel
|
6080 "Kext %s has IOService subclass %s; enabling autounload.",
6081 getIdentifierCString(),
6082 aClass
->getClassName());
6084 flags
.autounloadEnabled
= 1;
6090 result
= kOSReturnSuccess
;
6093 if (result
!= kOSReturnSuccess
) {
6095 kOSKextLogErrorLevel
|
6097 "Kext %s failed to register class %s.",
6098 getIdentifierCString(),
6099 aClass
->getClassName());
6105 /*********************************************************************
6106 *********************************************************************/
6108 OSKext::removeClass(
6109 OSMetaClass
* aClass
)
6111 OSReturn result
= kOSMetaClassNoKModSet
;
6117 if (!metaClasses
->containsObject(aClass
)) {
6119 kOSKextLogWarningLevel
|
6121 "Notice - kext %s asked to unregister unknown class %s.",
6122 getIdentifierCString(),
6123 aClass
->getClassName());
6124 result
= kOSReturnSuccess
;
6129 kOSKextLogDetailLevel
|
6131 "Kext %s unregistering class %s.",
6132 getIdentifierCString(),
6133 aClass
->getClassName());
6135 metaClasses
->removeObject(aClass
);
6137 result
= kOSReturnSuccess
;
6140 if (result
!= kOSReturnSuccess
) {
6142 kOSKextLogErrorLevel
|
6144 "Failed to unregister kext %s class %s.",
6145 getIdentifierCString(),
6146 aClass
->getClassName());
6151 /*********************************************************************
6152 *********************************************************************/
6154 OSKext::getMetaClasses(void)
6159 /*********************************************************************
6160 *********************************************************************/
6162 OSKext::hasOSMetaClassInstances(void)
6164 bool result
= false;
6165 OSCollectionIterator
* classIterator
= NULL
; // must release
6166 OSMetaClass
* checkClass
= NULL
; // do not release
6172 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6173 if (!classIterator
) {
6174 // xxx - log alloc failure?
6177 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6178 if (checkClass
->getInstanceCount()) {
6186 OSSafeRelease(classIterator
);
6190 /*********************************************************************
6191 *********************************************************************/
6194 OSKext::reportOSMetaClassInstances(
6195 const char * kextIdentifier
,
6196 OSKextLogSpec msgLogSpec
)
6198 OSKext
* theKext
= NULL
; // must release
6200 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
6205 theKext
->reportOSMetaClassInstances(msgLogSpec
);
6207 OSSafeRelease(theKext
);
6211 /*********************************************************************
6212 *********************************************************************/
6214 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
6216 OSCollectionIterator
* classIterator
= NULL
; // must release
6217 OSMetaClass
* checkClass
= NULL
; // do not release
6223 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6224 if (!classIterator
) {
6227 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6228 if (checkClass
->getInstanceCount()) {
6231 " Kext %s class %s has %d instance%s.",
6232 getIdentifierCString(),
6233 checkClass
->getClassName(),
6234 checkClass
->getInstanceCount(),
6235 checkClass
->getInstanceCount() == 1 ? "" : "s");
6240 OSSafeRelease(classIterator
);
6245 #pragma mark User-Space Requests
6247 /*********************************************************************
6248 * XXX - this function is a big ugly mess
6249 *********************************************************************/
6252 OSKext::handleRequest(
6253 host_priv_t hostPriv
,
6254 OSKextLogSpec clientLogFilter
,
6255 char * requestBuffer
,
6256 uint32_t requestLength
,
6257 char ** responseOut
,
6258 uint32_t * responseLengthOut
,
6260 uint32_t * logInfoLengthOut
)
6262 OSReturn result
= kOSReturnError
;
6263 kern_return_t kmem_result
= KERN_FAILURE
;
6265 char * response
= NULL
; // returned by reference
6266 uint32_t responseLength
= 0;
6268 OSObject
* parsedXML
= NULL
; // must release
6269 OSDictionary
* requestDict
= NULL
; // do not release
6270 OSString
* errorString
= NULL
; // must release
6272 OSData
* responseData
= NULL
; // must release
6273 OSObject
* responseObject
= NULL
; // must release
6275 OSSerialize
* serializer
= NULL
; // must release
6277 OSArray
* logInfoArray
= NULL
; // must release
6279 OSString
* predicate
= NULL
; // do not release
6280 OSString
* kextIdentifier
= NULL
; // do not release
6281 OSArray
* kextIdentifiers
= NULL
; // do not release
6282 OSKext
* theKext
= NULL
; // do not release
6283 OSBoolean
* boolArg
= NULL
; // do not release
6285 IORecursiveLockLock(sKextLock
);
6288 *responseOut
= NULL
;
6289 *responseLengthOut
= 0;
6293 *logInfoLengthOut
= 0;
6296 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
6298 /* XML must be nul-terminated.
6300 if (requestBuffer
[requestLength
- 1] != '\0') {
6301 OSKextLog(/* kext */ NULL
,
6302 kOSKextLogErrorLevel
|
6304 "Invalid request from user space (not nul-terminated).");
6305 result
= kOSKextReturnBadData
;
6308 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, &errorString
);
6310 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
);
6313 const char * errorCString
= "(unknown error)";
6315 if (errorString
&& errorString
->getCStringNoCopy()) {
6316 errorCString
= errorString
->getCStringNoCopy();
6317 } else if (parsedXML
) {
6318 errorCString
= "not a dictionary";
6320 OSKextLog(/* kext */ NULL
,
6321 kOSKextLogErrorLevel
|
6323 "Error unserializing request from user space: %s.",
6325 result
= kOSKextReturnSerialization
;
6329 predicate
= _OSKextGetRequestPredicate(requestDict
);
6331 OSKextLog(/* kext */ NULL
,
6332 kOSKextLogErrorLevel
|
6334 "Recieved kext request from user space with no predicate.");
6335 result
= kOSKextReturnInvalidArgument
;
6339 OSKextLog(/* kext */ NULL
,
6340 kOSKextLogDebugLevel
|
6342 "Received '%s' request from user space.",
6343 predicate
->getCStringNoCopy());
6345 result
= kOSKextReturnNotPrivileged
;
6346 if (hostPriv
== HOST_PRIV_NULL
) {
6347 if (!predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) &&
6348 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
) &&
6349 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6355 /* Get common args in anticipation of use.
6357 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
6358 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
6359 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
6360 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
6361 if (kextIdentifier
) {
6362 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
6364 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
6365 requestDict
, kKextRequestArgumentValueKey
));
6367 result
= kOSKextReturnInvalidArgument
;
6369 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
6370 if (!kextIdentifier
) {
6371 OSKextLog(/* kext */ NULL
,
6372 kOSKextLogErrorLevel
|
6374 "Invalid arguments to kext start request.");
6375 } else if (!theKext
) {
6376 OSKextLog(/* kext */ NULL
,
6377 kOSKextLogErrorLevel
|
6379 "Kext %s not found for start request.",
6380 kextIdentifier
->getCStringNoCopy());
6381 result
= kOSKextReturnNotFound
;
6383 result
= theKext
->start();
6386 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
6387 if (!kextIdentifier
) {
6388 OSKextLog(/* kext */ NULL
,
6389 kOSKextLogErrorLevel
|
6391 "Invalid arguments to kext stop request.");
6392 } else if (!theKext
) {
6393 OSKextLog(/* kext */ NULL
,
6394 kOSKextLogErrorLevel
|
6396 "Kext %s not found for stop request.",
6397 kextIdentifier
->getCStringNoCopy());
6398 result
= kOSKextReturnNotFound
;
6400 result
= theKext
->stop();
6403 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
6404 if (!kextIdentifier
) {
6405 OSKextLog(/* kext */ NULL
,
6406 kOSKextLogErrorLevel
|
6408 "Invalid arguments to kext unload request.");
6409 } else if (!theKext
) {
6410 OSKextLog(/* kext */ NULL
,
6411 kOSKextLogErrorLevel
|
6413 "Kext %s not found for unload request.",
6414 kextIdentifier
->getCStringNoCopy());
6415 result
= kOSKextReturnNotFound
;
6417 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
6418 _OSKextGetRequestArgument(requestDict
,
6419 kKextRequestArgumentTerminateIOServicesKey
));
6420 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
6423 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
6424 result
= OSKext::dispatchResource(requestDict
);
6426 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
6427 OSBoolean
* delayAutounloadBool
= NULL
;
6429 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
6430 _OSKextGetRequestArgument(requestDict
,
6431 kKextRequestArgumentDelayAutounloadKey
));
6433 /* If asked to delay autounload, reset the timer if it's currently set.
6434 * (That is, don't schedule an unload if one isn't already pending.
6436 if (delayAutounloadBool
== kOSBooleanTrue
) {
6437 OSKext::considerUnloads(/* rescheduleOnly? */ true);
6440 responseObject
= OSDynamicCast(OSObject
,
6441 OSKext::copyLoadedKextInfo(kextIdentifiers
));
6442 if (!responseObject
) {
6443 result
= kOSKextReturnInternalError
;
6445 OSKextLog(/* kext */ NULL
,
6446 kOSKextLogDebugLevel
|
6448 "Returning loaded kext info.");
6449 result
= kOSReturnSuccess
;
6452 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
6453 OSNumber
* addressNum
= NULL
; // released as responseObject
6454 kernel_segment_command_t
* textseg
= getsegbyname("__TEXT");
6457 OSKextLog(/* kext */ NULL
,
6458 kOSKextLogErrorLevel
|
6459 kOSKextLogGeneralFlag
| kOSKextLogIPCFlag
,
6460 "Can't find text segment for kernel load address.");
6461 result
= kOSReturnError
;
6465 OSKextLog(/* kext */ NULL
,
6466 kOSKextLogDebugLevel
|
6468 "Returning kernel load address 0x%llx.",
6469 (unsigned long long)textseg
->vmaddr
);
6470 addressNum
= OSNumber::withNumber((long long unsigned int)textseg
->vmaddr
,
6471 8 * sizeof(long long unsigned int));
6472 responseObject
= OSDynamicCast(OSObject
, addressNum
);
6473 result
= kOSReturnSuccess
;
6475 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLinkState
)) {
6476 OSKextLog(/* kext */ NULL
,
6477 kOSKextLogDebugLevel
|
6479 "Returning kernel link state.");
6480 responseData
= sKernelKext
->linkState
;
6481 responseData
->retain();
6482 result
= kOSReturnSuccess
;
6484 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
6486 /* Hand the current sKernelRequests array to the caller
6487 * (who must release it), and make a new one.
6489 responseObject
= OSDynamicCast(OSObject
, sKernelRequests
);
6490 sKernelRequests
= OSArray::withCapacity(0);
6491 sPostedKextLoadIdentifiers
->flushCollection();
6492 OSKextLog(/* kext */ NULL
,
6493 kOSKextLogDebugLevel
|
6495 "Returning kernel requests.");
6496 result
= kOSReturnSuccess
;
6498 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
6500 /* Return the set of all requested bundle identifiers */
6501 responseObject
= OSDynamicCast(OSObject
, sAllKextLoadIdentifiers
);
6502 responseObject
->retain();
6503 OSKextLog(/* kext */ NULL
,
6504 kOSKextLogDebugLevel
|
6506 "Returning load requests.");
6507 result
= kOSReturnSuccess
;
6511 * Now we have handle the request, or not. Gather up the response & logging
6512 * info to ship to user space.
6515 /* Note: Nothing in OSKext is supposed to retain requestDict,
6516 * but you never know....
6518 if (requestDict
->getRetainCount() > 1) {
6519 OSKextLog(/* kext */ NULL
,
6520 kOSKextLogWarningLevel
|
6522 "Request from user space still retained by a kext; "
6523 "probable memory leak.");
6526 if (responseData
&& responseObject
) {
6527 OSKextLog(/* kext */ NULL
,
6528 kOSKextLogErrorLevel
|
6530 "Mistakenly generated both data & plist responses to user request "
6531 "(returning only data).");
6534 if (responseData
&& responseData
->getLength() && responseOut
) {
6536 response
= (char *)responseData
->getBytesNoCopy();
6537 responseLength
= responseData
->getLength();
6538 } else if (responseOut
&& responseObject
) {
6539 serializer
= OSSerialize::withCapacity(0);
6541 result
= kOSKextReturnNoMemory
;
6545 if (!responseObject
->serialize(serializer
)) {
6546 OSKextLog(/* kext */ NULL
,
6547 kOSKextLogErrorLevel
|
6549 "Failed to serialize response to request from user space.");
6550 result
= kOSKextReturnSerialization
;
6554 response
= (char *)serializer
->text();
6555 responseLength
= serializer
->getLength();
6558 if (responseOut
&& response
) {
6561 /* This kmem_alloc sets the return value of the function.
6563 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
6565 if (kmem_result
!= KERN_SUCCESS
) {
6566 OSKextLog(/* kext */ NULL
,
6567 kOSKextLogErrorLevel
|
6569 "Failed to copy response to request from user space.");
6570 result
= kmem_result
;
6573 memcpy(buffer
, response
, responseLength
);
6574 *responseOut
= buffer
;
6575 *responseLengthOut
= responseLength
;
6581 /* Gather up the collected log messages for user space. Any messages
6582 * messages past this call will not make it up as log messages but
6583 * will be in the system log. Note that we ignore the return of the
6584 * serialize; it has no bearing on the operation at hand even if we
6585 * fail to get the log messages.
6587 logInfoArray
= OSKext::clearUserSpaceLogFilter();
6589 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
6590 (void)OSKext::serializeLogInfo(logInfoArray
,
6591 logInfoOut
, logInfoLengthOut
);
6594 IORecursiveLockUnlock(sKextLock
);
6596 OSSafeRelease(requestDict
);
6597 OSSafeRelease(errorString
);
6598 OSSafeRelease(responseData
);
6599 OSSafeRelease(responseObject
);
6600 OSSafeRelease(serializer
);
6601 OSSafeRelease(logInfoArray
);
6606 /*********************************************************************
6607 *********************************************************************/
6610 OSKext::copyLoadedKextInfo(OSArray
* kextIdentifiers
)
6612 OSArray
* result
= NULL
;
6613 OSDictionary
* kextInfo
= NULL
; // must release
6615 uint32_t idCount
= 0;
6616 uint32_t idIndex
= 0;
6618 IORecursiveLockLock(sKextLock
);
6620 /* Empty list of bundle ids is equivalent to no list (get all).
6622 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
6623 kextIdentifiers
= NULL
;
6624 } else if (kextIdentifiers
) {
6625 idCount
= kextIdentifiers
->getCount();
6628 count
= sLoadedKexts
->getCount();
6629 result
= OSArray::withCapacity(count
);
6633 for (i
= 0; i
< count
; i
++) {
6634 OSKext
* thisKext
= NULL
; // do not release
6635 Boolean includeThis
= true;
6638 kextInfo
->release();
6641 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6646 /* Skip current kext if we have a list of bundle IDs and
6647 * it isn't in the list.
6649 if (kextIdentifiers
) {
6650 const OSString
* thisKextID
= thisKext
->getIdentifier();
6652 includeThis
= false;
6654 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
6655 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
6656 kextIdentifiers
->getObject(idIndex
));
6657 if (thisKextID
->isEqualTo(thisRequestID
)) {
6668 kextInfo
= thisKext
->copyInfo();
6669 result
->setObject(kextInfo
);
6673 IORecursiveLockUnlock(sKextLock
);
6675 if (kextInfo
) kextInfo
->release();
6680 /*********************************************************************
6689 Dependency Load Tags
6690 # Dependent References
6693 *********************************************************************/
6694 #define _OSKextLoadInfoDictCapacity (12)
6697 OSKext::copyInfo(void)
6699 OSDictionary
* result
= NULL
;
6700 bool success
= false;
6701 OSNumber
* cpuTypeNumber
= NULL
; // must release
6702 OSNumber
* cpuSubtypeNumber
= NULL
; // must release
6703 OSString
* versionString
= NULL
; // do not release
6704 OSData
* uuid
= NULL
; // must release
6705 OSNumber
* scratchNumber
= NULL
; // must release
6706 OSArray
* dependencyLoadTags
= NULL
; // must release
6707 OSCollectionIterator
* metaClassIterator
= NULL
; // must release
6708 OSArray
* metaClassInfo
= NULL
; // must release
6709 OSDictionary
* metaClassDict
= NULL
; // must release
6710 OSMetaClass
* thisMetaClass
= NULL
; // do not release
6711 OSString
* metaClassName
= NULL
; // must release
6712 OSString
* superclassName
= NULL
; // must release
6715 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
6720 /* CPU Type & Subtype.
6721 * Use the CPU type of the kernel for all (loaded) kexts.
6722 * xxx - should we not include this for the kernel components,
6723 * xxx - or for any interface? they have mach-o files, they're just weird.
6725 if (linkedExecutable
|| (this == sKernelKext
)) {
6727 cpuTypeNumber
= OSNumber::withNumber(
6728 (long long unsigned int)_mh_execute_header
.cputype
,
6729 8 * sizeof(_mh_execute_header
.cputype
));
6730 if (cpuTypeNumber
) {
6731 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
);
6735 // I don't want to rely on a mach header for nonkernel kexts, yet
6736 if (this == sKernelKext
) {
6737 cpuSubtypeNumber
= OSNumber::withNumber(
6738 (long long unsigned int)_mh_execute_header
.cputype
,
6739 8 * sizeof(_mh_execute_header
.cputype
));
6740 if (cpuSubtypeNumber
) {
6741 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
);
6745 /* CFBundleIdentifier.
6747 result
->setObject(kCFBundleIdentifierKey
, bundleID
);
6751 versionString
= OSDynamicCast(OSString
,
6752 getPropertyForHostArch(kCFBundleVersionKey
));
6753 if (versionString
) {
6754 result
->setObject(kCFBundleVersionKey
, versionString
);
6757 /* OSBundleCompatibleVersion.
6759 versionString
= OSDynamicCast(OSString
,
6760 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
6761 if (versionString
) {
6762 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
6768 result
->setObject(kOSBundlePathKey
, path
);
6775 result
->setObject(kOSBundleUUIDKey
, uuid
);
6779 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
6781 result
->setObject(kOSKernelResourceKey
,
6782 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
6784 result
->setObject(kOSBundleIsInterfaceKey
,
6785 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
6787 result
->setObject(kOSBundlePrelinkedKey
,
6788 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
6790 result
->setObject(kOSBundleStartedKey
,
6791 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
6795 scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
6796 /* numBits */ 8 * sizeof(loadTag
));
6797 if (scratchNumber
) {
6798 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
);
6799 OSSafeReleaseNULL(scratchNumber
);
6802 /* LoadAddress, LoadSize.
6804 if (isInterface() || linkedExecutable
) {
6805 /* These go to userspace via serialization, so we don't want any doubts
6808 uint64_t loadAddress
= 0;
6809 uint32_t loadSize
= 0;
6810 uint32_t wiredSize
= 0;
6812 /* Interfaces always report 0 load address & size.
6813 * Just the way they roll.
6815 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
6816 * xxx - shouldn't have one!
6818 if (linkedExecutable
/* && !isInterface() */) {
6819 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
6820 loadSize
= linkedExecutable
->getLength();
6822 /* If we have a kmod_info struct, calculated the wired size
6823 * from that. Otherwise it's the full load size.
6826 wiredSize
= loadSize
- kmod_info
->hdr_size
;
6828 wiredSize
= loadSize
;
6832 scratchNumber
= OSNumber::withNumber(
6833 (unsigned long long)(loadAddress
),
6834 /* numBits */ 8 * sizeof(loadAddress
));
6835 if (scratchNumber
) {
6836 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
);
6837 OSSafeReleaseNULL(scratchNumber
);
6839 scratchNumber
= OSNumber::withNumber(
6840 (unsigned long long)(loadSize
),
6841 /* numBits */ 8 * sizeof(loadSize
));
6842 if (scratchNumber
) {
6843 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
);
6844 OSSafeReleaseNULL(scratchNumber
);
6846 scratchNumber
= OSNumber::withNumber(
6847 (unsigned long long)(wiredSize
),
6848 /* numBits */ 8 * sizeof(wiredSize
));
6849 if (scratchNumber
) {
6850 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
);
6851 OSSafeReleaseNULL(scratchNumber
);
6855 /* OSBundleDependencies. In descending order for
6856 * easy compatibility with kextstat(8).
6858 if ((count
= getNumDependencies())) {
6859 dependencyLoadTags
= OSArray::withCapacity(count
);
6860 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
);
6864 OSKext
* dependency
= OSDynamicCast(OSKext
,
6865 dependencies
->getObject(i
));
6867 OSSafeReleaseNULL(scratchNumber
);
6872 scratchNumber
= OSNumber::withNumber(
6873 (unsigned long long)dependency
->getLoadTag(),
6874 /* numBits*/ 8 * sizeof(loadTag
));
6875 if (scratchNumber
) {
6876 dependencyLoadTags
->setObject(scratchNumber
);
6881 OSSafeReleaseNULL(scratchNumber
);
6883 /* OSBundleMetaClasses.
6885 if (metaClasses
&& metaClasses
->getCount()) {
6886 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
);
6887 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
6888 if (!metaClassIterator
|| !metaClassInfo
) {
6891 result
->setObject(kOSBundleClassesKey
, metaClassInfo
);
6893 while ( (thisMetaClass
= OSDynamicCast(OSMetaClass
,
6894 metaClassIterator
->getNextObject())) ) {
6896 OSSafeReleaseNULL(metaClassDict
);
6897 OSSafeReleaseNULL(metaClassName
);
6898 OSSafeReleaseNULL(superclassName
);
6899 OSSafeReleaseNULL(scratchNumber
);
6901 metaClassDict
= OSDictionary::withCapacity(3);
6902 if (!metaClassDict
) {
6906 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
6907 if (thisMetaClass
->getSuperClass()) {
6908 superclassName
= OSString::withCString(
6909 thisMetaClass
->getSuperClass()->getClassName());
6911 scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
6912 8 * sizeof(unsigned int));
6913 if (!metaClassDict
|| !metaClassName
|| !superclassName
||
6919 metaClassInfo
->setObject(metaClassDict
);
6920 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
);
6921 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
);
6922 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
);
6926 /* OSBundleRetainCount.
6928 OSSafeReleaseNULL(scratchNumber
);
6930 int extRetainCount
= getRetainCount() - 1;
6934 scratchNumber
= OSNumber::withNumber(
6935 (int)extRetainCount
,
6936 /* numBits*/ 8 * sizeof(int));
6937 if (scratchNumber
) {
6938 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
);
6944 OSSafeRelease(cpuTypeNumber
);
6945 OSSafeRelease(cpuSubtypeNumber
);
6946 OSSafeRelease(uuid
);
6947 OSSafeRelease(scratchNumber
);
6948 OSSafeRelease(dependencyLoadTags
);
6949 OSSafeRelease(metaClassIterator
);
6950 OSSafeRelease(metaClassInfo
);
6951 OSSafeRelease(metaClassDict
);
6952 OSSafeRelease(metaClassName
);
6953 OSSafeRelease(superclassName
);
6955 OSSafeReleaseNULL(result
);
6960 /*********************************************************************
6961 *********************************************************************/
6964 OSKext::requestResource(
6965 const char * kextIdentifierCString
,
6966 const char * resourceNameCString
,
6967 OSKextRequestResourceCallback callback
,
6969 OSKextRequestTag
* requestTagOut
)
6971 OSReturn result
= kOSReturnError
;
6972 OSKext
* callbackKext
= NULL
; // must release (looked up)
6974 OSKextRequestTag requestTag
= -1;
6975 OSNumber
* requestTagNum
= NULL
; // must release
6977 OSDictionary
* requestDict
= NULL
; // must release
6978 OSString
* kextIdentifier
= NULL
; // must release
6979 OSString
* resourceName
= NULL
; // must release
6981 OSDictionary
* callbackRecord
= NULL
; // must release
6982 OSData
* callbackWrapper
= NULL
; // must release
6984 OSData
* contextWrapper
= NULL
; // must release
6986 IORecursiveLockLock(sKextLock
);
6988 if (requestTagOut
) {
6989 *requestTagOut
= kOSKextRequestTagInvalid
;
6992 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
6993 result
= kOSKextReturnInvalidArgument
;
6997 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
6998 if (!callbackKext
) {
6999 OSKextLog(/* kext */ NULL
,
7000 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7001 "Resource request has bad callback address.");
7002 result
= kOSKextReturnInvalidArgument
;
7005 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
7006 OSKextLog(/* kext */ NULL
,
7007 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7008 "Resource request callback is in a kext that is not started.");
7009 result
= kOSKextReturnInvalidArgument
;
7013 /* Do not allow any new requests to be made on a kext that is unloading.
7015 if (callbackKext
->flags
.stopping
) {
7016 result
= kOSKextReturnStopping
;
7020 /* If we're wrapped the next available request tag around to the negative
7021 * numbers, we can't service any more requests.
7023 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
7024 OSKextLog(/* kext */ NULL
,
7025 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7026 "No more request tags available; restart required.");
7027 result
= kOSKextReturnNoResources
;
7030 requestTag
= sNextRequestTag
++;
7032 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
7034 if (result
!= kOSReturnSuccess
) {
7038 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
7039 resourceName
= OSString::withCString(resourceNameCString
);
7040 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
7041 8 * sizeof(requestTag
));
7042 if (!kextIdentifier
||
7045 !_OSKextSetRequestArgument(requestDict
,
7046 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
7047 !_OSKextSetRequestArgument(requestDict
,
7048 kKextRequestArgumentNameKey
, resourceName
) ||
7049 !_OSKextSetRequestArgument(requestDict
,
7050 kKextRequestArgumentRequestTagKey
, requestTagNum
)) {
7052 result
= kOSKextReturnNoMemory
;
7056 callbackRecord
= OSDynamicCast(OSDictionary
, requestDict
->copyCollection());
7057 if (!callbackRecord
) {
7058 result
= kOSKextReturnNoMemory
;
7061 // we validate callback address at call time
7062 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
7064 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
7066 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7067 kKextRequestArgumentCallbackKey
, callbackWrapper
)) {
7069 result
= kOSKextReturnNoMemory
;
7074 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
7075 kKextRequestArgumentContextKey
, contextWrapper
)) {
7077 result
= kOSKextReturnNoMemory
;
7082 /* Only post the requests after all the other potential failure points
7085 if (!sKernelRequests
->setObject(requestDict
) ||
7086 !sRequestCallbackRecords
->setObject(callbackRecord
)) {
7088 result
= kOSKextReturnNoMemory
;
7094 result
= kOSReturnSuccess
;
7095 if (requestTagOut
) {
7096 *requestTagOut
= requestTag
;
7101 /* If we didn't succeed, yank the request & callback
7102 * from their holding arrays.
7104 if (result
!= kOSReturnSuccess
) {
7107 index
= sKernelRequests
->getNextIndexOfObject(requestDict
, 0);
7108 if (index
!= (unsigned int)-1) {
7109 sKernelRequests
->removeObject(index
);
7111 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
, 0);
7112 if (index
!= (unsigned int)-1) {
7113 sRequestCallbackRecords
->removeObject(index
);
7117 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7119 IORecursiveLockUnlock(sKextLock
);
7121 if (callbackKext
) callbackKext
->release();
7122 if (requestTagNum
) requestTagNum
->release();
7124 if (requestDict
) requestDict
->release();
7125 if (kextIdentifier
) kextIdentifier
->release();
7126 if (resourceName
) resourceName
->release();
7128 if (callbackRecord
) callbackRecord
->release();
7129 if (callbackWrapper
) callbackWrapper
->release();
7130 if (contextWrapper
) contextWrapper
->release();
7135 /*********************************************************************
7136 *********************************************************************/
7139 OSKext::dequeueCallbackForRequestTag(
7140 OSKextRequestTag requestTag
,
7141 OSDictionary
** callbackRecordOut
)
7143 OSReturn result
= kOSReturnError
;
7144 OSNumber
* requestTagNum
= NULL
; // must release
7146 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
7147 8 * sizeof(requestTag
));
7148 if (!requestTagNum
) {
7152 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
,
7156 OSSafeRelease(requestTagNum
);
7161 /*********************************************************************
7162 *********************************************************************/
7165 OSKext::dequeueCallbackForRequestTag(
7166 OSNumber
* requestTagNum
,
7167 OSDictionary
** callbackRecordOut
)
7169 OSReturn result
= kOSKextReturnInvalidArgument
;
7170 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
7171 OSNumber
* callbackTagNum
= NULL
; // do not release
7172 unsigned int count
, i
;
7174 IORecursiveLockLock(sKextLock
);
7176 result
= kOSReturnError
;
7177 count
= sRequestCallbackRecords
->getCount();
7178 for (i
= 0; i
< count
; i
++) {
7179 callbackRecord
= OSDynamicCast(OSDictionary
,
7180 sRequestCallbackRecords
->getObject(i
));
7181 if (!callbackRecord
) {
7185 /* If we don't find a tag, we basically have a leak here. Maybe
7186 * we should just remove it.
7188 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
7189 callbackRecord
, kKextRequestArgumentRequestTagKey
));
7190 if (!callbackTagNum
) {
7194 /* We could be even more paranoid and check that all the incoming
7195 * args match what's in the callback record.
7197 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
7198 if (callbackRecordOut
) {
7199 *callbackRecordOut
= callbackRecord
;
7200 callbackRecord
->retain();
7202 sRequestCallbackRecords
->removeObject(i
);
7203 result
= kOSReturnSuccess
;
7207 result
= kOSKextReturnNotFound
;
7210 IORecursiveLockUnlock(sKextLock
);
7214 /*********************************************************************
7215 *********************************************************************/
7218 OSKext::dispatchResource(OSDictionary
* requestDict
)
7220 OSReturn result
= kOSReturnError
;
7221 OSDictionary
* callbackRecord
= NULL
; // must release
7222 OSNumber
* requestTag
= NULL
; // do not release
7223 OSNumber
* requestResult
= NULL
; // do not release
7224 OSData
* dataObj
= NULL
; // do not release
7225 uint32_t dataLength
= 0;
7226 const void * dataPtr
= NULL
; // do not free
7227 OSData
* callbackWrapper
= NULL
; // do not release
7228 OSKextRequestResourceCallback callback
= NULL
;
7229 OSData
* contextWrapper
= NULL
; // do not release
7230 void * context
= NULL
; // do not free
7231 OSKext
* callbackKext
= NULL
; // must release (looked up)
7233 IORecursiveLockLock(sKextLock
);
7235 /* Get the args from the request. Right now we need the tag
7236 * to look up the callback record, and the result for invoking the callback.
7238 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7239 kKextRequestArgumentRequestTagKey
));
7240 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
7241 kKextRequestArgumentResultKey
));
7242 if (!requestTag
|| !requestResult
) {
7243 result
= kOSKextReturnInvalidArgument
;
7247 /* Look for a callback record matching this request's tag.
7249 result
= dequeueCallbackForRequestTag(requestTag
, &callbackRecord
);
7250 if (result
!= kOSReturnSuccess
) {
7255 * Get the context pointer of the callback record (if there is one).
7257 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
,
7258 kKextRequestArgumentContextKey
));
7259 context
= _OSKextExtractPointer(contextWrapper
);
7260 if (contextWrapper
&& !context
) {
7264 callbackWrapper
= OSDynamicCast(OSData
,
7265 _OSKextGetRequestArgument(callbackRecord
,
7266 kKextRequestArgumentCallbackKey
));
7267 callback
= (OSKextRequestResourceCallback
)
7268 _OSKextExtractPointer(callbackWrapper
);
7273 /* Check for a data obj. We might not have one and that's ok, that means
7274 * we didn't find the requested resource, and we still have to tell the
7275 * caller that via the callback.
7277 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
7278 kKextRequestArgumentValueKey
));
7280 dataPtr
= dataObj
->getBytesNoCopy();
7281 dataLength
= dataObj
->getLength();
7284 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
7285 if (!callbackKext
) {
7286 OSKextLog(/* kext */ NULL
,
7287 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7288 "Can't invoke callback for resource request; "
7289 "no kext loaded at callback address %p.",
7293 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
7294 OSKextLog(/* kext */ NULL
,
7295 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7296 "Can't invoke kext resource callback; "
7297 "kext at callback address %p is not running.",
7302 (void)callback(requestTag
->unsigned32BitValue(),
7303 (OSReturn
)requestResult
->unsigned32BitValue(),
7304 dataPtr
, dataLength
, context
);
7306 result
= kOSReturnSuccess
;
7309 if (callbackKext
) callbackKext
->release();
7310 if (callbackRecord
) callbackRecord
->release();
7312 IORecursiveLockUnlock(sKextLock
);
7316 /*********************************************************************
7317 *********************************************************************/
7320 OSKext::invokeRequestCallback(
7321 OSDictionary
* callbackRecord
,
7322 OSReturn callbackResult
)
7324 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
7325 OSNumber
* resultNum
= NULL
; // must release
7331 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
7332 8 * sizeof(callbackResult
));
7337 /* Insert the result into the callback record and dispatch it as if it
7338 * were the reply coming down from user space.
7340 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
7343 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
7344 /* This removes the pending callback record.
7346 OSKext::dispatchResource(callbackRecord
);
7350 if (resultNum
) resultNum
->release();
7354 /*********************************************************************
7355 *********************************************************************/
7358 OSKext::cancelRequest(
7359 OSKextRequestTag requestTag
,
7362 OSReturn result
= kOSKextReturnNoMemory
;
7363 OSDictionary
* callbackRecord
= NULL
; // must release
7364 OSData
* contextWrapper
= NULL
; // do not release
7366 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
7369 if (result
== kOSReturnSuccess
&& contextOut
) {
7370 contextWrapper
= OSDynamicCast(OSData
,
7371 _OSKextGetRequestArgument(callbackRecord
,
7372 kKextRequestArgumentContextKey
));
7373 *contextOut
= _OSKextExtractPointer(contextWrapper
);
7376 if (callbackRecord
) callbackRecord
->release();
7381 /*********************************************************************
7382 *********************************************************************/
7384 OSKext::invokeOrCancelRequestCallbacks(
7385 OSReturn callbackResult
,
7388 unsigned int count
, i
;
7390 IORecursiveLockLock(sKextLock
);
7392 count
= sRequestCallbackRecords
->getCount();
7399 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7400 sRequestCallbackRecords
->getObject(i
));
7405 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7406 _OSKextGetRequestArgument(request
,
7407 kKextRequestArgumentCallbackKey
));
7409 if (!callbackWrapper
) {
7410 sRequestCallbackRecords
->removeObject(i
);
7414 vm_address_t callbackAddress
= (vm_address_t
)
7415 _OSKextExtractPointer(callbackWrapper
);
7417 if ((kmod_info
->address
<= callbackAddress
) &&
7418 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7421 /* This removes the callback record.
7423 invokeRequestCallback(request
, callbackResult
);
7425 sRequestCallbackRecords
->removeObject(i
);
7431 IORecursiveLockUnlock(sKextLock
);
7435 /*********************************************************************
7436 *********************************************************************/
7438 OSKext::countRequestCallbacks(void)
7440 uint32_t result
= 0;
7441 unsigned int count
, i
;
7443 IORecursiveLockLock(sKextLock
);
7445 count
= sRequestCallbackRecords
->getCount();
7452 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
7453 sRequestCallbackRecords
->getObject(i
));
7458 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
7459 _OSKextGetRequestArgument(request
,
7460 kKextRequestArgumentCallbackKey
));
7462 if (!callbackWrapper
) {
7466 vm_address_t callbackAddress
= (vm_address_t
)
7467 _OSKextExtractPointer(callbackWrapper
);
7469 if ((kmod_info
->address
<= callbackAddress
) &&
7470 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
7477 IORecursiveLockUnlock(sKextLock
);
7481 /*********************************************************************
7482 *********************************************************************/
7483 static OSReturn
_OSKextCreateRequest(
7484 const char * predicate
,
7485 OSDictionary
** requestP
)
7487 OSReturn result
= kOSKextReturnNoMemory
;
7488 OSDictionary
* request
= NULL
; // must release on error
7489 OSDictionary
* args
= NULL
; // must release
7491 request
= OSDictionary::withCapacity(2);
7495 result
= _OSDictionarySetCStringValue(request
,
7496 kKextRequestPredicateKey
, predicate
);
7497 if (result
!= kOSReturnSuccess
) {
7500 result
= kOSReturnSuccess
;
7503 if (result
!= kOSReturnSuccess
) {
7504 if (request
) request
->release();
7506 *requestP
= request
;
7508 if (args
) args
->release();
7513 /*********************************************************************
7514 *********************************************************************/
7515 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
7517 return OSDynamicCast(OSString
,
7518 requestDict
->getObject(kKextRequestPredicateKey
));
7521 /*********************************************************************
7522 *********************************************************************/
7523 static OSObject
* _OSKextGetRequestArgument(
7524 OSDictionary
* requestDict
,
7525 const char * argName
)
7527 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7528 requestDict
->getObject(kKextRequestArgumentsKey
));
7530 return args
->getObject(argName
);
7535 /*********************************************************************
7536 *********************************************************************/
7537 static bool _OSKextSetRequestArgument(
7538 OSDictionary
* requestDict
,
7539 const char * argName
,
7542 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
7543 requestDict
->getObject(kKextRequestArgumentsKey
));
7545 args
= OSDictionary::withCapacity(2);
7549 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
7553 return args
->setObject(argName
, value
);
7559 /*********************************************************************
7560 *********************************************************************/
7561 static void * _OSKextExtractPointer(OSData
* wrapper
)
7563 void * result
= NULL
;
7564 const void * resultPtr
= NULL
;
7569 resultPtr
= wrapper
->getBytesNoCopy();
7570 result
= *(void **)resultPtr
;
7575 /*********************************************************************
7576 *********************************************************************/
7577 static OSReturn
_OSDictionarySetCStringValue(
7578 OSDictionary
* dict
,
7580 const char * cValue
)
7582 OSReturn result
= kOSKextReturnNoMemory
;
7583 const OSSymbol
* key
= NULL
; // must release
7584 OSString
* value
= NULL
; // must release
7586 key
= OSSymbol::withCString(cKey
);
7587 value
= OSString::withCString(cValue
);
7588 if (!key
|| !value
) {
7591 if (dict
->setObject(key
, value
)) {
7592 result
= kOSReturnSuccess
;
7596 if (key
) key
->release();
7597 if (value
) value
->release();
7603 #pragma mark Personalities (IOKit Drivers)
7605 /*********************************************************************
7606 *********************************************************************/
7609 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
7611 OSArray
* result
= NULL
; // returned
7612 OSCollectionIterator
* kextIterator
= NULL
; // must release
7613 OSArray
* personalities
= NULL
; // must release
7614 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7616 OSString
* kextID
= NULL
; // do not release
7617 OSKext
* theKext
= NULL
; // do not release
7619 IORecursiveLockLock(sKextLock
);
7621 /* Let's conservatively guess that any given kext has around 3
7622 * personalities for now.
7624 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
7629 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
7630 if (!kextIterator
) {
7634 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
7635 if (personalitiesIterator
) {
7636 personalitiesIterator
->release();
7637 personalitiesIterator
= NULL
;
7639 if (personalities
) {
7640 personalities
->release();
7641 personalities
= NULL
;
7644 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
7645 if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
7646 personalities
= theKext
->copyPersonalitiesArray();
7647 if (!personalities
) {
7650 result
->merge(personalities
);
7652 // xxx - check for better place to put this log msg
7654 kOSKextLogWarningLevel
|
7656 "Kext %s is not loadable during safe boot; "
7657 "omitting its personalities.",
7658 theKext
->getIdentifierCString());
7664 IORecursiveLockUnlock(sKextLock
);
7666 if (kextIterator
) kextIterator
->release();
7667 if (personalitiesIterator
) personalitiesIterator
->release();
7668 if (personalities
) personalities
->release();
7673 /*********************************************************************
7674 *********************************************************************/
7677 OSKext::setPrelinkedPersonalities(OSArray
* personalitiesArray
)
7679 sPrelinkedPersonalities
= personalitiesArray
;
7680 if (sPrelinkedPersonalities
) {
7681 sPrelinkedPersonalities
->retain();
7682 gIOCatalogue
->addDrivers(sPrelinkedPersonalities
);
7687 /*********************************************************************
7688 *********************************************************************/
7691 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
7693 int numPersonalities
= 0;
7695 OSKextLog(/* kext */ NULL
,
7696 kOSKextLogStepLevel
|
7698 "Sending all eligible registered kexts' personalities "
7699 "to the IOCatalogue %s.",
7700 startMatching
? "and starting matching" : "but not starting matching");
7702 OSArray
* personalities
= OSKext::copyAllKextPersonalities(
7703 /* filterSafeBootFlag */ true);
7705 if (personalities
) {
7706 gIOCatalogue
->addDrivers(personalities
, startMatching
);
7707 numPersonalities
= personalities
->getCount();
7708 personalities
->release();
7711 OSKextLog(/* kext */ NULL
,
7712 kOSKextLogStepLevel
|
7714 "%d kext personalit%s sent to the IOCatalogue; %s.",
7715 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
7716 startMatching
? "matching started" : "matching not started");
7720 /*********************************************************************
7721 * Do not make a deep copy, just convert the IOKitPersonalities dict
7722 * to an array for sending to the IOCatalogue.
7723 *********************************************************************/
7725 OSKext::copyPersonalitiesArray(void)
7727 OSArray
* result
= NULL
;
7728 OSDictionary
* personalities
= NULL
; // do not release
7729 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
7731 OSString
* personalityName
= NULL
; // do not release
7732 OSString
* personalityBundleIdentifier
= NULL
; // do not release
7734 personalities
= OSDynamicCast(OSDictionary
,
7735 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7736 if (!personalities
) {
7740 result
= OSArray::withCapacity(personalities
->getCount());
7745 personalitiesIterator
=
7746 OSCollectionIterator::withCollection(personalities
);
7747 if (!personalitiesIterator
) {
7750 while ((personalityName
= OSDynamicCast(OSString
,
7751 personalitiesIterator
->getNextObject()))) {
7753 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7754 personalities
->getObject(personalityName
));
7757 * If the personality doesn't have a CFBundleIdentifier, or if it
7758 * differs from the kext's, insert the kext's ID so we can find it.
7759 * The publisher ID is used to remove personalities from bundles
7762 personalityBundleIdentifier
= OSDynamicCast(OSString
,
7763 personality
->getObject(kCFBundleIdentifierKey
));
7765 if (!personalityBundleIdentifier
) {
7766 personality
->setObject(kCFBundleIdentifierKey
, bundleID
);
7767 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
)) {
7768 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
);
7771 result
->setObject(personality
);
7775 if (personalitiesIterator
) personalitiesIterator
->release();
7780 /*********************************************************************
7781 Might want to change this to a bool return?
7782 *********************************************************************/
7784 OSKext::sendPersonalitiesToCatalog(
7786 OSArray
* personalityNames
)
7788 OSArray
* personalitiesToSend
= NULL
; // must release
7789 OSDictionary
* kextPersonalities
= NULL
; // do not release
7792 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
7794 kOSKextLogErrorLevel
|
7796 "Kext %s is not loadable during safe boot; "
7797 "not sending personalities to the IOCatalogue.",
7798 getIdentifierCString());
7802 if (!personalityNames
|| !personalityNames
->getCount()) {
7803 personalitiesToSend
= copyPersonalitiesArray();
7805 kextPersonalities
= OSDynamicCast(OSDictionary
,
7806 getPropertyForHostArch(kIOKitPersonalitiesKey
));
7807 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
7810 personalitiesToSend
= OSArray::withCapacity(0);
7811 if (!personalitiesToSend
) {
7814 count
= personalityNames
->getCount();
7815 for (i
= 0; i
< count
; i
++) {
7816 OSString
* name
= OSDynamicCast(OSString
,
7817 personalityNames
->getObject(i
));
7821 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
7822 kextPersonalities
->getObject(name
));
7824 personalitiesToSend
->setObject(personality
);
7828 if (personalitiesToSend
) {
7829 unsigned numPersonalities
= personalitiesToSend
->getCount();
7831 kOSKextLogStepLevel
|
7833 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
7834 getIdentifierCString(),
7836 numPersonalities
> 1 ? "ies" : "y",
7837 startMatching
? " and starting matching" : " but not starting matching");
7838 gIOCatalogue
->addDrivers(personalitiesToSend
, startMatching
);
7841 if (personalitiesToSend
) {
7842 personalitiesToSend
->release();
7847 /*********************************************************************
7848 *********************************************************************/
7850 OSKext::removePersonalitiesFromCatalog(void)
7852 OSDictionary
* personality
= NULL
; // do not release
7854 personality
= OSDictionary::withCapacity(1);
7858 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
7861 kOSKextLogStepLevel
|
7863 "Kext %s removing all personalities naming it from the IOCatalogue.",
7864 getIdentifierCString());
7866 /* Have the IOCatalog remove all personalities matching this kext's
7867 * bundle ID and trigger matching anew.
7869 gIOCatalogue
->removeDrivers(personality
, /* startMatching */ true);
7872 if (personality
) personality
->release();
7879 #pragma mark Logging
7881 /*********************************************************************
7882 * Do not call any function that takes sKextLock here!
7883 *********************************************************************/
7886 OSKext::setUserSpaceLogFilter(
7887 OSKextLogSpec userLogFilter
,
7890 OSKextLogSpec result
;
7892 IORecursiveLockLock(sKextInnerLock
);
7894 result
= sUserSpaceKextLogFilter
;
7895 sUserSpaceKextLogFilter
= userLogFilter
;
7897 /* If the config flag itself is changing, log the state change
7898 * going both ways, before setting up the user-space log arrays,
7899 * so that this is only logged in the kernel.
7901 if (sUserSpaceKextLogFilter
!= result
) {
7902 OSKextLog(/* kext */ NULL
,
7903 kOSKextLogDebugLevel
|
7904 kOSKextLogGeneralFlag
,
7905 "User-space log flags changed from 0x%x to 0x%x.",
7906 result
, sUserSpaceKextLogFilter
);
7909 if (userLogFilter
&& captureFlag
&&
7910 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
7912 // xxx - do some measurements for a good initial capacity?
7913 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
7914 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
7916 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
7917 OSKextLog(/* kext */ NULL
,
7918 kOSKextLogErrorLevel
|
7919 kOSKextLogGeneralFlag
,
7920 "Failed to allocate user-space log message arrays.");
7921 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
7922 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
7926 IORecursiveLockUnlock(sKextInnerLock
);
7931 /*********************************************************************
7932 * Do not call any function that takes sKextLock here!
7933 *********************************************************************/
7936 OSKext::clearUserSpaceLogFilter(void)
7938 OSArray
* result
= NULL
;
7939 OSKextLogSpec oldLogFilter
;
7941 IORecursiveLockLock(sKextInnerLock
);
7943 result
= OSArray::withCapacity(2);
7945 result
->setObject(sUserSpaceLogSpecArray
);
7946 result
->setObject(sUserSpaceLogMessageArray
);
7948 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
7949 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
7951 oldLogFilter
= sUserSpaceKextLogFilter
;
7952 sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
7954 /* If the config flag itself is changing, log the state change
7955 * going both ways, after tearing down the user-space log
7956 * arrays, so this is only logged within the kernel.
7958 if (oldLogFilter
!= sUserSpaceKextLogFilter
) {
7959 OSKextLog(/* kext */ NULL
,
7960 kOSKextLogDebugLevel
|
7961 kOSKextLogGeneralFlag
,
7962 "User-space log flags changed from 0x%x to 0x%x.",
7963 oldLogFilter
, sUserSpaceKextLogFilter
);
7966 IORecursiveLockUnlock(sKextInnerLock
);
7971 /*********************************************************************
7972 * Do not call any function that takes sKextLock here!
7973 *********************************************************************/
7976 OSKext::getUserSpaceLogFilter(void)
7978 OSKextLogSpec result
;
7980 IORecursiveLockLock(sKextInnerLock
);
7981 result
= sUserSpaceKextLogFilter
;
7982 IORecursiveLockUnlock(sKextInnerLock
);
7987 /*********************************************************************
7988 * This function is called by OSMetaClass during kernel C++ setup.
7989 * Be careful what you access here; assume only OSKext::initialize()
7992 * Do not call any function that takes sKextLock here!
7993 *********************************************************************/
7994 #define VTRESET "\033[0m"
7996 #define VTBOLD "\033[1m"
7997 #define VTUNDER "\033[4m"
7999 #define VTRED "\033[31m"
8000 #define VTGREEN "\033[32m"
8001 #define VTYELLOW "\033[33m"
8002 #define VTBLUE "\033[34m"
8003 #define VTMAGENTA "\033[35m"
8004 #define VTCYAN "\033[36m"
8006 inline const char * colorForFlags(OSKextLogSpec flags
)
8008 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
8011 case kOSKextLogErrorLevel
:
8012 return VTRED VTBOLD
;
8014 case kOSKextLogWarningLevel
:
8017 case kOSKextLogBasicLevel
:
8018 return VTYELLOW VTUNDER
;
8020 case kOSKextLogProgressLevel
:
8023 case kOSKextLogStepLevel
:
8026 case kOSKextLogDetailLevel
:
8029 case kOSKextLogDebugLevel
:
8039 inline bool logSpecMatch(
8040 OSKextLogSpec msgLogSpec
,
8041 OSKextLogSpec logFilter
)
8043 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
8044 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
8045 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
8047 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
8048 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
8049 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
8051 /* Explicit messages always get logged.
8053 if (msgLevel
== kOSKextLogExplicitLevel
) {
8057 /* Warnings and errors are logged regardless of the flags.
8059 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
8063 /* A verbose message that isn't for a logging-enabled kext and isn't global
8064 * does *not* get logged.
8066 if (!msgKextGlobal
&& !filterKextGlobal
) {
8070 /* Warnings and errors are logged regardless of the flags.
8071 * All other messages must fit the flags and
8072 * have a level at or below the filter.
8075 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
8086 OSKextLogSpec msgLogSpec
,
8087 const char * format
, ...)
8091 va_start(argList
, format
);
8092 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
8099 OSKextLogSpec msgLogSpec
,
8100 const char * format
,
8103 extern int disableConsoleOutput
;
8105 bool logForKernel
= false;
8106 bool logForUser
= false;
8108 char stackBuffer
[120];
8109 uint32_t length
= 0;
8110 char * allocBuffer
= NULL
; // must kfree
8111 OSNumber
* logSpecNum
= NULL
; // must release
8112 OSString
* logString
= NULL
; // must release
8113 char * buffer
= stackBuffer
; // do not free
8115 IORecursiveLockLock(sKextInnerLock
);
8117 /* Set the kext/global bit in the message spec if we have no
8118 * kext or if the kext requests logging.
8120 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
8121 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
8124 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
8125 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
8126 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
8129 if (! (logForKernel
|| logForUser
) ) {
8133 /* No goto from here until past va_end()!
8135 va_copy(argList
, srcArgList
);
8136 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
8139 if (length
+ 1 >= sizeof(stackBuffer
)) {
8140 allocBuffer
= (char *)kalloc((length
+ 1) * sizeof(char));
8145 /* No goto from here until past va_end()!
8147 va_copy(argList
, srcArgList
);
8148 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
8151 buffer
= allocBuffer
;
8154 /* If user space wants the log message, queue it up.
8156 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
8157 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
8158 logString
= OSString::withCString(buffer
);
8159 if (logSpecNum
&& logString
) {
8160 sUserSpaceLogSpecArray
->setObject(logSpecNum
);
8161 sUserSpaceLogMessageArray
->setObject(logString
);
8165 /* Always log messages from the kernel according to the kernel's
8170 /* If we are in console mode and have a custom log filter,
8171 * colorize the log message.
8173 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
8174 const char * color
= ""; // do not free
8175 color
= colorForFlags(msgLogSpec
);
8176 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
8177 buffer
, color
[0] ? VTRESET
: "");
8179 printf("%s\n", buffer
);
8185 kfree(allocBuffer
, (length
+ 1) * sizeof(char));
8187 OSSafeRelease(logString
);
8188 OSSafeRelease(logSpecNum
);
8189 IORecursiveLockUnlock(sKextInnerLock
);
8196 #pragma mark Backtrace Dump & kmod_get_info() support
8198 /*********************************************************************
8199 *********************************************************************/
8202 OSKext::printKextsInBacktrace(
8205 int (* printf_func
)(const char *fmt
, ...),
8208 vm_offset_t
* kscan_addr
= NULL
;
8209 kmod_info_t
* k
= NULL
;
8210 kmod_reference_t
* r
= NULL
;
8215 IORecursiveLockLock(sKextLock
);
8218 for (k
= kmod
; k
; k
= k
->next
) {
8219 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)k
)) == 0) {
8220 (*printf_func
)(" kmod scan stopped due to missing "
8221 "kmod page: %p\n", k
);
8225 continue; // skip fake entries for built-in kernel components
8227 for (i
= 0, kscan_addr
= addr
; i
< cnt
; i
++, kscan_addr
++) {
8228 if ((*kscan_addr
>= k
->address
) &&
8229 (*kscan_addr
< (k
->address
+ k
->size
))) {
8232 (*printf_func
)(" Kernel Extensions in backtrace "
8233 "(with dependencies):\n");
8236 (*printf_func
)(" %s(%s)@%p->%p\n",
8237 k
->name
, k
->version
, k
->address
, k
->address
+ k
->size
- 1);
8239 for (r
= k
->reference_list
; r
; r
= r
->next
) {
8240 kmod_info_t
* rinfo
;
8242 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)r
)) == 0) {
8243 (*printf_func
)(" kmod dependency scan stopped "
8244 "due to missing dependency page: %p\n", r
);
8250 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
8251 (*printf_func
)(" kmod dependency scan stopped "
8252 "due to missing kmod page: %p\n", rinfo
);
8256 if (!rinfo
->address
) {
8257 continue; // skip fake entries for built-ins
8260 (*printf_func
)(" dependency: %s(%s)@%p\n",
8261 rinfo
->name
, rinfo
->version
, rinfo
->address
);
8264 break; // only report this kmod for one backtrace address
8270 IORecursiveLockUnlock(sKextLock
);
8276 /*******************************************************************************
8277 * substitute() looks at an input string (a pointer within a larger buffer)
8278 * for a match to a substring, and on match it writes the marker & substitution
8279 * character to an output string, updating the scan (from) and
8280 * output (to) indexes as appropriate.
8281 *******************************************************************************/
8282 static int substitute(
8283 const char * scan_string
,
8285 uint32_t * to_index
,
8286 uint32_t * from_index
,
8287 const char * substring
,
8291 /* string_out must be at least KMOD_MAX_NAME bytes.
8295 const char * scan_string
,
8297 uint32_t * to_index
,
8298 uint32_t * from_index
,
8299 const char * substring
,
8303 uint32_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
8305 /* On a substring match, append the marker (if there is one) and then
8306 * the substitution character, updating the output (to) index accordingly.
8307 * Then update the input (from) length by the length of the substring
8308 * that got replaced.
8310 if (!strncmp(scan_string
, substring
, substring_length
)) {
8312 string_out
[(*to_index
)++] = marker
;
8314 string_out
[(*to_index
)++] = substitution
;
8315 (*from_index
) += substring_length
;
8321 /*******************************************************************************
8322 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
8323 * KMOD_MAX_NAME characters and performs various substitutions of common
8324 * prefixes & substrings as defined by tables in kext_panic_report.h.
8325 *******************************************************************************/
8326 static void compactIdentifier(
8327 const char * identifier
,
8328 char * identifier_out
,
8329 char ** identifier_out_end
);
8333 const char * identifier
,
8334 char * identifier_out
,
8335 char ** identifier_out_end
)
8337 uint32_t from_index
, to_index
;
8338 uint32_t scan_from_index
= 0;
8339 uint32_t scan_to_index
= 0;
8340 subs_entry_t
* subs_entry
= NULL
;
8343 from_index
= to_index
= 0;
8344 identifier_out
[0] = '\0';
8346 /* Replace certain identifier prefixes with shorter @+character sequences.
8347 * Check the return value of substitute() so we only replace the prefix.
8349 for (subs_entry
= &kext_identifier_prefix_subs
[0];
8350 subs_entry
->substring
&& !did_sub
;
8353 did_sub
= substitute(identifier
, identifier_out
,
8354 &scan_to_index
, &scan_from_index
,
8355 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
8359 /* Now scan through the identifier looking for the common substrings
8360 * and replacing them with shorter !+character sequences via substitute().
8362 for (/* see above */;
8363 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
8366 const char * scan_string
= &identifier
[scan_from_index
];
8370 if (scan_from_index
) {
8371 for (subs_entry
= &kext_identifier_substring_subs
[0];
8372 subs_entry
->substring
&& !did_sub
;
8375 did_sub
= substitute(scan_string
, identifier_out
,
8376 &scan_to_index
, &scan_from_index
,
8377 subs_entry
->substring
, '!', subs_entry
->substitute
);
8381 /* If we didn't substitute, copy the input character to the output.
8384 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
8388 identifier_out
[scan_to_index
] = '\0';
8389 if (identifier_out_end
) {
8390 *identifier_out_end
= &identifier_out
[scan_to_index
];
8396 /*******************************************************************************
8397 * assemble_identifier_and_version() adds to a string buffer a compacted
8398 * bundle identifier followed by a version string.
8399 *******************************************************************************/
8401 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
8403 static int assemble_identifier_and_version(
8404 kmod_info_t
* kmod_info
,
8405 char * identPlusVers
);
8407 assemble_identifier_and_version(
8408 kmod_info_t
* kmod_info
,
8409 char * identPlusVers
)
8413 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
8414 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
8415 identPlusVers
[result
++] = '\t'; // increment for real char
8416 identPlusVers
[result
] = '\0'; // don't increment for nul char
8417 result
= strlcat(identPlusVers
, kmod_info
->version
, KMOD_MAX_NAME
);
8422 /*******************************************************************************
8423 *******************************************************************************/
8424 #define LAST_LOADED " - last loaded "
8425 #define LAST_LOADED_TS_WIDTH (16)
8429 OSKext::saveLoadedKextPanicListTyped(
8430 const char * prefix
,
8435 uint32_t * list_length_ptr
)
8437 uint32_t result
= 0;
8439 unsigned int count
, i
;
8441 count
= sLoadedKexts
->getCount();
8448 OSKext
* theKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
8449 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
8451 char identPlusVers
[2*KMOD_MAX_NAME
];
8452 uint32_t identPlusVersLength
;
8453 char timestampBuffer
[17]; // enough for a uint64_t
8455 /* Skip all built-in kexts.
8457 if (theKext
->isKernelComponent()) {
8461 /* Filter for kmod name (bundle identifier).
8463 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
8464 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
8468 /* Filter for libraries (kexts that have a compatible version).
8470 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
8471 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
8477 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
8479 printf("kext scan stopped due to missing kmod_info page: %p\n",
8485 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
8487 if (!identPlusVersLength
) {
8488 printf("error saving loaded kext info\n");
8492 /* We're going to note the last-loaded kext in the list.
8494 if (i
+ 1 == count
) {
8495 snprintf(timestampBuffer
, sizeof(timestampBuffer
), "%llu",
8496 AbsoluteTime_to_scalar(&last_loaded_timestamp
));
8497 identPlusVersLength
+= sizeof(LAST_LOADED
) - 1 +
8498 strnlen(timestampBuffer
, sizeof(timestampBuffer
));
8501 /* Adding 1 for the newline.
8503 if (*list_length_ptr
+ identPlusVersLength
+ 1 >= list_size
) {
8507 *list_length_ptr
= strlcat(paniclist
, identPlusVers
, list_size
);
8508 if (i
+ 1 == count
) {
8509 *list_length_ptr
= strlcat(paniclist
, LAST_LOADED
, list_size
);
8510 *list_length_ptr
= strlcat(paniclist
, timestampBuffer
, list_size
);
8512 *list_length_ptr
= strlcat(paniclist
, "\n", list_size
);
8518 if (*list_length_ptr
+ 1 <= list_size
) {
8519 result
= list_size
- (*list_length_ptr
+ 1);
8526 /*********************************************************************
8527 *********************************************************************/
8530 OSKext::saveLoadedKextPanicList(void)
8532 char * newlist
= NULL
;
8533 uint32_t newlist_size
= 0;
8534 uint32_t newlist_length
= 0;
8536 IORecursiveLockLock(sKextLock
);
8539 newlist_size
= KEXT_PANICLIST_SIZE
;
8540 newlist
= (char *)kalloc(newlist_size
);
8543 OSKextLog(/* kext */ NULL
,
8544 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
8545 "Couldn't allocate kext panic log buffer.");
8551 // non-"com.apple." kexts
8552 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
8553 /* libs? */ -1, newlist
, newlist_size
, &newlist_length
)) {
8557 // "com.apple." nonlibrary kexts
8558 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8559 /* libs? */ 0, newlist
, newlist_size
, &newlist_length
)) {
8563 // "com.apple." library kexts
8564 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
8565 /* libs? */ 1, newlist
, newlist_size
, &newlist_length
)) {
8570 if (loaded_kext_paniclist
) {
8571 kfree(loaded_kext_paniclist
, loaded_kext_paniclist_size
);
8573 loaded_kext_paniclist
= newlist
;
8574 loaded_kext_paniclist_size
= newlist_size
;
8575 loaded_kext_paniclist_length
= newlist_length
;
8578 IORecursiveLockUnlock(sKextLock
);
8582 /*********************************************************************
8583 *********************************************************************/
8586 OSKext::saveUnloadedKextPanicList(OSKext
* aKext
)
8588 char * newlist
= NULL
;
8589 uint32_t newlist_size
= 0;
8590 uint32_t newlist_length
= 0;
8591 char identPlusVers
[2*KMOD_MAX_NAME
];
8592 uint32_t identPlusVersLength
;
8594 if (!aKext
->kmod_info
) {
8595 return; // do not goto finish here b/c of lock
8598 IORecursiveLockLock(sKextLock
);
8600 clock_get_uptime(&last_unloaded_timestamp
);
8601 last_unloaded_address
= (void *)aKext
->kmod_info
->address
;
8602 last_unloaded_size
= aKext
->kmod_info
->size
;
8605 identPlusVersLength
= assemble_identifier_and_version(aKext
->kmod_info
,
8607 if (!identPlusVersLength
) {
8608 printf("error saving unloaded kext info\n");
8612 newlist_length
= identPlusVersLength
;
8613 newlist_size
= newlist_length
+ 1;
8614 newlist
= (char *)kalloc(newlist_size
);
8617 printf("couldn't allocate kext panic log buffer\n");
8623 strlcpy(newlist
, identPlusVers
, newlist_size
);
8625 if (unloaded_kext_paniclist
) {
8626 kfree(unloaded_kext_paniclist
, unloaded_kext_paniclist_size
);
8628 unloaded_kext_paniclist
= newlist
;
8629 unloaded_kext_paniclist_size
= newlist_size
;
8630 unloaded_kext_paniclist_length
= newlist_length
;
8633 IORecursiveLockUnlock(sKextLock
);
8637 /*********************************************************************
8638 *********************************************************************/
8640 #define __kLoadSizeEscape "0x%lld"
8642 #define __kLoadSizeEscape "0x%ld"
8643 #endif /* __LP64__ */
8647 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
8649 printf_func("unloaded kexts:\n");
8650 if (unloaded_kext_paniclist
&&
8651 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) unloaded_kext_paniclist
) &&
8652 unloaded_kext_paniclist
[0]) {
8655 "%.*s (addr %p, size " __kLoadSizeEscape
") - last unloaded %llu\n",
8656 unloaded_kext_paniclist_length
, unloaded_kext_paniclist
,
8657 last_unloaded_address
, last_unloaded_size
,
8658 AbsoluteTime_to_scalar(&last_unloaded_timestamp
));
8660 printf_func("(none)\n");
8662 printf_func("loaded kexts:\n");
8663 if (loaded_kext_paniclist
&&
8664 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
8665 loaded_kext_paniclist
[0]) {
8667 printf_func("%.*s", loaded_kext_paniclist_length
, loaded_kext_paniclist
);
8669 printf_func("(none)\n");
8674 /*********************************************************************
8675 *********************************************************************/
8676 #if __ppc__ || __i386__
8679 OSKext::getKmodInfo(
8680 kmod_info_array_t
* kmodList
,
8681 mach_msg_type_number_t
* kmodCount
)
8683 kern_return_t result
= KERN_FAILURE
;
8685 kmod_info_t
* k
, * kmod_info_scan_ptr
;
8686 kmod_reference_t
* r
, * ref_scan_ptr
;
8690 *kmodList
= (kmod_info_t
*)0;
8693 IORecursiveLockLock(sKextLock
);
8697 size
+= sizeof(kmod_info_t
);
8698 r
= k
->reference_list
;
8700 size
+=sizeof(kmod_reference_t
);
8706 result
= KERN_SUCCESS
;
8710 result
= kmem_alloc(kernel_map
, &data
, size
);
8711 if (result
!= KERN_SUCCESS
) {
8715 /* Copy each kmod_info struct sequentially into the data buffer.
8716 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
8717 * the kernel space address is used to match refs, and a zero 'next' flags
8718 * the end of kmod_infos in the data buffer and the beginning of references.
8721 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8723 *kmod_info_scan_ptr
= *k
;
8725 kmod_info_scan_ptr
->next
= k
;
8727 kmod_info_scan_ptr
++;
8731 /* Now add references after the kmod_info structs in the same buffer.
8732 * Update each kmod_info with the ref_count so we can associate
8733 * references with kmod_info structs.
8736 ref_scan_ptr
= (kmod_reference_t
*)kmod_info_scan_ptr
;
8737 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
8739 r
= k
->reference_list
;
8742 /* Note the last kmod_info in the data buffer has its next == 0.
8743 * Since there can only be one like that,
8744 * this case is handled by the caller.
8751 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
8752 * struct for the client to interpret.
8754 kmod_info_scan_ptr
->reference_list
= (kmod_reference_t
*)(long)ref_count
;
8755 kmod_info_scan_ptr
++;
8759 result
= vm_map_copyin(kernel_map
, data
, size
, TRUE
, (vm_map_copy_t
*)kmodList
);
8760 if (result
!= KERN_SUCCESS
) {
8765 result
= KERN_SUCCESS
;
8768 IORecursiveLockUnlock(sKextLock
);
8770 if (result
!= KERN_SUCCESS
&& data
) {
8771 kmem_free(kernel_map
, data
, size
);
8772 *kmodList
= (kmod_info_t
*)0;
8777 #endif /* __ppc__ || __i386__ */
8779 #pragma mark MAC Framework Support
8781 /*********************************************************************
8782 *********************************************************************/
8783 #if CONFIG_MACF_KEXT
8784 /* MAC Framework support */
8787 * define IOC_DEBUG to display run-time debugging information
8788 * #define IOC_DEBUG 1
8792 #define DPRINTF(x) printf x
8798 /*********************************************************************
8799 *********************************************************************/
8801 MACFObjectIsPrimitiveType(OSObject
* obj
)
8803 const OSMetaClass
* typeID
= NULL
; // do not release
8805 typeID
= OSTypeIDInst(obj
);
8806 if (typeID
== OSTypeID(OSString
) || typeID
== OSTypeID(OSNumber
) ||
8807 typeID
== OSTypeID(OSBoolean
) || typeID
== OSTypeID(OSData
)) {
8814 /*********************************************************************
8815 *********************************************************************/
8817 MACFLengthForObject(OSObject
* obj
)
8819 const OSMetaClass
* typeID
= NULL
; // do not release
8822 typeID
= OSTypeIDInst(obj
);
8823 if (typeID
== OSTypeID(OSString
)) {
8824 OSString
* stringObj
= OSDynamicCast(OSString
, obj
);
8825 len
= stringObj
->getLength() + 1;
8826 } else if (typeID
== OSTypeID(OSNumber
)) {
8827 len
= sizeof("4294967295"); /* UINT32_MAX */
8828 } else if (typeID
== OSTypeID(OSBoolean
)) {
8829 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, obj
);
8830 len
= boolObj
->isTrue() ? sizeof("true") : sizeof("false");
8831 } else if (typeID
== OSTypeID(OSData
)) {
8832 OSData
* dataObj
= OSDynamicCast(OSData
, obj
);
8833 len
= dataObj
->getLength();
8840 /*********************************************************************
8841 *********************************************************************/
8843 MACFInitElementFromObject(
8844 struct mac_module_data_element
* element
,
8847 const OSMetaClass
* typeID
= NULL
; // do not release
8849 typeID
= OSTypeIDInst(value
);
8850 if (typeID
== OSTypeID(OSString
)) {
8851 OSString
* stringObj
= OSDynamicCast(OSString
, value
);
8852 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8853 element
->value_size
= stringObj
->getLength() + 1;
8854 DPRINTF(("osdict: string %s size %d\n",
8855 stringObj
->getCStringNoCopy(), element
->value_size
));
8856 memcpy(element
->value
, stringObj
->getCStringNoCopy(),
8857 element
->value_size
);
8858 } else if (typeID
== OSTypeID(OSNumber
)) {
8859 OSNumber
* numberObj
= OSDynamicCast(OSNumber
, value
);
8860 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8861 element
->value_size
= sprintf(element
->value
, "%u",
8862 numberObj
->unsigned32BitValue()) + 1;
8863 } else if (typeID
== OSTypeID(OSBoolean
)) {
8864 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, value
);
8865 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8866 if (boolObj
->isTrue()) {
8867 strcpy(element
->value
, "true");
8868 element
->value_size
= 5;
8870 strcpy(element
->value
, "false");
8871 element
->value_size
= 6;
8873 } else if (typeID
== OSTypeID(OSData
)) {
8874 OSData
* dataObj
= OSDynamicCast(OSData
, value
);
8875 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
8876 element
->value_size
= dataObj
->getLength();
8877 DPRINTF(("osdict: data size %d\n", dataObj
->getLength()));
8878 memcpy(element
->value
, dataObj
->getBytesNoCopy(),
8879 element
->value_size
);
8884 /*********************************************************************
8885 * This function takes an OSDictionary and returns a struct mac_module_data
8887 *********************************************************************/
8888 static struct mac_module_data
*
8889 MACFEncodeOSDictionary(OSDictionary
* dict
)
8891 struct mac_module_data
* result
= NULL
; // do not free
8892 const OSMetaClass
* typeID
= NULL
; // do not release
8893 OSString
* key
= NULL
; // do not release
8894 OSCollectionIterator
* keyIterator
= NULL
; // must release
8895 struct mac_module_data_element
* element
= NULL
; // do not free
8896 unsigned int strtabsize
= 0;
8897 unsigned int listtabsize
= 0;
8898 unsigned int dicttabsize
= 0;
8899 unsigned int nkeys
= 0;
8900 unsigned int datalen
= 0;
8901 char * strtab
= NULL
; // do not free
8902 char * listtab
= NULL
; // do not free
8903 char * dicttab
= NULL
; // do not free
8904 vm_offset_t data_addr
= 0;
8906 keyIterator
= OSCollectionIterator::withCollection(dict
);
8911 /* Iterate over OSModuleData to figure out total size */
8912 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
8914 // Get the key's value and determine its type
8915 OSObject
* value
= dict
->getObject(key
);
8920 typeID
= OSTypeIDInst(value
);
8921 if (MACFObjectIsPrimitiveType(value
)) {
8922 strtabsize
+= MACFLengthForObject(value
);
8924 else if (typeID
== OSTypeID(OSArray
)) {
8925 unsigned int k
, cnt
, nents
;
8926 OSArray
* arrayObj
= OSDynamicCast(OSArray
, value
);
8929 cnt
= arrayObj
->getCount();
8930 for (k
= 0; k
< cnt
; k
++) {
8931 value
= arrayObj
->getObject(k
);
8932 typeID
= OSTypeIDInst(value
);
8933 if (MACFObjectIsPrimitiveType(value
)) {
8934 listtabsize
+= MACFLengthForObject(value
);
8937 else if (typeID
== OSTypeID(OSDictionary
)) {
8938 unsigned int dents
= 0;
8939 OSDictionary
* dictObj
= NULL
; // do not release
8940 OSString
* dictkey
= NULL
; // do not release
8941 OSCollectionIterator
* dictIterator
= NULL
; // must release
8943 dictObj
= OSDynamicCast(OSDictionary
, value
);
8944 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
8945 if (!dictIterator
) {
8948 while ((dictkey
= OSDynamicCast(OSString
,
8949 dictIterator
->getNextObject()))) {
8951 OSObject
* dictvalue
= NULL
; // do not release
8953 dictvalue
= dictObj
->getObject(dictkey
);
8957 if (MACFObjectIsPrimitiveType(dictvalue
)) {
8958 strtabsize
+= MACFLengthForObject(dictvalue
);
8960 continue; /* Only handle primitive types here. */
8963 * Allow for the "arraynnn/" prefix in the key length.
8965 strtabsize
+= dictkey
->getLength() + 1;
8968 dictIterator
->release();
8970 dicttabsize
+= sizeof(struct mac_module_data_list
) +
8971 dents
* sizeof(struct mac_module_data_element
);
8976 continue; /* Skip everything else. */
8982 listtabsize
+= sizeof(struct mac_module_data_list
) +
8983 (nents
- 1) * sizeof(struct mac_module_data_element
);
8985 continue; /* skip anything else */
8987 strtabsize
+= key
->getLength() + 1;
8995 * Allocate and fill in the module data structures.
8997 datalen
= sizeof(struct mac_module_data
) +
8998 sizeof(mac_module_data_element
) * (nkeys
- 1) +
8999 strtabsize
+ listtabsize
+ dicttabsize
;
9000 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
9001 datalen
, strtabsize
, listtabsize
, dicttabsize
));
9002 if (kmem_alloc(kernel_map
, &data_addr
, datalen
) != KERN_SUCCESS
) {
9005 result
= (mac_module_data
*)data_addr
;
9006 result
->base_addr
= data_addr
;
9007 result
->size
= datalen
;
9008 result
->count
= nkeys
;
9009 strtab
= (char *)&result
->data
[nkeys
];
9010 listtab
= strtab
+ strtabsize
;
9011 dicttab
= listtab
+ listtabsize
;
9012 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
9013 data_addr
, strtab
, listtab
, dicttab
, data_addr
+ datalen
));
9015 keyIterator
->reset();
9017 element
= &result
->data
[0];
9018 DPRINTF(("osdict: element %p\n", element
));
9019 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
9021 // Get the key's value and determine its type
9022 OSObject
* value
= dict
->getObject(key
);
9028 DPRINTF(("osdict: element @%p\n", element
));
9029 element
->key
= strtab
;
9030 element
->key_size
= key
->getLength() + 1;
9031 DPRINTF(("osdict: key %s size %d @%p\n", key
->getCStringNoCopy(),
9032 element
->key_size
, strtab
));
9033 memcpy(element
->key
, key
->getCStringNoCopy(), element
->key_size
);
9035 typeID
= OSTypeIDInst(value
);
9036 if (MACFObjectIsPrimitiveType(value
)) {
9038 element
->value
= element
->key
+ element
->key_size
;
9039 DPRINTF(("osdict: primitive element value %p\n", element
->value
));
9040 MACFInitElementFromObject(element
, value
);
9041 strtab
+= element
->key_size
+ element
->value_size
;
9042 DPRINTF(("osdict: new strtab %p\n", strtab
));
9043 } else if (typeID
== OSTypeID(OSArray
)) {
9044 unsigned int k
, cnt
, nents
;
9046 struct mac_module_data_list
*arrayhd
;
9047 struct mac_module_data_element
*ele
;
9048 OSArray
*arrayObj
= OSDynamicCast(OSArray
, value
);
9050 element
->value
= listtab
;
9051 DPRINTF(("osdict: array element value %p\n", element
->value
));
9052 element
->value_type
= MAC_DATA_TYPE_ARRAY
;
9053 arrayhd
= (struct mac_module_data_list
*)element
->value
;
9055 DPRINTF(("osdict: arrayhd %p\n", arrayhd
));
9057 astrtab
= strtab
+ element
->key_size
;
9058 ele
= &(arrayhd
->list
[0]);
9059 cnt
= arrayObj
->getCount();
9060 for (k
= 0; k
< cnt
; k
++) {
9061 value
= arrayObj
->getObject(k
);
9062 DPRINTF(("osdict: array ele %d @%p\n", nents
, ele
));
9065 typeID
= OSTypeIDInst(value
);
9066 if (MACFObjectIsPrimitiveType(value
)) {
9067 if (arrayhd
->type
!= 0 &&
9068 arrayhd
->type
!= MAC_DATA_TYPE_PRIMITIVE
) {
9072 arrayhd
->type
= MAC_DATA_TYPE_PRIMITIVE
;
9073 ele
->value
= astrtab
;
9074 MACFInitElementFromObject(ele
, value
);
9075 astrtab
+= ele
->value_size
;
9076 DPRINTF(("osdict: array new astrtab %p\n", astrtab
));
9077 } else if (typeID
== OSTypeID(OSDictionary
)) {
9079 char * dstrtab
= NULL
; // do not free
9080 OSDictionary
* dictObj
= NULL
; // do not release
9081 OSString
* dictkey
= NULL
; // do not release
9082 OSCollectionIterator
* dictIterator
= NULL
; // must release
9083 struct mac_module_data_list
* dicthd
= NULL
; // do not free
9084 struct mac_module_data_element
* dele
= NULL
; // do not free
9086 if (arrayhd
->type
!= 0 &&
9087 arrayhd
->type
!= MAC_DATA_TYPE_DICT
) {
9091 dictObj
= OSDynamicCast(OSDictionary
, value
);
9092 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
9093 if (!dictIterator
) {
9096 DPRINTF(("osdict: dict\n"));
9097 ele
->value
= dicttab
;
9098 ele
->value_type
= MAC_DATA_TYPE_DICT
;
9099 dicthd
= (struct mac_module_data_list
*)ele
->value
;
9100 DPRINTF(("osdict: dicthd %p\n", dicthd
));
9103 while ((dictkey
= OSDynamicCast(OSString
,
9104 dictIterator
->getNextObject()))) {
9106 OSObject
* dictvalue
= NULL
; // do not release
9108 dictvalue
= dictObj
->getObject(dictkey
);
9112 dele
= &(dicthd
->list
[dents
]);
9113 DPRINTF(("osdict: dict ele %d @%p\n", dents
, dele
));
9114 if (MACFObjectIsPrimitiveType(dictvalue
)) {
9115 dele
->key
= dstrtab
;
9116 dele
->key_size
= dictkey
->getLength() + 1;
9117 DPRINTF(("osdict: dictkey %s size %d @%p\n",
9118 dictkey
->getCStringNoCopy(), dictkey
->getLength(), dstrtab
));
9119 memcpy(dele
->key
, dictkey
->getCStringNoCopy(),
9121 dele
->value
= dele
->key
+ dele
->key_size
;
9122 MACFInitElementFromObject(dele
, dictvalue
);
9123 dstrtab
+= dele
->key_size
+ dele
->value_size
;
9124 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab
));
9126 continue; /* Only handle primitive types here. */
9130 dictIterator
->release();
9134 arrayhd
->type
= MAC_DATA_TYPE_DICT
;
9135 ele
->value_size
= sizeof(struct mac_module_data_list
) +
9136 (dents
- 1) * sizeof(struct mac_module_data_element
);
9137 DPRINTF(("osdict: dict ele size %d ents %d\n", ele
->value_size
, dents
));
9138 dicttab
+= ele
->value_size
;
9139 DPRINTF(("osdict: new dicttab %p\n", dicttab
));
9140 dicthd
->count
= dents
;
9143 continue; /* Skip everything else. */
9151 element
->value_size
= sizeof(struct mac_module_data_list
) +
9152 (nents
- 1) * sizeof(struct mac_module_data_element
);
9153 listtab
+= element
->value_size
;
9154 DPRINTF(("osdict: new listtab %p\n", listtab
));
9155 arrayhd
->count
= nents
;
9157 DPRINTF(("osdict: new strtab %p\n", strtab
));
9159 continue; /* skip anything else */
9163 DPRINTF(("result list @%p, key %p value %p\n",
9164 result
, result
->data
[0].key
, result
->data
[0].value
));
9166 if (keyIterator
) keyIterator
->release();
9170 /*********************************************************************
9171 * This function takes a plist and looks for an OSModuleData dictionary.
9172 * If it is found, an encoded copy is returned. The value must be
9174 *********************************************************************/
9176 MACFCopyModuleDataForKext(
9178 mach_msg_type_number_t
* datalen
)
9181 struct mac_module_data
* result
= NULL
;
9182 OSDictionary
* kextModuleData
= NULL
; // do not release
9183 vm_map_copy_t copy
= 0;
9185 kextModuleData
= OSDynamicCast(OSDictionary
,
9186 theKext
->getPropertyForHostArch("OSModuleData"));
9187 if (!kextModuleData
) {
9191 result
= MACFEncodeOSDictionary(kextModuleData
);
9195 *datalen
= module_data
->size
;
9198 return (void *)result
;
9200 #endif /* CONFIG_MACF_KEXT */