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/host_special_ports.h>
42 #include <mach/mach_vm.h>
43 #include <mach/mach_time.h>
44 #include <sys/sysctl.h>
45 #include <uuid/uuid.h>
46 // 04/18/11 - gab: <rdar://problem/9236163>
47 #include <sys/random.h>
50 #include <libkern/OSKextLibPrivate.h>
51 #include <libkern/c++/OSKext.h>
52 #include <libkern/c++/OSLib.h>
54 #include <IOKit/IOLib.h>
55 #include <IOKit/IOCatalogue.h>
56 #include <IOKit/IORegistryEntry.h>
57 #include <IOKit/IOService.h>
59 #include <IOKit/IOStatisticsPrivate.h>
62 #pragma mark External & Internal Function Protos
64 /*********************************************************************
65 *********************************************************************/
67 extern int IODTGetLoaderInfo(const char * key
, void ** infoAddr
, int * infoSize
);
68 extern void IODTFreeLoaderInfo(const char * key
, void * infoAddr
, int infoSize
);
69 extern void OSRuntimeUnloadCPPForSegment(kernel_segment_command_t
* segment
);
70 extern void OSRuntimeUnloadCPP(kmod_info_t
* ki
, void * data
);
72 extern ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
); /* osfmk/machine/pmap.h */
75 static OSReturn
_OSKextCreateRequest(
76 const char * predicate
,
77 OSDictionary
** requestP
);
78 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
);
79 static OSObject
* _OSKextGetRequestArgument(
80 OSDictionary
* requestDict
,
81 const char * argName
);
82 static bool _OSKextSetRequestArgument(
83 OSDictionary
* requestDict
,
86 static void * _OSKextExtractPointer(OSData
* wrapper
);
87 static OSReturn
_OSDictionarySetCStringValue(
92 // We really should add containsObject() & containsCString to OSCollection & subclasses.
93 // So few pad slots, though....
94 static bool _OSArrayContainsCString(OSArray
* array
, const char * cString
);
97 static void * MACFCopyModuleDataForKext(
99 mach_msg_type_number_t
* datalen
);
100 #endif /* CONFIG_MACF_KEXT */
103 #pragma mark Constants & Macros
105 /*********************************************************************
107 *********************************************************************/
109 /* A typical Snow Leopard system has a bit under 120 kexts loaded.
110 * Use this number to create containers.
112 #define kOSKextTypicalLoadCount (120)
114 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
115 * A loaded kext will no dependents or external retains will have 2 retains.
117 #define kOSKextMinRetainCount (1)
118 #define kOSKextMinLoadedRetainCount (2)
121 * Strings and substrings used in dependency resolution.
123 #define APPLE_KEXT_PREFIX "com.apple."
124 #define KERNEL_LIB "com.apple.kernel"
126 #define PRIVATE_KPI "com.apple.kpi.private"
128 /* Version for compatbility pseudokexts (com.apple.kernel.*),
129 * compatible back to v6.0.
131 #define KERNEL6_LIB "com.apple.kernel.6.0"
132 #define KERNEL6_VERSION "7.9.9"
134 #define KERNEL_LIB_PREFIX "com.apple.kernel."
135 #define KPI_LIB_PREFIX "com.apple.kpi."
137 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
139 /*********************************************************************
140 * infoDict keys for internally-stored data. Saves on ivar slots for
141 * objects we don't keep around past boot time or during active load.
142 *********************************************************************/
144 /* A usable, uncompressed file is stored under this key.
146 #define _kOSKextExecutableKey "_OSKextExecutable"
148 /* An indirect reference to the executable file from an mkext
149 * is stored under this key.
151 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
153 /* If the file is contained in a larger buffer laid down by the booter or
154 * sent from user space, the OSKext stores that OSData under this key so that
155 * references are properly tracked. This is always an mkext, right now.
157 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
160 #pragma mark Typedefs
162 /*********************************************************************
164 *********************************************************************/
166 /*********************************************************************
167 * MkextEntryRef describes the contents of an OSData object
168 * referencing a file entry from an mkext so that we can uncompress
169 * (if necessary) and extract it on demand.
171 * It contains the mkextVersion in case we ever wind up supporting
172 * multiple mkext formats. Mkext format 1 is officially retired as of
174 *********************************************************************/
175 typedef struct MkextEntryRef
{
176 mkext_basic_header
* mkext
; // beginning of whole mkext file
177 void * fileinfo
; // mkext2_file_entry or equiv; see mkext.h
181 #pragma mark Global and static Module Variables
183 /*********************************************************************
184 * Global & static variables, used to keep track of kexts.
185 *********************************************************************/
187 static bool sPrelinkBoot
= false;
188 static bool sSafeBoot
= false;
189 static bool sKeepSymbols
= false;
191 /*********************************************************************
192 * sKextLock is the principal lock for OSKext, and guards all static
193 * and global variables not owned by other locks (declared further
194 * below). It must be taken by any entry-point method or function,
195 * including internal functions called on scheduled threads.
197 * sKextLock and sKextInnerLock are recursive due to multiple functions
198 * that are called both externally and internally. The other locks are
201 * Which locks are taken depends on what they protect, but if more than
202 * one must be taken, they must always be locked in this order
203 * (and unlocked in reverse order) to prevent deadlocks:
207 * 3. sKextSummariesLock
208 * 4. sKextLoggingLock
210 static IORecursiveLock
* sKextLock
= NULL
;
212 static OSDictionary
* sKextsByID
= NULL
;
213 static OSArray
* sLoadedKexts
= NULL
;
214 static OSArray
* sUnloadedPrelinkedKexts
= NULL
;
216 // Requests to kextd waiting to be picked up.
217 static OSArray
* sKernelRequests
= NULL
;
218 // Identifier of kext load requests in sKernelRequests
219 static OSSet
* sPostedKextLoadIdentifiers
= NULL
;
220 static OSArray
* sRequestCallbackRecords
= NULL
;
222 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
223 static OSSet
* sAllKextLoadIdentifiers
= NULL
;
224 static KXLDContext
* sKxldContext
= NULL
;
225 static uint32_t sNextLoadTag
= 0;
226 static uint32_t sNextRequestTag
= 0;
228 static bool sUserLoadsActive
= false;
229 static bool sKextdActive
= false;
230 static bool sDeferredLoadSucceeded
= false;
231 static bool sConsiderUnloadsExecuted
= false;
234 static bool sKernelRequestsEnabled
= false;
236 static bool sKernelRequestsEnabled
= true;
238 static bool sLoadEnabled
= true;
239 static bool sUnloadEnabled
= true;
241 /*********************************************************************
242 * Stuff for the OSKext representing the kernel itself.
244 static OSKext
* sKernelKext
= NULL
;
246 /* Set up a fake kmod_info struct for the kernel.
247 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
248 * before OSKext is initialized; that call only needs the name
249 * and address to be set correctly.
251 * We don't do much else with the kerne's kmod_info; we never
252 * put it into the kmod list, never adjust the reference count,
253 * and never have kernel components reference it.
254 * For that matter, we don't do much with kmod_info structs
255 * at all anymore! We just keep them filled in for gdb and
256 * binary compability.
258 kmod_info_t g_kernel_kmod_info
= {
260 /* info_version */ KMOD_INFO_VERSION
,
261 /* id */ 0, // loadTag: kernel is always 0
262 /* name */ kOSKextKernelIdentifier
, // bundle identifier
263 /* version */ "0", // filled in in OSKext::initialize()
264 /* reference_count */ -1, // never adjusted; kernel never unloads
265 /* reference_list */ NULL
,
266 /* address */ (vm_address_t
)&_mh_execute_header
,
267 /* size */ 0, // filled in in OSKext::initialize()
274 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
275 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
276 // misc_protos.h, db_low_trace.c, kgmacros
277 // 'kmod' is a holdover from the old kmod system, we can't rename it.
278 kmod_info_t
* kmod
= NULL
;
280 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
283 static char * loaded_kext_paniclist
= NULL
;
284 static uint32_t loaded_kext_paniclist_size
= 0;
285 static uint32_t loaded_kext_paniclist_length
= 0;
287 AbsoluteTime last_loaded_timestamp
;
288 static char last_loaded_str
[2*KMOD_MAX_NAME
];
289 static u_long last_loaded_strlen
= 0;
290 static void * last_loaded_address
= NULL
;
291 static u_long last_loaded_size
= 0;
293 AbsoluteTime last_unloaded_timestamp
;
294 static char last_unloaded_str
[2*KMOD_MAX_NAME
];
295 static u_long last_unloaded_strlen
= 0;
296 static void * last_unloaded_address
= NULL
;
297 static u_long last_unloaded_size
= 0;
299 /*********************************************************************
300 * sKextInnerLock protects against cross-calls with IOService and
301 * IOCatalogue, and owns the variables declared immediately below.
303 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
305 * When both sKextLock and sKextInnerLock need to be taken,
306 * always lock sKextLock first and unlock it second. Never take both
307 * locks in an entry point to OSKext; if you need to do so, you must
308 * spawn an independent thread to avoid potential deadlocks for threads
309 * calling into OSKext.
311 static IORecursiveLock
* sKextInnerLock
= NULL
;
313 static bool sAutounloadEnabled
= true;
314 static bool sConsiderUnloadsCalled
= false;
315 static bool sConsiderUnloadsPending
= false;
317 static unsigned int sConsiderUnloadDelay
= 60; // seconds
318 static thread_call_t sUnloadCallout
= 0;
319 static thread_call_t sDestroyLinkContextThread
= 0; // one-shot, one-at-a-time thread
320 static bool sSystemSleep
= false; // true when system going to sleep
322 /*********************************************************************
323 * Backtraces can be printed at various times so we need a tight lock
324 * on data used for that. sKextSummariesLock protects the variables
325 * declared immediately below.
327 * gLoadedKextSummaries is accessed by other modules, but only during
328 * a panic so the lock isn't needed then.
330 static IOLock
* sKextSummariesLock
= NULL
;
332 void (*sLoadedKextSummariesUpdated
)(void) = OSKextLoadedKextSummariesUpdated
;
333 OSKextLoadedKextSummaryHeader
* gLoadedKextSummaries
= NULL
;
334 static size_t sLoadedKextSummariesAllocSize
= 0;
335 OSKextLoadedKextSummaryHeader
* sPrevLoadedKextSummaries
= NULL
;
336 static size_t sPrevLoadedKextSummariesAllocSize
= 0;
339 /*********************************************************************
340 * sKextLoggingLock protects the logging variables declared immediately below.
342 static IOLock
* sKextLoggingLock
= NULL
;
344 static const OSKextLogSpec kDefaultKernelLogFilter
= kOSKextLogBasicLevel
|
345 kOSKextLogVerboseFlagsMask
;
346 static OSKextLogSpec sKernelLogFilter
= kDefaultKernelLogFilter
;
347 static bool sBootArgLogFilterFound
= false;
348 SYSCTL_INT(_debug
, OID_AUTO
, kextlog
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &sKernelLogFilter
,
349 sKernelLogFilter
, "kernel kext logging");
351 static OSKextLogSpec sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
352 static OSArray
* sUserSpaceLogSpecArray
= NULL
;
353 static OSArray
* sUserSpaceLogMessageArray
= NULL
;
356 * End scope for sKextInnerLock-protected variables.
357 *********************************************************************/
360 #pragma mark OSData callbacks (need to move to OSData)
362 /*********************************************************************
363 * C functions used for callbacks.
364 *********************************************************************/
366 void osdata_kmem_free(void * ptr
, unsigned int length
) {
367 kmem_free(kernel_map
, (vm_address_t
)ptr
, length
);
371 void osdata_phys_free(void * ptr
, unsigned int length
) {
372 ml_static_mfree((vm_offset_t
)ptr
, length
);
376 void osdata_vm_deallocate(void * ptr
, unsigned int length
)
378 (void)vm_deallocate(kernel_map
, (vm_offset_t
)ptr
, length
);
382 void osdata_kext_free(void * ptr
, unsigned int length
)
384 (void)kext_free((vm_offset_t
)ptr
, length
);
390 #pragma mark KXLD Allocation Callback
392 /*********************************************************************
393 * KXLD Allocation Callback
394 *********************************************************************/
398 KXLDAllocateFlags
* flags
,
401 vm_address_t result
= 0; // returned
402 kern_return_t mach_result
= KERN_FAILURE
;
403 bool success
= false;
404 OSKext
* theKext
= (OSKext
*)user_data
;
405 u_long roundSize
= round_page(size
);
406 OSData
* linkBuffer
= NULL
; // must release
408 mach_result
= kext_alloc(&result
, roundSize
, /* fixed */ FALSE
);
409 if (mach_result
!= KERN_SUCCESS
) {
411 kOSKextLogErrorLevel
|
412 kOSKextLogGeneralFlag
,
413 "Can't allocate kernel memory to link %s.",
414 theKext
->getIdentifierCString());
418 /* Create an OSData wrapper for the allocated buffer.
420 linkBuffer
= OSData::withBytesNoCopy((void *)result
, roundSize
);
423 kOSKextLogErrorLevel
|
424 kOSKextLogGeneralFlag
,
425 "Can't allocate linked executable wrapper for %s.",
426 theKext
->getIdentifierCString());
429 linkBuffer
->setDeallocFunction(osdata_kext_free
);
432 kOSKextLogProgressLevel
|
433 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
434 "Allocated link buffer for kext %s at %p (%lu bytes).",
435 theKext
->getIdentifierCString(),
436 (void *)result
, (unsigned long)roundSize
);
438 theKext
->setLinkedExecutable(linkBuffer
);
440 *flags
= kKxldAllocateWritable
;
444 if (!success
&& result
) {
445 kext_free(result
, roundSize
);
449 OSSafeRelease(linkBuffer
);
451 return (kxld_addr_t
)result
;
454 /*********************************************************************
455 *********************************************************************/
458 KXLDLogSubsystem subsystem
,
464 OSKext
*theKext
= (OSKext
*) user_data
;
465 OSKextLogSpec logSpec
= 0;
468 case kKxldLogLinking
:
469 logSpec
|= kOSKextLogLinkFlag
;
471 case kKxldLogPatching
:
472 logSpec
|= kOSKextLogPatchFlag
;
477 case kKxldLogExplicit
:
478 logSpec
|= kOSKextLogExplicitLevel
;
481 logSpec
|= kOSKextLogErrorLevel
;
484 logSpec
|= kOSKextLogWarningLevel
;
487 logSpec
|= kOSKextLogProgressLevel
;
490 logSpec
|= kOSKextLogDetailLevel
;
493 logSpec
|= kOSKextLogDebugLevel
;
497 OSKextVLog(theKext
, logSpec
, format
, argList
);
501 #pragma mark IOStatistics defines
506 #define notifyKextLoadObservers(kext, kmod_info) \
508 IOStatistics::onKextLoad(kext, kmod_info); \
511 #define notifyKextUnloadObservers(kext) \
513 IOStatistics::onKextUnload(kext); \
516 #define notifyAddClassObservers(kext, addedClass, flags) \
518 IOStatistics::onClassAdded(kext, addedClass); \
521 #define notifyRemoveClassObservers(kext, removedClass, flags) \
523 IOStatistics::onClassRemoved(kext, removedClass); \
528 #define notifyKextLoadObservers(kext, kmod_info)
529 #define notifyKextUnloadObservers(kext)
530 #define notifyAddClassObservers(kext, addedClass, flags)
531 #define notifyRemoveClassObservers(kext, removedClass, flags)
533 #endif /* IOKITSTATS */
536 #pragma mark Module Config (Startup & Shutdown)
538 /*********************************************************************
539 * Module Config (Class Definition & Class Methods)
540 *********************************************************************/
541 #define super OSObject
542 OSDefineMetaClassAndStructors(OSKext
, OSObject
)
544 /*********************************************************************
545 *********************************************************************/
548 OSKext::initialize(void)
550 OSData
* kernelExecutable
= NULL
; // do not release
551 u_char
* kernelStart
= NULL
; // do not free
552 size_t kernelLength
= 0;
553 OSString
* scratchString
= NULL
; // must release
554 IORegistryEntry
* registryRoot
= NULL
; // do not release
555 OSNumber
* kernelCPUType
= NULL
; // must release
556 OSNumber
* kernelCPUSubtype
= NULL
; // must release
557 OSKextLogSpec bootLogFilter
= kOSKextLogSilentFilter
;
558 bool setResult
= false;
559 uint64_t * timestamp
= 0;
560 char bootArgBuffer
[16]; // for PE_parse_boot_argn w/strings
562 /* This must be the first thing allocated. Everything else grabs this lock.
564 sKextLock
= IORecursiveLockAlloc();
565 sKextInnerLock
= IORecursiveLockAlloc();
566 sKextSummariesLock
= IOLockAlloc();
567 sKextLoggingLock
= IOLockAlloc();
569 assert(sKextInnerLock
);
570 assert(sKextSummariesLock
);
571 assert(sKextLoggingLock
);
573 sKextsByID
= OSDictionary::withCapacity(kOSKextTypicalLoadCount
);
574 sLoadedKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
);
575 sUnloadedPrelinkedKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
/ 10);
576 sKernelRequests
= OSArray::withCapacity(0);
577 sPostedKextLoadIdentifiers
= OSSet::withCapacity(0);
578 sAllKextLoadIdentifiers
= OSSet::withCapacity(kOSKextTypicalLoadCount
);
579 sRequestCallbackRecords
= OSArray::withCapacity(0);
580 assert(sKextsByID
&& sLoadedKexts
&& sKernelRequests
&&
581 sPostedKextLoadIdentifiers
&& sAllKextLoadIdentifiers
&&
582 sRequestCallbackRecords
&& sUnloadedPrelinkedKexts
);
584 /* Read the log flag boot-args and set the log flags.
586 if (PE_parse_boot_argn("kextlog", &bootLogFilter
, sizeof("kextlog=0x00000000 "))) {
587 sBootArgLogFilterFound
= true;
588 sKernelLogFilter
= bootLogFilter
;
589 // log this if any flags are set
590 OSKextLog(/* kext */ NULL
,
591 kOSKextLogBasicLevel
|
593 "Kernel kext log filter 0x%x per kextlog boot arg.",
594 (unsigned)sKernelLogFilter
);
597 sSafeBoot
= PE_parse_boot_argn("-x", bootArgBuffer
,
598 sizeof(bootArgBuffer
)) ? true : false;
601 OSKextLog(/* kext */ NULL
,
602 kOSKextLogWarningLevel
|
603 kOSKextLogGeneralFlag
,
604 "SAFE BOOT DETECTED - "
605 "only valid OSBundleRequired kexts will be loaded.");
608 PE_parse_boot_argn("keepsyms", &sKeepSymbols
, sizeof(sKeepSymbols
));
610 /* Set up an OSKext instance to represent the kernel itself.
612 sKernelKext
= new OSKext
;
615 kernelStart
= (u_char
*)&_mh_execute_header
;
616 kernelLength
= getlastaddr() - (vm_offset_t
)kernelStart
;
617 kernelExecutable
= OSData::withBytesNoCopy(
618 kernelStart
, kernelLength
);
619 assert(kernelExecutable
);
621 sKernelKext
->loadTag
= sNextLoadTag
++; // the kernel is load tag 0
622 sKernelKext
->bundleID
= OSSymbol::withCString(kOSKextKernelIdentifier
);
624 sKernelKext
->version
= OSKextParseVersionString(osrelease
);
625 sKernelKext
->compatibleVersion
= sKernelKext
->version
;
626 sKernelKext
->linkedExecutable
= kernelExecutable
;
628 sKernelKext
->flags
.hasAllDependencies
= 1;
629 sKernelKext
->flags
.kernelComponent
= 1;
630 sKernelKext
->flags
.prelinked
= 0;
631 sKernelKext
->flags
.loaded
= 1;
632 sKernelKext
->flags
.started
= 1;
633 sKernelKext
->flags
.CPPInitialized
= 0;
635 sKernelKext
->kmod_info
= &g_kernel_kmod_info
;
636 strlcpy(g_kernel_kmod_info
.version
, osrelease
,
637 sizeof(g_kernel_kmod_info
.version
));
638 g_kernel_kmod_info
.size
= kernelLength
;
639 g_kernel_kmod_info
.id
= sKernelKext
->loadTag
;
641 /* Cons up an info dict, so we don't have to have special-case
644 sKernelKext
->infoDict
= OSDictionary::withCapacity(5);
645 assert(sKernelKext
->infoDict
);
646 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleIdentifierKey
,
647 sKernelKext
->bundleID
);
649 setResult
= sKernelKext
->infoDict
->setObject(kOSKernelResourceKey
,
653 scratchString
= OSString::withCStringNoCopy(osrelease
);
654 assert(scratchString
);
655 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleVersionKey
,
658 OSSafeReleaseNULL(scratchString
);
660 scratchString
= OSString::withCStringNoCopy("mach_kernel");
661 assert(scratchString
);
662 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleNameKey
,
665 OSSafeReleaseNULL(scratchString
);
667 /* Add the kernel kext to the bookkeeping dictionaries. Note that
668 * the kernel kext doesn't have a kmod_info struct. copyInfo()
669 * gathers info from other places anyhow.
671 setResult
= sKextsByID
->setObject(sKernelKext
->bundleID
, sKernelKext
);
673 setResult
= sLoadedKexts
->setObject(sKernelKext
);
675 sKernelKext
->release();
677 registryRoot
= IORegistryEntry::getRegistryRoot();
678 kernelCPUType
= OSNumber::withNumber(
679 (long long unsigned int)_mh_execute_header
.cputype
,
680 8 * sizeof(_mh_execute_header
.cputype
));
681 kernelCPUSubtype
= OSNumber::withNumber(
682 (long long unsigned int)_mh_execute_header
.cpusubtype
,
683 8 * sizeof(_mh_execute_header
.cpusubtype
));
684 assert(registryRoot
&& kernelCPUSubtype
&& kernelCPUType
);
686 registryRoot
->setProperty(kOSKernelCPUTypeKey
, kernelCPUType
);
687 registryRoot
->setProperty(kOSKernelCPUSubtypeKey
, kernelCPUSubtype
);
689 OSSafeRelease(kernelCPUType
);
690 OSSafeRelease(kernelCPUSubtype
);
692 timestamp
= __OSAbsoluteTimePtr(&last_loaded_timestamp
);
694 timestamp
= __OSAbsoluteTimePtr(&last_unloaded_timestamp
);
697 OSKextLog(/* kext */ NULL
,
698 kOSKextLogProgressLevel
|
699 kOSKextLogGeneralFlag
,
700 "Kext system initialized.");
702 notifyKextLoadObservers(sKernelKext
, sKernelKext
->kmod_info
);
707 /*********************************************************************
708 * This could be in OSKextLib.cpp but we need to hold a lock
709 * while removing all the segments and sKextLock will do.
710 *********************************************************************/
713 OSKext::removeKextBootstrap(void)
715 OSReturn result
= kOSReturnError
;
717 static bool alreadyDone
= false;
719 const char * dt_kernel_header_name
= "Kernel-__HEADER";
720 const char * dt_kernel_symtab_name
= "Kernel-__SYMTAB";
721 kernel_mach_header_t
* dt_mach_header
= NULL
;
722 int dt_mach_header_size
= 0;
723 struct symtab_command
* dt_symtab
= NULL
;
724 int dt_symtab_size
= 0;
727 kernel_segment_command_t
* seg_to_remove
= NULL
;
729 /* This must be the very first thing done by this function.
731 IORecursiveLockLock(sKextLock
);
733 /* If we already did this, it's a success.
736 result
= kOSReturnSuccess
;
740 OSKextLog(/* kext */ NULL
,
741 kOSKextLogProgressLevel
|
742 kOSKextLogGeneralFlag
,
743 "Jettisoning kext bootstrap segments.");
746 * Dispose of unnecessary stuff that the booter didn't need to load.
748 dt_result
= IODTGetLoaderInfo(dt_kernel_header_name
,
749 (void **)&dt_mach_header
, &dt_mach_header_size
);
750 if (dt_result
== 0 && dt_mach_header
) {
751 IODTFreeLoaderInfo(dt_kernel_header_name
, (void *)dt_mach_header
,
752 round_page_32(dt_mach_header_size
));
754 dt_result
= IODTGetLoaderInfo(dt_kernel_symtab_name
,
755 (void **)&dt_symtab
, &dt_symtab_size
);
756 if (dt_result
== 0 && dt_symtab
) {
757 IODTFreeLoaderInfo(dt_kernel_symtab_name
, (void *)dt_symtab
,
758 round_page_32(dt_symtab_size
));
762 * KLD bootstrap segment.
764 // xxx - should rename KLD segment
765 seg_to_remove
= getsegbyname("__KLD");
767 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
770 #if __i386__ || __x86_64__
771 /* On x86, use the mapping data from the segment load command to
772 * unload KLD directly.
773 * This may invalidate any assumptions about "avail_start"
774 * defining the lower bound for valid physical addresses.
776 if (seg_to_remove
&& seg_to_remove
->vmaddr
&& seg_to_remove
->vmsize
) {
777 // 04/18/11 - gab: <rdar://problem/9236163>
778 // overwrite memory occupied by KLD segment with random data before
780 read_random((void *) seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
781 ml_static_mfree(seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
787 seg_to_remove
= NULL
;
790 * Prelinked kernel's symtab (if there is one).
792 kernel_section_t
* sect
;
793 sect
= getsectbyname("__PRELINK", "__symtab");
794 if (sect
&& sect
->addr
&& sect
->size
) {
795 ml_static_mfree(sect
->addr
, sect
->size
);
798 seg_to_remove
= (kernel_segment_command_t
*)getsegbyname("__LINKEDIT");
800 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
801 * pageable, unless keepsyms is set. To do that, we have to copy it from
802 * its booter-allocated memory, free the booter memory, reallocate proper
803 * managed memory, then copy the segment back in.
807 kern_return_t mem_result
;
808 void *seg_copy
= NULL
;
809 void *seg_data
= NULL
;
810 vm_map_offset_t seg_offset
= 0;
811 vm_map_offset_t seg_copy_offset
= 0;
812 vm_map_size_t seg_length
= 0;
814 seg_data
= (void *) seg_to_remove
->vmaddr
;
815 seg_offset
= (vm_map_offset_t
) seg_to_remove
->vmaddr
;
816 seg_length
= (vm_map_size_t
) seg_to_remove
->vmsize
;
818 /* Allocate space for the LINKEDIT copy.
820 mem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*) &seg_copy
,
822 if (mem_result
!= KERN_SUCCESS
) {
823 OSKextLog(/* kext */ NULL
,
824 kOSKextLogErrorLevel
|
825 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
826 "Can't copy __LINKEDIT segment for VM reassign.");
829 seg_copy_offset
= (vm_map_offset_t
) seg_copy
;
833 memcpy(seg_copy
, seg_data
, seg_length
);
835 /* Dump the booter memory.
837 ml_static_mfree(seg_offset
, seg_length
);
839 /* Set up the VM region.
841 mem_result
= vm_map_enter_mem_object(
844 seg_length
, /* mask */ 0,
845 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
847 (vm_object_offset_t
) 0,
849 /* cur_protection */ VM_PROT_ALL
,
850 /* max_protection */ VM_PROT_ALL
,
851 /* inheritance */ VM_INHERIT_DEFAULT
);
852 if ((mem_result
!= KERN_SUCCESS
) ||
853 (seg_offset
!= (vm_map_offset_t
) seg_data
))
855 OSKextLog(/* kext */ NULL
,
856 kOSKextLogErrorLevel
|
857 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
858 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
859 seg_data
, seg_length
, mem_result
);
865 memcpy(seg_data
, seg_copy
, seg_length
);
869 kmem_free(kernel_map
, seg_copy_offset
, seg_length
);
871 #else /* we are not CONFIG_KXLD */
874 * Dump the LINKEDIT segment, unless keepsyms is set.
877 #if __i386__ || __x86_64__
878 if (seg_to_remove
&& seg_to_remove
->vmaddr
&& seg_to_remove
->vmsize
) {
879 ml_static_mfree(seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
881 #else /* from if __arm__ */
884 #endif /* from if __arm__ */
887 OSKextLog(/* kext */ NULL
,
888 kOSKextLogBasicLevel
|
889 kOSKextLogGeneralFlag
,
890 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
892 #endif /* CONFIG_KXLD */
894 seg_to_remove
= NULL
;
897 result
= kOSReturnSuccess
;
901 /* This must be the very last thing done before returning.
903 IORecursiveLockUnlock(sKextLock
);
908 /*********************************************************************
909 *********************************************************************/
911 OSKext::flushNonloadedKexts(
912 Boolean flushPrelinkedKexts
)
914 OSSet
* prelinkedKexts
= NULL
; // must release
915 OSCollectionIterator
* kextIterator
= NULL
; // must release
916 OSCollectionIterator
* prelinkIterator
= NULL
; // must release
917 const OSSymbol
* thisID
= NULL
; // do not release
918 OSKext
* thisKext
= NULL
; // do not release
921 IORecursiveLockLock(sKextLock
);
923 OSKextLog(/* kext */ NULL
,
924 kOSKextLogProgressLevel
|
925 kOSKextLogKextBookkeepingFlag
,
926 "Flushing nonloaded kexts and other unused data.");
928 OSKext::considerDestroyingLinkContext();
930 /* If we aren't flushing unused prelinked kexts, we have to put them
931 * aside while we flush everything else so make a container for them.
933 if (!flushPrelinkedKexts
) {
934 prelinkedKexts
= OSSet::withCapacity(0);
935 if (!prelinkedKexts
) {
940 /* Set aside prelinked kexts (in-use or not) and break
941 * any lingering inter-kext references for nonloaded kexts
942 * so they have min. retain counts.
944 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
949 while ((thisID
= OSDynamicCast(OSSymbol
,
950 kextIterator
->getNextObject()))) {
952 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
955 if (prelinkedKexts
&& thisKext
->isPrelinked()) {
956 prelinkedKexts
->setObject(thisKext
);
958 thisKext
->flushDependencies(/* forceIfLoaded */ false);
962 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
964 sKextsByID
->flushCollection();
966 /* Now put the loaded kexts back into the ID dictionary.
968 count
= sLoadedKexts
->getCount();
969 for (i
= 0; i
< count
; i
++) {
970 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
971 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
974 /* Finally, put back the prelinked kexts if we saved any.
976 if (prelinkedKexts
) {
977 prelinkIterator
= OSCollectionIterator::withCollection(prelinkedKexts
);
978 if (!prelinkIterator
) {
982 while ((thisKext
= OSDynamicCast(OSKext
,
983 prelinkIterator
->getNextObject()))) {
985 sKextsByID
->setObject(thisKext
->getIdentifierCString(),
991 IORecursiveLockUnlock(sKextLock
);
993 OSSafeRelease(prelinkedKexts
);
994 OSSafeRelease(kextIterator
);
995 OSSafeRelease(prelinkIterator
);
1000 /*********************************************************************
1001 *********************************************************************/
1004 OSKext::setKextdActive(Boolean active
)
1006 IORecursiveLockLock(sKextLock
);
1007 sKextdActive
= active
;
1008 if (sKernelRequests
->getCount()) {
1009 OSKext::pingKextd();
1011 IORecursiveLockUnlock(sKextLock
);
1016 /*********************************************************************
1017 * OSKextLib.cpp might need access to this someday but for now it's
1019 *********************************************************************/
1021 extern void ipc_port_release_send(ipc_port_t
);
1026 OSKext::pingKextd(void)
1028 OSReturn result
= kOSReturnError
;
1030 mach_port_t kextd_port
= IPC_PORT_NULL
;
1032 if (!sKextdActive
) {
1033 result
= kOSKextReturnDisabled
; // basically unavailable
1037 result
= host_get_kextd_port(host_priv_self(), &kextd_port
);
1038 if (result
!= KERN_SUCCESS
|| !IPC_PORT_VALID(kextd_port
)) {
1039 OSKextLog(/* kext */ NULL
,
1040 kOSKextLogErrorLevel
|
1042 "Can't get kextd port.");
1046 result
= kextd_ping(kextd_port
);
1047 if (result
!= KERN_SUCCESS
) {
1048 OSKextLog(/* kext */ NULL
,
1049 kOSKextLogErrorLevel
|
1051 "kextd ping failed (0x%x).", (int)result
);
1056 if (IPC_PORT_VALID(kextd_port
)) {
1057 ipc_port_release_send(kextd_port
);
1064 /*********************************************************************
1065 *********************************************************************/
1068 OSKext::setDeferredLoadSucceeded(Boolean succeeded
)
1070 IORecursiveLockLock(sKextLock
);
1071 sDeferredLoadSucceeded
= succeeded
;
1072 IORecursiveLockUnlock(sKextLock
);
1077 /*********************************************************************
1078 * Called from IOSystemShutdownNotification.
1079 *********************************************************************/
1082 OSKext::willShutdown(void)
1085 OSReturn checkResult
= kOSReturnError
;
1087 OSDictionary
* exitRequest
= NULL
; // must release
1089 IORecursiveLockLock(sKextLock
);
1091 OSKext::setLoadEnabled(false);
1092 OSKext::setUnloadEnabled(false);
1093 OSKext::setAutounloadsEnabled(false);
1094 OSKext::setKernelRequestsEnabled(false);
1097 OSKextLog(/* kext */ NULL
,
1098 kOSKextLogProgressLevel
|
1099 kOSKextLogGeneralFlag
,
1100 "System shutdown; requesting immediate kextd exit.");
1102 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestKextdExit
,
1104 if (checkResult
!= kOSReturnSuccess
) {
1107 if (!sKernelRequests
->setObject(exitRequest
)) {
1111 OSKext::pingKextd();
1116 IORecursiveLockUnlock(sKextLock
);
1118 OSSafeRelease(exitRequest
);
1122 /*********************************************************************
1123 *********************************************************************/
1126 OSKext::getLoadEnabled(void)
1130 IORecursiveLockLock(sKextLock
);
1131 result
= sLoadEnabled
;
1132 IORecursiveLockUnlock(sKextLock
);
1136 /*********************************************************************
1137 *********************************************************************/
1140 OSKext::setLoadEnabled(bool flag
)
1144 IORecursiveLockLock(sKextLock
);
1145 result
= sLoadEnabled
;
1146 sLoadEnabled
= (flag
? true : false);
1148 if (sLoadEnabled
!= result
) {
1149 OSKextLog(/* kext */ NULL
,
1150 kOSKextLogBasicLevel
|
1152 "Kext loading now %sabled.", sLoadEnabled
? "en" : "dis");
1155 IORecursiveLockUnlock(sKextLock
);
1160 /*********************************************************************
1161 *********************************************************************/
1164 OSKext::getUnloadEnabled(void)
1168 IORecursiveLockLock(sKextLock
);
1169 result
= sUnloadEnabled
;
1170 IORecursiveLockUnlock(sKextLock
);
1174 /*********************************************************************
1175 *********************************************************************/
1178 OSKext::setUnloadEnabled(bool flag
)
1182 IORecursiveLockLock(sKextLock
);
1183 result
= sUnloadEnabled
;
1184 sUnloadEnabled
= (flag
? true : false);
1185 IORecursiveLockUnlock(sKextLock
);
1187 if (sUnloadEnabled
!= result
) {
1188 OSKextLog(/* kext */ NULL
,
1189 kOSKextLogBasicLevel
|
1190 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1191 "Kext unloading now %sabled.", sUnloadEnabled
? "en" : "dis");
1197 /*********************************************************************
1198 * Do not call any function that takes sKextLock here!
1199 *********************************************************************/
1202 OSKext::getAutounloadEnabled(void)
1206 IORecursiveLockLock(sKextInnerLock
);
1207 result
= sAutounloadEnabled
? true : false;
1208 IORecursiveLockUnlock(sKextInnerLock
);
1212 /*********************************************************************
1213 * Do not call any function that takes sKextLock here!
1214 *********************************************************************/
1217 OSKext::setAutounloadsEnabled(bool flag
)
1221 IORecursiveLockLock(sKextInnerLock
);
1223 result
= sAutounloadEnabled
;
1224 sAutounloadEnabled
= (flag
? true : false);
1225 if (!sAutounloadEnabled
&& sUnloadCallout
) {
1226 thread_call_cancel(sUnloadCallout
);
1229 if (sAutounloadEnabled
!= result
) {
1230 OSKextLog(/* kext */ NULL
,
1231 kOSKextLogBasicLevel
|
1232 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1233 "Kext autounloading now %sabled.",
1234 sAutounloadEnabled
? "en" : "dis");
1237 IORecursiveLockUnlock(sKextInnerLock
);
1242 /*********************************************************************
1243 *********************************************************************/
1244 /* instance method operating on OSKext field */
1246 OSKext::setAutounloadEnabled(bool flag
)
1248 bool result
= flags
.autounloadEnabled
? true : false;
1249 flags
.autounloadEnabled
= flag
? 1 : 0;
1251 if (result
!= (flag
? true : false)) {
1253 kOSKextLogProgressLevel
|
1254 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
1255 "Autounloading for kext %s now %sabled.",
1256 getIdentifierCString(),
1257 flags
.autounloadEnabled
? "en" : "dis");
1262 /*********************************************************************
1263 *********************************************************************/
1266 OSKext::setKernelRequestsEnabled(bool flag
)
1270 IORecursiveLockLock(sKextLock
);
1271 result
= sKernelRequestsEnabled
;
1272 sKernelRequestsEnabled
= flag
? true : false;
1274 if (sKernelRequestsEnabled
!= result
) {
1275 OSKextLog(/* kext */ NULL
,
1276 kOSKextLogBasicLevel
|
1277 kOSKextLogGeneralFlag
,
1278 "Kernel requests now %sabled.",
1279 sKernelRequestsEnabled
? "en" : "dis");
1281 IORecursiveLockUnlock(sKextLock
);
1285 /*********************************************************************
1286 *********************************************************************/
1289 OSKext::getKernelRequestsEnabled(void)
1293 IORecursiveLockLock(sKextLock
);
1294 result
= sKernelRequestsEnabled
;
1295 IORecursiveLockUnlock(sKextLock
);
1300 #pragma mark Kext Life Cycle
1302 /*********************************************************************
1303 *********************************************************************/
1305 OSKext::withPrelinkedInfoDict(
1306 OSDictionary
* anInfoDict
)
1308 OSKext
* newKext
= new OSKext
;
1310 if (newKext
&& !newKext
->initWithPrelinkedInfoDict(anInfoDict
)) {
1318 /*********************************************************************
1319 *********************************************************************/
1321 OSKext::initWithPrelinkedInfoDict(
1322 OSDictionary
* anInfoDict
)
1324 bool result
= false;
1325 OSString
* kextPath
= NULL
; // do not release
1326 OSNumber
* addressNum
= NULL
; // reused; do not release
1327 OSNumber
* lengthNum
= NULL
; // reused; do not release
1328 void * data
= NULL
; // do not free
1329 void * srcData
= NULL
; // do not free
1330 OSData
* prelinkedExecutable
= NULL
; // must release
1331 uint32_t length
= 0; // reused
1333 if (!super::init()) {
1337 /* Get the path. Don't look for an arch-specific path property.
1339 kextPath
= OSDynamicCast(OSString
,
1340 anInfoDict
->getObject(kPrelinkBundlePathKey
));
1342 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
1346 /* Also get the executable's bundle-relative path if present.
1347 * Don't look for an arch-specific path property.
1349 executableRelPath
= OSDynamicCast(OSString
,
1350 anInfoDict
->getObject(kPrelinkExecutableRelativePathKey
));
1351 if (executableRelPath
) {
1352 executableRelPath
->retain();
1355 /* Don't need the paths to be in the info dictionary any more.
1357 anInfoDict
->removeObject(kPrelinkBundlePathKey
);
1358 anInfoDict
->removeObject(kPrelinkExecutableRelativePathKey
);
1360 /* Create an OSData wrapper around the linked executable.
1362 addressNum
= OSDynamicCast(OSNumber
,
1363 anInfoDict
->getObject(kPrelinkExecutableLoadKey
));
1365 lengthNum
= OSDynamicCast(OSNumber
,
1366 anInfoDict
->getObject(kPrelinkExecutableSizeKey
));
1369 kOSKextLogErrorLevel
|
1370 kOSKextLogArchiveFlag
,
1371 "Kext %s can't find prelinked kext executable size.",
1372 getIdentifierCString());
1376 data
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1377 length
= (uint32_t) (lengthNum
->unsigned32BitValue());
1379 anInfoDict
->removeObject(kPrelinkExecutableLoadKey
);
1380 anInfoDict
->removeObject(kPrelinkExecutableSizeKey
);
1382 /* If the kext's load address differs from its source address, allocate
1383 * space in the kext map at the load address and copy the kext over.
1385 addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject(kPrelinkExecutableSourceKey
));
1387 srcData
= (void *) (intptr_t) (addressNum
->unsigned64BitValue());
1389 if (data
!= srcData
) {
1391 kern_return_t alloc_result
;
1393 alloc_result
= kext_alloc((vm_offset_t
*)&data
, length
, /* fixed */ TRUE
);
1394 if (alloc_result
!= KERN_SUCCESS
) {
1396 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1397 "Failed to allocate space for prelinked kext %s.",
1398 getIdentifierCString());
1401 memcpy(data
, srcData
, length
);
1404 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1405 "Error: prelinked kext %s - source and load addresses "
1406 "differ on ILP32 architecture.",
1407 getIdentifierCString());
1409 #endif /* __LP64__ */
1412 anInfoDict
->removeObject(kPrelinkExecutableSourceKey
);
1415 prelinkedExecutable
= OSData::withBytesNoCopy(data
, length
);
1416 if (!prelinkedExecutable
) {
1418 kOSKextLogErrorLevel
|
1419 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1420 "Kext %s failed to create executable wrapper.",
1421 getIdentifierCString());
1424 prelinkedExecutable
->setDeallocFunction(osdata_kext_free
);
1425 setLinkedExecutable(prelinkedExecutable
);
1427 addressNum
= OSDynamicCast(OSNumber
,
1428 anInfoDict
->getObject(kPrelinkKmodInfoKey
));
1431 kOSKextLogErrorLevel
|
1432 kOSKextLogArchiveFlag
,
1433 "Kext %s can't find prelinked kext kmod_info address.",
1434 getIdentifierCString());
1438 kmod_info
= (kmod_info_t
*) (intptr_t) (addressNum
->unsigned64BitValue());
1440 anInfoDict
->removeObject(kPrelinkKmodInfoKey
);
1443 /* If the plist has a UUID for an interface, save that off.
1445 if (isInterface()) {
1446 interfaceUUID
= OSDynamicCast(OSData
,
1447 anInfoDict
->getObject(kPrelinkInterfaceUUIDKey
));
1448 if (interfaceUUID
) {
1449 interfaceUUID
->retain();
1450 anInfoDict
->removeObject(kPrelinkInterfaceUUIDKey
);
1454 flags
.prelinked
= true;
1456 /* If we created a kext from prelink info,
1457 * we must be booting from a prelinked kernel.
1459 sPrelinkBoot
= true;
1461 result
= registerIdentifier();
1464 OSSafeRelease(prelinkedExecutable
);
1469 /*********************************************************************
1470 *********************************************************************/
1472 OSKext::withBooterData(
1473 OSString
* deviceTreeName
,
1474 OSData
* booterData
)
1476 OSKext
* newKext
= new OSKext
;
1478 if (newKext
&& !newKext
->initWithBooterData(deviceTreeName
, booterData
)) {
1486 /*********************************************************************
1487 *********************************************************************/
1488 typedef struct _BooterKextFileInfo
{
1489 uint32_t infoDictPhysAddr
;
1490 uint32_t infoDictLength
;
1491 uint32_t executablePhysAddr
;
1492 uint32_t executableLength
;
1493 uint32_t bundlePathPhysAddr
;
1494 uint32_t bundlePathLength
;
1495 } _BooterKextFileInfo
;
1498 OSKext::initWithBooterData(
1499 OSString
* deviceTreeName
,
1500 OSData
* booterData
)
1502 bool result
= false;
1503 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not free
1504 char * infoDictAddr
= NULL
; // do not free
1505 void * executableAddr
= NULL
; // do not free
1506 char * bundlePathAddr
= NULL
; // do not free
1508 OSObject
* parsedXML
= NULL
; // must release
1509 OSDictionary
* theInfoDict
= NULL
; // do not release
1510 OSString
* kextPath
= NULL
; // must release
1511 OSString
* errorString
= NULL
; // must release
1512 OSData
* executable
= NULL
; // must release
1514 if (!super::init()) {
1518 kextFileInfo
= (_BooterKextFileInfo
*)booterData
->getBytesNoCopy();
1519 if (!kextFileInfo
) {
1521 kOSKextLogErrorLevel
|
1522 kOSKextLogGeneralFlag
,
1523 "No booter-provided data for kext device tree entry %s.",
1524 deviceTreeName
->getCStringNoCopy());
1528 /* The info plist must exist or we can't read the kext.
1530 if (!kextFileInfo
->infoDictPhysAddr
|| !kextFileInfo
->infoDictLength
) {
1532 kOSKextLogErrorLevel
|
1533 kOSKextLogGeneralFlag
,
1534 "No kext info dictionary for booter device tree entry %s.",
1535 deviceTreeName
->getCStringNoCopy());
1539 infoDictAddr
= (char *)ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
1540 if (!infoDictAddr
) {
1542 kOSKextLogErrorLevel
|
1543 kOSKextLogGeneralFlag
,
1544 "Can't translate physical address 0x%x of kext info dictionary "
1545 "for device tree entry %s.",
1546 (int)kextFileInfo
->infoDictPhysAddr
,
1547 deviceTreeName
->getCStringNoCopy());
1551 parsedXML
= OSUnserializeXML(infoDictAddr
, &errorString
);
1553 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
1556 const char * errorCString
= "(unknown error)";
1558 if (errorString
&& errorString
->getCStringNoCopy()) {
1559 errorCString
= errorString
->getCStringNoCopy();
1560 } else if (parsedXML
) {
1561 errorCString
= "not a dictionary";
1564 kOSKextLogErrorLevel
|
1565 kOSKextLogGeneralFlag
,
1566 "Error unserializing info dictionary for device tree entry %s: %s.",
1567 deviceTreeName
->getCStringNoCopy(), errorCString
);
1571 /* A bundle path is not mandatory.
1573 if (kextFileInfo
->bundlePathPhysAddr
&& kextFileInfo
->bundlePathLength
) {
1574 bundlePathAddr
= (char *)ml_static_ptovirt(kextFileInfo
->bundlePathPhysAddr
);
1575 if (!bundlePathAddr
) {
1577 kOSKextLogErrorLevel
|
1578 kOSKextLogGeneralFlag
,
1579 "Can't translate physical address 0x%x of kext bundle path "
1580 "for device tree entry %s.",
1581 (int)kextFileInfo
->bundlePathPhysAddr
,
1582 deviceTreeName
->getCStringNoCopy());
1585 bundlePathAddr
[kextFileInfo
->bundlePathLength
-1] = '\0'; // just in case!
1587 kextPath
= OSString::withCString(bundlePathAddr
);
1590 kOSKextLogErrorLevel
|
1591 kOSKextLogGeneralFlag
,
1592 "Failed to create wrapper for device tree entry %s kext path %s.",
1593 deviceTreeName
->getCStringNoCopy(), bundlePathAddr
);
1598 if (!setInfoDictionaryAndPath(theInfoDict
, kextPath
)) {
1602 /* An executable is not mandatory.
1604 if (kextFileInfo
->executablePhysAddr
&& kextFileInfo
->executableLength
) {
1605 executableAddr
= (void *)ml_static_ptovirt(kextFileInfo
->executablePhysAddr
);
1606 if (!executableAddr
) {
1608 kOSKextLogErrorLevel
|
1609 kOSKextLogGeneralFlag
,
1610 "Can't translate physical address 0x%x of kext executable "
1611 "for device tree entry %s.",
1612 (int)kextFileInfo
->executablePhysAddr
,
1613 deviceTreeName
->getCStringNoCopy());
1617 executable
= OSData::withBytesNoCopy(executableAddr
,
1618 kextFileInfo
->executableLength
);
1621 kOSKextLogErrorLevel
|
1622 kOSKextLogGeneralFlag
,
1623 "Failed to create executable wrapper for device tree entry %s.",
1624 deviceTreeName
->getCStringNoCopy());
1628 /* A kext with an executable needs to retain the whole booterData
1629 * object to keep the executable in memory.
1631 if (!setExecutable(executable
, booterData
)) {
1633 kOSKextLogErrorLevel
|
1634 kOSKextLogGeneralFlag
,
1635 "Failed to set kext executable for device tree entry %s.",
1636 deviceTreeName
->getCStringNoCopy());
1641 result
= registerIdentifier();
1644 OSSafeRelease(parsedXML
);
1645 OSSafeRelease(kextPath
);
1646 OSSafeRelease(errorString
);
1647 OSSafeRelease(executable
);
1652 /*********************************************************************
1653 *********************************************************************/
1655 OSKext::registerIdentifier(void)
1657 bool result
= false;
1658 OSKext
* existingKext
= NULL
; // do not release
1659 bool existingIsLoaded
= false;
1660 bool existingIsPrelinked
= false;
1661 OSKextVersion newVersion
= -1;
1662 OSKextVersion existingVersion
= -1;
1663 char newVersionCString
[kOSKextVersionMaxLength
];
1664 char existingVersionCString
[kOSKextVersionMaxLength
];
1665 OSData
* newUUID
= NULL
; // must release
1666 OSData
* existingUUID
= NULL
; // must release
1668 IORecursiveLockLock(sKextLock
);
1670 /* Get the new kext's version for checks & log messages.
1672 newVersion
= getVersion();
1673 OSKextVersionGetString(newVersion
, newVersionCString
,
1674 kOSKextVersionMaxLength
);
1676 /* If we don't have an existing kext with this identifier,
1677 * just record the new kext and we're done!
1679 existingKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
));
1680 if (!existingKext
) {
1681 sKextsByID
->setObject(bundleID
, this);
1686 /* Get the existing kext's version for checks & log messages.
1688 existingVersion
= existingKext
->getVersion();
1689 OSKextVersionGetString(existingVersion
,
1690 existingVersionCString
, kOSKextVersionMaxLength
);
1692 existingIsLoaded
= existingKext
->isLoaded();
1693 existingIsPrelinked
= existingKext
->isPrelinked();
1695 /* If we have a kext with this identifier that's already loaded/prelinked,
1696 * we can't use the new one, but let's be really thorough and check how
1697 * the two are related for a precise diagnostic log message.
1699 * Note that user space can't find out about nonloaded prelinked kexts,
1700 * so in this case we log a message when new & existing are equivalent
1701 * at the step rather than warning level, because we are always going
1702 * be getting a copy of the kext in the user load request mkext.
1704 if (existingIsLoaded
|| existingIsPrelinked
) {
1705 bool sameVersion
= (newVersion
== existingVersion
);
1706 bool sameExecutable
= true; // assume true unless we have UUIDs
1708 /* Only get the UUID if the existing kext is loaded. Doing so
1709 * might have to uncompress an mkext executable and we shouldn't
1710 * take that hit when neither kext is loaded.
1712 newUUID
= copyUUID();
1713 existingUUID
= existingKext
->copyUUID();
1715 /* I'm entirely too paranoid about checking equivalence of executables,
1716 * but I remember nasty problems with it in the past.
1718 * - If we have UUIDs for both kexts, compare them.
1719 * - If only one kext has a UUID, they're definitely different.
1721 if (newUUID
&& existingUUID
) {
1722 sameExecutable
= newUUID
->isEqualTo(existingUUID
);
1723 } else if (newUUID
|| existingUUID
) {
1724 sameExecutable
= false;
1727 if (!newUUID
&& !existingUUID
) {
1729 /* If there are no UUIDs, we can't really tell that the executables
1730 * are *different* without a lot of work; the loaded kext's
1731 * unrelocated executable is no longer around (and we never had it
1732 * in-kernel for a prelinked kext). We certainly don't want to do
1733 * a whole fake link for the new kext just to compare, either.
1736 OSKextVersionGetString(version
, newVersionCString
,
1737 sizeof(newVersionCString
));
1739 kOSKextLogWarningLevel
|
1740 kOSKextLogKextBookkeepingFlag
,
1741 "Notice - new kext %s, v%s matches %s kext "
1742 "but can't determine if executables are the same (no UUIDs).",
1743 getIdentifierCString(),
1745 (existingIsLoaded
? "loaded" : "prelinked"));
1748 if (sameVersion
&& sameExecutable
) {
1750 (existingIsLoaded
? kOSKextLogWarningLevel
: kOSKextLogStepLevel
) |
1751 kOSKextLogKextBookkeepingFlag
,
1752 "Refusing new kext %s, v%s: a %s copy is already present "
1753 "(same version and executable).",
1754 getIdentifierCString(), newVersionCString
,
1755 (existingIsLoaded
? "loaded" : "prelinked"));
1758 /* This condition is significant so log it under warnings.
1761 kOSKextLogWarningLevel
|
1762 kOSKextLogKextBookkeepingFlag
,
1763 "Refusing new kext %s, v%s: already have %s v%s.",
1764 getIdentifierCString(),
1766 (existingIsLoaded
? "loaded" : "prelinked"),
1767 existingVersionCString
);
1769 /* This condition is significant so log it under warnings.
1772 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
1773 "Refusing new kext %s, v%s: a %s copy with a different "
1774 "executable UUID is already present.",
1775 getIdentifierCString(), newVersionCString
,
1776 (existingIsLoaded
? "loaded" : "prelinked"));
1780 } /* if (existingIsLoaded || existingIsPrelinked) */
1782 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
1783 * user loads are happening or if we're still in early boot. User agents are
1784 * supposed to resolve dependencies topside and include only the exact
1785 * kexts needed; so we always accept the new kext (in fact we should never
1786 * see an older unloaded copy hanging around).
1788 if (sUserLoadsActive
) {
1789 sKextsByID
->setObject(bundleID
, this);
1793 kOSKextLogStepLevel
|
1794 kOSKextLogKextBookkeepingFlag
,
1795 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
1796 getIdentifierCString(),
1797 existingVersionCString
,
1803 /* During early boot, the kext with the highest version always wins out.
1804 * Prelinked kernels will never hit this, but mkexts and booter-read
1805 * kexts might have duplicates.
1807 if (newVersion
> existingVersion
) {
1808 sKextsByID
->setObject(bundleID
, this);
1812 kOSKextLogStepLevel
|
1813 kOSKextLogKextBookkeepingFlag
,
1814 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
1815 existingVersionCString
,
1816 getIdentifierCString(),
1821 kOSKextLogStepLevel
|
1822 kOSKextLogKextBookkeepingFlag
,
1823 "Kext %s is already registered with a higher/same version (v%s); "
1824 "dropping newly-added (v%s).",
1825 getIdentifierCString(),
1826 existingVersionCString
,
1830 /* result has been set appropriately by now. */
1834 IORecursiveLockUnlock(sKextLock
);
1838 kOSKextLogStepLevel
|
1839 kOSKextLogKextBookkeepingFlag
,
1840 "Kext %s, v%s registered and available for loading.",
1841 getIdentifierCString(), newVersionCString
);
1844 OSSafeRelease(newUUID
);
1845 OSSafeRelease(existingUUID
);
1850 /*********************************************************************
1851 * Does the bare minimum validation to look up a kext.
1852 * All other validation is done on the spot as needed.
1853 **********************************************************************/
1855 OSKext::setInfoDictionaryAndPath(
1856 OSDictionary
* aDictionary
,
1859 bool result
= false;
1860 OSString
* bundleIDString
= NULL
; // do not release
1861 OSString
* versionString
= NULL
; // do not release
1862 OSString
* compatibleVersionString
= NULL
; // do not release
1863 const char * versionCString
= NULL
; // do not free
1864 const char * compatibleVersionCString
= NULL
; // do not free
1865 OSBoolean
* scratchBool
= NULL
; // do not release
1866 OSDictionary
* scratchDict
= NULL
; // do not release
1869 panic("Attempt to set info dictionary on a kext "
1870 "that already has one (%s).",
1871 getIdentifierCString());
1874 if (!aDictionary
|| !OSDynamicCast(OSDictionary
, aDictionary
)) {
1878 infoDict
= aDictionary
;
1881 /* Check right away if the info dictionary has any log flags.
1883 scratchBool
= OSDynamicCast(OSBoolean
,
1884 getPropertyForHostArch(kOSBundleEnableKextLoggingKey
));
1885 if (scratchBool
== kOSBooleanTrue
) {
1886 flags
.loggingEnabled
= 1;
1889 /* The very next thing to get is the bundle identifier. Unlike
1890 * in user space, a kext with no bundle identifier gets axed
1893 bundleIDString
= OSDynamicCast(OSString
,
1894 getPropertyForHostArch(kCFBundleIdentifierKey
));
1895 if (!bundleIDString
) {
1897 kOSKextLogErrorLevel
|
1898 kOSKextLogValidationFlag
,
1899 "CFBundleIdentifier missing/invalid type in kext %s.",
1900 aPath
? aPath
->getCStringNoCopy() : "(unknown)");
1903 bundleID
= OSSymbol::withString(bundleIDString
);
1906 kOSKextLogErrorLevel
|
1907 kOSKextLogValidationFlag
,
1908 "Can't copy bundle identifier as symbol for kext %s.",
1909 bundleIDString
->getCStringNoCopy());
1913 /* Save the path if we got one (it should always be available but it's
1914 * just something nice to have for bookkeeping).
1922 * Minimal validation to initialize. We'll do other validation on the spot.
1924 if (bundleID
->getLength() >= KMOD_MAX_NAME
) {
1926 kOSKextLogErrorLevel
|
1927 kOSKextLogValidationFlag
,
1928 "Kext %s error - CFBundleIdentifier over max length %d.",
1929 getIdentifierCString(), KMOD_MAX_NAME
- 1);
1933 version
= compatibleVersion
= -1;
1935 versionString
= OSDynamicCast(OSString
,
1936 getPropertyForHostArch(kCFBundleVersionKey
));
1937 if (!versionString
) {
1939 kOSKextLogErrorLevel
|
1940 kOSKextLogValidationFlag
,
1941 "Kext %s error - CFBundleVersion missing/invalid type.",
1942 getIdentifierCString());
1945 versionCString
= versionString
->getCStringNoCopy();
1946 version
= OSKextParseVersionString(versionCString
);
1949 kOSKextLogErrorLevel
|
1950 kOSKextLogValidationFlag
,
1951 "Kext %s error - CFBundleVersion bad value '%s'.",
1952 getIdentifierCString(), versionCString
);
1956 compatibleVersion
= -1; // set to illegal value for kexts that don't have
1958 compatibleVersionString
= OSDynamicCast(OSString
,
1959 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
1960 if (compatibleVersionString
) {
1961 compatibleVersionCString
= compatibleVersionString
->getCStringNoCopy();
1962 compatibleVersion
= OSKextParseVersionString(compatibleVersionCString
);
1963 if (compatibleVersion
< 0) {
1965 kOSKextLogErrorLevel
|
1966 kOSKextLogValidationFlag
,
1967 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
1968 getIdentifierCString(), compatibleVersionCString
);
1972 if (compatibleVersion
> version
) {
1974 kOSKextLogErrorLevel
|
1975 kOSKextLogValidationFlag
,
1976 "Kext %s error - %s %s > %s %s (must be <=).",
1977 getIdentifierCString(),
1978 kOSBundleCompatibleVersionKey
, compatibleVersionCString
,
1979 kCFBundleVersionKey
, versionCString
);
1984 /* Set flags for later use if the infoDict gets flushed. We only
1985 * check for true values, not false ones(!)
1987 scratchBool
= OSDynamicCast(OSBoolean
,
1988 getPropertyForHostArch(kOSBundleIsInterfaceKey
));
1989 if (scratchBool
== kOSBooleanTrue
) {
1990 flags
.interface
= 1;
1993 scratchBool
= OSDynamicCast(OSBoolean
,
1994 getPropertyForHostArch(kOSKernelResourceKey
));
1995 if (scratchBool
== kOSBooleanTrue
) {
1996 flags
.kernelComponent
= 1;
1997 flags
.interface
= 1; // xxx - hm. the kernel itself isn't an interface...
2000 /* A kernel component has one implicit dependency on the kernel.
2002 flags
.hasAllDependencies
= 1;
2005 /* Make sure common string values in personalities are uniqued to OSSymbols.
2007 scratchDict
= OSDynamicCast(OSDictionary
,
2008 getPropertyForHostArch(kIOKitPersonalitiesKey
));
2010 uniquePersonalityProperties(scratchDict
);
2020 /*********************************************************************
2021 * Not used for prelinked kernel boot as there is no unrelocated
2023 *********************************************************************/
2025 OSKext::setExecutable(
2026 OSData
* anExecutable
,
2027 OSData
* externalData
,
2028 bool externalDataIsMkext
)
2030 bool result
= false;
2031 const char * executableKey
= NULL
; // do not free
2033 if (!anExecutable
) {
2034 infoDict
->removeObject(_kOSKextExecutableKey
);
2035 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
2036 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
2041 if (infoDict
->getObject(_kOSKextExecutableKey
) ||
2042 infoDict
->getObject(_kOSKextMkextExecutableReferenceKey
)) {
2044 panic("Attempt to set an executable on a kext "
2045 "that already has one (%s).",
2046 getIdentifierCString());
2050 if (externalDataIsMkext
) {
2051 executableKey
= _kOSKextMkextExecutableReferenceKey
;
2053 executableKey
= _kOSKextExecutableKey
;
2057 infoDict
->setObject(executableKey
, anExecutable
);
2059 infoDict
->setObject(_kOSKextExecutableExternalDataKey
, externalData
);
2069 /*********************************************************************
2070 *********************************************************************/
2072 uniqueStringPlistProperty(OSDictionary
* dict
, const char * key
)
2074 OSString
* stringValue
= NULL
; // do not release
2075 const OSSymbol
* symbolValue
= NULL
; // must release
2077 stringValue
= OSDynamicCast(OSString
, dict
->getObject(key
));
2082 symbolValue
= OSSymbol::withString(stringValue
);
2087 dict
->setObject(key
, symbolValue
);
2090 if (symbolValue
) symbolValue
->release();
2095 /*********************************************************************
2096 *********************************************************************/
2098 uniqueStringPlistProperty(OSDictionary
* dict
, const OSString
* key
)
2100 OSString
* stringValue
= NULL
; // do not release
2101 const OSSymbol
* symbolValue
= NULL
; // must release
2103 stringValue
= OSDynamicCast(OSString
, dict
->getObject(key
));
2108 symbolValue
= OSSymbol::withString(stringValue
);
2113 dict
->setObject(key
, symbolValue
);
2116 if (symbolValue
) symbolValue
->release();
2121 /*********************************************************************
2122 * Replace common personality property values with uniqued instances
2123 * to save on wired memory.
2124 *********************************************************************/
2127 OSKext::uniquePersonalityProperties(OSDictionary
* personalityDict
)
2129 /* Properties every personality has.
2131 uniqueStringPlistProperty(personalityDict
, kCFBundleIdentifierKey
);
2132 uniqueStringPlistProperty(personalityDict
, kIOProviderClassKey
);
2133 uniqueStringPlistProperty(personalityDict
, gIOClassKey
);
2135 /* Other commonly used properties.
2137 uniqueStringPlistProperty(personalityDict
, gIOMatchCategoryKey
);
2138 uniqueStringPlistProperty(personalityDict
, gIOResourceMatchKey
);
2139 uniqueStringPlistProperty(personalityDict
, gIOUserClientClassKey
);
2141 uniqueStringPlistProperty(personalityDict
, "HIDDefaultBehavior");
2142 uniqueStringPlistProperty(personalityDict
, "HIDPointerAccelerationType");
2143 uniqueStringPlistProperty(personalityDict
, "HIDRemoteControlType");
2144 uniqueStringPlistProperty(personalityDict
, "HIDScrollAccelerationType");
2145 uniqueStringPlistProperty(personalityDict
, "IOPersonalityPublisher");
2146 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect");
2147 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect Location");
2148 uniqueStringPlistProperty(personalityDict
, "Vendor");
2149 uniqueStringPlistProperty(personalityDict
, "Vendor Identification");
2150 uniqueStringPlistProperty(personalityDict
, "Vendor Name");
2151 uniqueStringPlistProperty(personalityDict
, "bConfigurationValue");
2152 uniqueStringPlistProperty(personalityDict
, "bInterfaceNumber");
2153 uniqueStringPlistProperty(personalityDict
, "idProduct");
2158 /*********************************************************************
2159 *********************************************************************/
2164 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2167 OSSafeRelease(infoDict
);
2168 OSSafeRelease(bundleID
);
2169 OSSafeRelease(path
);
2170 OSSafeRelease(executableRelPath
);
2171 OSSafeRelease(dependencies
);
2172 OSSafeRelease(linkedExecutable
);
2173 OSSafeRelease(metaClasses
);
2174 OSSafeRelease(interfaceUUID
);
2176 if (isInterface() && kmod_info
) {
2177 kfree(kmod_info
, sizeof(kmod_info_t
));
2185 #pragma mark Mkext files
2187 /*********************************************************************
2188 *********************************************************************/
2190 OSKext::readMkextArchive(OSData
* mkextData
,
2191 uint32_t * checksumPtr
)
2193 OSReturn result
= kOSKextReturnBadData
;
2194 uint32_t mkextLength
= 0;
2195 mkext_header
* mkextHeader
= 0; // do not free
2196 uint32_t mkextVersion
= 0;
2198 /* Note default return of kOSKextReturnBadData above.
2200 mkextLength
= mkextData
->getLength();
2201 if (mkextLength
< sizeof(mkext_basic_header
)) {
2202 OSKextLog(/* kext */ NULL
,
2203 kOSKextLogErrorLevel
|
2204 kOSKextLogArchiveFlag
,
2205 "Mkext archive too small to be valid.");
2209 mkextHeader
= (mkext_header
*)mkextData
->getBytesNoCopy();
2211 if (MKEXT_GET_MAGIC(mkextHeader
) != MKEXT_MAGIC
||
2212 MKEXT_GET_SIGNATURE(mkextHeader
) != MKEXT_SIGN
) {
2213 OSKextLog(/* kext */ NULL
,
2214 kOSKextLogErrorLevel
|
2215 kOSKextLogArchiveFlag
,
2216 "Mkext archive has invalid magic or signature.");
2220 if (MKEXT_GET_LENGTH(mkextHeader
) != mkextLength
) {
2221 OSKextLog(/* kext */ NULL
,
2222 kOSKextLogErrorLevel
|
2223 kOSKextLogArchiveFlag
,
2224 "Mkext archive recorded length doesn't match actual file length.");
2228 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2230 if (mkextVersion
== MKEXT_VERS_2
) {
2231 result
= OSKext::readMkext2Archive(mkextData
, NULL
, checksumPtr
);
2232 } else if (mkextVersion
== MKEXT_VERS_1
) {
2233 result
= OSKext::readMkext1Archive(mkextData
, checksumPtr
);
2235 OSKextLog(/* kext */ NULL
,
2236 kOSKextLogErrorLevel
|
2237 kOSKextLogArchiveFlag
,
2238 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion
);
2239 result
= kOSKextReturnUnsupported
;
2246 /*********************************************************************
2247 * Assumes magic, signature, version, length have been checked.
2249 * Doesn't do as much bounds-checking as it should, but we're dropping
2250 * mkext1 support from the kernel for SnowLeopard soon.
2252 * Should keep track of all kexts created so far, and if we hit a
2253 * fatal error halfway through, remove those kexts. If we've dropped
2254 * an older version that had already been read, whoops! Might want to
2255 * add a level of buffering?
2256 *********************************************************************/
2259 OSKext::readMkext1Archive(
2261 uint32_t * checksumPtr
)
2263 OSReturn result
= kOSReturnError
;
2264 uint32_t mkextLength
;
2265 mkext1_header
* mkextHeader
= 0; // do not free
2266 void * mkextEnd
= 0; // do not free
2267 uint32_t mkextVersion
;
2268 uint8_t * crc_address
= 0;
2270 uint32_t numKexts
= 0;
2272 OSData
* infoDictDataObject
= NULL
; // must release
2273 OSObject
* parsedXML
= NULL
; // must release
2274 OSDictionary
* infoDict
= NULL
; // do not release
2275 OSString
* errorString
= NULL
; // must release
2276 OSData
* mkextExecutableInfo
= NULL
; // must release
2277 OSKext
* theKext
= NULL
; // must release
2279 mkextLength
= mkextData
->getLength();
2280 mkextHeader
= (mkext1_header
*)mkextData
->getBytesNoCopy();
2281 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2282 mkextVersion
= OSSwapBigToHostInt32(mkextHeader
->version
);
2284 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
2285 checksum
= mkext_adler32(crc_address
,
2286 (uintptr_t)mkextHeader
+
2287 OSSwapBigToHostInt32(mkextHeader
->length
) - (uintptr_t)crc_address
);
2289 if (OSSwapBigToHostInt32(mkextHeader
->adler32
) != checksum
) {
2290 OSKextLog(/* kext */ NULL
,
2291 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2292 "Kext archive has a bad checksum.");
2293 result
= kOSKextReturnBadData
;
2298 *checksumPtr
= checksum
;
2301 /* Check that the CPU type & subtype match that of the running kernel. */
2302 if (OSSwapBigToHostInt32(mkextHeader
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
2303 if ((UInt32
)_mh_execute_header
.cputype
!=
2304 OSSwapBigToHostInt32(mkextHeader
->cputype
)) {
2306 OSKextLog(/* kext */ NULL
,
2307 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2308 "Kext archive doesn't contain software "
2309 "for this computer's CPU type.");
2310 result
= kOSKextReturnArchNotFound
;
2315 numKexts
= OSSwapBigToHostInt32(mkextHeader
->numkexts
);
2317 for (uint32_t i
= 0; i
< numKexts
; i
++) {
2319 OSSafeReleaseNULL(infoDictDataObject
);
2320 OSSafeReleaseNULL(infoDict
);
2321 OSSafeReleaseNULL(mkextExecutableInfo
);
2322 OSSafeReleaseNULL(errorString
);
2323 OSSafeReleaseNULL(theKext
);
2325 mkext_kext
* kextEntry
= &mkextHeader
->kext
[i
];
2326 mkext_file
* infoDictPtr
= &kextEntry
->plist
;
2327 mkext_file
* executablePtr
= &kextEntry
->module;
2328 if (kextEntry
>= mkextEnd
) {
2329 OSKextLog(/* kext */ NULL
,
2330 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2331 "Mkext file overrun.");
2332 result
= kOSKextReturnBadData
;
2336 /* Note that we're pretty tolerant of errors in individual entries.
2337 * As long as we can keep processing, we do.
2339 infoDictDataObject
= OSKext::extractMkext1Entry(
2340 mkextHeader
, infoDictPtr
);
2341 if (!infoDictDataObject
) {
2342 OSKextLog(/* kext */ NULL
,
2343 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2344 "Can't uncompress info dictionary "
2345 "from mkext archive entry %d.", i
);
2349 parsedXML
= OSUnserializeXML(
2350 (const char *)infoDictDataObject
->getBytesNoCopy(),
2353 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
2356 const char * errorCString
= "(unknown error)";
2358 if (errorString
&& errorString
->getCStringNoCopy()) {
2359 errorCString
= errorString
->getCStringNoCopy();
2360 } else if (parsedXML
) {
2361 errorCString
= "not a dictionary";
2363 OSKextLog(/* kext */ NULL
,
2364 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2365 "Error: Can't read XML property list "
2366 "for mkext archive entry %d: %s.", i
, errorCString
);
2370 theKext
= new OSKext
;
2372 OSKextLog(/* kext */ NULL
,
2373 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2374 "Kext allocation failure.");
2379 * Prepare an entry to hold the mkext entry info for the
2380 * compressed binary module, if there is one. If all four fields
2381 * of the module entry are zero, there isn't one.
2383 if ((OSSwapBigToHostInt32(executablePtr
->offset
) ||
2384 OSSwapBigToHostInt32(executablePtr
->compsize
) ||
2385 OSSwapBigToHostInt32(executablePtr
->realsize
) ||
2386 OSSwapBigToHostInt32(executablePtr
->modifiedsecs
))) {
2388 MkextEntryRef entryRef
;
2390 mkextExecutableInfo
= OSData::withCapacity(sizeof(entryRef
));
2391 if (!mkextExecutableInfo
) {
2392 panic("Error: Couldn't allocate data object "
2393 "for mkext archive entry %d.\n", i
);
2396 entryRef
.mkext
= (mkext_basic_header
*)mkextHeader
;
2397 entryRef
.fileinfo
= (uint8_t *)executablePtr
;
2398 if (!mkextExecutableInfo
->appendBytes(&entryRef
,
2399 sizeof(entryRef
))) {
2401 OSKextLog(/* kext */ NULL
,
2402 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2403 "Couldn't record executable info "
2404 "for mkext archive entry %d.", i
);
2405 // we might hit a load error later but oh well
2406 // xxx - should probably remove theKext
2412 /* Init can fail because of a data/runtime error, or because the
2413 * kext is a dup. Either way, we don't care here.
2415 if (!theKext
->initWithMkext1Info(infoDict
, mkextExecutableInfo
,
2418 // theKext is released at the top of the loop or in the finish block
2422 /* If we got even one kext out of the mkext archive,
2423 * we have successfully read the archive, in that we
2424 * have data references into its mapped memory.
2426 result
= kOSReturnSuccess
;
2431 OSSafeRelease(infoDictDataObject
);
2432 OSSafeRelease(parsedXML
);
2433 OSSafeRelease(errorString
);
2434 OSSafeRelease(mkextExecutableInfo
);
2435 OSSafeRelease(theKext
);
2440 /*********************************************************************
2441 *********************************************************************/
2443 OSKext::initWithMkext1Info(
2444 OSDictionary
* anInfoDict
,
2445 OSData
* executableWrapper
,
2448 bool result
= false;
2450 // mkext1 doesn't allow for path (might stuff in info dict)
2451 if (!setInfoDictionaryAndPath(anInfoDict
, /* path */ NULL
)) {
2455 if (!registerIdentifier()) {
2459 if (!setExecutable(executableWrapper
, mkextData
, true)) {
2467 /* If we can't init, remove the kext from the lookup dictionary.
2468 * This is safe to call in init because there's an implicit retain.
2471 OSKext::removeKext(this, /* removePersonalities? */ false);
2477 /*********************************************************************
2478 * xxx - this should take the input data length
2479 *********************************************************************/
2482 OSKext::extractMkext1Entry(
2483 const void * mkextFileBase
,
2486 OSData
* result
= NULL
;
2487 OSData
* uncompressedData
= NULL
; // release on error
2488 const char * errmsg
= NULL
;
2490 mkext_file
* fileinfo
;
2491 uint8_t * uncompressedDataBuffer
= 0; // do not free (panic on alloc. fail)
2492 size_t uncompressed_size
= 0;
2493 kern_return_t kern_result
;
2495 fileinfo
= (mkext_file
*)entry
;
2497 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
2498 size_t compressed_size
= OSSwapBigToHostInt32(fileinfo
->compsize
);
2499 size_t expected_size
= OSSwapBigToHostInt32(fileinfo
->realsize
);
2501 // Add 1 for '\0' to terminate XML string (for plists)
2502 // (we really should have the archive format include that).
2503 size_t alloc_size
= expected_size
+ 1;
2504 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
2506 /* If these four fields are zero there's no file, but it's up to
2507 * the calling context to decide if that's an error.
2509 if (offset
== 0 && compressed_size
== 0 &&
2510 expected_size
== 0 && modifiedsecs
== 0) {
2514 kern_result
= kmem_alloc(kernel_map
,
2515 (vm_offset_t
*)&uncompressedDataBuffer
,
2517 if (kern_result
!= KERN_SUCCESS
) {
2522 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
,
2524 if (uncompressedData
== NULL
) {
2525 /* No need to free uncompressedDataBuffer here, either. */
2529 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
2531 /* Do the decompression if necessary. Note that even if the file isn't
2532 * compressed, we want to make a copy so that we don't have the tie to
2533 * the larger mkext file buffer any more.
2534 * xxx - need to detect decompression overflow too
2536 if (compressed_size
!= 0) {
2537 errmsg
= "OSKext::uncompressMkext - "
2538 "uncompressed file shorter than expected";
2539 uncompressed_size
= decompress_lzss(uncompressedDataBuffer
,
2541 ((uint8_t *)mkextFileBase
) + offset
,
2543 if (uncompressed_size
!= expected_size
) {
2547 memcpy(uncompressedDataBuffer
,
2548 ((uint8_t *)mkextFileBase
) + offset
,
2552 // Add a terminating nul character in case the data is XML.
2553 // (we really should have the archive format include that).
2554 uncompressedDataBuffer
[expected_size
] = '\0';
2556 result
= uncompressedData
;
2561 OSKextLog(/* kext */ NULL
,
2562 kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
2565 if (uncompressedData
) {
2566 uncompressedData
->release();
2572 /*********************************************************************
2573 * Assumes magic, signature, version, length have been checked.
2574 * xxx - need to add further bounds checking for each file entry
2576 * Should keep track of all kexts created so far, and if we hit a
2577 * fatal error halfway through, remove those kexts. If we've dropped
2578 * an older version that had already been read, whoops! Might want to
2579 * add a level of buffering?
2580 *********************************************************************/
2583 OSKext::readMkext2Archive(
2585 OSDictionary
** mkextPlistOut
,
2586 uint32_t * checksumPtr
)
2588 OSReturn result
= kOSReturnError
;
2589 uint32_t mkextLength
;
2590 mkext2_header
* mkextHeader
= NULL
; // do not free
2591 void * mkextEnd
= NULL
; // do not free
2592 uint32_t mkextVersion
;
2593 uint8_t * crc_address
= NULL
;
2595 uint32_t mkextPlistOffset
;
2596 uint32_t mkextPlistCompressedSize
;
2597 char * mkextPlistEnd
= NULL
; // do not free
2598 uint32_t mkextPlistFullSize
;
2599 OSString
* errorString
= NULL
; // must release
2600 OSData
* mkextPlistUncompressedData
= NULL
; // must release
2601 const char * mkextPlistDataBuffer
= NULL
; // do not free
2602 OSObject
* parsedXML
= NULL
; // must release
2603 OSDictionary
* mkextPlist
= NULL
; // do not release
2604 OSArray
* mkextInfoDictArray
= NULL
; // do not release
2607 mkextLength
= mkextData
->getLength();
2608 mkextHeader
= (mkext2_header
*)mkextData
->getBytesNoCopy();
2609 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2610 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2612 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
2613 checksum
= mkext_adler32(crc_address
,
2614 (uintptr_t)mkextHeader
+
2615 MKEXT_GET_LENGTH(mkextHeader
) - (uintptr_t)crc_address
);
2617 if (MKEXT_GET_CHECKSUM(mkextHeader
) != checksum
) {
2618 OSKextLog(/* kext */ NULL
,
2619 kOSKextLogErrorLevel
|
2620 kOSKextLogArchiveFlag
,
2621 "Mkext archive has bad checksum.");
2622 result
= kOSKextReturnBadData
;
2627 *checksumPtr
= checksum
;
2630 /* Check that the CPU type & subtype match that of the running kernel. */
2631 if (MKEXT_GET_CPUTYPE(mkextHeader
) == (UInt32
)CPU_TYPE_ANY
) {
2632 OSKextLog(/* kext */ NULL
,
2633 kOSKextLogErrorLevel
|
2634 kOSKextLogArchiveFlag
,
2635 "Mkext archive must have a specific CPU type.");
2636 result
= kOSKextReturnBadData
;
2639 if ((UInt32
)_mh_execute_header
.cputype
!=
2640 MKEXT_GET_CPUTYPE(mkextHeader
)) {
2642 OSKextLog(/* kext */ NULL
,
2643 kOSKextLogErrorLevel
|
2644 kOSKextLogArchiveFlag
,
2645 "Mkext archive does not match the running kernel's CPU type.");
2646 result
= kOSKextReturnArchNotFound
;
2651 mkextPlistOffset
= MKEXT2_GET_PLIST(mkextHeader
);
2652 mkextPlistCompressedSize
= MKEXT2_GET_PLIST_COMPSIZE(mkextHeader
);
2653 mkextPlistEnd
= (char *)mkextHeader
+ mkextPlistOffset
+
2654 mkextPlistCompressedSize
;
2655 if (mkextPlistEnd
> mkextEnd
) {
2656 OSKextLog(/* kext */ NULL
,
2657 kOSKextLogErrorLevel
|
2658 kOSKextLogArchiveFlag
,
2659 "Mkext archive file overrun.");
2660 result
= kOSKextReturnBadData
;
2663 mkextPlistFullSize
= MKEXT2_GET_PLIST_FULLSIZE(mkextHeader
);
2664 if (mkextPlistCompressedSize
) {
2665 mkextPlistUncompressedData
= sKernelKext
->extractMkext2FileData(
2666 (UInt8
*)mkextHeader
+ mkextPlistOffset
,
2668 mkextPlistCompressedSize
, mkextPlistFullSize
);
2669 if (!mkextPlistUncompressedData
) {
2672 mkextPlistDataBuffer
= (const char *)
2673 mkextPlistUncompressedData
->getBytesNoCopy();
2675 mkextPlistDataBuffer
= (const char *)mkextHeader
+ mkextPlistOffset
;
2678 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
2680 parsedXML
= OSUnserializeXML(mkextPlistDataBuffer
, &errorString
);
2682 mkextPlist
= OSDynamicCast(OSDictionary
, parsedXML
);
2685 const char * errorCString
= "(unknown error)";
2687 if (errorString
&& errorString
->getCStringNoCopy()) {
2688 errorCString
= errorString
->getCStringNoCopy();
2689 } else if (parsedXML
) {
2690 errorCString
= "not a dictionary";
2692 OSKextLog(/* kext */ NULL
,
2693 kOSKextLogErrorLevel
|
2694 kOSKextLogArchiveFlag
,
2695 "Error unserializing mkext plist: %s.", errorCString
);
2699 /* If the caller needs the plist, hand it back and retain it.
2700 * (This function releases it at the end.)
2702 if (mkextPlistOut
) {
2703 *mkextPlistOut
= mkextPlist
;
2704 (*mkextPlistOut
)->retain();
2707 mkextInfoDictArray
= OSDynamicCast(OSArray
,
2708 mkextPlist
->getObject(kMKEXTInfoDictionariesKey
));
2709 if (!mkextInfoDictArray
) {
2710 OSKextLog(/* kext */ NULL
,
2711 kOSKextLogErrorLevel
|
2712 kOSKextLogArchiveFlag
,
2713 "Mkext archive contains no kext info dictionaries.");
2717 count
= mkextInfoDictArray
->getCount();
2718 for (i
= 0; i
< count
; i
++) {
2719 OSDictionary
* infoDict
;
2722 infoDict
= OSDynamicCast(OSDictionary
,
2723 mkextInfoDictArray
->getObject(i
));
2725 /* Create the kext for the entry, then release it, because the
2726 * kext system keeps them around until explicitly removed.
2727 * Any creation/registration failures are already logged for us.
2729 OSKext
* newKext
= OSKext::withMkext2Info(infoDict
, mkextData
);
2730 OSSafeRelease(newKext
);
2733 /* Even if we didn't keep any kexts from the mkext, we may have a load
2734 * request to process, so we are successful (no errors occurred).
2736 result
= kOSReturnSuccess
;
2740 OSSafeRelease(parsedXML
);
2741 OSSafeRelease(mkextPlistUncompressedData
);
2742 OSSafeRelease(errorString
);
2747 /*********************************************************************
2748 *********************************************************************/
2751 OSKext::withMkext2Info(
2752 OSDictionary
* anInfoDict
,
2755 OSKext
* newKext
= new OSKext
;
2757 if (newKext
&& !newKext
->initWithMkext2Info(anInfoDict
, mkextData
)) {
2765 /*********************************************************************
2766 *********************************************************************/
2768 OSKext::initWithMkext2Info(
2769 OSDictionary
* anInfoDict
,
2772 bool result
= false;
2773 OSString
* kextPath
= NULL
; // do not release
2774 OSNumber
* executableOffsetNum
= NULL
; // do not release
2775 OSCollectionIterator
* iterator
= NULL
; // must release
2776 OSData
* executable
= NULL
; // must release
2778 if (!super::init()) {
2782 /* Get the path. Don't look for an arch-specific path property.
2784 kextPath
= OSDynamicCast(OSString
,
2785 anInfoDict
->getObject(kMKEXTBundlePathKey
));
2787 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
2791 /* If we have a path to the executable, save it.
2793 executableRelPath
= OSDynamicCast(OSString
,
2794 anInfoDict
->getObject(kMKEXTExecutableRelativePathKey
));
2795 if (executableRelPath
) {
2796 executableRelPath
->retain();
2799 /* Don't need the paths to be in the info dictionary any more.
2801 anInfoDict
->removeObject(kMKEXTBundlePathKey
);
2802 anInfoDict
->removeObject(kMKEXTExecutableRelativePathKey
);
2804 executableOffsetNum
= OSDynamicCast(OSNumber
,
2805 infoDict
->getObject(kMKEXTExecutableKey
));
2806 if (executableOffsetNum
) {
2807 executable
= createMkext2FileEntry(mkextData
,
2808 executableOffsetNum
, "executable");
2809 infoDict
->removeObject(kMKEXTExecutableKey
);
2813 if (!setExecutable(executable
, mkextData
, true)) {
2818 result
= registerIdentifier();
2822 OSSafeRelease(executable
);
2823 OSSafeRelease(iterator
);
2827 /*********************************************************************
2828 *********************************************************************/
2830 OSKext::createMkext2FileEntry(
2832 OSNumber
* offsetNum
,
2835 OSData
* result
= NULL
;
2836 MkextEntryRef entryRef
;
2837 uint8_t * mkextBuffer
= (uint8_t *)mkextData
->getBytesNoCopy();
2838 uint32_t entryOffset
= offsetNum
->unsigned32BitValue();
2840 result
= OSData::withCapacity(sizeof(entryRef
));
2845 entryRef
.mkext
= (mkext_basic_header
*)mkextBuffer
;
2846 entryRef
.fileinfo
= mkextBuffer
+ entryOffset
;
2847 if (!result
->appendBytes(&entryRef
, sizeof(entryRef
))) {
2848 OSSafeReleaseNULL(result
);
2855 kOSKextLogErrorLevel
|
2856 kOSKextLogArchiveFlag
,
2857 "Can't create wrapper for mkext file entry '%s' of kext %s.",
2858 name
, getIdentifierCString());
2863 /*********************************************************************
2864 *********************************************************************/
2866 static void * z_alloc(void *, u_int items
, u_int size
);
2867 static void z_free(void *, void *ptr
);
2869 typedef struct z_mem
{
2870 uint32_t alloc_size
;
2875 * Space allocation and freeing routines for use by zlib routines.
2878 z_alloc(void * notused __unused
, u_int num_items
, u_int size
)
2880 void * result
= NULL
;
2881 z_mem
* zmem
= NULL
;
2882 uint32_t total
= num_items
* size
;
2883 uint32_t allocSize
= total
+ sizeof(zmem
);
2885 zmem
= (z_mem
*)kalloc(allocSize
);
2889 zmem
->alloc_size
= allocSize
;
2890 result
= (void *)&(zmem
->data
);
2896 z_free(void * notused __unused
, void * ptr
)
2898 uint32_t * skipper
= (uint32_t *)ptr
- 1;
2899 z_mem
* zmem
= (z_mem
*)skipper
;
2900 kfree((void *)zmem
, zmem
->alloc_size
);
2906 OSKext::extractMkext2FileData(
2909 uint32_t compressedSize
,
2912 OSData
* result
= NULL
;
2914 OSData
* uncompressedData
= NULL
; // release on error
2916 uint8_t * uncompressedDataBuffer
= 0; // do not free
2917 unsigned long uncompressedSize
;
2919 bool zstream_inited
= false;
2922 /* If the file isn't compressed, we want to make a copy
2923 * so that we don't have the tie to the larger mkext file buffer any more.
2925 if (!compressedSize
) {
2926 uncompressedData
= OSData::withBytes(data
, fullSize
);
2927 // xxx - no check for failure?
2928 result
= uncompressedData
;
2932 if (KERN_SUCCESS
!= kmem_alloc(kernel_map
,
2933 (vm_offset_t
*)&uncompressedDataBuffer
, fullSize
)) {
2935 /* How's this for cheesy? The kernel is only asked to extract
2936 * kext plists so we tailor the log messages.
2940 kOSKextLogErrorLevel
|
2941 kOSKextLogArchiveFlag
,
2942 "Allocation failure extracting %s from mkext.", name
);
2945 kOSKextLogErrorLevel
|
2946 kOSKextLogArchiveFlag
,
2947 "Allocation failure extracting %s from mkext for kext %s.",
2948 name
, getIdentifierCString());
2953 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
, fullSize
);
2954 if (!uncompressedData
) {
2957 kOSKextLogErrorLevel
|
2958 kOSKextLogArchiveFlag
,
2959 "Allocation failure extracting %s from mkext.", name
);
2962 kOSKextLogErrorLevel
|
2963 kOSKextLogArchiveFlag
,
2964 "Allocation failure extracting %s from mkext for kext %s.",
2965 name
, getIdentifierCString());
2969 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
2973 kOSKextLogDetailLevel
|
2974 kOSKextLogArchiveFlag
,
2975 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
2976 name
, compressedSize
, fullSize
);
2979 kOSKextLogDetailLevel
|
2980 kOSKextLogArchiveFlag
,
2981 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
2982 getIdentifierCString(), name
, compressedSize
, fullSize
);
2985 bzero(&zstream
, sizeof(zstream
));
2986 zstream
.next_in
= (UInt8
*)data
;
2987 zstream
.avail_in
= compressedSize
;
2989 zstream
.next_out
= uncompressedDataBuffer
;
2990 zstream
.avail_out
= fullSize
;
2992 zstream
.zalloc
= z_alloc
;
2993 zstream
.zfree
= z_free
;
2995 zlib_result
= inflateInit(&zstream
);
2996 if (Z_OK
!= zlib_result
) {
2999 kOSKextLogErrorLevel
|
3000 kOSKextLogArchiveFlag
,
3001 "Mkext error; zlib inflateInit failed (%d) for %s.",
3005 kOSKextLogErrorLevel
|
3006 kOSKextLogArchiveFlag
,
3007 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3008 getIdentifierCString(), zlib_result
, name
);
3012 zstream_inited
= true;
3015 zlib_result
= inflate(&zstream
, Z_FINISH
);
3017 if (zlib_result
== Z_STREAM_END
|| zlib_result
== Z_OK
) {
3018 uncompressedSize
= zstream
.total_out
;
3022 kOSKextLogErrorLevel
|
3023 kOSKextLogArchiveFlag
,
3024 "Mkext error; zlib inflate failed (%d) for %s.",
3028 kOSKextLogErrorLevel
|
3029 kOSKextLogArchiveFlag
,
3030 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3031 getIdentifierCString(), zlib_result
, name
);
3035 kOSKextLogErrorLevel
|
3036 kOSKextLogArchiveFlag
,
3037 "zlib error: %s.", zstream
.msg
);
3042 if (uncompressedSize
!= fullSize
) {
3045 kOSKextLogErrorLevel
|
3046 kOSKextLogArchiveFlag
,
3047 "Mkext error; zlib inflate discrepancy for %s, "
3048 "uncompressed size != original size.", name
);
3051 kOSKextLogErrorLevel
|
3052 kOSKextLogArchiveFlag
,
3053 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3054 "uncompressed size != original size.",
3055 getIdentifierCString(), name
);
3060 result
= uncompressedData
;
3063 /* Don't bother checking return, nothing we can do on fail.
3065 if (zstream_inited
) inflateEnd(&zstream
);
3068 OSSafeRelease(uncompressedData
);
3074 /*********************************************************************
3075 *********************************************************************/
3078 OSKext::loadFromMkext(
3079 OSKextLogSpec clientLogFilter
,
3081 uint32_t mkextBufferLength
,
3083 uint32_t * logInfoLengthOut
)
3085 OSReturn result
= kOSReturnError
;
3086 OSReturn tempResult
= kOSReturnError
;
3088 OSData
* mkextData
= NULL
; // must release
3089 OSDictionary
* mkextPlist
= NULL
; // must release
3091 OSArray
* logInfoArray
= NULL
; // must release
3092 OSSerialize
* serializer
= NULL
; // must release
3094 OSString
* predicate
= NULL
; // do not release
3095 OSDictionary
* requestArgs
= NULL
; // do not release
3097 OSString
* kextIdentifier
= NULL
; // do not release
3098 OSNumber
* startKextExcludeNum
= NULL
; // do not release
3099 OSNumber
* startMatchingExcludeNum
= NULL
; // do not release
3100 OSBoolean
* delayAutounloadBool
= NULL
; // do not release
3101 OSArray
* personalityNames
= NULL
; // do not release
3103 /* Default values for these two options: regular autounload behavior,
3104 * load all kexts, send no personalities.
3106 Boolean delayAutounload
= false;
3107 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
3108 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeAll
;
3110 IORecursiveLockLock(sKextLock
);
3114 *logInfoLengthOut
= 0;
3117 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
3119 OSKextLog(/* kext */ NULL
,
3120 kOSKextLogDebugLevel
|
3122 "Received kext load request from user space.");
3124 /* Regardless of processing, the fact that we have gotten here means some
3125 * user-space program is up and talking to us, so we'll switch our kext
3126 * registration to reflect that.
3128 if (!sUserLoadsActive
) {
3129 OSKextLog(/* kext */ NULL
,
3130 kOSKextLogProgressLevel
|
3131 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
3132 "Switching to late startup (user-space) kext loading policy.");
3134 sUserLoadsActive
= true;
3137 if (!sLoadEnabled
) {
3138 OSKextLog(/* kext */ NULL
,
3139 kOSKextLogErrorLevel
|
3141 "Kext loading is disabled.");
3142 result
= kOSKextReturnDisabled
;
3146 /* Note that we do not set a dealloc function on this OSData
3147 * object! No references to it can remain after the loadFromMkext()
3148 * call since we are in a MIG function, and will vm_deallocate()
3151 mkextData
= OSData::withBytesNoCopy(mkextBuffer
,
3154 OSKextLog(/* kext */ NULL
,
3155 kOSKextLogErrorLevel
|
3156 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3157 "Failed to create wrapper for kext load request.");
3158 result
= kOSKextReturnNoMemory
;
3162 result
= readMkext2Archive(mkextData
, &mkextPlist
, NULL
);
3163 if (result
!= kOSReturnSuccess
) {
3164 OSKextLog(/* kext */ NULL
,
3165 kOSKextLogErrorLevel
|
3167 "Failed to read kext load request.");
3171 predicate
= _OSKextGetRequestPredicate(mkextPlist
);
3172 if (!predicate
|| !predicate
->isEqualTo(kKextRequestPredicateLoad
)) {
3173 OSKextLog(/* kext */ NULL
,
3174 kOSKextLogErrorLevel
|
3176 "Received kext load request with no predicate; skipping.");
3177 result
= kOSKextReturnInvalidArgument
;
3181 requestArgs
= OSDynamicCast(OSDictionary
,
3182 mkextPlist
->getObject(kKextRequestArgumentsKey
));
3183 if (!requestArgs
|| !requestArgs
->getCount()) {
3184 OSKextLog(/* kext */ NULL
,
3185 kOSKextLogErrorLevel
|
3187 "Received kext load request with no arguments.");
3188 result
= kOSKextReturnInvalidArgument
;
3192 kextIdentifier
= OSDynamicCast(OSString
,
3193 requestArgs
->getObject(kKextRequestArgumentBundleIdentifierKey
));
3194 if (!kextIdentifier
) {
3195 OSKextLog(/* kext */ NULL
,
3196 kOSKextLogErrorLevel
|
3198 "Received kext load request with no kext identifier.");
3199 result
= kOSKextReturnInvalidArgument
;
3203 startKextExcludeNum
= OSDynamicCast(OSNumber
,
3204 requestArgs
->getObject(kKextRequestArgumentStartExcludeKey
));
3205 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
3206 requestArgs
->getObject(kKextRequestArgumentStartMatchingExcludeKey
));
3207 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
3208 requestArgs
->getObject(kKextRequestArgumentDelayAutounloadKey
));
3209 personalityNames
= OSDynamicCast(OSArray
,
3210 requestArgs
->getObject(kKextRequestArgumentPersonalityNamesKey
));
3212 if (delayAutounloadBool
) {
3213 delayAutounload
= delayAutounloadBool
->getValue();
3215 if (startKextExcludeNum
) {
3216 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
3218 if (startMatchingExcludeNum
) {
3219 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
3222 OSKextLog(/* kext */ NULL
,
3223 kOSKextLogProgressLevel
|
3225 "Received request from user space to load kext %s.",
3226 kextIdentifier
->getCStringNoCopy());
3228 /* Load the kext, with no deferral, since this is a load from outside
3230 * xxx - Would like a better way to handle the default values for the
3231 * xxx - start/match opt args.
3233 result
= OSKext::loadKextWithIdentifier(
3235 /* allowDefer */ false,
3237 startKextExcludeLevel
,
3238 startMatchingExcludeLevel
,
3240 if (result
!= kOSReturnSuccess
) {
3243 /* If the load came down from kextd, it will shortly inform IOCatalogue
3244 * for matching via a separate IOKit calldown.
3249 /* Gather up the collected log messages for user space. Any
3250 * error messages past this call will not make it up as log messages
3251 * but will be in the system log.
3253 logInfoArray
= OSKext::clearUserSpaceLogFilter();
3255 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
3256 tempResult
= OSKext::serializeLogInfo(logInfoArray
,
3257 logInfoOut
, logInfoLengthOut
);
3258 if (tempResult
!= kOSReturnSuccess
) {
3259 result
= tempResult
;
3263 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3265 /* Note: mkextDataObject will have been retained by every kext w/an
3266 * executable in it. That should all have been flushed out at the
3267 * and of the load operation, but you never know....
3269 if (mkextData
&& mkextData
->getRetainCount() > 1) {
3270 OSKextLog(/* kext */ NULL
,
3271 kOSKextLogErrorLevel
|
3272 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3273 "Kext load request buffer from user space still retained by a kext; "
3274 "probable memory leak.");
3277 IORecursiveLockUnlock(sKextLock
);
3279 OSSafeRelease(mkextData
);
3280 OSSafeRelease(mkextPlist
);
3281 OSSafeRelease(serializer
);
3282 OSSafeRelease(logInfoArray
);
3287 /*********************************************************************
3288 *********************************************************************/
3291 OSKext::serializeLogInfo(
3292 OSArray
* logInfoArray
,
3294 uint32_t * logInfoLengthOut
)
3296 OSReturn result
= kOSReturnError
;
3297 char * buffer
= NULL
;
3298 kern_return_t kmem_result
= KERN_FAILURE
;
3299 OSSerialize
* serializer
= NULL
; // must release; reused
3300 char * logInfo
= NULL
; // returned by reference
3301 uint32_t logInfoLength
= 0;
3303 if (!logInfoArray
|| !logInfoOut
|| !logInfoLengthOut
) {
3304 OSKextLog(/* kext */ NULL
,
3305 kOSKextLogErrorLevel
|
3307 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3308 /* Bad programmer. */
3309 result
= kOSKextReturnInvalidArgument
;
3313 serializer
= OSSerialize::withCapacity(0);
3315 OSKextLog(/* kext */ NULL
,
3316 kOSKextLogErrorLevel
|
3318 "Failed to create serializer on log info for request from user space.");
3319 /* Incidental error; we're going to (try to) allow the request
3320 * itself to succeed. */
3323 if (!logInfoArray
->serialize(serializer
)) {
3324 OSKextLog(/* kext */ NULL
,
3325 kOSKextLogErrorLevel
|
3327 "Failed to serialize log info for request from user space.");
3328 /* Incidental error; we're going to (try to) allow the request
3329 * itself to succeed. */
3331 logInfo
= serializer
->text();
3332 logInfoLength
= serializer
->getLength();
3334 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
, logInfoLength
);
3335 if (kmem_result
!= KERN_SUCCESS
) {
3336 OSKextLog(/* kext */ NULL
,
3337 kOSKextLogErrorLevel
|
3339 "Failed to copy log info for request from user space.");
3340 /* Incidental error; we're going to (try to) allow the request
3343 memcpy(buffer
, logInfo
, logInfoLength
);
3344 *logInfoOut
= buffer
;
3345 *logInfoLengthOut
= logInfoLength
;
3349 result
= kOSReturnSuccess
;
3351 OSSafeRelease(serializer
);
3356 #pragma mark Instance Management Methods
3358 /*********************************************************************
3359 *********************************************************************/
3361 OSKext::lookupKextWithIdentifier(const char * kextIdentifier
)
3363 OSKext
* foundKext
= NULL
;
3365 IORecursiveLockLock(sKextLock
);
3366 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3368 foundKext
->retain();
3370 IORecursiveLockUnlock(sKextLock
);
3375 /*********************************************************************
3376 *********************************************************************/
3378 OSKext::lookupKextWithIdentifier(OSString
* kextIdentifier
)
3380 return OSKext::lookupKextWithIdentifier(kextIdentifier
->getCStringNoCopy());
3383 /*********************************************************************
3384 *********************************************************************/
3386 OSKext::lookupKextWithLoadTag(uint32_t aTag
)
3388 OSKext
* foundKext
= NULL
; // returned
3391 IORecursiveLockLock(sKextLock
);
3393 count
= sLoadedKexts
->getCount();
3394 for (i
= 0; i
< count
; i
++) {
3395 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3396 if (thisKext
->getLoadTag() == aTag
) {
3397 foundKext
= thisKext
;
3398 foundKext
->retain();
3404 IORecursiveLockUnlock(sKextLock
);
3409 /*********************************************************************
3410 *********************************************************************/
3412 OSKext::lookupKextWithAddress(vm_address_t address
)
3414 OSKext
* foundKext
= NULL
; // returned
3417 IORecursiveLockLock(sKextLock
);
3419 count
= sLoadedKexts
->getCount();
3420 for (i
= 0; i
< count
; i
++) {
3421 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3422 if (thisKext
->linkedExecutable
) {
3423 vm_address_t kext_start
=
3424 (vm_address_t
)thisKext
->linkedExecutable
->getBytesNoCopy();
3425 vm_address_t kext_end
= kext_start
+
3426 thisKext
->linkedExecutable
->getLength();
3428 if ((kext_start
<= address
) && (address
< kext_end
)) {
3429 foundKext
= thisKext
;
3430 foundKext
->retain();
3437 IORecursiveLockUnlock(sKextLock
);
3442 /*********************************************************************
3443 *********************************************************************/
3445 bool OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
3447 bool result
= false;
3448 OSKext
* foundKext
= NULL
; // returned
3450 IORecursiveLockLock(sKextLock
);
3452 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3453 if (foundKext
&& foundKext
->isLoaded()) {
3457 IORecursiveLockUnlock(sKextLock
);
3462 /*********************************************************************
3463 * xxx - should spawn a separate thread so a kext can safely have
3464 * xxx - itself unloaded.
3465 *********************************************************************/
3470 bool terminateServicesAndRemovePersonalitiesFlag
)
3472 OSReturn result
= kOSKextReturnInUse
;
3473 OSKext
* checkKext
= NULL
; // do not release
3475 IORecursiveLockLock(sKextLock
);
3477 /* If the kext has no identifier, it failed to init
3478 * so isn't in sKextsByID and it isn't loaded.
3480 if (!aKext
->getIdentifier()) {
3481 result
= kOSReturnSuccess
;
3485 checkKext
= OSDynamicCast(OSKext
,
3486 sKextsByID
->getObject(aKext
->getIdentifier()));
3487 if (checkKext
!= aKext
) {
3488 result
= kOSKextReturnNotFound
;
3492 if (aKext
->isLoaded()) {
3494 /* If we are terminating, send the request to the IOCatalogue
3495 * (which will actually call us right back but that's ok we have
3496 * a recursive lock don't you know) but do not ask the IOCatalogue
3497 * to call back with an unload, we'll do that right here.
3499 if (terminateServicesAndRemovePersonalitiesFlag
) {
3500 result
= gIOCatalogue
->terminateDriversForModule(
3501 aKext
->getIdentifierCString(), /* unload */ false);
3502 if (result
!= kOSReturnSuccess
) {
3504 kOSKextLogErrorLevel
|
3505 kOSKextLogKextBookkeepingFlag
,
3506 "Can't remove kext %s; services failed to terminate - 0x%x.",
3507 aKext
->getIdentifierCString(), result
);
3512 result
= aKext
->unload();
3513 if (result
!= kOSReturnSuccess
) {
3518 /* Remove personalities as requested. This is a bit redundant for a loaded
3519 * kext as IOCatalogue::terminateDriversForModule() removes driver
3520 * personalities, but it doesn't restart matching, which we always want
3521 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
3524 if (terminateServicesAndRemovePersonalitiesFlag
) {
3525 aKext
->removePersonalitiesFromCatalog();
3529 kOSKextLogProgressLevel
|
3530 kOSKextLogKextBookkeepingFlag
,
3531 "Removing kext %s.",
3532 aKext
->getIdentifierCString());
3534 sKextsByID
->removeObject(aKext
->getIdentifier());
3535 result
= kOSReturnSuccess
;
3538 IORecursiveLockUnlock(sKextLock
);
3542 /*********************************************************************
3543 *********************************************************************/
3546 OSKext::removeKextWithIdentifier(
3547 const char * kextIdentifier
,
3548 bool terminateServicesAndRemovePersonalitiesFlag
)
3550 OSReturn result
= kOSReturnError
;
3552 IORecursiveLockLock(sKextLock
);
3554 OSKext
* aKext
= OSDynamicCast(OSKext
,
3555 sKextsByID
->getObject(kextIdentifier
));
3557 result
= kOSKextReturnNotFound
;
3558 OSKextLog(/* kext */ NULL
,
3559 kOSKextLogErrorLevel
|
3560 kOSKextLogKextBookkeepingFlag
,
3561 "Can't remove kext %s - not found.",
3566 result
= OSKext::removeKext(aKext
,
3567 terminateServicesAndRemovePersonalitiesFlag
);
3570 IORecursiveLockUnlock(sKextLock
);
3575 /*********************************************************************
3576 *********************************************************************/
3579 OSKext::removeKextWithLoadTag(
3580 OSKextLoadTag loadTag
,
3581 bool terminateServicesAndRemovePersonalitiesFlag
)
3583 OSReturn result
= kOSReturnError
;
3584 OSKext
* foundKext
= NULL
;
3587 IORecursiveLockLock(sKextLock
);
3589 count
= sLoadedKexts
->getCount();
3590 for (i
= 0; i
< count
; i
++) {
3591 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3592 if (thisKext
->loadTag
== loadTag
) {
3593 foundKext
= thisKext
;
3599 result
= kOSKextReturnNotFound
;
3600 OSKextLog(/* kext */ NULL
,
3601 kOSKextLogErrorLevel
|
3602 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
3603 "Can't remove kext with load tag %d - not found.",
3608 result
= OSKext::removeKext(foundKext
,
3609 terminateServicesAndRemovePersonalitiesFlag
);
3612 IORecursiveLockUnlock(sKextLock
);
3617 /*********************************************************************
3618 *********************************************************************/
3620 OSKext::copyKexts(void)
3622 OSDictionary
* result
;
3624 IORecursiveLockLock(sKextLock
);
3625 result
= OSDynamicCast(OSDictionary
, sKextsByID
->copyCollection());
3626 IORecursiveLockUnlock(sKextLock
);
3632 #pragma mark Accessors
3634 /*********************************************************************
3635 *********************************************************************/
3637 OSKext::getIdentifier(void)
3642 /*********************************************************************
3643 * A kext must have a bundle identifier to even survive initialization;
3644 * this is guaranteed to exist past then.
3645 *********************************************************************/
3647 OSKext::getIdentifierCString(void)
3649 return bundleID
->getCStringNoCopy();
3652 /*********************************************************************
3653 *********************************************************************/
3655 OSKext::getVersion(void)
3660 /*********************************************************************
3661 *********************************************************************/
3663 OSKext::getCompatibleVersion(void)
3665 return compatibleVersion
;
3668 /*********************************************************************
3669 *********************************************************************/
3671 OSKext::isLibrary(void)
3673 return (getCompatibleVersion() > 0);
3676 /*********************************************************************
3677 *********************************************************************/
3679 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
3681 if ((compatibleVersion
> -1 && version
> -1) &&
3682 (compatibleVersion
<= version
&& aVersion
<= version
)) {
3688 /*********************************************************************
3689 *********************************************************************/
3691 OSKext::declaresExecutable(void)
3693 return (getPropertyForHostArch(kCFBundleExecutableKey
) != NULL
);
3696 /*********************************************************************
3697 *********************************************************************/
3699 OSKext::getExecutable(void)
3701 OSData
* result
= NULL
;
3702 OSData
* extractedExecutable
= NULL
; // must release
3703 OSData
* mkextExecutableRef
= NULL
; // do not release
3705 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
3710 mkextExecutableRef
= OSDynamicCast(OSData
,
3711 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
3713 if (mkextExecutableRef
) {
3715 MkextEntryRef
* mkextEntryRef
= (MkextEntryRef
*)
3716 mkextExecutableRef
->getBytesNoCopy();
3717 uint32_t mkextVersion
= MKEXT_GET_VERSION(mkextEntryRef
->mkext
);
3718 if (mkextVersion
== MKEXT_VERS_2
) {
3719 mkext2_file_entry
* fileinfo
=
3720 (mkext2_file_entry
*)mkextEntryRef
->fileinfo
;
3721 uint32_t compressedSize
= MKEXT2_GET_ENTRY_COMPSIZE(fileinfo
);
3722 uint32_t fullSize
= MKEXT2_GET_ENTRY_FULLSIZE(fileinfo
);
3723 extractedExecutable
= extractMkext2FileData(
3724 MKEXT2_GET_ENTRY_DATA(fileinfo
), "executable",
3725 compressedSize
, fullSize
);
3726 } else if (mkextVersion
== MKEXT_VERS_1
) {
3727 extractedExecutable
= extractMkext1Entry(
3728 mkextEntryRef
->mkext
, mkextEntryRef
->fileinfo
);
3730 OSKextLog(this, kOSKextLogErrorLevel
|
3731 kOSKextLogArchiveFlag
,
3732 "Kext %s - unknown mkext version 0x%x for executable.",
3733 getIdentifierCString(), mkextVersion
);
3736 /* Regardless of success, remove the mkext executable,
3737 * and drop one reference on the mkext. (setExecutable() does not
3738 * replace, it removes, or panics if asked to replace.)
3740 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
3741 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
3743 if (extractedExecutable
&& extractedExecutable
->getLength()) {
3744 if (!setExecutable(extractedExecutable
)) {
3747 result
= extractedExecutable
;
3755 OSSafeRelease(extractedExecutable
);
3760 /*********************************************************************
3761 *********************************************************************/
3763 OSKext::isInterface(void)
3765 return flags
.interface
;
3768 /*********************************************************************
3769 *********************************************************************/
3771 OSKext::isKernel(void)
3773 return (this == sKernelKext
);
3776 /*********************************************************************
3777 *********************************************************************/
3779 OSKext::isKernelComponent(void)
3781 return flags
.kernelComponent
? true : false;
3784 /*********************************************************************
3785 *********************************************************************/
3787 OSKext::isExecutable(void)
3789 return (!isKernel() && !isInterface() && declaresExecutable());
3792 /*********************************************************************
3793 * We might want to check this recursively for all dependencies,
3794 * since a subtree of dependencies could get loaded before we hit
3795 * a dependency that isn't safe-boot-loadable.
3797 * xxx - Might want to return false if OSBundleEnableKextLogging or
3798 * OSBundleDebugLevel
3799 * or IOKitDebug is nonzero too (we used to do that, but I don't see
3800 * the point except it's usually development drivers, which might
3801 * cause panics on startup, that have those properties). Heh; could
3802 * use a "kx" boot-arg!
3803 *********************************************************************/
3805 OSKext::isLoadableInSafeBoot(void)
3807 bool result
= false;
3808 OSString
* required
= NULL
; // do not release
3815 required
= OSDynamicCast(OSString
,
3816 getPropertyForHostArch(kOSBundleRequiredKey
));
3820 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
3821 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
3822 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
3823 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
3824 required
->isEqualTo(kOSBundleRequiredConsole
)) {
3833 /*********************************************************************
3834 *********************************************************************/
3836 OSKext::isPrelinked(void)
3838 return flags
.prelinked
? true : false;
3841 /*********************************************************************
3842 *********************************************************************/
3843 bool OSKext::isLoaded(void)
3845 return flags
.loaded
? true : false;
3848 /*********************************************************************
3849 *********************************************************************/
3851 OSKext::isStarted(void)
3853 return flags
.started
? true : false;
3856 /*********************************************************************
3857 *********************************************************************/
3859 OSKext::isCPPInitialized(void)
3861 return flags
.CPPInitialized
;
3864 /*********************************************************************
3865 *********************************************************************/
3867 OSKext::setCPPInitialized(bool initialized
)
3869 flags
.CPPInitialized
= initialized
;
3872 /*********************************************************************
3873 *********************************************************************/
3875 OSKext::getLoadTag(void)
3880 /*********************************************************************
3881 *********************************************************************/
3882 void OSKext::getSizeInfo(uint32_t *loadSize
, uint32_t *wiredSize
)
3884 if (linkedExecutable
) {
3885 *loadSize
= linkedExecutable
->getLength();
3887 /* If we have a kmod_info struct, calculated the wired size
3888 * from that. Otherwise it's the full load size.
3891 *wiredSize
= *loadSize
- kmod_info
->hdr_size
;
3893 *wiredSize
= *loadSize
;
3902 /*********************************************************************
3903 *********************************************************************/
3905 OSKext::copyUUID(void)
3907 OSData
* result
= NULL
;
3908 OSData
* theExecutable
= NULL
; // do not release
3909 const kernel_mach_header_t
* header
= NULL
;
3910 const struct load_command
* load_cmd
= NULL
;
3911 const struct uuid_command
* uuid_cmd
= NULL
;
3914 /* An interface kext doesn't have a linked executable with an LC_UUID,
3915 * we create one when it's linked.
3917 if (interfaceUUID
) {
3918 result
= interfaceUUID
;
3923 /* For real kexts, try to get the UUID from the linked executable,
3924 * or if is hasn't been linked yet, the unrelocated executable.
3926 theExecutable
= linkedExecutable
;
3927 if (!theExecutable
) {
3928 theExecutable
= getExecutable();
3930 if (!theExecutable
) {
3934 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
3935 load_cmd
= (const struct load_command
*)&header
[1];
3937 for (i
= 0; i
< header
->ncmds
; i
++) {
3938 if (load_cmd
->cmd
== LC_UUID
) {
3939 uuid_cmd
= (struct uuid_command
*)load_cmd
;
3940 result
= OSData::withBytes(uuid_cmd
->uuid
, sizeof(uuid_cmd
->uuid
));
3943 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
3950 /*********************************************************************
3951 *********************************************************************/
3952 #if defined (__i386__)
3953 #define ARCHNAME "i386"
3954 #elif defined (__x86_64__)
3955 #define ARCHNAME "x86_64"
3957 #error architecture not supported
3960 #define ARCH_SEPARATOR_CHAR '_'
3962 static char * makeHostArchKey(const char * key
, uint32_t * keySizeOut
)
3964 char * result
= NULL
;
3965 uint32_t keyLength
= strlen(key
);
3968 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
3970 keySize
= 1 + 1 + strlen(key
) + strlen(ARCHNAME
);
3971 result
= (char *)kalloc(keySize
);
3975 strlcpy(result
, key
, keySize
);
3976 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
3977 result
[keyLength
] = '\0';
3978 strlcat(result
, ARCHNAME
, keySize
);
3979 *keySizeOut
= keySize
;
3985 /*********************************************************************
3986 *********************************************************************/
3988 OSKext::getPropertyForHostArch(const char * key
)
3990 OSObject
* result
= NULL
; // do not release
3991 uint32_t hostArchKeySize
= 0;
3992 char * hostArchKey
= NULL
; // must kfree
3994 if (!key
|| !infoDict
) {
3998 /* Some properties are not allowed to be arch-variant:
3999 * - Any CFBundle... property.
4000 * - OSBundleIsInterface.
4001 * - OSKernelResource.
4003 if (STRING_HAS_PREFIX(key
, "OS") ||
4004 STRING_HAS_PREFIX(key
, "IO")) {
4006 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
4008 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
4009 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4010 "Allocation failure.");
4013 result
= infoDict
->getObject(hostArchKey
);
4017 result
= infoDict
->getObject(key
);
4021 if (hostArchKey
) kfree(hostArchKey
, hostArchKeySize
);
4026 #pragma mark Load/Start/Stop/Unload
4028 /*********************************************************************
4029 *********************************************************************/
4032 OSKext::loadKextWithIdentifier(
4033 const char * kextIdentifierCString
,
4034 Boolean allowDeferFlag
,
4035 Boolean delayAutounloadFlag
,
4036 OSKextExcludeLevel startOpt
,
4037 OSKextExcludeLevel startMatchingOpt
,
4038 OSArray
* personalityNames
)
4040 OSReturn result
= kOSReturnError
;
4041 OSString
* kextIdentifier
= NULL
; // must release
4043 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
4044 if (!kextIdentifier
) {
4045 result
= kOSKextReturnNoMemory
;
4048 result
= OSKext::loadKextWithIdentifier(kextIdentifier
,
4049 allowDeferFlag
, delayAutounloadFlag
,
4050 startOpt
, startMatchingOpt
, personalityNames
);
4053 OSSafeRelease(kextIdentifier
);
4057 /*********************************************************************
4058 *********************************************************************/
4060 OSKext::loadKextWithIdentifier(
4061 OSString
* kextIdentifier
,
4062 Boolean allowDeferFlag
,
4063 Boolean delayAutounloadFlag
,
4064 OSKextExcludeLevel startOpt
,
4065 OSKextExcludeLevel startMatchingOpt
,
4066 OSArray
* personalityNames
)
4068 OSReturn result
= kOSReturnError
;
4069 OSReturn pingResult
= kOSReturnError
;
4070 OSKext
* theKext
= NULL
; // do not release
4071 OSDictionary
* loadRequest
= NULL
; // must release
4072 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
4074 IORecursiveLockLock(sKextLock
);
4076 if (!kextIdentifier
) {
4077 result
= kOSKextReturnInvalidArgument
;
4081 OSKext::recordIdentifierRequest(kextIdentifier
);
4083 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4085 if (!allowDeferFlag
) {
4086 OSKextLog(/* kext */ NULL
,
4087 kOSKextLogErrorLevel
|
4089 "Can't load kext %s - not found.",
4090 kextIdentifier
->getCStringNoCopy());
4094 if (!sKernelRequestsEnabled
) {
4096 kOSKextLogErrorLevel
|
4098 "Can't load kext %s - requests to user space are disabled.",
4099 kextIdentifier
->getCStringNoCopy());
4100 result
= kOSKextReturnDisabled
;
4104 /* Create a new request unless one is already sitting
4105 * in sKernelRequests for this bundle identifier
4107 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
4108 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
4109 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
4111 if (result
!= kOSReturnSuccess
) {
4114 if (!_OSKextSetRequestArgument(loadRequest
,
4115 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
4117 result
= kOSKextReturnNoMemory
;
4120 if (!sKernelRequests
->setObject(loadRequest
)) {
4121 result
= kOSKextReturnNoMemory
;
4125 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
4126 result
= kOSKextReturnNoMemory
;
4131 kOSKextLogDebugLevel
|
4133 "Kext %s not found; queued load request to user space.",
4134 kextIdentifier
->getCStringNoCopy());
4137 pingResult
= OSKext::pingKextd();
4138 if (pingResult
== kOSKextReturnDisabled
) {
4139 OSKextLog(/* kext */ NULL
,
4140 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
4142 "Kext %s might not load - kextd is currently unavailable.",
4143 kextIdentifier
->getCStringNoCopy());
4146 result
= kOSKextReturnDeferred
;
4150 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
4152 if (result
!= kOSReturnSuccess
) {
4154 kOSKextLogErrorLevel
|
4156 "Failed to load kext %s (error 0x%x).",
4157 kextIdentifier
->getCStringNoCopy(), (int)result
);
4159 OSKext::removeKext(theKext
,
4160 /* terminateService/removePersonalities */ true);
4164 if (delayAutounloadFlag
) {
4166 kOSKextLogProgressLevel
|
4167 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
4168 "Setting delayed autounload for %s.",
4169 kextIdentifier
->getCStringNoCopy());
4170 theKext
->flags
.delayAutounload
= 1;
4174 OSSafeRelease(loadRequest
);
4175 OSSafeRelease(kextIdentifierSymbol
);
4177 IORecursiveLockUnlock(sKextLock
);
4182 /*********************************************************************
4183 *********************************************************************/
4186 OSKext::recordIdentifierRequest(
4187 OSString
* kextIdentifier
)
4189 const OSSymbol
* kextIdentifierSymbol
= NULL
; // must release
4192 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
4196 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
4197 if (!kextIdentifierSymbol
) {
4198 // xxx - this is really a basic alloc failure
4203 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
)) {
4204 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
)) {
4207 // xxx - need to find a way to associate this whole func w/the kext
4208 OSKextLog(/* kext */ NULL
,
4209 // xxx - check level
4210 kOSKextLogStepLevel
|
4211 kOSKextLogArchiveFlag
,
4212 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
4213 kextIdentifier
->getCStringNoCopy());
4219 OSKextLog(/* kext */ NULL
,
4220 kOSKextLogErrorLevel
|
4221 kOSKextLogArchiveFlag
,
4222 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
4223 kextIdentifier
->getCStringNoCopy());
4225 OSSafeRelease(kextIdentifierSymbol
);
4229 /*********************************************************************
4230 *********************************************************************/
4233 OSKextExcludeLevel startOpt
,
4234 OSKextExcludeLevel startMatchingOpt
,
4235 OSArray
* personalityNames
)
4237 OSReturn result
= kOSReturnError
;
4238 kern_return_t kxldResult
;
4239 OSKextExcludeLevel dependenciesStartOpt
= startOpt
;
4240 OSKextExcludeLevel dependenciesStartMatchingOpt
= startMatchingOpt
;
4241 unsigned int i
, count
;
4242 Boolean alreadyLoaded
= false;
4243 OSKext
* lastLoadedKext
= NULL
;
4246 alreadyLoaded
= true;
4247 result
= kOSReturnSuccess
;
4250 kOSKextLogDebugLevel
|
4251 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
4252 "Kext %s is already loaded.",
4253 getIdentifierCString());
4257 if (!sLoadEnabled
) {
4259 kOSKextLogErrorLevel
|
4261 "Kext loading is disabled (attempt to load kext %s).",
4262 getIdentifierCString());
4263 result
= kOSKextReturnDisabled
;
4267 /* If we've pushed the next available load tag to the invalid value,
4268 * we can't load any more kexts.
4270 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
4272 kOSKextLogErrorLevel
|
4274 "Can't load kext %s - no more load tags to assign.",
4275 getIdentifierCString());
4276 result
= kOSKextReturnNoResources
;
4280 /* This is a bit of a hack, because we shouldn't be handling
4281 * personalities within the load function.
4283 if (!declaresExecutable()) {
4284 result
= kOSReturnSuccess
;
4288 /* Are we in safe boot?
4290 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
4292 kOSKextLogErrorLevel
|
4294 "Can't load kext %s - not loadable during safe boot.",
4295 getIdentifierCString());
4296 result
= kOSKextReturnBootLevel
;
4301 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
4303 getIdentifierCString());
4306 if (!sKxldContext
) {
4307 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
4308 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
4309 /* cputype */ 0, /* cpusubtype */ 0);
4312 kOSKextLogErrorLevel
|
4313 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4314 "Can't load kext %s - failed to create link context.",
4315 getIdentifierCString());
4316 result
= kOSKextReturnNoMemory
;
4321 /* We only need to resolve dependencies once for the whole graph, but
4322 * resolveDependencies will just return if there's no work to do, so it's
4323 * safe to call it more than once.
4325 if (!resolveDependencies()) {
4326 // xxx - check resolveDependencies() for log msg
4328 kOSKextLogErrorLevel
|
4329 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4330 "Can't load kext %s - failed to resolve library dependencies.",
4331 getIdentifierCString());
4332 result
= kOSKextReturnDependencies
;
4336 /* If we are excluding just the kext being loaded now (and not its
4337 * dependencies), drop the exclusion level to none so dependencies
4338 * start and/or add their personalities.
4340 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
4341 dependenciesStartOpt
= kOSKextExcludeNone
;
4344 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
4345 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
4348 /* Load the dependencies, recursively.
4350 count
= getNumDependencies();
4351 for (i
= 0; i
< count
; i
++) {
4352 OSKext
* dependency
= OSDynamicCast(OSKext
,
4353 dependencies
->getObject(i
));
4354 if (dependency
== NULL
) {
4356 kOSKextLogErrorLevel
|
4357 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4358 "Internal error loading kext %s; dependency disappeared.",
4359 getIdentifierCString());
4360 result
= kOSKextReturnInternalError
;
4364 /* Dependencies must be started accorting to the opt,
4365 * but not given the personality names of the main kext.
4367 result
= dependency
->load(dependenciesStartOpt
,
4368 dependenciesStartMatchingOpt
,
4369 /* personalityNames */ NULL
);
4370 if (result
!= KERN_SUCCESS
) {
4372 kOSKextLogErrorLevel
|
4373 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4374 "Dependency %s of kext %s failed to load.",
4375 dependency
->getIdentifierCString(),
4376 getIdentifierCString());
4378 OSKext::removeKext(dependency
,
4379 /* terminateService/removePersonalities */ true);
4380 result
= kOSKextReturnDependencyLoadError
;
4386 result
= loadExecutable();
4387 if (result
!= KERN_SUCCESS
) {
4391 flags
.loaded
= true;
4393 /* Add the kext to the list of loaded kexts and update the kmod_info
4394 * struct to point to that of the last loaded kext (which is the way
4395 * it's always been done, though I'd rather do them in order now).
4397 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
4398 sLoadedKexts
->setObject(this);
4400 /* Keep the kernel itself out of the kmod list.
4402 if (lastLoadedKext
->isKernel()) {
4403 lastLoadedKext
= NULL
;
4406 if (lastLoadedKext
) {
4407 kmod_info
->next
= lastLoadedKext
->kmod_info
;
4410 notifyKextLoadObservers(this, kmod_info
);
4412 /* Make the global kmod list point at the just-loaded kext. Note that the
4413 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
4414 * although we do report it in kextstat these days by using the newer
4415 * OSArray of loaded kexts, which does contain it.
4417 * (The OSKext object representing the kernel doesn't even have a kmod_info
4418 * struct, though I suppose we could stick a pointer to it from the
4419 * static struct in OSRuntime.cpp.)
4423 /* Save the list of loaded kexts in case we panic.
4425 OSKext::saveLoadedKextPanicList();
4427 if (isExecutable()) {
4428 OSKext::updateLoadedKextSummaries();
4429 savePanicString(/* isLoading */ true);
4432 registerWithDTrace();
4434 jettisonLinkeditSegment();
4435 #endif /* CONFIG_DTRACE */
4439 if (isExecutable() && !flags
.started
) {
4440 if (startOpt
== kOSKextExcludeNone
) {
4442 if (result
!= kOSReturnSuccess
) {
4444 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
4445 "Kext %s start failed (result 0x%x).",
4446 getIdentifierCString(), result
);
4447 result
= kOSKextReturnStartStopError
;
4452 /* If not excluding matching, send the personalities to the kernel.
4453 * This never affects the result of the load operation.
4454 * This is a bit of a hack, because we shouldn't be handling
4455 * personalities within the load function.
4457 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
4458 result
= sendPersonalitiesToCatalog(true, personalityNames
);
4463 /* More hack! If the kext doesn't declare an executable, even if we
4464 * "loaded" it, we have to remove any personalities naming it, or we'll
4465 * never see the registry go quiet. Errors here do not count for the
4466 * load operation itself.
4468 * Note that in every other regard it's perfectly ok for a kext to
4469 * not declare an executable and serve only as a package for personalities
4470 * naming another kext, so we do have to allow such kexts to be "loaded"
4471 * so that those other personalities get added & matched.
4473 if (!declaresExecutable()) {
4475 kOSKextLogStepLevel
| kOSKextLogLoadFlag
,
4476 "Kext %s has no executable; removing any personalities naming it.",
4477 getIdentifierCString());
4478 removePersonalitiesFromCatalog();
4481 if (result
!= kOSReturnSuccess
) {
4483 kOSKextLogErrorLevel
|
4485 "Kext %s failed to load (0x%x).",
4486 getIdentifierCString(), (int)result
);
4487 } else if (!alreadyLoaded
) {
4489 kOSKextLogProgressLevel
|
4492 getIdentifierCString());
4494 queueKextNotification(kKextRequestPredicateLoadNotification
,
4495 OSDynamicCast(OSString
, bundleID
));
4500 /*********************************************************************
4502 *********************************************************************/
4503 static char * strdup(const char * string
)
4505 char * result
= NULL
;
4512 size
= 1 + strlen(string
);
4513 result
= (char *)kalloc(size
);
4518 memcpy(result
, string
, size
);
4524 /*********************************************************************
4525 * called only by load()
4526 *********************************************************************/
4528 OSKext::loadExecutable()
4530 OSReturn result
= kOSReturnError
;
4531 kern_return_t kxldResult
;
4532 KXLDDependency
* kxlddeps
= NULL
; // must kfree
4533 uint32_t num_kxlddeps
= 0;
4534 OSArray
* linkDependencies
= NULL
; // must release
4535 uint32_t numDirectDependencies
= 0;
4536 uint32_t num_kmod_refs
= 0;
4537 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
4538 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
4539 OSData
* theExecutable
= NULL
; // do not release
4540 OSString
* versString
= NULL
; // do not release
4541 const char * versCString
= NULL
; // do not free
4542 const char * string
= NULL
; // do not free
4545 /* We need the version string for a variety of bits below.
4547 versString
= OSDynamicCast(OSString
,
4548 getPropertyForHostArch(kCFBundleVersionKey
));
4552 versCString
= versString
->getCStringNoCopy();
4554 if (isKernelComponent()) {
4555 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
4557 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
4559 kOSKextLogErrorLevel
|
4561 "Kernel component %s has incorrect version %s; "
4563 getIdentifierCString(),
4564 versCString
, KERNEL6_VERSION
);
4565 result
= kOSKextReturnInternalError
;
4567 } else if (strcmp(versCString
, osrelease
)) {
4569 kOSKextLogErrorLevel
|
4571 "Kernel component %s has incorrect version %s; "
4573 getIdentifierCString(),
4574 versCString
, osrelease
);
4575 result
= kOSKextReturnInternalError
;
4581 if (isPrelinked()) {
4585 theExecutable
= getExecutable();
4586 if (!theExecutable
) {
4587 if (declaresExecutable()) {
4589 kOSKextLogErrorLevel
|
4591 "Can't load kext %s - executable is missing.",
4592 getIdentifierCString());
4593 result
= kOSKextReturnValidation
;
4599 if (isInterface()) {
4600 OSData
*executableCopy
= OSData::withData(theExecutable
);
4601 setLinkedExecutable(executableCopy
);
4602 executableCopy
->release();
4606 numDirectDependencies
= getNumDependencies();
4608 if (flags
.hasBleedthrough
) {
4609 linkDependencies
= dependencies
;
4610 linkDependencies
->retain();
4612 linkDependencies
= OSArray::withArray(dependencies
);
4613 if (!linkDependencies
) {
4615 kOSKextLogErrorLevel
|
4616 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4617 "Can't allocate link dependencies to load kext %s.",
4618 getIdentifierCString());
4622 for (i
= 0; i
< numDirectDependencies
; ++i
) {
4623 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
4624 dependencies
->getObject(i
));
4625 dependencyKext
->addBleedthroughDependencies(linkDependencies
);
4629 num_kxlddeps
= linkDependencies
->getCount();
4630 if (!num_kxlddeps
) {
4632 kOSKextLogErrorLevel
|
4633 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
4634 "Can't load kext %s - it has no library dependencies.",
4635 getIdentifierCString());
4639 kxlddeps
= (KXLDDependency
*)kalloc(num_kxlddeps
* sizeof(*kxlddeps
));
4642 kOSKextLogErrorLevel
|
4643 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4644 "Can't allocate link context to load kext %s.",
4645 getIdentifierCString());
4648 bzero(kxlddeps
, num_kxlddeps
* sizeof(*kxlddeps
));
4650 for (i
= 0; i
< num_kxlddeps
; ++i
) {
4651 OSKext
* dependency
= OSDynamicCast(OSKext
, linkDependencies
->getObject(i
));
4653 if (dependency
->isInterface()) {
4654 OSKext
*interfaceTargetKext
= NULL
;
4655 OSData
* interfaceTarget
= NULL
;
4657 if (dependency
->isKernelComponent()) {
4658 interfaceTargetKext
= sKernelKext
;
4659 interfaceTarget
= sKernelKext
->linkedExecutable
;
4661 interfaceTargetKext
= OSDynamicCast(OSKext
,
4662 dependency
->dependencies
->getObject(0));
4664 interfaceTarget
= interfaceTargetKext
->linkedExecutable
;
4667 if (!interfaceTarget
) {
4672 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
4673 * it will be useful to have them in the debugger.
4674 * strdup() failing isn't critical right here so we don't check that.
4676 kxlddeps
[i
].kext
= (u_char
*) interfaceTarget
->getBytesNoCopy();
4677 kxlddeps
[i
].kext_size
= interfaceTarget
->getLength();
4678 kxlddeps
[i
].kext_name
= strdup(interfaceTargetKext
->getIdentifierCString());
4680 kxlddeps
[i
].interface
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
4681 kxlddeps
[i
].interface_size
= dependency
->linkedExecutable
->getLength();
4682 kxlddeps
[i
].interface_name
= strdup(dependency
->getIdentifierCString());
4684 kxlddeps
[i
].kext
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
4685 kxlddeps
[i
].kext_size
= dependency
->linkedExecutable
->getLength();
4686 kxlddeps
[i
].kext_name
= strdup(dependency
->getIdentifierCString());
4689 kxlddeps
[i
].is_direct_dependency
= (i
< numDirectDependencies
);
4692 kxldHeaderPtr
= &kxld_header
;
4696 kOSKextLogExplicitLevel
|
4697 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
4698 "Kext %s - calling kxld_link_file:\n"
4699 " kxld_context: %p\n"
4700 " executable: %p executable_length: %d\n"
4702 " kxld_dependencies: %p num_dependencies: %d\n"
4703 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
4704 getIdentifierCString(), sKxldContext
,
4705 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
4706 this, kxlddeps
, num_kxlddeps
,
4707 kxldHeaderPtr
, &kmod_info
);
4710 /* After this call, the linkedExecutable instance variable
4713 kxldResult
= kxld_link_file(sKxldContext
,
4714 (u_char
*)theExecutable
->getBytesNoCopy(),
4715 theExecutable
->getLength(),
4716 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
4717 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
);
4719 if (kxldResult
!= KERN_SUCCESS
) {
4720 // xxx - add kxldResult here?
4722 kOSKextLogErrorLevel
|
4724 "Can't load kext %s - link failed.",
4725 getIdentifierCString());
4726 result
= kOSKextReturnLinkError
;
4730 /* We've written data & instructions into kernel memory, so flush the data
4731 * cache and invalidate the instruction cache.
4732 * I/D caches are coherent on x86
4734 #if !defined(__i386__) && !defined(__x86_64__)
4735 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
4736 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
4740 if (isInterface()) {
4742 /* Whip up a fake kmod_info entry for the interface kext.
4744 kmod_info
= (kmod_info_t
*)kalloc(sizeof(kmod_info_t
));
4746 result
= KERN_MEMORY_ERROR
;
4750 /* A pseudokext has almost nothing in its kmod_info struct.
4752 bzero(kmod_info
, sizeof(kmod_info_t
));
4754 kmod_info
->info_version
= KMOD_INFO_VERSION
;
4756 /* An interface kext doesn't have a linkedExecutable, so save a
4757 * copy of the UUID out of the original executable via copyUUID()
4758 * while we still have the original executable.
4760 interfaceUUID
= copyUUID();
4763 kmod_info
->id
= loadTag
= sNextLoadTag
++;
4764 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
4766 /* Stamp the bundle ID and version from the OSKext over anything
4767 * resident inside the kmod_info.
4769 string
= getIdentifierCString();
4770 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
4772 string
= versCString
;
4773 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
4775 /* Add the dependencies' kmod_info structs as kmod_references.
4777 num_kmod_refs
= getNumDependencies();
4778 if (num_kmod_refs
) {
4779 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc(
4780 num_kmod_refs
* sizeof(kmod_reference_t
));
4781 if (!kmod_info
->reference_list
) {
4782 result
= KERN_MEMORY_ERROR
;
4785 bzero(kmod_info
->reference_list
,
4786 num_kmod_refs
* sizeof(kmod_reference_t
));
4787 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
4788 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
4789 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
4790 ref
->info
= refKext
->kmod_info
;
4791 ref
->info
->reference_count
++;
4793 if (refIndex
+ 1 < num_kmod_refs
) {
4794 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
4799 if (!isInterface() && linkedExecutable
) {
4801 kOSKextLogProgressLevel
|
4803 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
4805 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
4806 (unsigned long)kmod_info
->address
,
4807 (unsigned)kmod_info
->id
);
4810 result
= setVMProtections();
4811 if (result
!= KERN_SUCCESS
) {
4815 result
= kOSReturnSuccess
;
4818 OSSafeRelease(linkDependencies
);
4820 /* Clear up locally allocated dependency info.
4822 for (i
= 0; i
< num_kxlddeps
; ++i
) {
4825 if (kxlddeps
[i
].kext_name
) {
4826 size
= 1 + strlen(kxlddeps
[i
].kext_name
);
4827 kfree(kxlddeps
[i
].kext_name
, size
);
4829 if (kxlddeps
[i
].interface_name
) {
4830 size
= 1 + strlen(kxlddeps
[i
].interface_name
);
4831 kfree(kxlddeps
[i
].interface_name
, size
);
4834 if (kxlddeps
) kfree(kxlddeps
, (num_kxlddeps
* sizeof(*kxlddeps
)));
4836 /* We no longer need the unrelocated executable (which the linker
4837 * has altered anyhow).
4839 setExecutable(NULL
);
4841 if (result
!= kOSReturnSuccess
) {
4843 kOSKextLogErrorLevel
|
4845 "Failed to load executable for kext %s.",
4846 getIdentifierCString());
4848 if (kmod_info
&& kmod_info
->reference_list
) {
4849 kfree(kmod_info
->reference_list
,
4850 num_kmod_refs
* sizeof(kmod_reference_t
));
4852 if (isInterface()) {
4853 kfree(kmod_info
, sizeof(kmod_info_t
));
4856 if (linkedExecutable
) {
4857 linkedExecutable
->release();
4858 linkedExecutable
= NULL
;
4865 /*********************************************************************
4866 * The linkedit segment is used by the kext linker for dependency
4867 * resolution, and by dtrace for probe initialization. We can free it
4868 * for non-library kexts, since no kexts depend on non-library kexts
4869 * by definition, once dtrace has been initialized.
4870 *********************************************************************/
4872 OSKext::jettisonLinkeditSegment(void)
4874 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
4875 kernel_segment_command_t
* linkedit
= NULL
;
4876 vm_size_t linkeditsize
, kextsize
;
4877 OSData
* data
= NULL
;
4879 if (sKeepSymbols
|| isLibrary() || !isExecutable() || !linkedExecutable
) {
4883 /* Find the linkedit segment. If it's not the last segment, then freeing
4884 * it will fragment the kext into multiple VM regions, which OSKext is not
4885 * designed to handle, so we'll have to skip it.
4887 linkedit
= getsegbynamefromheader(machhdr
, SEG_LINKEDIT
);
4892 if (round_page(kmod_info
->address
+ kmod_info
->size
) !=
4893 round_page(linkedit
->vmaddr
+ linkedit
->vmsize
))
4898 /* Create a new OSData for the smaller kext object.
4900 linkeditsize
= round_page(linkedit
->vmsize
);
4901 kextsize
= kmod_info
->size
- linkeditsize
;
4903 data
= OSData::withBytesNoCopy((void *)kmod_info
->address
, kextsize
);
4907 data
->setDeallocFunction(osdata_kext_free
);
4909 /* Rewrite the Mach-O headers.
4911 if (KERN_SUCCESS
!= removeLinkeditHeaders(linkedit
)) {
4915 /* Fix the kmod info and linkedExecutable.
4917 kmod_info
->size
= kextsize
;
4918 linkedExecutable
->setDeallocFunction(NULL
);
4919 linkedExecutable
->release();
4920 linkedExecutable
= data
;
4922 /* Free the linkedit segment.
4924 kext_free(linkedit
->vmaddr
, linkeditsize
);
4930 /*********************************************************************
4931 *********************************************************************/
4933 OSKext::removeLinkeditHeaders(kernel_segment_command_t
*linkedit
)
4935 OSReturn result
= KERN_FAILURE
;
4936 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
4938 u_char
* src
, * dst
;
4939 uint32_t cmdsize
, ncmds
;
4942 kext_map
= kext_get_vm_map(kmod_info
);
4944 result
= KERN_MEMORY_ERROR
;
4948 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4949 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_DEFAULT
, TRUE
);
4950 if (result
!= KERN_SUCCESS
) {
4954 ncmds
= machhdr
->ncmds
;
4955 src
= dst
= (u_char
*)(kmod_info
->address
+ sizeof(*machhdr
));
4957 for (i
= 0; i
< ncmds
; ++i
, src
+= cmdsize
) {
4958 struct load_command
* lc
= (struct load_command
*) src
;
4959 cmdsize
= lc
->cmdsize
;
4964 if (src
!= (u_char
*)linkedit
) break;
4968 bzero(src
, cmdsize
);
4970 machhdr
->sizeofcmds
-= cmdsize
;
4974 memmove(dst
, src
, cmdsize
);
4978 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4979 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
4980 if (result
!= KERN_SUCCESS
) {
4984 result
= KERN_SUCCESS
;
4990 /*********************************************************************
4991 *********************************************************************/
4993 OSKext::setLinkedExecutable(OSData
* anExecutable
)
4995 if (linkedExecutable
) {
4996 panic("Attempt to set linked executable on kext "
4997 "that already has one (%s).\n",
4998 getIdentifierCString());
5000 linkedExecutable
= anExecutable
;
5001 linkedExecutable
->retain();
5006 /*********************************************************************
5007 * Go through all loaded kexts and tell them to register with dtrace.
5008 * The instance method only registers if necessary.
5009 *********************************************************************/
5012 OSKext::registerKextsWithDTrace(void)
5014 uint32_t count
= sLoadedKexts
->getCount();
5017 IORecursiveLockLock(sKextLock
);
5019 for (i
= 0; i
< count
; i
++) {
5020 OSKext
* thisKext
= NULL
; // do not release
5022 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
5023 if (!thisKext
|| !thisKext
->isExecutable()) {
5027 thisKext
->registerWithDTrace();
5030 IORecursiveLockUnlock(sKextLock
);
5036 extern int (*dtrace_modload
)(struct kmod_info
*);
5037 extern int (*dtrace_modunload
)(struct kmod_info
*);
5040 /*********************************************************************
5041 *********************************************************************/
5043 OSKext::registerWithDTrace(void)
5045 /* Register kext with dtrace. A dtrace_modload failure should not
5046 * prevent a kext from loading, so we ignore the return code.
5048 if (!flags
.dtraceInitialized
&& (dtrace_modload
!= NULL
)) {
5049 (void)(*dtrace_modload
)(kmod_info
);
5050 flags
.dtraceInitialized
= true;
5051 jettisonLinkeditSegment();
5055 /*********************************************************************
5056 *********************************************************************/
5058 OSKext::unregisterWithDTrace(void)
5060 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5061 * prevent a kext from loading, so we ignore the return code.
5063 if (flags
.dtraceInitialized
&& (dtrace_modunload
!= NULL
)) {
5064 (void)(*dtrace_modunload
)(kmod_info
);
5065 flags
.dtraceInitialized
= false;
5069 #endif /* CONFIG_DTRACE */
5072 /*********************************************************************
5073 * called only by loadExecutable()
5074 *********************************************************************/
5076 OSKext::setVMProtections(void)
5078 vm_map_t kext_map
= NULL
;
5079 kernel_segment_command_t
* seg
= NULL
;
5080 vm_map_offset_t start
= 0;
5081 vm_map_offset_t end
= 0;
5082 OSReturn result
= kOSReturnError
;
5084 if (!kmod_info
->address
&& !kmod_info
->size
) {
5085 result
= kOSReturnSuccess
;
5089 /* Get the kext's vm map */
5090 kext_map
= kext_get_vm_map(kmod_info
);
5092 result
= KERN_MEMORY_ERROR
;
5096 /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
5097 * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
5098 * so the vm_map_protect calls below fail
5099 * I believe this happens in the call to vm_map_enter in kmem_init but I
5102 /* Protect the headers as read-only; they do not need to be wired */
5103 result
= vm_map_protect(kext_map
, kmod_info
->address
,
5104 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
5105 if (result
!= KERN_SUCCESS
) {
5109 /* Set the VM protections and wire down each of the segments */
5110 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5112 start
= round_page(seg
->vmaddr
);
5113 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
5115 result
= vm_map_protect(kext_map
, start
, end
, seg
->maxprot
, TRUE
);
5116 if (result
!= KERN_SUCCESS
) {
5118 kOSKextLogErrorLevel
|
5120 "Kext %s failed to set maximum VM protections "
5121 "for segment %s - 0x%x.",
5122 getIdentifierCString(), seg
->segname
, (int)result
);
5126 result
= vm_map_protect(kext_map
, start
, end
, seg
->initprot
, FALSE
);
5127 if (result
!= KERN_SUCCESS
) {
5129 kOSKextLogErrorLevel
|
5131 "Kext %s failed to set initial VM protections "
5132 "for segment %s - 0x%x.",
5133 getIdentifierCString(), seg
->segname
, (int)result
);
5137 if (segmentShouldBeWired(seg
)) {
5138 result
= vm_map_wire(kext_map
, start
, end
, seg
->initprot
, FALSE
);
5139 if (result
!= KERN_SUCCESS
) {
5144 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5151 /*********************************************************************
5152 *********************************************************************/
5154 OSKext::segmentShouldBeWired(kernel_segment_command_t
*seg
)
5156 return (sKeepSymbols
|| strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)));
5159 /*********************************************************************
5160 *********************************************************************/
5162 OSKext::validateKextMapping(bool startFlag
)
5164 OSReturn result
= kOSReturnError
;
5165 const char * whichOp
= startFlag
? "start" : "stop";
5166 kern_return_t kern_result
= 0;
5167 vm_map_t kext_map
= NULL
;
5168 kernel_segment_command_t
* seg
= NULL
;
5169 mach_vm_address_t address
= 0;
5170 mach_vm_size_t size
= 0;
5172 mach_msg_type_number_t count
;
5173 vm_region_submap_short_info_data_64_t info
;
5175 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
5176 bzero(&info
, sizeof(info
));
5178 // xxx - do we need a distinct OSReturn value for these or is "bad data"
5179 // xxx - sufficient?
5181 /* Verify that the kmod_info and start/stop pointers are non-NULL.
5185 kOSKextLogErrorLevel
|
5187 "Kext %s - NULL kmod_info pointer.",
5188 getIdentifierCString());
5189 result
= kOSKextReturnBadData
;
5194 address
= (mach_vm_address_t
)kmod_info
->start
;
5196 address
= (mach_vm_address_t
)kmod_info
->stop
;
5201 kOSKextLogErrorLevel
|
5203 "Kext %s - NULL module %s pointer.",
5204 getIdentifierCString(), whichOp
);
5205 result
= kOSKextReturnBadData
;
5209 kext_map
= kext_get_vm_map(kmod_info
);
5210 depth
= (kernel_map
== kext_map
) ? 1 : 2;
5212 /* Verify that the start/stop function lies within the kext's address range.
5214 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
5215 kmod_info
->address
+ kmod_info
->size
<= address
)
5218 kOSKextLogErrorLevel
|
5220 "Kext %s module %s pointer is outside of kext range "
5221 "(%s %p - kext at %p-%p)..",
5222 getIdentifierCString(),
5226 (void *)kmod_info
->address
,
5227 (void *)(kmod_info
->address
+ kmod_info
->size
));
5228 result
= kOSKextReturnBadData
;
5232 /* Only do these checks before calling the start function;
5233 * If anything goes wrong with the mapping while the kext is running,
5234 * we'll likely have panicked well before any attempt to stop the kext.
5238 /* Verify that the start/stop function is executable.
5240 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
5241 (vm_region_recurse_info_t
)&info
, &count
);
5242 if (kern_result
!= KERN_SUCCESS
) {
5244 kOSKextLogErrorLevel
|
5246 "Kext %s - bad %s pointer %p.",
5247 getIdentifierCString(),
5248 whichOp
, (void *)address
);
5249 result
= kOSKextReturnBadData
;
5253 if (!(info
.protection
& VM_PROT_EXECUTE
)) {
5255 kOSKextLogErrorLevel
|
5257 "Kext %s - memory region containing module %s function "
5258 "is not executable.",
5259 getIdentifierCString(), whichOp
);
5260 result
= kOSKextReturnBadData
;
5264 /* Verify that the kext's segments are backed by physical memory.
5266 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5268 if (!verifySegmentMapping(seg
)) {
5269 result
= kOSKextReturnBadData
;
5273 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5278 result
= kOSReturnSuccess
;
5283 /*********************************************************************
5284 *********************************************************************/
5286 OSKext::verifySegmentMapping(kernel_segment_command_t
*seg
)
5288 mach_vm_address_t address
= 0;
5290 if (!segmentShouldBeWired(seg
)) return true;
5292 for (address
= seg
->vmaddr
;
5293 address
< round_page(seg
->vmaddr
+ seg
->vmsize
);
5294 address
+= PAGE_SIZE
)
5296 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
5298 kOSKextLogErrorLevel
|
5300 "Kext %s - page %p is not backed by physical memory.",
5301 getIdentifierCString(),
5310 /*********************************************************************
5311 *********************************************************************/
5313 OSKext::start(bool startDependenciesFlag
)
5315 OSReturn result
= kOSReturnError
;
5316 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
5317 unsigned int i
, count
;
5318 void * kmodStartData
= NULL
; // special handling needed
5319 #if CONFIG_MACF_KEXT
5320 mach_msg_type_number_t kmodStartDataCount
= 0;
5321 #endif /* CONFIG_MACF_KEXT */
5323 if (isStarted() || isInterface() || isKernelComponent()) {
5324 result
= kOSReturnSuccess
;
5330 kOSKextLogErrorLevel
|
5332 "Attempt to start nonloaded kext %s.",
5333 getIdentifierCString());
5334 result
= kOSKextReturnInvalidArgument
;
5338 if (!sLoadEnabled
) {
5340 kOSKextLogErrorLevel
|
5342 "Kext loading is disabled (attempt to start kext %s).",
5343 getIdentifierCString());
5344 result
= kOSKextReturnDisabled
;
5348 result
= validateKextMapping(/* start? */ true);
5349 if (result
!= kOSReturnSuccess
) {
5353 startfunc
= kmod_info
->start
;
5355 count
= getNumDependencies();
5356 for (i
= 0; i
< count
; i
++) {
5357 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
5358 if (dependency
== NULL
) {
5360 kOSKextLogErrorLevel
|
5362 "Kext %s start - internal error, dependency disappeared.",
5363 getIdentifierCString());
5366 if (!dependency
->isStarted()) {
5367 if (startDependenciesFlag
) {
5368 OSReturn dependencyResult
=
5369 dependency
->start(startDependenciesFlag
);
5370 if (dependencyResult
!= KERN_SUCCESS
) {
5372 kOSKextLogErrorLevel
|
5374 "Kext %s start - dependency %s failed to start (error 0x%x).",
5375 getIdentifierCString(),
5376 dependency
->getIdentifierCString(),
5382 kOSKextLogErrorLevel
|
5384 "Not starting %s - dependency %s not started yet.",
5385 getIdentifierCString(),
5386 dependency
->getIdentifierCString());
5387 result
= kOSKextReturnStartStopError
; // xxx - make new return?
5393 #if CONFIG_MACF_KEXT
5394 /* See if the kext has any MAC framework module data in its plist.
5395 * This is passed in as arg #2 of the kext's start routine,
5396 * which is otherwise reserved for any other kext.
5398 kmodStartData
= MACFCopyModuleDataForKext(this, &kmodStartDataCount
);
5399 #endif /* CONFIG_MACF_KEXT */
5402 kOSKextLogDetailLevel
|
5404 "Kext %s calling module start function.",
5405 getIdentifierCString());
5409 #if !CONFIG_STATIC_CPPINIT
5410 result
= OSRuntimeInitializeCPP(kmod_info
, NULL
);
5411 if (result
== KERN_SUCCESS
) {
5414 result
= startfunc(kmod_info
, kmodStartData
);
5416 #if !CONFIG_STATIC_CPPINIT
5417 if (result
!= KERN_SUCCESS
) {
5418 (void) OSRuntimeFinalizeCPP(kmod_info
, NULL
);
5425 /* On success overlap the setting of started/starting. On failure just
5428 if (result
== KERN_SUCCESS
) {
5431 // xxx - log start error from kernel?
5433 kOSKextLogProgressLevel
|
5435 "Kext %s is now started.",
5436 getIdentifierCString());
5438 invokeOrCancelRequestCallbacks(
5439 /* result not actually used */ kOSKextReturnStartStopError
,
5440 /* invokeFlag */ false);
5442 kOSKextLogProgressLevel
|
5444 "Kext %s did not start (return code 0x%x).",
5445 getIdentifierCString(), result
);
5449 #if CONFIG_MACF_KEXT
5450 /* Free the module data for a MAC framework kext. When we start using
5451 * param #2 we'll have to distinguish and free/release appropriately.
5453 * xxx - I'm pretty sure the old codepath freed the data and that it's
5454 * xxx - up to the kext to copy it.
5456 if (kmodStartData
) {
5457 kmem_free(kernel_map
, (vm_offset_t
)kmodStartData
, kmodStartDataCount
);
5459 #endif /* CONFIG_MACF_KEXT */
5464 /*********************************************************************
5465 *********************************************************************/
5467 bool OSKext::canUnloadKextWithIdentifier(
5468 OSString
* kextIdentifier
,
5469 bool checkClassesFlag
)
5471 bool result
= false;
5472 OSKext
* aKext
= NULL
; // do not release
5474 IORecursiveLockLock(sKextLock
);
5476 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
5479 goto finish
; // can't unload what's not loaded
5482 if (aKext
->isLoaded()) {
5483 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
5486 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
5494 IORecursiveLockUnlock(sKextLock
);
5498 /*********************************************************************
5499 *********************************************************************/
5503 OSReturn result
= kOSReturnError
;
5504 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
5506 if (!isStarted() || isInterface()) {
5507 result
= kOSReturnSuccess
;
5513 kOSKextLogErrorLevel
|
5515 "Attempt to stop nonloaded kext %s.",
5516 getIdentifierCString());
5517 result
= kOSKextReturnInvalidArgument
;
5521 /* Refuse to stop if we have clients or instances. It is up to
5522 * the caller to make sure those aren't true.
5524 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5526 kOSKextLogErrorLevel
|
5528 "Kext %s - C++ instances; can't stop.",
5529 getIdentifierCString());
5530 result
= kOSKextReturnInUse
;
5534 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5537 kOSKextLogErrorLevel
|
5539 "Kext %s - has references (linkage or tracking object); "
5541 getIdentifierCString());
5542 result
= kOSKextReturnInUse
;
5546 /* Note: If validateKextMapping fails on the stop & unload path,
5547 * we are in serious trouble and a kernel panic is likely whether
5548 * we stop & unload the kext or not.
5550 result
= validateKextMapping(/* start? */ false);
5551 if (result
!= kOSReturnSuccess
) {
5555 stopfunc
= kmod_info
->stop
;
5558 kOSKextLogDetailLevel
|
5560 "Kext %s calling module stop function.",
5561 getIdentifierCString());
5565 result
= stopfunc(kmod_info
, /* userData */ NULL
);
5566 #if !CONFIG_STATIC_CPPINIT
5567 if (result
== KERN_SUCCESS
) {
5568 result
= OSRuntimeFinalizeCPP(kmod_info
, NULL
);
5574 if (result
== KERN_SUCCESS
) {
5578 kOSKextLogDetailLevel
|
5580 "Kext %s is now stopped and ready to unload.",
5581 getIdentifierCString());
5584 kOSKextLogErrorLevel
|
5586 "Kext %s did not stop (return code 0x%x).",
5587 getIdentifierCString(), result
);
5588 result
= kOSKextReturnStartStopError
;
5596 /*********************************************************************
5597 *********************************************************************/
5599 OSKext::unload(void)
5601 OSReturn result
= kOSReturnError
;
5603 uint32_t num_kmod_refs
= 0;
5605 if (!sUnloadEnabled
) {
5607 kOSKextLogErrorLevel
|
5609 "Kext unloading is disabled (%s).",
5610 this->getIdentifierCString());
5612 result
= kOSKextReturnDisabled
;
5616 /* Refuse to unload if we have clients or instances. It is up to
5617 * the caller to make sure those aren't true.
5619 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5620 // xxx - Don't log under errors? this is more of an info thing
5622 kOSKextLogErrorLevel
|
5623 kOSKextLogKextBookkeepingFlag
,
5624 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5625 getIdentifierCString());
5626 result
= kOSKextReturnInUse
;
5630 if (hasOSMetaClassInstances()) {
5632 kOSKextLogErrorLevel
|
5633 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5634 "Can't unload kext %s; classes have instances:",
5635 getIdentifierCString());
5636 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
5637 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
5638 result
= kOSKextReturnInUse
;
5643 result
= kOSReturnSuccess
;
5647 if (isKernelComponent()) {
5648 result
= kOSKextReturnInvalidArgument
;
5652 /* Note that the kext is unloading before running any code that
5653 * might be in the kext (request callbacks, module stop function).
5654 * We will deny certain requests made against a kext in the process
5657 flags
.unloading
= 1;
5659 /* Update the string describing the last kext to unload in case we panic.
5661 savePanicString(/* isLoading */ false);
5665 if (result
!= KERN_SUCCESS
) {
5667 kOSKextLogErrorLevel
|
5669 "Kext %s can't unload - module stop returned 0x%x.",
5670 getIdentifierCString(), (unsigned)result
);
5671 result
= kOSKextReturnStartStopError
;
5677 kOSKextLogProgressLevel
|
5679 "Kext %s unloading.",
5680 getIdentifierCString());
5682 /* Even if we don't call the stop function, we want to be sure we
5683 * have no OSMetaClass references before unloading the kext executable
5684 * from memory. OSMetaClasses may have pointers into the kext executable
5685 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5688 metaClasses
->flushCollection();
5691 /* Remove the kext from the list of loaded kexts, patch the gap
5692 * in the kmod_info_t linked list, and reset "kmod" to point to the
5693 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5695 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
5696 if (index
!= (unsigned int)-1) {
5698 sLoadedKexts
->removeObject(index
);
5700 OSKext
* nextKext
= OSDynamicCast(OSKext
,
5701 sLoadedKexts
->getObject(index
));
5705 OSKext
* gapKext
= OSDynamicCast(OSKext
,
5706 sLoadedKexts
->getObject(index
- 1));
5708 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
5710 } else /* index == 0 */ {
5711 nextKext
->kmod_info
->next
= NULL
;
5715 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5716 if (lastKext
&& !lastKext
->isKernel()) {
5717 kmod
= lastKext
->kmod_info
;
5719 kmod
= NULL
; // clear the global kmod variable
5723 /* Clear out the kmod references that we're keeping for compatibility
5724 * with current panic backtrace code & kgmacros.
5725 * xxx - will want to update those bits sometime and remove this.
5727 num_kmod_refs
= getNumDependencies();
5728 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
5729 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
5730 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
5731 ref
->info
->reference_count
--;
5733 kfree(kmod_info
->reference_list
,
5734 num_kmod_refs
* sizeof(kmod_reference_t
));
5738 unregisterWithDTrace();
5739 #endif /* CONFIG_DTRACE */
5741 notifyKextUnloadObservers(this);
5743 /* Unwire and free the linked executable.
5745 if (linkedExecutable
) {
5746 if (!isInterface()) {
5747 kernel_segment_command_t
*seg
= NULL
;
5748 vm_map_t kext_map
= kext_get_vm_map(kmod_info
);
5752 kOSKextLogErrorLevel
|
5754 "Failed to free kext %s; couldn't find the kext map.",
5755 getIdentifierCString());
5756 result
= kOSKextReturnInternalError
;
5761 kOSKextLogProgressLevel
|
5763 "Kext %s unwiring and unmapping linked executable.",
5764 getIdentifierCString());
5766 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5768 if (segmentShouldBeWired(seg
)) {
5769 result
= vm_map_unwire(kext_map
, seg
->vmaddr
,
5770 seg
->vmaddr
+ seg
->vmsize
, FALSE
);
5771 if (result
!= KERN_SUCCESS
) {
5773 kOSKextLogErrorLevel
|
5775 "Failed to unwire kext %s.",
5776 getIdentifierCString());
5777 result
= kOSKextReturnInternalError
;
5782 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5786 OSSafeReleaseNULL(linkedExecutable
);
5789 /* An interface kext has a fake kmod_info that was allocated,
5790 * so we have to free it.
5792 if (isInterface()) {
5793 kfree(kmod_info
, sizeof(kmod_info_t
));
5798 flags
.loaded
= false;
5799 flushDependencies();
5801 /* save a copy of the bundle ID for us to check when deciding to
5802 * rebuild the kernel cache file. If a kext was already in the kernel
5803 * cache and unloaded then later loaded we do not need to rebuild the
5804 * kernel cache. 9055303
5806 if (isPrelinked()) {
5807 sUnloadedPrelinkedKexts
->setObject(bundleID
);
5811 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5812 "Kext %s unloaded.", getIdentifierCString());
5814 queueKextNotification(kKextRequestPredicateUnloadNotification
,
5815 OSDynamicCast(OSString
, bundleID
));
5818 OSKext::saveLoadedKextPanicList();
5819 OSKext::updateLoadedKextSummaries();
5821 flags
.unloading
= 0;
5825 /*********************************************************************
5826 * Assumes sKextLock is held.
5827 *********************************************************************/
5830 OSKext::queueKextNotification(
5831 const char * notificationName
,
5832 OSString
* kextIdentifier
)
5834 OSReturn result
= kOSReturnError
;
5835 OSDictionary
* loadRequest
= NULL
; // must release
5837 if (!kextIdentifier
) {
5838 result
= kOSKextReturnInvalidArgument
;
5842 /* Create a new request unless one is already sitting
5843 * in sKernelRequests for this bundle identifier
5845 result
= _OSKextCreateRequest(notificationName
, &loadRequest
);
5846 if (result
!= kOSReturnSuccess
) {
5849 if (!_OSKextSetRequestArgument(loadRequest
,
5850 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
5852 result
= kOSKextReturnNoMemory
;
5855 if (!sKernelRequests
->setObject(loadRequest
)) {
5856 result
= kOSKextReturnNoMemory
;
5860 /* We might want to only queue the notification if kextd is active,
5861 * but that wouldn't work for embedded. Note that we don't care if
5862 * the ping immediately succeeds here so don't do anything with the
5863 * result of this call.
5865 OSKext::pingKextd();
5867 result
= kOSReturnSuccess
;
5870 OSSafeRelease(loadRequest
);
5875 /*********************************************************************
5876 *********************************************************************/
5878 _OSKextConsiderDestroyingLinkContext(
5879 __unused thread_call_param_t p0
,
5880 __unused thread_call_param_t p1
)
5882 /* Take multiple locks in the correct order.
5884 IORecursiveLockLock(sKextLock
);
5885 IORecursiveLockLock(sKextInnerLock
);
5887 /* The first time we destroy the kxldContext is in the first
5888 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5889 * before calling this function. Thereafter any call to this function
5890 * will actually destroy the context.
5892 if (sConsiderUnloadsCalled
&& sKxldContext
) {
5893 kxld_destroy_context(sKxldContext
);
5894 sKxldContext
= NULL
;
5897 /* Free the thread_call that was allocated to execute this function.
5899 if (sDestroyLinkContextThread
) {
5900 if (!thread_call_free(sDestroyLinkContextThread
)) {
5901 OSKextLog(/* kext */ NULL
,
5902 kOSKextLogErrorLevel
|
5903 kOSKextLogGeneralFlag
,
5904 "thread_call_free() failed for kext link context.");
5906 sDestroyLinkContextThread
= 0;
5909 IORecursiveLockUnlock(sKextInnerLock
);
5910 IORecursiveLockUnlock(sKextLock
);
5915 /*********************************************************************
5916 * Destroying the kxldContext requires checking variables under both
5917 * sKextInnerLock and sKextLock, so we do it on a separate thread
5918 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5919 * call relationship.
5921 * This function must be invoked with sKextInnerLock held.
5922 * Do not call any function that takes sKextLock here!
5923 *********************************************************************/
5926 OSKext::considerDestroyingLinkContext(void)
5928 IORecursiveLockLock(sKextInnerLock
);
5930 /* If we have already queued a thread to destroy the link context,
5931 * don't bother resetting; that thread will take care of it.
5933 if (sDestroyLinkContextThread
) {
5937 /* The function to be invoked in the thread will deallocate
5938 * this thread_call, so don't share it around.
5940 sDestroyLinkContextThread
= thread_call_allocate(
5941 &_OSKextConsiderDestroyingLinkContext
, 0);
5942 if (!sDestroyLinkContextThread
) {
5943 OSKextLog(/* kext */ NULL
,
5944 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
5945 "Can't create thread to destroy kext link context.");
5949 thread_call_enter(sDestroyLinkContextThread
);
5952 IORecursiveLockUnlock(sKextInnerLock
);
5957 #pragma mark Autounload
5959 /*********************************************************************
5960 * This is a static method because the kext will be deallocated if it
5962 *********************************************************************/
5965 OSKext::autounloadKext(OSKext
* aKext
)
5967 OSReturn result
= kOSKextReturnInUse
;
5969 /* Check for external references to this kext (usu. dependents),
5970 * instances of defined classes (or classes derived from them),
5971 * outstanding requests.
5973 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
5974 !aKext
->flags
.autounloadEnabled
||
5975 aKext
->isKernelComponent()) {
5980 /* Skip a delay-autounload kext, once.
5982 if (aKext
->flags
.delayAutounload
) {
5984 kOSKextLogProgressLevel
|
5985 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5986 "Kext %s has delayed autounload set; skipping and clearing flag.",
5987 aKext
->getIdentifierCString());
5988 aKext
->flags
.delayAutounload
= 0;
5992 if (aKext
->hasOSMetaClassInstances() ||
5993 aKext
->countRequestCallbacks()) {
5997 result
= OSKext::removeKext(aKext
);
6004 /*********************************************************************
6005 *********************************************************************/
6007 _OSKextConsiderUnloads(
6008 __unused thread_call_param_t p0
,
6009 __unused thread_call_param_t p1
)
6011 bool didUnload
= false;
6012 unsigned int count
, i
;
6014 /* Take multiple locks in the correct order
6015 * (note also sKextSummaries lock further down).
6017 IORecursiveLockLock(sKextLock
);
6018 IORecursiveLockLock(sKextInnerLock
);
6020 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
6022 IOLockLock(sKextSummariesLock
);
6024 /* If there is an old kext summary, free that now.
6026 if (sPrevLoadedKextSummaries
) {
6027 kmem_free(kernel_map
, (vm_offset_t
)sPrevLoadedKextSummaries
,
6028 sPrevLoadedKextSummariesAllocSize
);
6029 sPrevLoadedKextSummaries
= NULL
;
6030 sPrevLoadedKextSummariesAllocSize
= 0;
6033 IOLockUnlock(sKextSummariesLock
);
6035 /* If the system is powering down, don't try to unload anything.
6041 OSKextLog(/* kext */ NULL
,
6042 kOSKextLogProgressLevel
|
6044 "Checking for unused kexts to autounload.");
6047 * Remove any request callbacks marked as stale,
6048 * and mark as stale any currently in flight.
6050 count
= sRequestCallbackRecords
->getCount();
6054 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
6055 sRequestCallbackRecords
->getObject(i
));
6056 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
6057 callbackRecord
->getObject(kKextRequestStaleKey
));
6059 if (stale
== kOSBooleanTrue
) {
6060 OSKext::invokeRequestCallback(callbackRecord
,
6061 kOSKextReturnTimeout
);
6063 callbackRecord
->setObject(kKextRequestStaleKey
,
6070 * Make multiple passes through the array of loaded kexts until
6071 * we don't unload any. This handles unwinding of dependency
6072 * chains. We have to go *backwards* through the array because
6073 * kexts are removed from it when unloaded, and we cannot make
6074 * a copy or we'll mess up the retain counts we rely on to
6075 * check whether a kext will unload. If only we could have
6076 * nonretaining collections like CF has....
6081 count
= sLoadedKexts
->getCount();
6085 OSKext
* thisKext
= OSDynamicCast(OSKext
,
6086 sLoadedKexts
->getObject(i
));
6087 didUnload
= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
6090 } while (didUnload
);
6093 sConsiderUnloadsPending
= false;
6094 sConsiderUnloadsExecuted
= true;
6096 (void) OSKext::considerRebuildOfPrelinkedKernel(NULL
);
6098 IORecursiveLockUnlock(sKextInnerLock
);
6099 IORecursiveLockUnlock(sKextLock
);
6104 /*********************************************************************
6105 * Do not call any function that takes sKextLock here!
6106 *********************************************************************/
6107 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
6111 IORecursiveLockLock(sKextInnerLock
);
6113 if (!sUnloadCallout
) {
6114 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, 0);
6117 /* we only reset delay value for unloading if we already have something
6118 * pending. rescheduleOnlyFlag should not start the count down.
6120 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
6124 thread_call_cancel(sUnloadCallout
);
6125 if (OSKext::getAutounloadEnabled() && !sSystemSleep
) {
6126 clock_interval_to_deadline(sConsiderUnloadDelay
,
6127 1000 * 1000 * 1000, &when
);
6129 OSKextLog(/* kext */ NULL
,
6130 kOSKextLogProgressLevel
|
6132 "%scheduling %sscan for unused kexts in %lu seconds.",
6133 sConsiderUnloadsPending
? "Res" : "S",
6134 sConsiderUnloadsCalled
? "" : "initial ",
6135 (unsigned long)sConsiderUnloadDelay
);
6137 sConsiderUnloadsPending
= true;
6138 thread_call_enter_delayed(sUnloadCallout
, when
);
6142 /* The kxld context should be reused throughout boot. We mark the end of
6143 * period as the first time considerUnloads() is called, and we destroy
6144 * the first kxld context in that function. Afterwards, it will be
6145 * destroyed in flushNonloadedKexts.
6147 if (!sConsiderUnloadsCalled
) {
6148 sConsiderUnloadsCalled
= true;
6149 OSKext::considerDestroyingLinkContext();
6152 IORecursiveLockUnlock(sKextInnerLock
);
6156 /*********************************************************************
6157 * Do not call any function that takes sKextLock here!
6158 *********************************************************************/
6161 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
)
6163 IORecursiveLockLock(sKextInnerLock
);
6165 /* If the system is going to sleep, cancel the reaper thread timer,
6166 * and note that we're in a sleep state in case it just fired but hasn't
6167 * taken the lock yet. If we are coming back from sleep, just
6168 * clear the sleep flag; IOService's normal operation will cause
6169 * unloads to be considered soon enough.
6171 if (messageType
== kIOMessageSystemWillSleep
) {
6172 if (sUnloadCallout
) {
6173 thread_call_cancel(sUnloadCallout
);
6175 sSystemSleep
= true;
6176 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
6177 sSystemSleep
= false;
6179 IORecursiveLockUnlock(sKextInnerLock
);
6181 return kIOReturnSuccess
;
6188 #pragma mark Prelinked Kernel
6190 /*********************************************************************
6191 * Do not access sConsiderUnloads... variables other than
6192 * sConsiderUnloadsExecuted in this function. They are guarded by a
6194 *********************************************************************/
6197 OSKext::considerRebuildOfPrelinkedKernel(OSString
* moduleName
)
6199 OSReturn checkResult
= kOSReturnError
;
6200 static bool requestedPrelink
= false;
6201 OSDictionary
* prelinkRequest
= NULL
; // must release
6203 IORecursiveLockLock(sKextLock
);
6205 /* moduleName is only passed when we see a load come in. We are only
6206 * interested in rebuilding the kernel cache if the kext we are loading
6207 * is not already in the original kernel cache. 9055303
6210 int count
= sUnloadedPrelinkedKexts
->getCount();
6213 for (i
= 0; i
< count
; i
++) {
6214 const OSSymbol
* myBundleID
; // do not release
6216 myBundleID
= OSDynamicCast(OSSymbol
, sUnloadedPrelinkedKexts
->getObject(i
));
6217 if (!myBundleID
) continue;
6218 if (moduleName
->isEqualTo(myBundleID
->getCStringNoCopy())) {
6219 OSKextLog(/* kext */ NULL
,
6220 kOSKextLogDetailLevel
|
6221 kOSKextLogArchiveFlag
,
6222 "bundleID %s already in cache skipping rebuild.",
6223 myBundleID
->getCStringNoCopy());
6225 /* no need to rebuild, already in kernel cache */
6229 (void) OSKext::setDeferredLoadSucceeded();
6232 if (!sDeferredLoadSucceeded
|| !sConsiderUnloadsExecuted
||
6233 sSafeBoot
|| requestedPrelink
)
6238 OSKextLog(/* kext */ NULL
,
6239 kOSKextLogProgressLevel
|
6240 kOSKextLogArchiveFlag
,
6241 "Requesting build of prelinked kernel.");
6243 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
6245 if (checkResult
!= kOSReturnSuccess
) {
6249 if (!sKernelRequests
->setObject(prelinkRequest
)) {
6253 OSKext::pingKextd();
6254 requestedPrelink
= true;
6257 IORecursiveLockUnlock(sKextLock
);
6258 OSSafeRelease(prelinkRequest
);
6263 #pragma mark Dependencies
6265 /*********************************************************************
6266 *********************************************************************/
6268 OSKext::resolveDependencies(
6269 OSArray
* loopStack
)
6271 bool result
= false;
6272 OSArray
* localLoopStack
= NULL
; // must release
6273 bool addedToLoopStack
= false;
6274 OSDictionary
* libraries
= NULL
; // do not release
6275 OSCollectionIterator
* libraryIterator
= NULL
; // must release
6276 OSString
* libraryID
= NULL
; // do not release
6277 OSString
* infoString
= NULL
; // do not release
6278 OSString
* readableString
= NULL
; // do not release
6279 OSKext
* libraryKext
= NULL
; // do not release
6280 bool hasRawKernelDependency
= false;
6281 bool hasKernelDependency
= false;
6282 bool hasKPIDependency
= false;
6283 bool hasPrivateKPIDependency
= false;
6286 /* A kernel component will automatically have this flag set,
6287 * and a loaded kext should also have it set (as should all its
6288 * loaded dependencies).
6290 if (flags
.hasAllDependencies
) {
6295 /* Check for loops in the dependency graph.
6298 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
6300 kOSKextLogErrorLevel
|
6301 kOSKextLogDependenciesFlag
,
6302 "Kext %s has a dependency loop; can't resolve dependencies.",
6303 getIdentifierCString());
6308 kOSKextLogStepLevel
|
6309 kOSKextLogDependenciesFlag
,
6310 "Kext %s resolving dependencies.",
6311 getIdentifierCString());
6313 loopStack
= OSArray::withCapacity(6); // any small capacity will do
6316 kOSKextLogErrorLevel
|
6317 kOSKextLogDependenciesFlag
,
6318 "Kext %s can't create bookkeeping stack to resolve dependencies.",
6319 getIdentifierCString());
6322 localLoopStack
= loopStack
;
6324 if (!loopStack
->setObject(this)) {
6326 kOSKextLogErrorLevel
|
6327 kOSKextLogDependenciesFlag
,
6328 "Kext %s - internal error resolving dependencies.",
6329 getIdentifierCString());
6332 addedToLoopStack
= true;
6334 /* Purge any existing kexts in the dependency list and start over.
6336 flushDependencies();
6339 kOSKextLogErrorLevel
|
6340 kOSKextLogDependenciesFlag
,
6341 "Kext %s - internal error resolving dependencies.",
6342 getIdentifierCString());
6345 libraries
= OSDynamicCast(OSDictionary
,
6346 getPropertyForHostArch(kOSBundleLibrariesKey
));
6347 if (libraries
== NULL
|| libraries
->getCount() == 0) {
6349 kOSKextLogErrorLevel
|
6350 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6351 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
6352 getIdentifierCString(), kOSBundleLibrariesKey
);
6356 /* Make a new array to hold the dependencies (flush freed the old one).
6358 dependencies
= OSArray::withCapacity(libraries
->getCount());
6359 if (!dependencies
) {
6361 kOSKextLogErrorLevel
|
6362 kOSKextLogDependenciesFlag
,
6363 "Kext %s - can't allocate dependencies array.",
6364 getIdentifierCString());
6368 // xxx - compat: We used to add an implicit dependency on kernel 6.0
6369 // xxx - compat: if none were declared.
6371 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
6372 if (!libraryIterator
) {
6374 kOSKextLogErrorLevel
|
6375 kOSKextLogDependenciesFlag
,
6376 "Kext %s - can't allocate dependencies iterator.",
6377 getIdentifierCString());
6381 while ((libraryID
= OSDynamicCast(OSString
,
6382 libraryIterator
->getNextObject()))) {
6384 const char * library_id
= libraryID
->getCStringNoCopy();
6386 OSString
* libraryVersion
= OSDynamicCast(OSString
,
6387 libraries
->getObject(libraryID
));
6388 if (libraryVersion
== NULL
) {
6390 kOSKextLogErrorLevel
|
6391 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6392 "Kext %s - illegal type in OSBundleLibraries.",
6393 getIdentifierCString());
6397 OSKextVersion libraryVers
=
6398 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
6399 if (libraryVers
== -1) {
6401 kOSKextLogErrorLevel
|
6402 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6403 "Kext %s - invalid library version %s.",
6404 getIdentifierCString(),
6405 libraryVersion
->getCStringNoCopy());
6409 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
6410 if (libraryKext
== NULL
) {
6412 kOSKextLogErrorLevel
|
6413 kOSKextLogDependenciesFlag
,
6414 "Kext %s - library kext %s not found.",
6415 getIdentifierCString(), library_id
);
6419 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
6421 kOSKextLogErrorLevel
|
6422 kOSKextLogDependenciesFlag
,
6423 "Kext %s - library kext %s not compatible "
6424 "with requested version %s.",
6425 getIdentifierCString(), library_id
,
6426 libraryVersion
->getCStringNoCopy());
6430 /* If a nonprelinked library somehow got into the mix for a
6431 * prelinked kext, at any point in the chain, we must fail
6432 * because the prelinked relocs for the library will be all wrong.
6434 if (this->isPrelinked() &&
6435 libraryKext
->declaresExecutable() &&
6436 !libraryKext
->isPrelinked()) {
6439 kOSKextLogErrorLevel
|
6440 kOSKextLogDependenciesFlag
,
6441 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
6442 getIdentifierCString(), library_id
,
6443 libraryVersion
->getCStringNoCopy());
6447 if (!libraryKext
->resolveDependencies(loopStack
)) {
6451 /* Add the library directly only if it has an executable to link.
6452 * Otherwise it's just used to collect other dependencies, so put
6453 * *its* dependencies on the list for this kext.
6455 // xxx - We are losing info here; would like to make fake entries or
6456 // xxx - keep these in the dependency graph for loaded kexts.
6457 // xxx - I really want to make kernel components not a special case!
6458 if (libraryKext
->declaresExecutable() ||
6459 libraryKext
->isInterface()) {
6461 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
6462 dependencies
->setObject(libraryKext
);
6465 kOSKextLogDetailLevel
|
6466 kOSKextLogDependenciesFlag
,
6467 "Kext %s added dependency %s.",
6468 getIdentifierCString(),
6469 libraryKext
->getIdentifierCString());
6472 int numLibDependencies
= libraryKext
->getNumDependencies();
6473 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
6476 if (numLibDependencies
) {
6477 // xxx - this msg level should be 1 lower than the per-kext one
6479 kOSKextLogDetailLevel
|
6480 kOSKextLogDependenciesFlag
,
6481 "Kext %s pulling %d dependencies from codeless library %s.",
6482 getIdentifierCString(),
6484 libraryKext
->getIdentifierCString());
6486 for (index
= 0; index
< numLibDependencies
; index
++) {
6487 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
6488 libraryDependencies
->getObject(index
));
6489 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
6490 dependencies
->setObject(thisLibDependency
);
6492 kOSKextLogDetailLevel
|
6493 kOSKextLogDependenciesFlag
,
6494 "Kext %s added dependency %s from codeless library %s.",
6495 getIdentifierCString(),
6496 thisLibDependency
->getIdentifierCString(),
6497 libraryKext
->getIdentifierCString());
6502 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
6503 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
)-1)) {
6505 hasRawKernelDependency
= true;
6506 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
6507 hasKernelDependency
= true;
6508 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
6509 hasKPIDependency
= true;
6510 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
)-1)) {
6511 hasPrivateKPIDependency
= true;
6516 if (hasRawKernelDependency
) {
6518 kOSKextLogErrorLevel
|
6519 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6520 "Error - kext %s declares a dependency on %s, which is not permitted.",
6521 getIdentifierCString(), KERNEL_LIB
);
6525 if (hasKernelDependency
) {
6527 kOSKextLogErrorLevel
|
6528 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6529 "Error - kext %s declares %s dependencies. "
6530 "Only %s* dependencies are supported for 64-bit kexts.",
6531 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
6534 if (!hasKPIDependency
) {
6536 kOSKextLogWarningLevel
|
6537 kOSKextLogDependenciesFlag
,
6538 "Warning - kext %s declares no %s* dependencies. "
6539 "If it uses any KPIs, the link may fail with undefined symbols.",
6540 getIdentifierCString(), KPI_LIB_PREFIX
);
6542 #else /* __LP64__ */
6543 // xxx - will change to flatly disallow "kernel" dependencies at some point
6544 // xxx - is it invalid to do both "com.apple.kernel" and any
6545 // xxx - "com.apple.kernel.*"?
6547 if (hasKernelDependency
&& hasKPIDependency
) {
6549 kOSKextLogWarningLevel
|
6550 kOSKextLogDependenciesFlag
,
6551 "Warning - kext %s has immediate dependencies on both "
6552 "%s* and %s* components; use only one style.",
6553 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
6556 if (!hasKernelDependency
&& !hasKPIDependency
) {
6557 // xxx - do we want to use validation flag for these too?
6559 kOSKextLogWarningLevel
|
6560 kOSKextLogDependenciesFlag
,
6561 "Warning - %s declares no kernel dependencies; using %s.",
6562 getIdentifierCString(), KERNEL6_LIB
);
6563 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
6564 sKextsByID
->getObject(KERNEL6_LIB
));
6566 dependencies
->setObject(kernelKext
);
6569 kOSKextLogErrorLevel
|
6570 kOSKextLogDependenciesFlag
,
6571 "Error - Library %s not found for %s.",
6572 KERNEL6_LIB
, getIdentifierCString());
6576 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
6577 * its indirect dependencies to simulate old-style linking. XXX - Should
6578 * check for duplicates.
6580 if (!hasKPIDependency
) {
6583 flags
.hasBleedthrough
= true;
6585 count
= getNumDependencies();
6587 /* We add to the dependencies array in this loop, but do not iterate
6588 * past its original count.
6590 for (i
= 0; i
< count
; i
++) {
6591 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
6592 dependencies
->getObject(i
));
6593 dependencyKext
->addBleedthroughDependencies(dependencies
);
6596 #endif /* __LP64__ */
6598 if (hasPrivateKPIDependency
) {
6599 bool hasApplePrefix
= false;
6600 bool infoCopyrightIsValid
= false;
6601 bool readableCopyrightIsValid
= false;
6603 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
6606 infoString
= OSDynamicCast(OSString
,
6607 getPropertyForHostArch("CFBundleGetInfoString"));
6609 infoCopyrightIsValid
=
6610 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
6613 readableString
= OSDynamicCast(OSString
,
6614 getPropertyForHostArch("NSHumanReadableCopyright"));
6615 if (readableString
) {
6616 readableCopyrightIsValid
=
6617 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
6620 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
6622 kOSKextLogErrorLevel
|
6623 kOSKextLogDependenciesFlag
,
6624 "Error - kext %s declares a dependency on %s. "
6625 "Only Apple kexts may declare a dependency on %s.",
6626 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
6632 flags
.hasAllDependencies
= 1;
6636 if (addedToLoopStack
) {
6637 count
= loopStack
->getCount();
6638 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
6639 loopStack
->removeObject(count
- 1);
6642 kOSKextLogErrorLevel
|
6643 kOSKextLogDependenciesFlag
,
6644 "Kext %s - internal error resolving dependencies.",
6645 getIdentifierCString());
6649 if (result
&& localLoopStack
) {
6651 kOSKextLogStepLevel
|
6652 kOSKextLogDependenciesFlag
,
6653 "Kext %s successfully resolved dependencies.",
6654 getIdentifierCString());
6657 OSSafeRelease(localLoopStack
);
6658 OSSafeRelease(libraryIterator
);
6663 /*********************************************************************
6664 *********************************************************************/
6666 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
6668 bool result
= false;
6669 unsigned int dependencyIndex
, dependencyCount
;
6671 dependencyCount
= getNumDependencies();
6673 for (dependencyIndex
= 0;
6674 dependencyIndex
< dependencyCount
;
6675 dependencyIndex
++) {
6677 OSKext
* dependency
= OSDynamicCast(OSKext
,
6678 dependencies
->getObject(dependencyIndex
));
6681 kOSKextLogErrorLevel
|
6682 kOSKextLogDependenciesFlag
,
6683 "Kext %s - internal error propagating compatibility dependencies.",
6684 getIdentifierCString());
6687 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
6688 anArray
->setObject(dependency
);
6690 dependency
->addBleedthroughDependencies(anArray
);
6699 /*********************************************************************
6700 *********************************************************************/
6702 OSKext::flushDependencies(bool forceFlag
)
6704 bool result
= false;
6706 /* Only clear the dependencies if the kext isn't loaded;
6707 * we need the info for loaded kexts to track references.
6709 if (!isLoaded() || forceFlag
) {
6711 // xxx - check level
6713 kOSKextLogProgressLevel
|
6714 kOSKextLogDependenciesFlag
,
6715 "Kext %s flushing dependencies.",
6716 getIdentifierCString());
6717 OSSafeReleaseNULL(dependencies
);
6720 if (!isKernelComponent()) {
6721 flags
.hasAllDependencies
= 0;
6729 /*********************************************************************
6730 *********************************************************************/
6732 OSKext::getNumDependencies(void)
6734 if (!dependencies
) {
6737 return dependencies
->getCount();
6740 /*********************************************************************
6741 *********************************************************************/
6743 OSKext::getDependencies(void)
6745 return dependencies
;
6749 #pragma mark OSMetaClass Support
6751 /*********************************************************************
6752 *********************************************************************/
6755 OSMetaClass
* aClass
,
6756 uint32_t numClasses
)
6758 OSReturn result
= kOSMetaClassNoInsKModSet
;
6761 metaClasses
= OSSet::withCapacity(numClasses
);
6767 if (metaClasses
->containsObject(aClass
)) {
6769 kOSKextLogWarningLevel
|
6771 "Notice - kext %s has already registered class %s.",
6772 getIdentifierCString(),
6773 aClass
->getClassName());
6774 result
= kOSReturnSuccess
;
6778 if (!metaClasses
->setObject(aClass
)) {
6782 kOSKextLogDetailLevel
|
6784 "Kext %s registered class %s.",
6785 getIdentifierCString(),
6786 aClass
->getClassName());
6789 if (!flags
.autounloadEnabled
) {
6790 const OSMetaClass
* metaScan
= NULL
; // do not release
6792 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
6793 if (metaScan
== OSTypeID(IOService
)) {
6796 kOSKextLogProgressLevel
|
6798 "Kext %s has IOService subclass %s; enabling autounload.",
6799 getIdentifierCString(),
6800 aClass
->getClassName());
6802 flags
.autounloadEnabled
= 1;
6808 notifyAddClassObservers(this, aClass
, flags
);
6810 result
= kOSReturnSuccess
;
6813 if (result
!= kOSReturnSuccess
) {
6815 kOSKextLogErrorLevel
|
6817 "Kext %s failed to register class %s.",
6818 getIdentifierCString(),
6819 aClass
->getClassName());
6825 /*********************************************************************
6826 *********************************************************************/
6828 OSKext::removeClass(
6829 OSMetaClass
* aClass
)
6831 OSReturn result
= kOSMetaClassNoKModSet
;
6837 if (!metaClasses
->containsObject(aClass
)) {
6839 kOSKextLogWarningLevel
|
6841 "Notice - kext %s asked to unregister unknown class %s.",
6842 getIdentifierCString(),
6843 aClass
->getClassName());
6844 result
= kOSReturnSuccess
;
6849 kOSKextLogDetailLevel
|
6851 "Kext %s unregistering class %s.",
6852 getIdentifierCString(),
6853 aClass
->getClassName());
6855 metaClasses
->removeObject(aClass
);
6857 notifyRemoveClassObservers(this, aClass
, flags
);
6859 result
= kOSReturnSuccess
;
6862 if (result
!= kOSReturnSuccess
) {
6864 kOSKextLogErrorLevel
|
6866 "Failed to unregister kext %s class %s.",
6867 getIdentifierCString(),
6868 aClass
->getClassName());
6873 /*********************************************************************
6874 *********************************************************************/
6876 OSKext::getMetaClasses(void)
6881 /*********************************************************************
6882 *********************************************************************/
6884 OSKext::hasOSMetaClassInstances(void)
6886 bool result
= false;
6887 OSCollectionIterator
* classIterator
= NULL
; // must release
6888 OSMetaClass
* checkClass
= NULL
; // do not release
6894 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6895 if (!classIterator
) {
6896 // xxx - log alloc failure?
6899 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6900 if (checkClass
->getInstanceCount()) {
6908 OSSafeRelease(classIterator
);
6912 /*********************************************************************
6913 *********************************************************************/
6916 OSKext::reportOSMetaClassInstances(
6917 const char * kextIdentifier
,
6918 OSKextLogSpec msgLogSpec
)
6920 OSKext
* theKext
= NULL
; // must release
6922 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
6927 theKext
->reportOSMetaClassInstances(msgLogSpec
);
6929 OSSafeRelease(theKext
);
6933 /*********************************************************************
6934 *********************************************************************/
6936 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
6938 OSCollectionIterator
* classIterator
= NULL
; // must release
6939 OSMetaClass
* checkClass
= NULL
; // do not release
6945 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6946 if (!classIterator
) {
6949 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6950 if (checkClass
->getInstanceCount()) {
6953 " Kext %s class %s has %d instance%s.",
6954 getIdentifierCString(),
6955 checkClass
->getClassName(),
6956 checkClass
->getInstanceCount(),
6957 checkClass
->getInstanceCount() == 1 ? "" : "s");
6962 OSSafeRelease(classIterator
);
6967 #pragma mark User-Space Requests
6969 /*********************************************************************
6970 * XXX - this function is a big ugly mess
6971 *********************************************************************/
6974 OSKext::handleRequest(
6975 host_priv_t hostPriv
,
6976 OSKextLogSpec clientLogFilter
,
6977 char * requestBuffer
,
6978 uint32_t requestLength
,
6979 char ** responseOut
,
6980 uint32_t * responseLengthOut
,
6982 uint32_t * logInfoLengthOut
)
6984 OSReturn result
= kOSReturnError
;
6985 kern_return_t kmem_result
= KERN_FAILURE
;
6987 char * response
= NULL
; // returned by reference
6988 uint32_t responseLength
= 0;
6990 OSObject
* parsedXML
= NULL
; // must release
6991 OSDictionary
* requestDict
= NULL
; // do not release
6992 OSString
* errorString
= NULL
; // must release
6994 OSData
* responseData
= NULL
; // must release
6995 OSObject
* responseObject
= NULL
; // must release
6997 OSSerialize
* serializer
= NULL
; // must release
6999 OSArray
* logInfoArray
= NULL
; // must release
7001 OSString
* predicate
= NULL
; // do not release
7002 OSString
* kextIdentifier
= NULL
; // do not release
7003 OSArray
* kextIdentifiers
= NULL
; // do not release
7004 OSKext
* theKext
= NULL
; // do not release
7005 OSBoolean
* boolArg
= NULL
; // do not release
7007 IORecursiveLockLock(sKextLock
);
7010 *responseOut
= NULL
;
7011 *responseLengthOut
= 0;
7015 *logInfoLengthOut
= 0;
7018 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
7020 /* XML must be nul-terminated.
7022 if (requestBuffer
[requestLength
- 1] != '\0') {
7023 OSKextLog(/* kext */ NULL
,
7024 kOSKextLogErrorLevel
|
7026 "Invalid request from user space (not nul-terminated).");
7027 result
= kOSKextReturnBadData
;
7030 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, &errorString
);
7032 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
);
7035 const char * errorCString
= "(unknown error)";
7037 if (errorString
&& errorString
->getCStringNoCopy()) {
7038 errorCString
= errorString
->getCStringNoCopy();
7039 } else if (parsedXML
) {
7040 errorCString
= "not a dictionary";
7042 OSKextLog(/* kext */ NULL
,
7043 kOSKextLogErrorLevel
|
7045 "Error unserializing request from user space: %s.",
7047 result
= kOSKextReturnSerialization
;
7051 predicate
= _OSKextGetRequestPredicate(requestDict
);
7053 OSKextLog(/* kext */ NULL
,
7054 kOSKextLogErrorLevel
|
7056 "Recieved kext request from user space with no predicate.");
7057 result
= kOSKextReturnInvalidArgument
;
7061 OSKextLog(/* kext */ NULL
,
7062 kOSKextLogDebugLevel
|
7064 "Received '%s' request from user space.",
7065 predicate
->getCStringNoCopy());
7067 result
= kOSKextReturnNotPrivileged
;
7068 if (hostPriv
== HOST_PRIV_NULL
) {
7069 if (!predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) &&
7070 !predicate
->isEqualTo(kKextRequestPredicateGetKernelImage
) &&
7071 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
7077 /* Get common args in anticipation of use.
7079 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
7080 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
7081 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
7082 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
7083 if (kextIdentifier
) {
7084 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
7086 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
7087 requestDict
, kKextRequestArgumentValueKey
));
7089 result
= kOSKextReturnInvalidArgument
;
7091 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
7092 if (!kextIdentifier
) {
7093 OSKextLog(/* kext */ NULL
,
7094 kOSKextLogErrorLevel
|
7096 "Invalid arguments to kext start request.");
7097 } else if (!theKext
) {
7098 OSKextLog(/* kext */ NULL
,
7099 kOSKextLogErrorLevel
|
7101 "Kext %s not found for start request.",
7102 kextIdentifier
->getCStringNoCopy());
7103 result
= kOSKextReturnNotFound
;
7105 result
= theKext
->start();
7108 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
7109 if (!kextIdentifier
) {
7110 OSKextLog(/* kext */ NULL
,
7111 kOSKextLogErrorLevel
|
7113 "Invalid arguments to kext stop request.");
7114 } else if (!theKext
) {
7115 OSKextLog(/* kext */ NULL
,
7116 kOSKextLogErrorLevel
|
7118 "Kext %s not found for stop request.",
7119 kextIdentifier
->getCStringNoCopy());
7120 result
= kOSKextReturnNotFound
;
7122 result
= theKext
->stop();
7125 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
7126 if (!kextIdentifier
) {
7127 OSKextLog(/* kext */ NULL
,
7128 kOSKextLogErrorLevel
|
7130 "Invalid arguments to kext unload request.");
7131 } else if (!theKext
) {
7132 OSKextLog(/* kext */ NULL
,
7133 kOSKextLogErrorLevel
|
7135 "Kext %s not found for unload request.",
7136 kextIdentifier
->getCStringNoCopy());
7137 result
= kOSKextReturnNotFound
;
7139 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
7140 _OSKextGetRequestArgument(requestDict
,
7141 kKextRequestArgumentTerminateIOServicesKey
));
7142 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
7145 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
7146 result
= OSKext::dispatchResource(requestDict
);
7148 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
7149 OSBoolean
* delayAutounloadBool
= NULL
;
7150 OSObject
* infoKeysRaw
= NULL
;
7151 OSArray
* infoKeys
= NULL
;
7152 uint32_t infoKeysCount
= 0;
7154 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
7155 _OSKextGetRequestArgument(requestDict
,
7156 kKextRequestArgumentDelayAutounloadKey
));
7158 /* If asked to delay autounload, reset the timer if it's currently set.
7159 * (That is, don't schedule an unload if one isn't already pending.
7161 if (delayAutounloadBool
== kOSBooleanTrue
) {
7162 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7165 infoKeysRaw
= _OSKextGetRequestArgument(requestDict
,
7166 kKextRequestArgumentInfoKeysKey
);
7167 infoKeys
= OSDynamicCast(OSArray
, infoKeysRaw
);
7168 if (infoKeysRaw
&& !infoKeys
) {
7169 OSKextLog(/* kext */ NULL
,
7170 kOSKextLogErrorLevel
|
7172 "Invalid arguments to kext info request.");
7177 infoKeysCount
= infoKeys
->getCount();
7178 for (uint32_t i
= 0; i
< infoKeysCount
; i
++) {
7179 if (!OSDynamicCast(OSString
, infoKeys
->getObject(i
))) {
7180 OSKextLog(/* kext */ NULL
,
7181 kOSKextLogErrorLevel
|
7183 "Invalid arguments to kext info request.");
7189 responseObject
= OSKext::copyLoadedKextInfo(kextIdentifiers
, infoKeys
);
7190 if (!responseObject
) {
7191 result
= kOSKextReturnInternalError
;
7193 OSKextLog(/* kext */ NULL
,
7194 kOSKextLogDebugLevel
|
7196 "Returning loaded kext info.");
7197 result
= kOSReturnSuccess
;
7200 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
7201 OSNumber
* addressNum
= NULL
; // released as responseObject
7202 kernel_segment_command_t
* textseg
= getsegbyname("__TEXT");
7205 OSKextLog(/* kext */ NULL
,
7206 kOSKextLogErrorLevel
|
7207 kOSKextLogGeneralFlag
| kOSKextLogIPCFlag
,
7208 "Can't find text segment for kernel load address.");
7209 result
= kOSReturnError
;
7213 OSKextLog(/* kext */ NULL
,
7214 kOSKextLogDebugLevel
|
7216 "Returning kernel load address 0x%llx.",
7217 (unsigned long long)textseg
->vmaddr
);
7218 addressNum
= OSNumber::withNumber((long long unsigned int)textseg
->vmaddr
,
7219 8 * sizeof(long long unsigned int));
7220 responseObject
= addressNum
;
7221 result
= kOSReturnSuccess
;
7223 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelImage
)) {
7224 OSKextLog(/* kext */ NULL
,
7225 kOSKextLogDebugLevel
|
7227 "Returning kernel image.");
7228 responseData
= OSKext::copySanitizedKernelImage();
7229 result
= kOSReturnSuccess
;
7231 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
7233 /* Hand the current sKernelRequests array to the caller
7234 * (who must release it), and make a new one.
7236 responseObject
= sKernelRequests
;
7237 sKernelRequests
= OSArray::withCapacity(0);
7238 sPostedKextLoadIdentifiers
->flushCollection();
7239 OSKextLog(/* kext */ NULL
,
7240 kOSKextLogDebugLevel
|
7242 "Returning kernel requests.");
7243 result
= kOSReturnSuccess
;
7245 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
7247 /* Return the set of all requested bundle identifiers */
7248 responseObject
= sAllKextLoadIdentifiers
;
7249 responseObject
->retain();
7250 OSKextLog(/* kext */ NULL
,
7251 kOSKextLogDebugLevel
|
7253 "Returning load requests.");
7254 result
= kOSReturnSuccess
;
7258 * Now we have handle the request, or not. Gather up the response & logging
7259 * info to ship to user space.
7262 /* Note: Nothing in OSKext is supposed to retain requestDict,
7263 * but you never know....
7265 if (requestDict
->getRetainCount() > 1) {
7266 OSKextLog(/* kext */ NULL
,
7267 kOSKextLogWarningLevel
|
7269 "Request from user space still retained by a kext; "
7270 "probable memory leak.");
7273 if (responseData
&& responseObject
) {
7274 OSKextLog(/* kext */ NULL
,
7275 kOSKextLogErrorLevel
|
7277 "Mistakenly generated both data & plist responses to user request "
7278 "(returning only data).");
7281 if (responseData
&& responseData
->getLength() && responseOut
) {
7283 response
= (char *)responseData
->getBytesNoCopy();
7284 responseLength
= responseData
->getLength();
7285 } else if (responseOut
&& responseObject
) {
7286 serializer
= OSSerialize::withCapacity(0);
7288 result
= kOSKextReturnNoMemory
;
7292 if (!responseObject
->serialize(serializer
)) {
7293 OSKextLog(/* kext */ NULL
,
7294 kOSKextLogErrorLevel
|
7296 "Failed to serialize response to request from user space.");
7297 result
= kOSKextReturnSerialization
;
7301 response
= (char *)serializer
->text();
7302 responseLength
= serializer
->getLength();
7305 if (responseOut
&& response
) {
7308 /* This kmem_alloc sets the return value of the function.
7310 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
7312 if (kmem_result
!= KERN_SUCCESS
) {
7313 OSKextLog(/* kext */ NULL
,
7314 kOSKextLogErrorLevel
|
7316 "Failed to copy response to request from user space.");
7317 result
= kmem_result
;
7320 memcpy(buffer
, response
, responseLength
);
7321 *responseOut
= buffer
;
7322 *responseLengthOut
= responseLength
;
7328 /* Gather up the collected log messages for user space. Any messages
7329 * messages past this call will not make it up as log messages but
7330 * will be in the system log. Note that we ignore the return of the
7331 * serialize; it has no bearing on the operation at hand even if we
7332 * fail to get the log messages.
7334 logInfoArray
= OSKext::clearUserSpaceLogFilter();
7336 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
7337 (void)OSKext::serializeLogInfo(logInfoArray
,
7338 logInfoOut
, logInfoLengthOut
);
7341 IORecursiveLockUnlock(sKextLock
);
7343 OSSafeRelease(parsedXML
);
7344 OSSafeRelease(errorString
);
7345 OSSafeRelease(responseData
);
7346 OSSafeRelease(responseObject
);
7347 OSSafeRelease(serializer
);
7348 OSSafeRelease(logInfoArray
);
7353 /*********************************************************************
7354 *********************************************************************/
7357 OSKext::copyLoadedKextInfo(
7358 OSArray
* kextIdentifiers
,
7361 OSDictionary
* result
= NULL
;
7362 OSDictionary
* kextInfo
= NULL
; // must release
7364 uint32_t idCount
= 0;
7365 uint32_t idIndex
= 0;
7367 IORecursiveLockLock(sKextLock
);
7369 /* Empty list of bundle ids is equivalent to no list (get all).
7371 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
7372 kextIdentifiers
= NULL
;
7373 } else if (kextIdentifiers
) {
7374 idCount
= kextIdentifiers
->getCount();
7379 if (infoKeys
&& !infoKeys
->getCount()) {
7383 count
= sLoadedKexts
->getCount();
7384 result
= OSDictionary::withCapacity(count
);
7388 for (i
= 0; i
< count
; i
++) {
7389 OSKext
* thisKext
= NULL
; // do not release
7390 Boolean includeThis
= true;
7393 kextInfo
->release();
7396 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
7401 /* Skip current kext if we have a list of bundle IDs and
7402 * it isn't in the list.
7404 if (kextIdentifiers
) {
7405 const OSString
* thisKextID
= thisKext
->getIdentifier();
7407 includeThis
= false;
7409 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
7410 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
7411 kextIdentifiers
->getObject(idIndex
));
7412 if (thisKextID
->isEqualTo(thisRequestID
)) {
7423 kextInfo
= thisKext
->copyInfo(infoKeys
);
7425 result
->setObject(thisKext
->getIdentifier(), kextInfo
);
7430 IORecursiveLockUnlock(sKextLock
);
7432 if (kextInfo
) kextInfo
->release();
7437 /*********************************************************************
7438 * Any info that needs to do allocations must goto finish on alloc
7439 * failure. Info that is just a lookup should just not set the object
7440 * if the info does not exist.
7441 *********************************************************************/
7442 #define _OSKextLoadInfoDictCapacity (12)
7445 OSKext::copyInfo(OSArray
* infoKeys
)
7447 OSDictionary
* result
= NULL
;
7448 bool success
= false;
7449 OSData
* headerData
= NULL
; // must release
7450 OSNumber
* cpuTypeNumber
= NULL
; // must release
7451 OSNumber
* cpuSubtypeNumber
= NULL
; // must release
7452 OSString
* versionString
= NULL
; // do not release
7453 uint32_t executablePathCStringSize
= 0;
7454 char * executablePathCString
= NULL
; // must release
7455 OSString
* executablePathString
= NULL
; // must release
7456 OSData
* uuid
= NULL
; // must release
7457 OSNumber
* scratchNumber
= NULL
; // must release
7458 OSArray
* dependencyLoadTags
= NULL
; // must release
7459 OSCollectionIterator
* metaClassIterator
= NULL
; // must release
7460 OSArray
* metaClassInfo
= NULL
; // must release
7461 OSDictionary
* metaClassDict
= NULL
; // must release
7462 OSMetaClass
* thisMetaClass
= NULL
; // do not release
7463 OSString
* metaClassName
= NULL
; // must release
7464 OSString
* superclassName
= NULL
; // must release
7467 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
7473 /* Empty keys means no keys, but NULL is quicker to check.
7475 if (infoKeys
&& !infoKeys
->getCount()) {
7479 /* Headers, CPU type, and CPU subtype.
7482 _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
) ||
7483 _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
) ||
7484 _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
))
7487 if (linkedExecutable
&& !isInterface()) {
7489 kernel_mach_header_t
*kext_mach_hdr
= (kernel_mach_header_t
*)
7490 linkedExecutable
->getBytesNoCopy();
7492 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
)) {
7493 headerData
= OSData::withBytes(kext_mach_hdr
,
7494 (u_int
) (sizeof(*kext_mach_hdr
) + kext_mach_hdr
->sizeofcmds
));
7498 result
->setObject(kOSBundleMachOHeadersKey
, headerData
);
7501 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
)) {
7502 cpuTypeNumber
= OSNumber::withNumber(
7503 (uint64_t) kext_mach_hdr
->cputype
,
7504 8 * sizeof(kext_mach_hdr
->cputype
));
7505 if (!cpuTypeNumber
) {
7508 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
);
7511 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
7512 cpuSubtypeNumber
= OSNumber::withNumber(
7513 (uint64_t) kext_mach_hdr
->cpusubtype
,
7514 8 * sizeof(kext_mach_hdr
->cpusubtype
));
7515 if (!cpuSubtypeNumber
) {
7518 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
);
7523 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
7525 result
->setObject(kCFBundleIdentifierKey
, bundleID
);
7529 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kCFBundleVersionKey
)) {
7530 versionString
= OSDynamicCast(OSString
,
7531 getPropertyForHostArch(kCFBundleVersionKey
));
7532 if (versionString
) {
7533 result
->setObject(kCFBundleVersionKey
, versionString
);
7537 /* OSBundleCompatibleVersion.
7539 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCompatibleVersionKey
)) {
7540 versionString
= OSDynamicCast(OSString
,
7541 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
7542 if (versionString
) {
7543 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
7549 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePathKey
)) {
7551 result
->setObject(kOSBundlePathKey
, path
);
7556 /* OSBundleExecutablePath.
7558 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecutablePathKey
)) {
7559 if (path
&& executableRelPath
) {
7561 uint32_t pathLength
= path
->getLength(); // gets incremented below
7563 // +1 for slash, +1 for \0
7564 executablePathCStringSize
= pathLength
+ executableRelPath
->getLength() + 2;
7566 executablePathCString
= (char *)kalloc((executablePathCStringSize
) *
7567 sizeof(char)); // +1 for \0
7568 if (!executablePathCString
) {
7571 strlcpy(executablePathCString
, path
->getCStringNoCopy(),
7572 executablePathCStringSize
);
7573 executablePathCString
[pathLength
++] = '/';
7574 executablePathCString
[pathLength
++] = '\0';
7575 strlcat(executablePathCString
, executableRelPath
->getCStringNoCopy(),
7576 executablePathCStringSize
);
7578 executablePathString
= OSString::withCString(executablePathCString
);
7580 if (!executablePathCString
) {
7584 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
);
7588 /* UUID, if the kext has one.
7590 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
7593 result
->setObject(kOSBundleUUIDKey
, uuid
);
7598 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
7600 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
7601 result
->setObject(kOSKernelResourceKey
,
7602 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
7605 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleIsInterfaceKey
)) {
7606 result
->setObject(kOSBundleIsInterfaceKey
,
7607 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
7610 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePrelinkedKey
)) {
7611 result
->setObject(kOSBundlePrelinkedKey
,
7612 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
7615 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleStartedKey
)) {
7616 result
->setObject(kOSBundleStartedKey
,
7617 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
7622 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadTagKey
)) {
7623 scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
7624 /* numBits */ 8 * sizeof(loadTag
));
7625 if (!scratchNumber
) {
7628 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
);
7629 OSSafeReleaseNULL(scratchNumber
);
7632 /* LoadAddress, LoadSize.
7635 _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
) ||
7636 _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
) ||
7637 _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
))
7639 if (isInterface() || linkedExecutable
) {
7640 /* These go to userspace via serialization, so we don't want any doubts
7643 uint64_t loadAddress
= 0;
7644 uint32_t loadSize
= 0;
7645 uint32_t wiredSize
= 0;
7647 /* Interfaces always report 0 load address & size.
7648 * Just the way they roll.
7650 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
7651 * xxx - shouldn't have one!
7653 if (linkedExecutable
/* && !isInterface() */) {
7654 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
7655 loadSize
= linkedExecutable
->getLength();
7657 /* If we have a kmod_info struct, calculated the wired size
7658 * from that. Otherwise it's the full load size.
7661 wiredSize
= loadSize
- kmod_info
->hdr_size
;
7663 wiredSize
= loadSize
;
7667 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
)) {
7668 scratchNumber
= OSNumber::withNumber(
7669 (unsigned long long)(loadAddress
),
7670 /* numBits */ 8 * sizeof(loadAddress
));
7671 if (!scratchNumber
) {
7674 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
);
7675 OSSafeReleaseNULL(scratchNumber
);
7677 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
)) {
7678 scratchNumber
= OSNumber::withNumber(
7679 (unsigned long long)(loadSize
),
7680 /* numBits */ 8 * sizeof(loadSize
));
7681 if (!scratchNumber
) {
7684 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
);
7685 OSSafeReleaseNULL(scratchNumber
);
7687 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
7688 scratchNumber
= OSNumber::withNumber(
7689 (unsigned long long)(wiredSize
),
7690 /* numBits */ 8 * sizeof(wiredSize
));
7691 if (!scratchNumber
) {
7694 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
);
7695 OSSafeReleaseNULL(scratchNumber
);
7700 /* OSBundleDependencies. In descending order for
7701 * easy compatibility with kextstat(8).
7703 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleDependenciesKey
)) {
7704 if ((count
= getNumDependencies())) {
7705 dependencyLoadTags
= OSArray::withCapacity(count
);
7706 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
);
7710 OSKext
* dependency
= OSDynamicCast(OSKext
,
7711 dependencies
->getObject(i
));
7713 OSSafeReleaseNULL(scratchNumber
);
7718 scratchNumber
= OSNumber::withNumber(
7719 (unsigned long long)dependency
->getLoadTag(),
7720 /* numBits*/ 8 * sizeof(loadTag
));
7721 if (!scratchNumber
) {
7724 dependencyLoadTags
->setObject(scratchNumber
);
7729 OSSafeReleaseNULL(scratchNumber
);
7731 /* OSBundleMetaClasses.
7733 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleClassesKey
)) {
7734 if (metaClasses
&& metaClasses
->getCount()) {
7735 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
);
7736 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
7737 if (!metaClassIterator
|| !metaClassInfo
) {
7740 result
->setObject(kOSBundleClassesKey
, metaClassInfo
);
7742 while ( (thisMetaClass
= OSDynamicCast(OSMetaClass
,
7743 metaClassIterator
->getNextObject())) ) {
7745 OSSafeReleaseNULL(metaClassDict
);
7746 OSSafeReleaseNULL(scratchNumber
);
7747 OSSafeReleaseNULL(metaClassName
);
7748 OSSafeReleaseNULL(superclassName
);
7750 metaClassDict
= OSDictionary::withCapacity(3);
7751 if (!metaClassDict
) {
7755 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
7756 if (thisMetaClass
->getSuperClass()) {
7757 superclassName
= OSString::withCString(
7758 thisMetaClass
->getSuperClass()->getClassName());
7760 scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
7761 8 * sizeof(unsigned int));
7763 /* Bail if any of the essentials is missing. The root class lacks a superclass,
7766 if (!metaClassDict
|| !metaClassName
|| !scratchNumber
) {
7770 metaClassInfo
->setObject(metaClassDict
);
7771 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
);
7772 if (superclassName
) {
7773 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
);
7775 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
);
7780 /* OSBundleRetainCount.
7782 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleRetainCountKey
)) {
7783 OSSafeReleaseNULL(scratchNumber
);
7785 int kextRetainCount
= getRetainCount() - 1;
7789 scratchNumber
= OSNumber::withNumber(
7790 (int)kextRetainCount
,
7791 /* numBits*/ 8 * sizeof(int));
7792 if (scratchNumber
) {
7793 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
);
7801 OSSafeRelease(headerData
);
7802 OSSafeRelease(cpuTypeNumber
);
7803 OSSafeRelease(cpuSubtypeNumber
);
7804 OSSafeRelease(executablePathString
);
7805 if (executablePathString
) kfree(executablePathCString
, executablePathCStringSize
);
7806 OSSafeRelease(uuid
);
7807 OSSafeRelease(scratchNumber
);
7808 OSSafeRelease(dependencyLoadTags
);
7809 OSSafeRelease(metaClassIterator
);
7810 OSSafeRelease(metaClassInfo
);
7811 OSSafeRelease(metaClassDict
);
7812 OSSafeRelease(metaClassName
);
7813 OSSafeRelease(superclassName
);
7815 OSSafeReleaseNULL(result
);
7820 /********************************************************************/
7821 static struct symtab_command
* getKernelSymtab(void)
7823 struct symtab_command
* result
= NULL
;
7824 struct load_command
* load_cmd
= NULL
;
7827 load_cmd
= (struct load_command
*)
7828 ((uintptr_t)&_mh_execute_header
+ sizeof(_mh_execute_header
));
7829 for(i
= 0; i
< _mh_execute_header
.ncmds
; i
++){
7830 if (load_cmd
->cmd
== LC_SYMTAB
) {
7831 result
= (struct symtab_command
*)load_cmd
;
7834 load_cmd
= (struct load_command
*)
7835 ((uintptr_t)load_cmd
+ load_cmd
->cmdsize
);
7842 /*********************************************************************
7843 *********************************************************************/
7846 OSKext::copySanitizedKernelImage(void)
7848 OSData
* result
= NULL
;
7850 kernel_mach_header_t
* kernelHeader
= NULL
;
7851 uint32_t sizeofcmds
= 0;
7853 /* These start out pointing to running kernel but
7854 * after copying point to the copied info.
7856 kernel_segment_command_t
* text_seg
= NULL
;
7857 kernel_segment_command_t
* data_seg
= NULL
;
7858 kernel_segment_command_t
* linkedit_seg
= NULL
;
7859 struct symtab_command
* symtab_cmd
= NULL
;
7860 kernel_section_t
* text_const_sect
= NULL
;
7861 kernel_section_t
* data_const_sect
= NULL
;
7863 kern_return_t kern_result
= 0;
7864 u_long kernelCopyLength
= 0;
7865 vm_offset_t kernelCopyAddr
= 0;
7866 u_char
* kernelCopy
= NULL
;
7868 vm_offset_t contentOffset
= 0;
7869 struct load_command
* scan_cmd
= NULL
;
7870 kernel_section_t
* scan_sect
= NULL
;
7871 int64_t stroff_shift
= 0;
7875 text_seg
= getsegbyname("__TEXT");
7876 data_seg
= getsegbyname("__DATA");
7877 linkedit_seg
= getsegbyname("__LINKEDIT");
7878 symtab_cmd
= getKernelSymtab();
7880 text_const_sect
= getsectbyname("__TEXT", "__const");
7881 data_const_sect
= getsectbyname("__DATA", "__const");
7883 if (!text_seg
|| !data_seg
|| !linkedit_seg
|| !symtab_cmd
||
7884 !text_const_sect
|| ! data_const_sect
) {
7886 OSKextLog(/* kext */ NULL
,
7887 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7888 "Can't provide kernel image for linking; missing component.");
7892 /* Figure the size of the kernel image to build. We don't use the sizes of
7893 * the __TEXT & __DATA segments overall as we only use the __const sections,
7894 * so add those in manually. We're going to round each part to page size
7895 * multiples too, just to be extra cautious.
7897 sizeofcmds
= text_seg
->cmdsize
+ data_seg
->cmdsize
+
7898 linkedit_seg
->cmdsize
+ symtab_cmd
->cmdsize
;
7899 kernelCopyLength
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
) +
7900 round_page(text_const_sect
->size
) +
7901 round_page(data_const_sect
->size
) +
7902 round_page(linkedit_seg
->filesize
);
7904 kern_result
= kmem_alloc(kernel_map
, &kernelCopyAddr
, kernelCopyLength
);
7905 if (kern_result
!= KERN_SUCCESS
) {
7909 kernelCopy
= (u_char
*)kernelCopyAddr
;
7910 bzero(kernelCopy
, kernelCopyLength
); // ??? - is this really necessary?
7913 * Copy the kernel Mach header and the load commands we want.
7915 memcpy(kernelCopy
, &_mh_execute_header
, sizeof(_mh_execute_header
));
7916 kernelHeader
= (kernel_mach_header_t
*)kernelCopy
;
7917 kernelHeader
->ncmds
= 0;
7918 kernelHeader
->sizeofcmds
= sizeofcmds
;
7919 contentOffset
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
);
7921 /* __TEXT segment load command and sections.
7922 * Note that the __TEXT segment's 'offset' and 'filesize' include
7923 * the data from the beginning of the mach header.
7925 * Don't muck with the __TEXT segment's vmsize here;
7926 * user-space linking requires it to match what is in the running kernel.
7927 * We'll just have to live with it not being accurate
7928 * (not like we can run the sanitized image after all).
7930 scan_cmd
= (struct load_command
*)&kernelHeader
[1]; // just past mach header
7931 memcpy(scan_cmd
, text_seg
, text_seg
->cmdsize
);
7932 kernelHeader
->ncmds
++;
7933 text_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
7934 text_seg
->fileoff
= 0;
7935 text_seg
->filesize
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
);
7937 scan_sect
= (kernel_section_t
*)(text_seg
+ 1);
7938 for (i
= 0; i
< text_seg
->nsects
; i
++, scan_sect
++) {
7939 if (0 == strncmp("__const", scan_sect
->sectname
, sizeof("__const"))) {
7940 text_const_sect
= scan_sect
; // retarget to constructed section
7942 text_seg
->filesize
+= scan_sect
->size
;
7944 scan_sect
->offset
= contentOffset
;
7945 contentOffset
+= scan_sect
->size
;
7947 memcpy(kernelCopy
+ scan_sect
->offset
, (void *)(uintptr_t)scan_sect
->addr
,
7950 scan_sect
->addr
= 0;
7951 scan_sect
->size
= 0;
7952 scan_sect
->offset
= contentOffset
;
7953 scan_sect
->nreloc
= 0;
7957 contentOffset
= round_page(contentOffset
);
7959 /* __DATA segment load command and sections.
7960 * Leave the vmsize as in the running kernel here, too.
7962 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
7963 memcpy(scan_cmd
, data_seg
, data_seg
->cmdsize
);
7964 kernelHeader
->ncmds
++;
7965 data_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
7966 data_seg
->fileoff
= contentOffset
;
7967 data_seg
->filesize
= 0;
7969 scan_sect
= (kernel_section_t
*)(data_seg
+ 1);
7970 for (i
= 0; i
< data_seg
->nsects
; i
++, scan_sect
++) {
7971 if (0 == strncmp("__const", scan_sect
->sectname
, sizeof("__const"))) {
7972 data_const_sect
= scan_sect
; // retarget to constructed section
7974 data_seg
->filesize
+= scan_sect
->size
;
7976 scan_sect
->offset
= contentOffset
;
7977 contentOffset
+= scan_sect
->size
;
7979 memcpy(kernelCopy
+ scan_sect
->offset
, (void *)(uintptr_t)scan_sect
->addr
,
7982 scan_sect
->addr
= 0;
7983 scan_sect
->size
= 0;
7984 scan_sect
->offset
= contentOffset
;
7985 scan_sect
->nreloc
= 0;
7989 contentOffset
= round_page(contentOffset
);
7991 /* __LINKEDIT segment load command.
7992 * Leave the vmsize as in the running kernel here, too.
7994 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
7995 memcpy(scan_cmd
, linkedit_seg
, linkedit_seg
->cmdsize
);
7996 kernelHeader
->ncmds
++;
7997 linkedit_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
7998 linkedit_seg
->fileoff
= contentOffset
;
7999 linkedit_seg
->filesize
= linkedit_seg
->vmsize
;
8001 contentOffset
+= round_page(linkedit_seg
->vmsize
);
8003 memcpy(kernelCopy
+ linkedit_seg
->fileoff
, (void *)(uintptr_t)linkedit_seg
->vmaddr
,
8004 linkedit_seg
->vmsize
);
8006 /* __SYMTAB load command (contents shared with __LINKEDIT).
8008 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
8009 memcpy(scan_cmd
, symtab_cmd
, symtab_cmd
->cmdsize
);
8010 kernelHeader
->ncmds
++;
8011 symtab_cmd
= (struct symtab_command
*)scan_cmd
; // retarget to constructed cmd
8012 stroff_shift
= symtab_cmd
->stroff
- symtab_cmd
->symoff
;
8013 symtab_cmd
->symoff
= linkedit_seg
->fileoff
;
8014 symtab_cmd
->stroff
= symtab_cmd
->symoff
+ stroff_shift
;
8016 /* Wrap the thing up in an OSData.
8018 result
= OSData::withBytesNoCopy(kernelCopy
, kernelCopyLength
);
8020 result
->setDeallocFunction(osdata_kmem_free
);
8025 if (kernelCopy
) kmem_free(kernel_map
, kernelCopyAddr
, kernelCopyLength
);
8030 /*********************************************************************
8031 *********************************************************************/
8034 OSKext::requestResource(
8035 const char * kextIdentifierCString
,
8036 const char * resourceNameCString
,
8037 OSKextRequestResourceCallback callback
,
8039 OSKextRequestTag
* requestTagOut
)
8041 OSReturn result
= kOSReturnError
;
8042 OSKext
* callbackKext
= NULL
; // must release (looked up)
8044 OSKextRequestTag requestTag
= -1;
8045 OSNumber
* requestTagNum
= NULL
; // must release
8047 OSDictionary
* requestDict
= NULL
; // must release
8048 OSString
* kextIdentifier
= NULL
; // must release
8049 OSString
* resourceName
= NULL
; // must release
8051 OSDictionary
* callbackRecord
= NULL
; // must release
8052 OSData
* callbackWrapper
= NULL
; // must release
8054 OSData
* contextWrapper
= NULL
; // must release
8056 IORecursiveLockLock(sKextLock
);
8058 if (requestTagOut
) {
8059 *requestTagOut
= kOSKextRequestTagInvalid
;
8062 /* If requests to user space are disabled, don't go any further */
8063 if (!sKernelRequestsEnabled
) {
8064 OSKextLog(/* kext */ NULL
,
8065 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8066 "Can't request resource %s for %s - requests to user space are disabled.",
8067 resourceNameCString
,
8068 kextIdentifierCString
);
8069 result
= kOSKextReturnDisabled
;
8073 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
8074 result
= kOSKextReturnInvalidArgument
;
8078 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
8079 if (!callbackKext
) {
8080 OSKextLog(/* kext */ NULL
,
8081 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8082 "Resource request has bad callback address.");
8083 result
= kOSKextReturnInvalidArgument
;
8086 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
8087 OSKextLog(/* kext */ NULL
,
8088 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8089 "Resource request callback is in a kext that is not started.");
8090 result
= kOSKextReturnInvalidArgument
;
8094 /* Do not allow any new requests to be made on a kext that is unloading.
8096 if (callbackKext
->flags
.stopping
) {
8097 result
= kOSKextReturnStopping
;
8101 /* If we're wrapped the next available request tag around to the negative
8102 * numbers, we can't service any more requests.
8104 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
8105 OSKextLog(/* kext */ NULL
,
8106 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8107 "No more request tags available; restart required.");
8108 result
= kOSKextReturnNoResources
;
8111 requestTag
= sNextRequestTag
++;
8113 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
8115 if (result
!= kOSReturnSuccess
) {
8119 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
8120 resourceName
= OSString::withCString(resourceNameCString
);
8121 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
8122 8 * sizeof(requestTag
));
8123 if (!kextIdentifier
||
8126 !_OSKextSetRequestArgument(requestDict
,
8127 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
8128 !_OSKextSetRequestArgument(requestDict
,
8129 kKextRequestArgumentNameKey
, resourceName
) ||
8130 !_OSKextSetRequestArgument(requestDict
,
8131 kKextRequestArgumentRequestTagKey
, requestTagNum
)) {
8133 result
= kOSKextReturnNoMemory
;
8137 callbackRecord
= OSDynamicCast(OSDictionary
, requestDict
->copyCollection());
8138 if (!callbackRecord
) {
8139 result
= kOSKextReturnNoMemory
;
8142 // we validate callback address at call time
8143 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
8145 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
8147 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
8148 kKextRequestArgumentCallbackKey
, callbackWrapper
)) {
8150 result
= kOSKextReturnNoMemory
;
8155 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
8156 kKextRequestArgumentContextKey
, contextWrapper
)) {
8158 result
= kOSKextReturnNoMemory
;
8163 /* Only post the requests after all the other potential failure points
8166 if (!sKernelRequests
->setObject(requestDict
) ||
8167 !sRequestCallbackRecords
->setObject(callbackRecord
)) {
8169 result
= kOSKextReturnNoMemory
;
8173 OSKext::pingKextd();
8175 result
= kOSReturnSuccess
;
8176 if (requestTagOut
) {
8177 *requestTagOut
= requestTag
;
8182 /* If we didn't succeed, yank the request & callback
8183 * from their holding arrays.
8185 if (result
!= kOSReturnSuccess
) {
8188 index
= sKernelRequests
->getNextIndexOfObject(requestDict
, 0);
8189 if (index
!= (unsigned int)-1) {
8190 sKernelRequests
->removeObject(index
);
8192 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
, 0);
8193 if (index
!= (unsigned int)-1) {
8194 sRequestCallbackRecords
->removeObject(index
);
8198 OSKext::considerUnloads(/* rescheduleOnly? */ true);
8200 IORecursiveLockUnlock(sKextLock
);
8202 if (callbackKext
) callbackKext
->release();
8203 if (requestTagNum
) requestTagNum
->release();
8205 if (requestDict
) requestDict
->release();
8206 if (kextIdentifier
) kextIdentifier
->release();
8207 if (resourceName
) resourceName
->release();
8209 if (callbackRecord
) callbackRecord
->release();
8210 if (callbackWrapper
) callbackWrapper
->release();
8211 if (contextWrapper
) contextWrapper
->release();
8216 /*********************************************************************
8217 * Assumes sKextLock is held.
8218 *********************************************************************/
8221 OSKext::dequeueCallbackForRequestTag(
8222 OSKextRequestTag requestTag
,
8223 OSDictionary
** callbackRecordOut
)
8225 OSReturn result
= kOSReturnError
;
8226 OSNumber
* requestTagNum
= NULL
; // must release
8228 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
8229 8 * sizeof(requestTag
));
8230 if (!requestTagNum
) {
8234 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
,
8238 OSSafeRelease(requestTagNum
);
8243 /*********************************************************************
8244 * Assumes sKextLock is held.
8245 *********************************************************************/
8248 OSKext::dequeueCallbackForRequestTag(
8249 OSNumber
* requestTagNum
,
8250 OSDictionary
** callbackRecordOut
)
8252 OSReturn result
= kOSKextReturnInvalidArgument
;
8253 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
8254 OSNumber
* callbackTagNum
= NULL
; // do not release
8255 unsigned int count
, i
;
8257 result
= kOSReturnError
;
8258 count
= sRequestCallbackRecords
->getCount();
8259 for (i
= 0; i
< count
; i
++) {
8260 callbackRecord
= OSDynamicCast(OSDictionary
,
8261 sRequestCallbackRecords
->getObject(i
));
8262 if (!callbackRecord
) {
8266 /* If we don't find a tag, we basically have a leak here. Maybe
8267 * we should just remove it.
8269 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
8270 callbackRecord
, kKextRequestArgumentRequestTagKey
));
8271 if (!callbackTagNum
) {
8275 /* We could be even more paranoid and check that all the incoming
8276 * args match what's in the callback record.
8278 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
8279 if (callbackRecordOut
) {
8280 *callbackRecordOut
= callbackRecord
;
8281 callbackRecord
->retain();
8283 sRequestCallbackRecords
->removeObject(i
);
8284 result
= kOSReturnSuccess
;
8288 result
= kOSKextReturnNotFound
;
8294 /*********************************************************************
8295 * Assumes sKextLock is held.
8296 *********************************************************************/
8299 OSKext::dispatchResource(OSDictionary
* requestDict
)
8301 OSReturn result
= kOSReturnError
;
8302 OSDictionary
* callbackRecord
= NULL
; // must release
8303 OSNumber
* requestTag
= NULL
; // do not release
8304 OSNumber
* requestResult
= NULL
; // do not release
8305 OSData
* dataObj
= NULL
; // do not release
8306 uint32_t dataLength
= 0;
8307 const void * dataPtr
= NULL
; // do not free
8308 OSData
* callbackWrapper
= NULL
; // do not release
8309 OSKextRequestResourceCallback callback
= NULL
;
8310 OSData
* contextWrapper
= NULL
; // do not release
8311 void * context
= NULL
; // do not free
8312 OSKext
* callbackKext
= NULL
; // must release (looked up)
8314 /* Get the args from the request. Right now we need the tag
8315 * to look up the callback record, and the result for invoking the callback.
8317 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
8318 kKextRequestArgumentRequestTagKey
));
8319 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
8320 kKextRequestArgumentResultKey
));
8321 if (!requestTag
|| !requestResult
) {
8322 result
= kOSKextReturnInvalidArgument
;
8326 /* Look for a callback record matching this request's tag.
8328 result
= dequeueCallbackForRequestTag(requestTag
, &callbackRecord
);
8329 if (result
!= kOSReturnSuccess
) {
8334 * Get the context pointer of the callback record (if there is one).
8336 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
,
8337 kKextRequestArgumentContextKey
));
8338 context
= _OSKextExtractPointer(contextWrapper
);
8339 if (contextWrapper
&& !context
) {
8343 callbackWrapper
= OSDynamicCast(OSData
,
8344 _OSKextGetRequestArgument(callbackRecord
,
8345 kKextRequestArgumentCallbackKey
));
8346 callback
= (OSKextRequestResourceCallback
)
8347 _OSKextExtractPointer(callbackWrapper
);
8352 /* Check for a data obj. We might not have one and that's ok, that means
8353 * we didn't find the requested resource, and we still have to tell the
8354 * caller that via the callback.
8356 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
8357 kKextRequestArgumentValueKey
));
8359 dataPtr
= dataObj
->getBytesNoCopy();
8360 dataLength
= dataObj
->getLength();
8363 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
8364 if (!callbackKext
) {
8365 OSKextLog(/* kext */ NULL
,
8366 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8367 "Can't invoke callback for resource request; "
8368 "no kext loaded at callback address %p.",
8372 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
8373 OSKextLog(/* kext */ NULL
,
8374 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8375 "Can't invoke kext resource callback; "
8376 "kext at callback address %p is not running.",
8381 (void)callback(requestTag
->unsigned32BitValue(),
8382 (OSReturn
)requestResult
->unsigned32BitValue(),
8383 dataPtr
, dataLength
, context
);
8385 result
= kOSReturnSuccess
;
8388 if (callbackKext
) callbackKext
->release();
8389 if (callbackRecord
) callbackRecord
->release();
8394 /*********************************************************************
8395 *********************************************************************/
8398 OSKext::invokeRequestCallback(
8399 OSDictionary
* callbackRecord
,
8400 OSReturn callbackResult
)
8402 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
8403 OSNumber
* resultNum
= NULL
; // must release
8409 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
8410 8 * sizeof(callbackResult
));
8415 /* Insert the result into the callback record and dispatch it as if it
8416 * were the reply coming down from user space.
8418 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
8421 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
8422 /* This removes the pending callback record.
8424 OSKext::dispatchResource(callbackRecord
);
8428 if (resultNum
) resultNum
->release();
8432 /*********************************************************************
8433 * Assumes sKextLock is held.
8434 *********************************************************************/
8437 OSKext::cancelRequest(
8438 OSKextRequestTag requestTag
,
8441 OSReturn result
= kOSKextReturnNoMemory
;
8442 OSDictionary
* callbackRecord
= NULL
; // must release
8443 OSData
* contextWrapper
= NULL
; // do not release
8445 IORecursiveLockLock(sKextLock
);
8446 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
8448 IORecursiveLockUnlock(sKextLock
);
8450 if (result
== kOSReturnSuccess
&& contextOut
) {
8451 contextWrapper
= OSDynamicCast(OSData
,
8452 _OSKextGetRequestArgument(callbackRecord
,
8453 kKextRequestArgumentContextKey
));
8454 *contextOut
= _OSKextExtractPointer(contextWrapper
);
8457 if (callbackRecord
) callbackRecord
->release();
8462 /*********************************************************************
8463 * Assumes sKextLock is held.
8464 *********************************************************************/
8466 OSKext::invokeOrCancelRequestCallbacks(
8467 OSReturn callbackResult
,
8470 unsigned int count
, i
;
8472 count
= sRequestCallbackRecords
->getCount();
8479 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
8480 sRequestCallbackRecords
->getObject(i
));
8485 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
8486 _OSKextGetRequestArgument(request
,
8487 kKextRequestArgumentCallbackKey
));
8489 if (!callbackWrapper
) {
8490 sRequestCallbackRecords
->removeObject(i
);
8494 vm_address_t callbackAddress
= (vm_address_t
)
8495 _OSKextExtractPointer(callbackWrapper
);
8497 if ((kmod_info
->address
<= callbackAddress
) &&
8498 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
8501 /* This removes the callback record.
8503 invokeRequestCallback(request
, callbackResult
);
8505 sRequestCallbackRecords
->removeObject(i
);
8514 /*********************************************************************
8515 * Assumes sKextLock is held.
8516 *********************************************************************/
8518 OSKext::countRequestCallbacks(void)
8520 uint32_t result
= 0;
8521 unsigned int count
, i
;
8523 count
= sRequestCallbackRecords
->getCount();
8530 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
8531 sRequestCallbackRecords
->getObject(i
));
8536 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
8537 _OSKextGetRequestArgument(request
,
8538 kKextRequestArgumentCallbackKey
));
8540 if (!callbackWrapper
) {
8544 vm_address_t callbackAddress
= (vm_address_t
)
8545 _OSKextExtractPointer(callbackWrapper
);
8547 if ((kmod_info
->address
<= callbackAddress
) &&
8548 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
8558 /*********************************************************************
8559 *********************************************************************/
8560 static OSReturn
_OSKextCreateRequest(
8561 const char * predicate
,
8562 OSDictionary
** requestP
)
8564 OSReturn result
= kOSKextReturnNoMemory
;
8565 OSDictionary
* request
= NULL
; // must release on error
8566 OSDictionary
* args
= NULL
; // must release
8568 request
= OSDictionary::withCapacity(2);
8572 result
= _OSDictionarySetCStringValue(request
,
8573 kKextRequestPredicateKey
, predicate
);
8574 if (result
!= kOSReturnSuccess
) {
8577 result
= kOSReturnSuccess
;
8580 if (result
!= kOSReturnSuccess
) {
8581 if (request
) request
->release();
8583 *requestP
= request
;
8585 if (args
) args
->release();
8590 /*********************************************************************
8591 *********************************************************************/
8592 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
8594 return OSDynamicCast(OSString
,
8595 requestDict
->getObject(kKextRequestPredicateKey
));
8598 /*********************************************************************
8599 *********************************************************************/
8600 static OSObject
* _OSKextGetRequestArgument(
8601 OSDictionary
* requestDict
,
8602 const char * argName
)
8604 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
8605 requestDict
->getObject(kKextRequestArgumentsKey
));
8607 return args
->getObject(argName
);
8612 /*********************************************************************
8613 *********************************************************************/
8614 static bool _OSKextSetRequestArgument(
8615 OSDictionary
* requestDict
,
8616 const char * argName
,
8619 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
8620 requestDict
->getObject(kKextRequestArgumentsKey
));
8622 args
= OSDictionary::withCapacity(2);
8626 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
8630 return args
->setObject(argName
, value
);
8636 /*********************************************************************
8637 *********************************************************************/
8638 static void * _OSKextExtractPointer(OSData
* wrapper
)
8640 void * result
= NULL
;
8641 const void * resultPtr
= NULL
;
8646 resultPtr
= wrapper
->getBytesNoCopy();
8647 result
= *(void **)resultPtr
;
8652 /*********************************************************************
8653 *********************************************************************/
8654 static OSReturn
_OSDictionarySetCStringValue(
8655 OSDictionary
* dict
,
8657 const char * cValue
)
8659 OSReturn result
= kOSKextReturnNoMemory
;
8660 const OSSymbol
* key
= NULL
; // must release
8661 OSString
* value
= NULL
; // must release
8663 key
= OSSymbol::withCString(cKey
);
8664 value
= OSString::withCString(cValue
);
8665 if (!key
|| !value
) {
8668 if (dict
->setObject(key
, value
)) {
8669 result
= kOSReturnSuccess
;
8673 if (key
) key
->release();
8674 if (value
) value
->release();
8679 /*********************************************************************
8680 *********************************************************************/
8681 static bool _OSArrayContainsCString(
8683 const char * cString
)
8685 bool result
= false;
8686 const OSSymbol
* symbol
= NULL
;
8689 if (!array
|| !cString
) {
8693 symbol
= OSSymbol::withCStringNoCopy(cString
);
8698 count
= array
->getCount();
8699 for (i
= 0; i
< count
; i
++) {
8700 OSObject
* thisObject
= array
->getObject(i
);
8701 if (symbol
->isEqualTo(thisObject
)) {
8708 if (symbol
) symbol
->release();
8713 #pragma mark Personalities (IOKit Drivers)
8715 /*********************************************************************
8716 *********************************************************************/
8719 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
8721 OSArray
* result
= NULL
; // returned
8722 OSCollectionIterator
* kextIterator
= NULL
; // must release
8723 OSArray
* personalities
= NULL
; // must release
8724 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
8726 OSString
* kextID
= NULL
; // do not release
8727 OSKext
* theKext
= NULL
; // do not release
8729 IORecursiveLockLock(sKextLock
);
8731 /* Let's conservatively guess that any given kext has around 3
8732 * personalities for now.
8734 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
8739 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
8740 if (!kextIterator
) {
8744 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
8745 if (personalitiesIterator
) {
8746 personalitiesIterator
->release();
8747 personalitiesIterator
= NULL
;
8749 if (personalities
) {
8750 personalities
->release();
8751 personalities
= NULL
;
8754 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
8755 if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
8756 personalities
= theKext
->copyPersonalitiesArray();
8757 if (!personalities
) {
8760 result
->merge(personalities
);
8762 // xxx - check for better place to put this log msg
8764 kOSKextLogWarningLevel
|
8766 "Kext %s is not loadable during safe boot; "
8767 "omitting its personalities.",
8768 theKext
->getIdentifierCString());
8774 IORecursiveLockUnlock(sKextLock
);
8776 if (kextIterator
) kextIterator
->release();
8777 if (personalitiesIterator
) personalitiesIterator
->release();
8778 if (personalities
) personalities
->release();
8783 /*********************************************************************
8784 *********************************************************************/
8787 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
8789 int numPersonalities
= 0;
8791 OSKextLog(/* kext */ NULL
,
8792 kOSKextLogStepLevel
|
8794 "Sending all eligible registered kexts' personalities "
8795 "to the IOCatalogue %s.",
8796 startMatching
? "and starting matching" : "but not starting matching");
8798 OSArray
* personalities
= OSKext::copyAllKextPersonalities(
8799 /* filterSafeBootFlag */ true);
8801 if (personalities
) {
8802 gIOCatalogue
->addDrivers(personalities
, startMatching
);
8803 numPersonalities
= personalities
->getCount();
8804 personalities
->release();
8807 OSKextLog(/* kext */ NULL
,
8808 kOSKextLogStepLevel
|
8810 "%d kext personalit%s sent to the IOCatalogue; %s.",
8811 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
8812 startMatching
? "matching started" : "matching not started");
8816 /*********************************************************************
8817 * Do not make a deep copy, just convert the IOKitPersonalities dict
8818 * to an array for sending to the IOCatalogue.
8819 *********************************************************************/
8821 OSKext::copyPersonalitiesArray(void)
8823 OSArray
* result
= NULL
;
8824 OSDictionary
* personalities
= NULL
; // do not release
8825 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
8827 OSString
* personalityName
= NULL
; // do not release
8828 OSString
* personalityBundleIdentifier
= NULL
; // do not release
8830 personalities
= OSDynamicCast(OSDictionary
,
8831 getPropertyForHostArch(kIOKitPersonalitiesKey
));
8832 if (!personalities
) {
8836 result
= OSArray::withCapacity(personalities
->getCount());
8841 personalitiesIterator
=
8842 OSCollectionIterator::withCollection(personalities
);
8843 if (!personalitiesIterator
) {
8846 while ((personalityName
= OSDynamicCast(OSString
,
8847 personalitiesIterator
->getNextObject()))) {
8849 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
8850 personalities
->getObject(personalityName
));
8853 * If the personality doesn't have a CFBundleIdentifier, or if it
8854 * differs from the kext's, insert the kext's ID so we can find it.
8855 * The publisher ID is used to remove personalities from bundles
8858 personalityBundleIdentifier
= OSDynamicCast(OSString
,
8859 personality
->getObject(kCFBundleIdentifierKey
));
8861 if (!personalityBundleIdentifier
) {
8862 personality
->setObject(kCFBundleIdentifierKey
, bundleID
);
8863 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
)) {
8864 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
);
8867 result
->setObject(personality
);
8871 if (personalitiesIterator
) personalitiesIterator
->release();
8876 /*********************************************************************
8877 Might want to change this to a bool return?
8878 *********************************************************************/
8880 OSKext::sendPersonalitiesToCatalog(
8882 OSArray
* personalityNames
)
8884 OSReturn result
= kOSReturnSuccess
;
8885 OSArray
* personalitiesToSend
= NULL
; // must release
8886 OSDictionary
* kextPersonalities
= NULL
; // do not release
8889 if (!sLoadEnabled
) {
8891 kOSKextLogErrorLevel
|
8893 "Kext loading is disabled (attempt to start matching for kext %s).",
8894 getIdentifierCString());
8895 result
= kOSKextReturnDisabled
;
8899 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
8901 kOSKextLogErrorLevel
|
8903 "Kext %s is not loadable during safe boot; "
8904 "not sending personalities to the IOCatalogue.",
8905 getIdentifierCString());
8906 result
= kOSKextReturnNotLoadable
;
8910 if (!personalityNames
|| !personalityNames
->getCount()) {
8911 personalitiesToSend
= copyPersonalitiesArray();
8913 kextPersonalities
= OSDynamicCast(OSDictionary
,
8914 getPropertyForHostArch(kIOKitPersonalitiesKey
));
8915 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
8919 personalitiesToSend
= OSArray::withCapacity(0);
8920 if (!personalitiesToSend
) {
8921 result
= kOSKextReturnNoMemory
;
8924 count
= personalityNames
->getCount();
8925 for (i
= 0; i
< count
; i
++) {
8926 OSString
* name
= OSDynamicCast(OSString
,
8927 personalityNames
->getObject(i
));
8931 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
8932 kextPersonalities
->getObject(name
));
8934 personalitiesToSend
->setObject(personality
);
8938 if (personalitiesToSend
) {
8939 unsigned numPersonalities
= personalitiesToSend
->getCount();
8941 kOSKextLogStepLevel
|
8943 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
8944 getIdentifierCString(),
8946 numPersonalities
> 1 ? "ies" : "y",
8947 startMatching
? " and starting matching" : " but not starting matching");
8948 gIOCatalogue
->addDrivers(personalitiesToSend
, startMatching
);
8951 if (personalitiesToSend
) {
8952 personalitiesToSend
->release();
8957 /*********************************************************************
8958 * xxx - We should allow removing the kext's declared personalities,
8959 * xxx - even with other bundle identifiers.
8960 *********************************************************************/
8962 OSKext::removePersonalitiesFromCatalog(void)
8964 OSDictionary
* personality
= NULL
; // do not release
8966 personality
= OSDictionary::withCapacity(1);
8970 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
8973 kOSKextLogStepLevel
|
8975 "Kext %s removing all personalities naming it from the IOCatalogue.",
8976 getIdentifierCString());
8978 /* Have the IOCatalog remove all personalities matching this kext's
8979 * bundle ID and trigger matching anew.
8981 gIOCatalogue
->removeDrivers(personality
, /* startMatching */ true);
8984 if (personality
) personality
->release();
8991 #pragma mark Logging
8993 /*********************************************************************
8994 * Do not call any function that takes sKextLock here!
8995 *********************************************************************/
8998 OSKext::setUserSpaceLogFilter(
8999 OSKextLogSpec newUserLogFilter
,
9002 OSKextLogSpec result
;
9003 bool allocError
= false;
9005 /* Do not call any function that takes sKextLoggingLock during
9006 * this critical block. That means do logging after.
9008 IOLockLock(sKextLoggingLock
);
9010 result
= sUserSpaceKextLogFilter
;
9011 sUserSpaceKextLogFilter
= newUserLogFilter
;
9013 if (newUserLogFilter
&& captureFlag
&&
9014 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
9016 // xxx - do some measurements for a good initial capacity?
9017 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
9018 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
9020 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
9021 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
9022 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
9027 IOLockUnlock(sKextLoggingLock
);
9029 /* If the config flag itself is changing, log the state change
9030 * going both ways, before setting up the user-space log arrays,
9031 * so that this is only logged in the kernel.
9033 if (result
!= newUserLogFilter
) {
9034 OSKextLog(/* kext */ NULL
,
9035 kOSKextLogDebugLevel
|
9036 kOSKextLogGeneralFlag
,
9037 "User-space log flags changed from 0x%x to 0x%x.",
9038 result
, newUserLogFilter
);
9041 OSKextLog(/* kext */ NULL
,
9042 kOSKextLogErrorLevel
|
9043 kOSKextLogGeneralFlag
,
9044 "Failed to allocate user-space log message arrays.");
9050 /*********************************************************************
9051 * Do not call any function that takes sKextLock here!
9052 *********************************************************************/
9055 OSKext::clearUserSpaceLogFilter(void)
9057 OSArray
* result
= NULL
;
9058 OSKextLogSpec oldLogFilter
;
9059 OSKextLogSpec newLogFilter
= kOSKextLogSilentFilter
;
9061 /* Do not call any function that takes sKextLoggingLock during
9062 * this critical block. That means do logging after.
9064 IOLockLock(sKextLoggingLock
);
9066 result
= OSArray::withCapacity(2);
9068 result
->setObject(sUserSpaceLogSpecArray
);
9069 result
->setObject(sUserSpaceLogMessageArray
);
9071 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
9072 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
9074 oldLogFilter
= sUserSpaceKextLogFilter
;
9075 sUserSpaceKextLogFilter
= newLogFilter
;
9077 IOLockUnlock(sKextLoggingLock
);
9079 /* If the config flag itself is changing, log the state change
9080 * going both ways, after tearing down the user-space log
9081 * arrays, so this is only logged within the kernel.
9083 if (oldLogFilter
!= newLogFilter
) {
9084 OSKextLog(/* kext */ NULL
,
9085 kOSKextLogDebugLevel
|
9086 kOSKextLogGeneralFlag
,
9087 "User-space log flags changed from 0x%x to 0x%x.",
9088 oldLogFilter
, newLogFilter
);
9095 /*********************************************************************
9096 * Do not call any function that takes sKextLock here!
9097 *********************************************************************/
9100 OSKext::getUserSpaceLogFilter(void)
9102 OSKextLogSpec result
;
9104 IOLockLock(sKextLoggingLock
);
9105 result
= sUserSpaceKextLogFilter
;
9106 IOLockUnlock(sKextLoggingLock
);
9111 /*********************************************************************
9112 * This function is called by OSMetaClass during kernel C++ setup.
9113 * Be careful what you access here; assume only OSKext::initialize()
9116 * Do not call any function that takes sKextLock here!
9117 *********************************************************************/
9118 #define VTRESET "\033[0m"
9120 #define VTBOLD "\033[1m"
9121 #define VTUNDER "\033[4m"
9123 #define VTRED "\033[31m"
9124 #define VTGREEN "\033[32m"
9125 #define VTYELLOW "\033[33m"
9126 #define VTBLUE "\033[34m"
9127 #define VTMAGENTA "\033[35m"
9128 #define VTCYAN "\033[36m"
9130 inline const char * colorForFlags(OSKextLogSpec flags
)
9132 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
9135 case kOSKextLogErrorLevel
:
9136 return VTRED VTBOLD
;
9138 case kOSKextLogWarningLevel
:
9141 case kOSKextLogBasicLevel
:
9142 return VTYELLOW VTUNDER
;
9144 case kOSKextLogProgressLevel
:
9147 case kOSKextLogStepLevel
:
9150 case kOSKextLogDetailLevel
:
9153 case kOSKextLogDebugLevel
:
9163 inline bool logSpecMatch(
9164 OSKextLogSpec msgLogSpec
,
9165 OSKextLogSpec logFilter
)
9167 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
9168 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
9169 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
9171 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
9172 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
9173 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
9175 /* Explicit messages always get logged.
9177 if (msgLevel
== kOSKextLogExplicitLevel
) {
9181 /* Warnings and errors are logged regardless of the flags.
9183 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
9187 /* A verbose message that isn't for a logging-enabled kext and isn't global
9188 * does *not* get logged.
9190 if (!msgKextGlobal
&& !filterKextGlobal
) {
9194 /* Warnings and errors are logged regardless of the flags.
9195 * All other messages must fit the flags and
9196 * have a level at or below the filter.
9199 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
9210 OSKextLogSpec msgLogSpec
,
9211 const char * format
, ...)
9215 va_start(argList
, format
);
9216 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
9223 OSKextLogSpec msgLogSpec
,
9224 const char * format
,
9227 extern int disableConsoleOutput
;
9229 bool logForKernel
= false;
9230 bool logForUser
= false;
9232 char stackBuffer
[120];
9233 uint32_t length
= 0;
9234 char * allocBuffer
= NULL
; // must kfree
9235 OSNumber
* logSpecNum
= NULL
; // must release
9236 OSString
* logString
= NULL
; // must release
9237 char * buffer
= stackBuffer
; // do not free
9239 IOLockLock(sKextLoggingLock
);
9241 /* Set the kext/global bit in the message spec if we have no
9242 * kext or if the kext requests logging.
9244 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
9245 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
9248 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
9249 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
9250 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
9253 if (! (logForKernel
|| logForUser
) ) {
9257 /* No goto from here until past va_end()!
9259 va_copy(argList
, srcArgList
);
9260 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
9263 if (length
+ 1 >= sizeof(stackBuffer
)) {
9264 allocBuffer
= (char *)kalloc((length
+ 1) * sizeof(char));
9269 /* No goto from here until past va_end()!
9271 va_copy(argList
, srcArgList
);
9272 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
9275 buffer
= allocBuffer
;
9278 /* If user space wants the log message, queue it up.
9280 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
9281 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
9282 logString
= OSString::withCString(buffer
);
9283 if (logSpecNum
&& logString
) {
9284 sUserSpaceLogSpecArray
->setObject(logSpecNum
);
9285 sUserSpaceLogMessageArray
->setObject(logString
);
9289 /* Always log messages from the kernel according to the kernel's
9294 /* If we are in console mode and have a custom log filter,
9295 * colorize the log message.
9297 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
9298 const char * color
= ""; // do not free
9299 color
= colorForFlags(msgLogSpec
);
9300 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
9301 buffer
, color
[0] ? VTRESET
: "");
9303 printf("%s\n", buffer
);
9308 IOLockUnlock(sKextLoggingLock
);
9311 kfree(allocBuffer
, (length
+ 1) * sizeof(char));
9313 OSSafeRelease(logString
);
9314 OSSafeRelease(logSpecNum
);
9321 #pragma mark Backtrace Dump & kmod_get_info() support
9323 /*********************************************************************
9324 * This function must be safe to call in panic context.
9325 *********************************************************************/
9328 OSKext::printKextsInBacktrace(
9331 int (* printf_func
)(const char *fmt
, ...),
9334 addr64_t summary_page
= 0;
9335 addr64_t last_summary_page
= 0;
9336 bool found_kmod
= false;
9340 IOLockLock(sKextSummariesLock
);
9343 if (!gLoadedKextSummaries
) {
9344 (*printf_func
)(" can't perform kext scan: no kext summary");
9348 summary_page
= trunc_page((addr64_t
)(uintptr_t)gLoadedKextSummaries
);
9349 last_summary_page
= round_page(summary_page
+ sLoadedKextSummariesAllocSize
);
9350 for (; summary_page
< last_summary_page
; summary_page
+= PAGE_SIZE
) {
9351 if (pmap_find_phys(kernel_pmap
, summary_page
) == 0) {
9352 (*printf_func
)(" can't perform kext scan: "
9353 "missing kext summary page %p", summary_page
);
9358 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
9359 OSKextLoadedKextSummary
* summary
;
9361 summary
= gLoadedKextSummaries
->summaries
+ i
;
9362 if (!summary
->address
) {
9366 if (!summaryIsInBacktrace(summary
, addr
, cnt
)) {
9371 (*printf_func
)(" Kernel Extensions in backtrace:\n");
9375 printSummary(summary
, printf_func
);
9380 IOLockUnlock(sKextSummariesLock
);
9386 /*********************************************************************
9387 * This function must be safe to call in panic context.
9388 *********************************************************************/
9391 OSKext::summaryIsInBacktrace(
9392 OSKextLoadedKextSummary
* summary
,
9398 for (i
= 0; i
< cnt
; i
++) {
9399 vm_offset_t kscan_addr
= addr
[i
];
9400 if ((kscan_addr
>= summary
->address
) &&
9401 (kscan_addr
< (summary
->address
+ summary
->size
)))
9410 /*********************************************************************
9411 * scan list of loaded kext summaries looking for a load address match and if
9412 * found return the UUID C string. If not found then set empty string.
9413 *********************************************************************/
9414 static void findSummaryUUID(
9416 uuid_string_t uuid
);
9418 static void findSummaryUUID(
9424 uuid
[0] = 0x00; // default to no UUID
9426 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
9427 OSKextLoadedKextSummary
* summary
;
9429 summary
= gLoadedKextSummaries
->summaries
+ i
;
9431 if (summary
->loadTag
== tag_ID
) {
9432 (void) uuid_unparse(summary
->uuid
, uuid
);
9439 /*********************************************************************
9440 * This function must be safe to call in panic context.
9441 *********************************************************************/
9442 void OSKext::printSummary(
9443 OSKextLoadedKextSummary
* summary
,
9444 int (* printf_func
)(const char *fmt
, ...))
9446 kmod_reference_t
* kmod_ref
= NULL
;
9448 char version
[kOSKextVersionMaxLength
];
9450 if (!OSKextVersionGetString(summary
->version
, version
, sizeof(version
))) {
9451 strlcpy(version
, "unknown version", sizeof(version
));
9453 (void) uuid_unparse(summary
->uuid
, uuid
);
9455 (*printf_func
)(" %s(%s)[%s]@0x%llx->0x%llx\n",
9456 summary
->name
, version
, uuid
,
9457 summary
->address
, summary
->address
+ summary
->size
- 1);
9459 /* print dependency info */
9460 for (kmod_ref
= (kmod_reference_t
*) summary
->reference_list
;
9462 kmod_ref
= kmod_ref
->next
) {
9463 kmod_info_t
* rinfo
;
9465 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_ref
)) == 0) {
9466 (*printf_func
)(" kmod dependency scan stopped "
9467 "due to missing dependency page: %p\n", kmod_ref
);
9470 rinfo
= kmod_ref
->info
;
9472 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
9473 (*printf_func
)(" kmod dependency scan stopped "
9474 "due to missing kmod page: %p\n", rinfo
);
9478 if (!rinfo
->address
) {
9479 continue; // skip fake entries for built-ins
9482 /* locate UUID in gLoadedKextSummaries */
9483 findSummaryUUID(rinfo
->id
, uuid
);
9485 (*printf_func
)(" dependency: %s(%s)[%s]@%p\n",
9486 rinfo
->name
, rinfo
->version
, uuid
, rinfo
->address
);
9492 /*******************************************************************************
9493 * substitute() looks at an input string (a pointer within a larger buffer)
9494 * for a match to a substring, and on match it writes the marker & substitution
9495 * character to an output string, updating the scan (from) and
9496 * output (to) indexes as appropriate.
9497 *******************************************************************************/
9498 static int substitute(
9499 const char * scan_string
,
9501 uint32_t * to_index
,
9502 uint32_t * from_index
,
9503 const char * substring
,
9507 /* string_out must be at least KMOD_MAX_NAME bytes.
9511 const char * scan_string
,
9513 uint32_t * to_index
,
9514 uint32_t * from_index
,
9515 const char * substring
,
9519 uint32_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
9521 /* On a substring match, append the marker (if there is one) and then
9522 * the substitution character, updating the output (to) index accordingly.
9523 * Then update the input (from) length by the length of the substring
9524 * that got replaced.
9526 if (!strncmp(scan_string
, substring
, substring_length
)) {
9528 string_out
[(*to_index
)++] = marker
;
9530 string_out
[(*to_index
)++] = substitution
;
9531 (*from_index
) += substring_length
;
9537 /*******************************************************************************
9538 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
9539 * KMOD_MAX_NAME characters and performs various substitutions of common
9540 * prefixes & substrings as defined by tables in kext_panic_report.h.
9541 *******************************************************************************/
9542 static void compactIdentifier(
9543 const char * identifier
,
9544 char * identifier_out
,
9545 char ** identifier_out_end
);
9549 const char * identifier
,
9550 char * identifier_out
,
9551 char ** identifier_out_end
)
9553 uint32_t from_index
, to_index
;
9554 uint32_t scan_from_index
= 0;
9555 uint32_t scan_to_index
= 0;
9556 subs_entry_t
* subs_entry
= NULL
;
9559 from_index
= to_index
= 0;
9560 identifier_out
[0] = '\0';
9562 /* Replace certain identifier prefixes with shorter @+character sequences.
9563 * Check the return value of substitute() so we only replace the prefix.
9565 for (subs_entry
= &kext_identifier_prefix_subs
[0];
9566 subs_entry
->substring
&& !did_sub
;
9569 did_sub
= substitute(identifier
, identifier_out
,
9570 &scan_to_index
, &scan_from_index
,
9571 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
9575 /* Now scan through the identifier looking for the common substrings
9576 * and replacing them with shorter !+character sequences via substitute().
9578 for (/* see above */;
9579 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
9582 const char * scan_string
= &identifier
[scan_from_index
];
9586 if (scan_from_index
) {
9587 for (subs_entry
= &kext_identifier_substring_subs
[0];
9588 subs_entry
->substring
&& !did_sub
;
9591 did_sub
= substitute(scan_string
, identifier_out
,
9592 &scan_to_index
, &scan_from_index
,
9593 subs_entry
->substring
, '!', subs_entry
->substitute
);
9597 /* If we didn't substitute, copy the input character to the output.
9600 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
9604 identifier_out
[scan_to_index
] = '\0';
9605 if (identifier_out_end
) {
9606 *identifier_out_end
= &identifier_out
[scan_to_index
];
9612 /*******************************************************************************
9613 * assemble_identifier_and_version() adds to a string buffer a compacted
9614 * bundle identifier followed by a version string.
9615 *******************************************************************************/
9617 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
9619 static int assemble_identifier_and_version(
9620 kmod_info_t
* kmod_info
,
9621 char * identPlusVers
);
9623 assemble_identifier_and_version(
9624 kmod_info_t
* kmod_info
,
9625 char * identPlusVers
)
9629 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
9630 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
9631 identPlusVers
[result
++] = '\t'; // increment for real char
9632 identPlusVers
[result
] = '\0'; // don't increment for nul char
9633 result
= strlcat(identPlusVers
, kmod_info
->version
, KMOD_MAX_NAME
);
9638 /*******************************************************************************
9639 * Assumes sKextLock is held.
9640 *******************************************************************************/
9643 OSKext::saveLoadedKextPanicListTyped(
9644 const char * prefix
,
9649 uint32_t * list_length_ptr
)
9651 uint32_t result
= 0;
9653 unsigned int count
, i
;
9655 count
= sLoadedKexts
->getCount();
9662 OSObject
* rawKext
= sLoadedKexts
->getObject(i
);
9663 OSKext
* theKext
= OSDynamicCast(OSKext
, rawKext
);
9665 char identPlusVers
[2*KMOD_MAX_NAME
];
9666 uint32_t identPlusVersLength
;
9669 printf("OSKext::saveLoadedKextPanicListTyped - "
9670 "NULL kext in loaded kext list; continuing\n");
9675 printf("OSKext::saveLoadedKextPanicListTyped - "
9676 "Kext type cast failed in loaded kext list; continuing\n");
9680 /* Skip all built-in kexts.
9682 if (theKext
->isKernelComponent()) {
9686 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
9688 /* Filter for kmod name (bundle identifier).
9690 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
9691 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
9695 /* Filter for libraries (kexts that have a compatible version).
9697 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
9698 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
9704 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
9706 printf("kext scan stopped due to missing kmod_info page: %p\n",
9712 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
9714 if (!identPlusVersLength
) {
9715 printf("error saving loaded kext info\n");
9719 /* Adding 1 for the newline.
9721 if (*list_length_ptr
+ identPlusVersLength
+ 1 >= list_size
) {
9725 *list_length_ptr
= strlcat(paniclist
, identPlusVers
, list_size
);
9726 *list_length_ptr
= strlcat(paniclist
, "\n", list_size
);
9732 if (*list_length_ptr
+ 1 <= list_size
) {
9733 result
= list_size
- (*list_length_ptr
+ 1);
9740 /*********************************************************************
9741 *********************************************************************/
9744 OSKext::saveLoadedKextPanicList(void)
9746 char * newlist
= NULL
;
9747 uint32_t newlist_size
= 0;
9748 uint32_t newlist_length
= 0;
9751 newlist_size
= KEXT_PANICLIST_SIZE
;
9752 newlist
= (char *)kalloc(newlist_size
);
9755 OSKextLog(/* kext */ NULL
,
9756 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
9757 "Couldn't allocate kext panic log buffer.");
9763 // non-"com.apple." kexts
9764 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
9765 /* libs? */ -1, newlist
, newlist_size
, &newlist_length
)) {
9769 // "com.apple." nonlibrary kexts
9770 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
9771 /* libs? */ 0, newlist
, newlist_size
, &newlist_length
)) {
9775 // "com.apple." library kexts
9776 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
9777 /* libs? */ 1, newlist
, newlist_size
, &newlist_length
)) {
9782 if (loaded_kext_paniclist
) {
9783 kfree(loaded_kext_paniclist
, loaded_kext_paniclist_size
);
9785 loaded_kext_paniclist
= newlist
;
9786 loaded_kext_paniclist_size
= newlist_size
;
9787 loaded_kext_paniclist_length
= newlist_length
;
9793 /*********************************************************************
9794 * Assumes sKextLock is held.
9795 *********************************************************************/
9797 OSKext::savePanicString(bool isLoading
)
9802 return; // do not goto finish here b/c of lock
9805 len
= assemble_identifier_and_version(kmod_info
,
9806 (isLoading
) ? last_loaded_str
: last_unloaded_str
);
9808 printf("error saving unloaded kext info\n");
9813 last_loaded_strlen
= len
;
9814 last_loaded_address
= (void *)kmod_info
->address
;
9815 last_loaded_size
= kmod_info
->size
;
9816 clock_get_uptime(&last_loaded_timestamp
);
9818 last_unloaded_strlen
= len
;
9819 last_unloaded_address
= (void *)kmod_info
->address
;
9820 last_unloaded_size
= kmod_info
->size
;
9821 clock_get_uptime(&last_unloaded_timestamp
);
9828 /*********************************************************************
9829 *********************************************************************/
9832 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
9834 if (last_loaded_strlen
) {
9835 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
9836 AbsoluteTime_to_scalar(&last_loaded_timestamp
),
9837 last_loaded_strlen
, last_loaded_str
,
9838 last_loaded_address
, last_loaded_size
);
9841 if (last_unloaded_strlen
) {
9842 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
9843 AbsoluteTime_to_scalar(&last_unloaded_timestamp
),
9844 last_unloaded_strlen
, last_unloaded_str
,
9845 last_unloaded_address
, last_unloaded_size
);
9848 printf_func("loaded kexts:\n");
9849 if (loaded_kext_paniclist
&&
9850 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
9851 loaded_kext_paniclist
[0]) {
9853 printf_func("%.*s", loaded_kext_paniclist_length
, loaded_kext_paniclist
);
9855 printf_func("(none)\n");
9860 /*********************************************************************
9861 * Assumes sKextLock is held.
9862 *********************************************************************/
9865 OSKext::updateLoadedKextSummaries(void)
9867 kern_return_t result
= KERN_FAILURE
;
9868 OSKextLoadedKextSummaryHeader
*summaryHeader
= NULL
;
9869 OSKextLoadedKextSummaryHeader
*summaryHeaderAlloc
= NULL
;
9871 vm_map_offset_t start
, end
;
9872 size_t summarySize
= 0;
9878 IOLockLock(sKextSummariesLock
);
9880 count
= sLoadedKexts
->getCount();
9881 for (i
= 0, numKexts
= 0; i
< count
; ++i
) {
9882 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
9883 numKexts
+= (aKext
&& aKext
->isExecutable());
9886 if (!numKexts
) goto finish
;
9888 /* Calculate the size needed for the new summary headers.
9891 size
= sizeof(*gLoadedKextSummaries
);
9892 size
+= numKexts
* sizeof(*gLoadedKextSummaries
->summaries
);
9893 size
= round_page(size
);
9895 /* If the previous summary is large enough, use it (and be sure to make
9896 * it writable). If it's too small, free it and allocate a new buffer.
9899 if (sPrevLoadedKextSummariesAllocSize
< size
) {
9900 if (sPrevLoadedKextSummaries
) {
9901 kmem_free(kernel_map
, (vm_offset_t
)sPrevLoadedKextSummaries
,
9902 sPrevLoadedKextSummariesAllocSize
);
9903 sPrevLoadedKextSummaries
= NULL
;
9904 sPrevLoadedKextSummariesAllocSize
= 0;
9907 result
= kmem_alloc(kernel_map
,
9908 (vm_offset_t
*)&summaryHeaderAlloc
, size
);
9909 if (result
!= KERN_SUCCESS
) goto finish
;
9911 summaryHeader
= summaryHeaderAlloc
;
9914 summaryHeader
= sPrevLoadedKextSummaries
;
9915 summarySize
= sPrevLoadedKextSummariesAllocSize
;
9917 start
= (vm_map_offset_t
) summaryHeader
;
9918 end
= start
+ summarySize
;
9919 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_DEFAULT
, FALSE
);
9920 if (result
!= KERN_SUCCESS
) goto finish
;
9923 /* Populate the summary header.
9926 bzero(summaryHeader
, summarySize
);
9927 summaryHeader
->version
= kOSKextLoadedKextSummaryVersion
;
9928 summaryHeader
->entry_size
= sizeof(OSKextLoadedKextSummary
);
9929 summaryHeader
->numSummaries
= numKexts
;
9931 /* Populate each kext summary.
9934 count
= sLoadedKexts
->getCount();
9935 for (i
= 0, j
= 0; i
< count
; ++i
) {
9936 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
9937 if (!aKext
|| !aKext
->isExecutable()) continue;
9939 aKext
->updateLoadedKextSummary(&summaryHeader
->summaries
[j
++]);
9942 /* Write protect the buffer and move it into place.
9945 start
= (vm_map_offset_t
) summaryHeader
;
9946 end
= start
+ summarySize
;
9947 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_READ
, FALSE
);
9948 if (result
!= KERN_SUCCESS
) goto finish
;
9950 sPrevLoadedKextSummaries
= gLoadedKextSummaries
;
9951 sPrevLoadedKextSummariesAllocSize
= sLoadedKextSummariesAllocSize
;
9953 gLoadedKextSummaries
= summaryHeader
;
9954 sLoadedKextSummariesAllocSize
= summarySize
;
9956 summaryHeaderAlloc
= NULL
;
9958 /* Call the magic breakpoint function through a static function pointer so
9959 * the compiler can't optimize the function away.
9961 if (sLoadedKextSummariesUpdated
) (*sLoadedKextSummariesUpdated
)();
9964 IOLockUnlock(sKextSummariesLock
);
9966 /* If we had to allocate a new buffer but failed to generate the summaries,
9969 if (summaryHeaderAlloc
) {
9970 kmem_free(kernel_map
, (vm_offset_t
)summaryHeaderAlloc
, summarySize
);
9976 /*********************************************************************
9977 *********************************************************************/
9979 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary
*summary
)
9983 strlcpy(summary
->name
, getIdentifierCString(),
9984 sizeof(summary
->name
));
9988 memcpy(summary
->uuid
, uuid
->getBytesNoCopy(), sizeof(summary
->uuid
));
9989 OSSafeRelease(uuid
);
9992 summary
->address
= kmod_info
->address
;
9993 summary
->size
= kmod_info
->size
;
9994 summary
->version
= getVersion();
9995 summary
->loadTag
= kmod_info
->id
;
9997 summary
->reference_list
= (uint64_t) kmod_info
->reference_list
;
10002 /*********************************************************************
10003 *********************************************************************/
10007 OSKext::getKmodInfo(
10008 kmod_info_array_t
* kmodList
,
10009 mach_msg_type_number_t
* kmodCount
)
10011 kern_return_t result
= KERN_FAILURE
;
10012 vm_offset_t data
= 0;
10013 kmod_info_t
* k
, * kmod_info_scan_ptr
;
10014 kmod_reference_t
* r
, * ref_scan_ptr
;
10018 *kmodList
= (kmod_info_t
*)0;
10021 IORecursiveLockLock(sKextLock
);
10025 size
+= sizeof(kmod_info_t
);
10026 r
= k
->reference_list
;
10028 size
+=sizeof(kmod_reference_t
);
10034 result
= KERN_SUCCESS
;
10038 result
= kmem_alloc(kernel_map
, &data
, size
);
10039 if (result
!= KERN_SUCCESS
) {
10043 /* Copy each kmod_info struct sequentially into the data buffer.
10044 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
10045 * the kernel space address is used to match refs, and a zero 'next' flags
10046 * the end of kmod_infos in the data buffer and the beginning of references.
10049 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
10051 *kmod_info_scan_ptr
= *k
;
10053 kmod_info_scan_ptr
->next
= k
;
10055 kmod_info_scan_ptr
++;
10059 /* Now add references after the kmod_info structs in the same buffer.
10060 * Update each kmod_info with the ref_count so we can associate
10061 * references with kmod_info structs.
10064 ref_scan_ptr
= (kmod_reference_t
*)kmod_info_scan_ptr
;
10065 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
10067 r
= k
->reference_list
;
10070 /* Note the last kmod_info in the data buffer has its next == 0.
10071 * Since there can only be one like that,
10072 * this case is handled by the caller.
10074 *ref_scan_ptr
= *r
;
10079 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
10080 * struct for the client to interpret.
10082 kmod_info_scan_ptr
->reference_list
= (kmod_reference_t
*)(long)ref_count
;
10083 kmod_info_scan_ptr
++;
10087 result
= vm_map_copyin(kernel_map
, data
, size
, TRUE
, (vm_map_copy_t
*)kmodList
);
10088 if (result
!= KERN_SUCCESS
) {
10093 result
= KERN_SUCCESS
;
10096 IORecursiveLockUnlock(sKextLock
);
10098 if (result
!= KERN_SUCCESS
&& data
) {
10099 kmem_free(kernel_map
, data
, size
);
10100 *kmodList
= (kmod_info_t
*)0;
10105 #endif /* __i386__ */
10107 #pragma mark MAC Framework Support
10109 /*********************************************************************
10110 *********************************************************************/
10111 #if CONFIG_MACF_KEXT
10112 /* MAC Framework support */
10115 * define IOC_DEBUG to display run-time debugging information
10116 * #define IOC_DEBUG 1
10120 #define DPRINTF(x) printf x
10126 /*********************************************************************
10127 *********************************************************************/
10129 MACFObjectIsPrimitiveType(OSObject
* obj
)
10131 const OSMetaClass
* typeID
= NULL
; // do not release
10133 typeID
= OSTypeIDInst(obj
);
10134 if (typeID
== OSTypeID(OSString
) || typeID
== OSTypeID(OSNumber
) ||
10135 typeID
== OSTypeID(OSBoolean
) || typeID
== OSTypeID(OSData
)) {
10142 /*********************************************************************
10143 *********************************************************************/
10145 MACFLengthForObject(OSObject
* obj
)
10147 const OSMetaClass
* typeID
= NULL
; // do not release
10150 typeID
= OSTypeIDInst(obj
);
10151 if (typeID
== OSTypeID(OSString
)) {
10152 OSString
* stringObj
= OSDynamicCast(OSString
, obj
);
10153 len
= stringObj
->getLength() + 1;
10154 } else if (typeID
== OSTypeID(OSNumber
)) {
10155 len
= sizeof("4294967295"); /* UINT32_MAX */
10156 } else if (typeID
== OSTypeID(OSBoolean
)) {
10157 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, obj
);
10158 len
= (boolObj
== kOSBooleanTrue
) ? sizeof("true") : sizeof("false");
10159 } else if (typeID
== OSTypeID(OSData
)) {
10160 OSData
* dataObj
= OSDynamicCast(OSData
, obj
);
10161 len
= dataObj
->getLength();
10168 /*********************************************************************
10169 *********************************************************************/
10171 MACFInitElementFromObject(
10172 struct mac_module_data_element
* element
,
10175 const OSMetaClass
* typeID
= NULL
; // do not release
10177 typeID
= OSTypeIDInst(value
);
10178 if (typeID
== OSTypeID(OSString
)) {
10179 OSString
* stringObj
= OSDynamicCast(OSString
, value
);
10180 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10181 element
->value_size
= stringObj
->getLength() + 1;
10182 DPRINTF(("osdict: string %s size %d\n",
10183 stringObj
->getCStringNoCopy(), element
->value_size
));
10184 memcpy(element
->value
, stringObj
->getCStringNoCopy(),
10185 element
->value_size
);
10186 } else if (typeID
== OSTypeID(OSNumber
)) {
10187 OSNumber
* numberObj
= OSDynamicCast(OSNumber
, value
);
10188 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10189 element
->value_size
= sprintf(element
->value
, "%u",
10190 numberObj
->unsigned32BitValue()) + 1;
10191 } else if (typeID
== OSTypeID(OSBoolean
)) {
10192 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, value
);
10193 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10194 if (boolObj
== kOSBooleanTrue
) {
10195 strcpy(element
->value
, "true");
10196 element
->value_size
= 5;
10198 strcpy(element
->value
, "false");
10199 element
->value_size
= 6;
10201 } else if (typeID
== OSTypeID(OSData
)) {
10202 OSData
* dataObj
= OSDynamicCast(OSData
, value
);
10203 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10204 element
->value_size
= dataObj
->getLength();
10205 DPRINTF(("osdict: data size %d\n", dataObj
->getLength()));
10206 memcpy(element
->value
, dataObj
->getBytesNoCopy(),
10207 element
->value_size
);
10212 /*********************************************************************
10213 * This function takes an OSDictionary and returns a struct mac_module_data
10215 *********************************************************************/
10216 static struct mac_module_data
*
10217 MACFEncodeOSDictionary(OSDictionary
* dict
)
10219 struct mac_module_data
* result
= NULL
; // do not free
10220 const OSMetaClass
* typeID
= NULL
; // do not release
10221 OSString
* key
= NULL
; // do not release
10222 OSCollectionIterator
* keyIterator
= NULL
; // must release
10223 struct mac_module_data_element
* element
= NULL
; // do not free
10224 unsigned int strtabsize
= 0;
10225 unsigned int listtabsize
= 0;
10226 unsigned int dicttabsize
= 0;
10227 unsigned int nkeys
= 0;
10228 unsigned int datalen
= 0;
10229 char * strtab
= NULL
; // do not free
10230 char * listtab
= NULL
; // do not free
10231 char * dicttab
= NULL
; // do not free
10232 vm_offset_t data_addr
= 0;
10234 keyIterator
= OSCollectionIterator::withCollection(dict
);
10235 if (!keyIterator
) {
10239 /* Iterate over OSModuleData to figure out total size */
10240 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
10242 // Get the key's value and determine its type
10243 OSObject
* value
= dict
->getObject(key
);
10248 typeID
= OSTypeIDInst(value
);
10249 if (MACFObjectIsPrimitiveType(value
)) {
10250 strtabsize
+= MACFLengthForObject(value
);
10252 else if (typeID
== OSTypeID(OSArray
)) {
10253 unsigned int k
, cnt
, nents
;
10254 OSArray
* arrayObj
= OSDynamicCast(OSArray
, value
);
10257 cnt
= arrayObj
->getCount();
10258 for (k
= 0; k
< cnt
; k
++) {
10259 value
= arrayObj
->getObject(k
);
10260 typeID
= OSTypeIDInst(value
);
10261 if (MACFObjectIsPrimitiveType(value
)) {
10262 listtabsize
+= MACFLengthForObject(value
);
10265 else if (typeID
== OSTypeID(OSDictionary
)) {
10266 unsigned int dents
= 0;
10267 OSDictionary
* dictObj
= NULL
; // do not release
10268 OSString
* dictkey
= NULL
; // do not release
10269 OSCollectionIterator
* dictIterator
= NULL
; // must release
10271 dictObj
= OSDynamicCast(OSDictionary
, value
);
10272 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
10273 if (!dictIterator
) {
10276 while ((dictkey
= OSDynamicCast(OSString
,
10277 dictIterator
->getNextObject()))) {
10279 OSObject
* dictvalue
= NULL
; // do not release
10281 dictvalue
= dictObj
->getObject(dictkey
);
10285 if (MACFObjectIsPrimitiveType(dictvalue
)) {
10286 strtabsize
+= MACFLengthForObject(dictvalue
);
10288 continue; /* Only handle primitive types here. */
10291 * Allow for the "arraynnn/" prefix in the key length.
10293 strtabsize
+= dictkey
->getLength() + 1;
10296 dictIterator
->release();
10298 dicttabsize
+= sizeof(struct mac_module_data_list
) +
10299 dents
* sizeof(struct mac_module_data_element
);
10304 continue; /* Skip everything else. */
10310 listtabsize
+= sizeof(struct mac_module_data_list
) +
10311 (nents
- 1) * sizeof(struct mac_module_data_element
);
10313 continue; /* skip anything else */
10315 strtabsize
+= key
->getLength() + 1;
10323 * Allocate and fill in the module data structures.
10325 datalen
= sizeof(struct mac_module_data
) +
10326 sizeof(mac_module_data_element
) * (nkeys
- 1) +
10327 strtabsize
+ listtabsize
+ dicttabsize
;
10328 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
10329 datalen
, strtabsize
, listtabsize
, dicttabsize
));
10330 if (kmem_alloc(kernel_map
, &data_addr
, datalen
) != KERN_SUCCESS
) {
10333 result
= (mac_module_data
*)data_addr
;
10334 result
->base_addr
= data_addr
;
10335 result
->size
= datalen
;
10336 result
->count
= nkeys
;
10337 strtab
= (char *)&result
->data
[nkeys
];
10338 listtab
= strtab
+ strtabsize
;
10339 dicttab
= listtab
+ listtabsize
;
10340 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
10341 data_addr
, strtab
, listtab
, dicttab
, data_addr
+ datalen
));
10343 keyIterator
->reset();
10345 element
= &result
->data
[0];
10346 DPRINTF(("osdict: element %p\n", element
));
10347 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
10349 // Get the key's value and determine its type
10350 OSObject
* value
= dict
->getObject(key
);
10356 DPRINTF(("osdict: element @%p\n", element
));
10357 element
->key
= strtab
;
10358 element
->key_size
= key
->getLength() + 1;
10359 DPRINTF(("osdict: key %s size %d @%p\n", key
->getCStringNoCopy(),
10360 element
->key_size
, strtab
));
10361 memcpy(element
->key
, key
->getCStringNoCopy(), element
->key_size
);
10363 typeID
= OSTypeIDInst(value
);
10364 if (MACFObjectIsPrimitiveType(value
)) {
10366 element
->value
= element
->key
+ element
->key_size
;
10367 DPRINTF(("osdict: primitive element value %p\n", element
->value
));
10368 MACFInitElementFromObject(element
, value
);
10369 strtab
+= element
->key_size
+ element
->value_size
;
10370 DPRINTF(("osdict: new strtab %p\n", strtab
));
10371 } else if (typeID
== OSTypeID(OSArray
)) {
10372 unsigned int k
, cnt
, nents
;
10374 struct mac_module_data_list
*arrayhd
;
10375 struct mac_module_data_element
*ele
;
10376 OSArray
*arrayObj
= OSDynamicCast(OSArray
, value
);
10378 element
->value
= listtab
;
10379 DPRINTF(("osdict: array element value %p\n", element
->value
));
10380 element
->value_type
= MAC_DATA_TYPE_ARRAY
;
10381 arrayhd
= (struct mac_module_data_list
*)element
->value
;
10383 DPRINTF(("osdict: arrayhd %p\n", arrayhd
));
10385 astrtab
= strtab
+ element
->key_size
;
10386 ele
= &(arrayhd
->list
[0]);
10387 cnt
= arrayObj
->getCount();
10388 for (k
= 0; k
< cnt
; k
++) {
10389 value
= arrayObj
->getObject(k
);
10390 DPRINTF(("osdict: array ele %d @%p\n", nents
, ele
));
10393 typeID
= OSTypeIDInst(value
);
10394 if (MACFObjectIsPrimitiveType(value
)) {
10395 if (arrayhd
->type
!= 0 &&
10396 arrayhd
->type
!= MAC_DATA_TYPE_PRIMITIVE
) {
10400 arrayhd
->type
= MAC_DATA_TYPE_PRIMITIVE
;
10401 ele
->value
= astrtab
;
10402 MACFInitElementFromObject(ele
, value
);
10403 astrtab
+= ele
->value_size
;
10404 DPRINTF(("osdict: array new astrtab %p\n", astrtab
));
10405 } else if (typeID
== OSTypeID(OSDictionary
)) {
10406 unsigned int dents
;
10407 char * dstrtab
= NULL
; // do not free
10408 OSDictionary
* dictObj
= NULL
; // do not release
10409 OSString
* dictkey
= NULL
; // do not release
10410 OSCollectionIterator
* dictIterator
= NULL
; // must release
10411 struct mac_module_data_list
* dicthd
= NULL
; // do not free
10412 struct mac_module_data_element
* dele
= NULL
; // do not free
10414 if (arrayhd
->type
!= 0 &&
10415 arrayhd
->type
!= MAC_DATA_TYPE_DICT
) {
10419 dictObj
= OSDynamicCast(OSDictionary
, value
);
10420 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
10421 if (!dictIterator
) {
10424 DPRINTF(("osdict: dict\n"));
10425 ele
->value
= dicttab
;
10426 ele
->value_type
= MAC_DATA_TYPE_DICT
;
10427 dicthd
= (struct mac_module_data_list
*)ele
->value
;
10428 DPRINTF(("osdict: dicthd %p\n", dicthd
));
10431 while ((dictkey
= OSDynamicCast(OSString
,
10432 dictIterator
->getNextObject()))) {
10434 OSObject
* dictvalue
= NULL
; // do not release
10436 dictvalue
= dictObj
->getObject(dictkey
);
10440 dele
= &(dicthd
->list
[dents
]);
10441 DPRINTF(("osdict: dict ele %d @%p\n", dents
, dele
));
10442 if (MACFObjectIsPrimitiveType(dictvalue
)) {
10443 dele
->key
= dstrtab
;
10444 dele
->key_size
= dictkey
->getLength() + 1;
10445 DPRINTF(("osdict: dictkey %s size %d @%p\n",
10446 dictkey
->getCStringNoCopy(), dictkey
->getLength(), dstrtab
));
10447 memcpy(dele
->key
, dictkey
->getCStringNoCopy(),
10449 dele
->value
= dele
->key
+ dele
->key_size
;
10450 MACFInitElementFromObject(dele
, dictvalue
);
10451 dstrtab
+= dele
->key_size
+ dele
->value_size
;
10452 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab
));
10454 continue; /* Only handle primitive types here. */
10458 dictIterator
->release();
10462 arrayhd
->type
= MAC_DATA_TYPE_DICT
;
10463 ele
->value_size
= sizeof(struct mac_module_data_list
) +
10464 (dents
- 1) * sizeof(struct mac_module_data_element
);
10465 DPRINTF(("osdict: dict ele size %d ents %d\n", ele
->value_size
, dents
));
10466 dicttab
+= ele
->value_size
;
10467 DPRINTF(("osdict: new dicttab %p\n", dicttab
));
10468 dicthd
->count
= dents
;
10471 continue; /* Skip everything else. */
10479 element
->value_size
= sizeof(struct mac_module_data_list
) +
10480 (nents
- 1) * sizeof(struct mac_module_data_element
);
10481 listtab
+= element
->value_size
;
10482 DPRINTF(("osdict: new listtab %p\n", listtab
));
10483 arrayhd
->count
= nents
;
10485 DPRINTF(("osdict: new strtab %p\n", strtab
));
10487 continue; /* skip anything else */
10491 DPRINTF(("result list @%p, key %p value %p\n",
10492 result
, result
->data
[0].key
, result
->data
[0].value
));
10494 if (keyIterator
) keyIterator
->release();
10498 /*********************************************************************
10499 * This function takes a plist and looks for an OSModuleData dictionary.
10500 * If it is found, an encoded copy is returned. The value must be
10502 *********************************************************************/
10504 MACFCopyModuleDataForKext(
10506 mach_msg_type_number_t
* datalen
)
10509 struct mac_module_data
* result
= NULL
;
10510 OSDictionary
* kextModuleData
= NULL
; // do not release
10511 vm_map_copy_t copy
= 0;
10513 kextModuleData
= OSDynamicCast(OSDictionary
,
10514 theKext
->getPropertyForHostArch("OSModuleData"));
10515 if (!kextModuleData
) {
10519 result
= MACFEncodeOSDictionary(kextModuleData
);
10523 *datalen
= module_data
->size
;
10526 return (void *)result
;
10528 #endif /* CONFIG_MACF_KEXT */