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 vm_offset_t linkeditaddr
= 0;
4878 OSData
* data
= NULL
;
4880 if (sKeepSymbols
|| isLibrary() || !isExecutable() || !linkedExecutable
) {
4884 /* Find the linkedit segment. If it's not the last segment, then freeing
4885 * it will fragment the kext into multiple VM regions, which OSKext is not
4886 * designed to handle, so we'll have to skip it.
4888 linkedit
= getsegbynamefromheader(machhdr
, SEG_LINKEDIT
);
4893 if (round_page(kmod_info
->address
+ kmod_info
->size
) !=
4894 round_page(linkedit
->vmaddr
+ linkedit
->vmsize
))
4899 /* Create a new OSData for the smaller kext object.
4901 linkeditsize
= round_page(linkedit
->vmsize
);
4902 kextsize
= kmod_info
->size
- linkeditsize
;
4904 /* Save linkedit address as removeLinkeditHeaders() will zero it */
4905 linkeditaddr
= trunc_page(linkedit
->vmaddr
);
4907 data
= OSData::withBytesNoCopy((void *)kmod_info
->address
, kextsize
);
4911 data
->setDeallocFunction(osdata_kext_free
);
4913 /* Rewrite the Mach-O headers.
4915 if (KERN_SUCCESS
!= removeLinkeditHeaders(linkedit
)) {
4919 /* Fix the kmod info and linkedExecutable.
4921 kmod_info
->size
= kextsize
;
4922 linkedExecutable
->setDeallocFunction(NULL
);
4923 linkedExecutable
->release();
4924 linkedExecutable
= data
;
4926 /* Free the linkedit segment.
4928 kext_free(linkeditaddr
, linkeditsize
);
4934 /*********************************************************************
4935 *********************************************************************/
4937 OSKext::removeLinkeditHeaders(kernel_segment_command_t
*linkedit
)
4939 OSReturn result
= KERN_FAILURE
;
4940 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
4942 u_char
* src
, * dst
;
4943 uint32_t cmdsize
, ncmds
;
4946 kext_map
= kext_get_vm_map(kmod_info
);
4948 result
= KERN_MEMORY_ERROR
;
4952 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4953 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_DEFAULT
, TRUE
);
4954 if (result
!= KERN_SUCCESS
) {
4958 ncmds
= machhdr
->ncmds
;
4959 src
= dst
= (u_char
*)(kmod_info
->address
+ sizeof(*machhdr
));
4961 for (i
= 0; i
< ncmds
; ++i
, src
+= cmdsize
) {
4962 struct load_command
* lc
= (struct load_command
*) src
;
4963 cmdsize
= lc
->cmdsize
;
4968 if (src
!= (u_char
*)linkedit
) break;
4972 bzero(src
, cmdsize
);
4974 machhdr
->sizeofcmds
-= cmdsize
;
4978 memmove(dst
, src
, cmdsize
);
4982 result
= vm_map_protect(kext_map
, kmod_info
->address
,
4983 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
4984 if (result
!= KERN_SUCCESS
) {
4988 result
= KERN_SUCCESS
;
4994 /*********************************************************************
4995 *********************************************************************/
4997 OSKext::setLinkedExecutable(OSData
* anExecutable
)
4999 if (linkedExecutable
) {
5000 panic("Attempt to set linked executable on kext "
5001 "that already has one (%s).\n",
5002 getIdentifierCString());
5004 linkedExecutable
= anExecutable
;
5005 linkedExecutable
->retain();
5010 /*********************************************************************
5011 * Go through all loaded kexts and tell them to register with dtrace.
5012 * The instance method only registers if necessary.
5013 *********************************************************************/
5016 OSKext::registerKextsWithDTrace(void)
5018 uint32_t count
= sLoadedKexts
->getCount();
5021 IORecursiveLockLock(sKextLock
);
5023 for (i
= 0; i
< count
; i
++) {
5024 OSKext
* thisKext
= NULL
; // do not release
5026 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
5027 if (!thisKext
|| !thisKext
->isExecutable()) {
5031 thisKext
->registerWithDTrace();
5034 IORecursiveLockUnlock(sKextLock
);
5040 extern int (*dtrace_modload
)(struct kmod_info
*);
5041 extern int (*dtrace_modunload
)(struct kmod_info
*);
5044 /*********************************************************************
5045 *********************************************************************/
5047 OSKext::registerWithDTrace(void)
5049 /* Register kext with dtrace. A dtrace_modload failure should not
5050 * prevent a kext from loading, so we ignore the return code.
5052 if (!flags
.dtraceInitialized
&& (dtrace_modload
!= NULL
)) {
5053 (void)(*dtrace_modload
)(kmod_info
);
5054 flags
.dtraceInitialized
= true;
5055 jettisonLinkeditSegment();
5059 /*********************************************************************
5060 *********************************************************************/
5062 OSKext::unregisterWithDTrace(void)
5064 /* Unregister kext with dtrace. A dtrace_modunload failure should not
5065 * prevent a kext from loading, so we ignore the return code.
5067 if (flags
.dtraceInitialized
&& (dtrace_modunload
!= NULL
)) {
5068 (void)(*dtrace_modunload
)(kmod_info
);
5069 flags
.dtraceInitialized
= false;
5073 #endif /* CONFIG_DTRACE */
5076 /*********************************************************************
5077 * called only by loadExecutable()
5078 *********************************************************************/
5080 OSKext::setVMProtections(void)
5082 vm_map_t kext_map
= NULL
;
5083 kernel_segment_command_t
* seg
= NULL
;
5084 vm_map_offset_t start
= 0;
5085 vm_map_offset_t end
= 0;
5086 OSReturn result
= kOSReturnError
;
5088 if (!kmod_info
->address
&& !kmod_info
->size
) {
5089 result
= kOSReturnSuccess
;
5093 /* Get the kext's vm map */
5094 kext_map
= kext_get_vm_map(kmod_info
);
5096 result
= KERN_MEMORY_ERROR
;
5100 /* XXX: On arm, the vme covering the prelinked kernel (really, the whole
5101 * range from 0xc0000000 to a little over 0xe0000000) has maxprot set to 0
5102 * so the vm_map_protect calls below fail
5103 * I believe this happens in the call to vm_map_enter in kmem_init but I
5106 /* Protect the headers as read-only; they do not need to be wired */
5107 result
= vm_map_protect(kext_map
, kmod_info
->address
,
5108 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
);
5109 if (result
!= KERN_SUCCESS
) {
5113 /* Set the VM protections and wire down each of the segments */
5114 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5116 start
= round_page(seg
->vmaddr
);
5117 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
5119 result
= vm_map_protect(kext_map
, start
, end
, seg
->maxprot
, TRUE
);
5120 if (result
!= KERN_SUCCESS
) {
5122 kOSKextLogErrorLevel
|
5124 "Kext %s failed to set maximum VM protections "
5125 "for segment %s - 0x%x.",
5126 getIdentifierCString(), seg
->segname
, (int)result
);
5130 result
= vm_map_protect(kext_map
, start
, end
, seg
->initprot
, FALSE
);
5131 if (result
!= KERN_SUCCESS
) {
5133 kOSKextLogErrorLevel
|
5135 "Kext %s failed to set initial VM protections "
5136 "for segment %s - 0x%x.",
5137 getIdentifierCString(), seg
->segname
, (int)result
);
5141 if (segmentShouldBeWired(seg
)) {
5142 result
= vm_map_wire(kext_map
, start
, end
, seg
->initprot
, FALSE
);
5143 if (result
!= KERN_SUCCESS
) {
5148 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5155 /*********************************************************************
5156 *********************************************************************/
5158 OSKext::segmentShouldBeWired(kernel_segment_command_t
*seg
)
5160 return (sKeepSymbols
|| strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)));
5163 /*********************************************************************
5164 *********************************************************************/
5166 OSKext::validateKextMapping(bool startFlag
)
5168 OSReturn result
= kOSReturnError
;
5169 const char * whichOp
= startFlag
? "start" : "stop";
5170 kern_return_t kern_result
= 0;
5171 vm_map_t kext_map
= NULL
;
5172 kernel_segment_command_t
* seg
= NULL
;
5173 mach_vm_address_t address
= 0;
5174 mach_vm_size_t size
= 0;
5176 mach_msg_type_number_t count
;
5177 vm_region_submap_short_info_data_64_t info
;
5179 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
5180 bzero(&info
, sizeof(info
));
5182 // xxx - do we need a distinct OSReturn value for these or is "bad data"
5183 // xxx - sufficient?
5185 /* Verify that the kmod_info and start/stop pointers are non-NULL.
5189 kOSKextLogErrorLevel
|
5191 "Kext %s - NULL kmod_info pointer.",
5192 getIdentifierCString());
5193 result
= kOSKextReturnBadData
;
5198 address
= (mach_vm_address_t
)kmod_info
->start
;
5200 address
= (mach_vm_address_t
)kmod_info
->stop
;
5205 kOSKextLogErrorLevel
|
5207 "Kext %s - NULL module %s pointer.",
5208 getIdentifierCString(), whichOp
);
5209 result
= kOSKextReturnBadData
;
5213 kext_map
= kext_get_vm_map(kmod_info
);
5214 depth
= (kernel_map
== kext_map
) ? 1 : 2;
5216 /* Verify that the start/stop function lies within the kext's address range.
5218 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
5219 kmod_info
->address
+ kmod_info
->size
<= address
)
5222 kOSKextLogErrorLevel
|
5224 "Kext %s module %s pointer is outside of kext range "
5225 "(%s %p - kext at %p-%p)..",
5226 getIdentifierCString(),
5230 (void *)kmod_info
->address
,
5231 (void *)(kmod_info
->address
+ kmod_info
->size
));
5232 result
= kOSKextReturnBadData
;
5236 /* Only do these checks before calling the start function;
5237 * If anything goes wrong with the mapping while the kext is running,
5238 * we'll likely have panicked well before any attempt to stop the kext.
5242 /* Verify that the start/stop function is executable.
5244 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
5245 (vm_region_recurse_info_t
)&info
, &count
);
5246 if (kern_result
!= KERN_SUCCESS
) {
5248 kOSKextLogErrorLevel
|
5250 "Kext %s - bad %s pointer %p.",
5251 getIdentifierCString(),
5252 whichOp
, (void *)address
);
5253 result
= kOSKextReturnBadData
;
5257 if (!(info
.protection
& VM_PROT_EXECUTE
)) {
5259 kOSKextLogErrorLevel
|
5261 "Kext %s - memory region containing module %s function "
5262 "is not executable.",
5263 getIdentifierCString(), whichOp
);
5264 result
= kOSKextReturnBadData
;
5268 /* Verify that the kext's segments are backed by physical memory.
5270 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5272 if (!verifySegmentMapping(seg
)) {
5273 result
= kOSKextReturnBadData
;
5277 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5282 result
= kOSReturnSuccess
;
5287 /*********************************************************************
5288 *********************************************************************/
5290 OSKext::verifySegmentMapping(kernel_segment_command_t
*seg
)
5292 mach_vm_address_t address
= 0;
5294 if (!segmentShouldBeWired(seg
)) return true;
5296 for (address
= seg
->vmaddr
;
5297 address
< round_page(seg
->vmaddr
+ seg
->vmsize
);
5298 address
+= PAGE_SIZE
)
5300 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
5302 kOSKextLogErrorLevel
|
5304 "Kext %s - page %p is not backed by physical memory.",
5305 getIdentifierCString(),
5314 /*********************************************************************
5315 *********************************************************************/
5317 OSKext::start(bool startDependenciesFlag
)
5319 OSReturn result
= kOSReturnError
;
5320 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
5321 unsigned int i
, count
;
5322 void * kmodStartData
= NULL
; // special handling needed
5323 #if CONFIG_MACF_KEXT
5324 mach_msg_type_number_t kmodStartDataCount
= 0;
5325 #endif /* CONFIG_MACF_KEXT */
5327 if (isStarted() || isInterface() || isKernelComponent()) {
5328 result
= kOSReturnSuccess
;
5334 kOSKextLogErrorLevel
|
5336 "Attempt to start nonloaded kext %s.",
5337 getIdentifierCString());
5338 result
= kOSKextReturnInvalidArgument
;
5342 if (!sLoadEnabled
) {
5344 kOSKextLogErrorLevel
|
5346 "Kext loading is disabled (attempt to start kext %s).",
5347 getIdentifierCString());
5348 result
= kOSKextReturnDisabled
;
5352 result
= validateKextMapping(/* start? */ true);
5353 if (result
!= kOSReturnSuccess
) {
5357 startfunc
= kmod_info
->start
;
5359 count
= getNumDependencies();
5360 for (i
= 0; i
< count
; i
++) {
5361 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
5362 if (dependency
== NULL
) {
5364 kOSKextLogErrorLevel
|
5366 "Kext %s start - internal error, dependency disappeared.",
5367 getIdentifierCString());
5370 if (!dependency
->isStarted()) {
5371 if (startDependenciesFlag
) {
5372 OSReturn dependencyResult
=
5373 dependency
->start(startDependenciesFlag
);
5374 if (dependencyResult
!= KERN_SUCCESS
) {
5376 kOSKextLogErrorLevel
|
5378 "Kext %s start - dependency %s failed to start (error 0x%x).",
5379 getIdentifierCString(),
5380 dependency
->getIdentifierCString(),
5386 kOSKextLogErrorLevel
|
5388 "Not starting %s - dependency %s not started yet.",
5389 getIdentifierCString(),
5390 dependency
->getIdentifierCString());
5391 result
= kOSKextReturnStartStopError
; // xxx - make new return?
5397 #if CONFIG_MACF_KEXT
5398 /* See if the kext has any MAC framework module data in its plist.
5399 * This is passed in as arg #2 of the kext's start routine,
5400 * which is otherwise reserved for any other kext.
5402 kmodStartData
= MACFCopyModuleDataForKext(this, &kmodStartDataCount
);
5403 #endif /* CONFIG_MACF_KEXT */
5406 kOSKextLogDetailLevel
|
5408 "Kext %s calling module start function.",
5409 getIdentifierCString());
5413 #if !CONFIG_STATIC_CPPINIT
5414 result
= OSRuntimeInitializeCPP(kmod_info
, NULL
);
5415 if (result
== KERN_SUCCESS
) {
5418 result
= startfunc(kmod_info
, kmodStartData
);
5420 #if !CONFIG_STATIC_CPPINIT
5421 if (result
!= KERN_SUCCESS
) {
5422 (void) OSRuntimeFinalizeCPP(kmod_info
, NULL
);
5429 /* On success overlap the setting of started/starting. On failure just
5432 if (result
== KERN_SUCCESS
) {
5435 // xxx - log start error from kernel?
5437 kOSKextLogProgressLevel
|
5439 "Kext %s is now started.",
5440 getIdentifierCString());
5442 invokeOrCancelRequestCallbacks(
5443 /* result not actually used */ kOSKextReturnStartStopError
,
5444 /* invokeFlag */ false);
5446 kOSKextLogProgressLevel
|
5448 "Kext %s did not start (return code 0x%x).",
5449 getIdentifierCString(), result
);
5453 #if CONFIG_MACF_KEXT
5454 /* Free the module data for a MAC framework kext. When we start using
5455 * param #2 we'll have to distinguish and free/release appropriately.
5457 * xxx - I'm pretty sure the old codepath freed the data and that it's
5458 * xxx - up to the kext to copy it.
5460 if (kmodStartData
) {
5461 kmem_free(kernel_map
, (vm_offset_t
)kmodStartData
, kmodStartDataCount
);
5463 #endif /* CONFIG_MACF_KEXT */
5468 /*********************************************************************
5469 *********************************************************************/
5471 bool OSKext::canUnloadKextWithIdentifier(
5472 OSString
* kextIdentifier
,
5473 bool checkClassesFlag
)
5475 bool result
= false;
5476 OSKext
* aKext
= NULL
; // do not release
5478 IORecursiveLockLock(sKextLock
);
5480 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
5483 goto finish
; // can't unload what's not loaded
5486 if (aKext
->isLoaded()) {
5487 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
5490 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
5498 IORecursiveLockUnlock(sKextLock
);
5502 /*********************************************************************
5503 *********************************************************************/
5507 OSReturn result
= kOSReturnError
;
5508 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
5510 if (!isStarted() || isInterface()) {
5511 result
= kOSReturnSuccess
;
5517 kOSKextLogErrorLevel
|
5519 "Attempt to stop nonloaded kext %s.",
5520 getIdentifierCString());
5521 result
= kOSKextReturnInvalidArgument
;
5525 /* Refuse to stop if we have clients or instances. It is up to
5526 * the caller to make sure those aren't true.
5528 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5530 kOSKextLogErrorLevel
|
5532 "Kext %s - C++ instances; can't stop.",
5533 getIdentifierCString());
5534 result
= kOSKextReturnInUse
;
5538 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5541 kOSKextLogErrorLevel
|
5543 "Kext %s - has references (linkage or tracking object); "
5545 getIdentifierCString());
5546 result
= kOSKextReturnInUse
;
5550 /* Note: If validateKextMapping fails on the stop & unload path,
5551 * we are in serious trouble and a kernel panic is likely whether
5552 * we stop & unload the kext or not.
5554 result
= validateKextMapping(/* start? */ false);
5555 if (result
!= kOSReturnSuccess
) {
5559 stopfunc
= kmod_info
->stop
;
5562 kOSKextLogDetailLevel
|
5564 "Kext %s calling module stop function.",
5565 getIdentifierCString());
5569 result
= stopfunc(kmod_info
, /* userData */ NULL
);
5570 #if !CONFIG_STATIC_CPPINIT
5571 if (result
== KERN_SUCCESS
) {
5572 result
= OSRuntimeFinalizeCPP(kmod_info
, NULL
);
5578 if (result
== KERN_SUCCESS
) {
5582 kOSKextLogDetailLevel
|
5584 "Kext %s is now stopped and ready to unload.",
5585 getIdentifierCString());
5588 kOSKextLogErrorLevel
|
5590 "Kext %s did not stop (return code 0x%x).",
5591 getIdentifierCString(), result
);
5592 result
= kOSKextReturnStartStopError
;
5600 /*********************************************************************
5601 *********************************************************************/
5603 OSKext::unload(void)
5605 OSReturn result
= kOSReturnError
;
5607 uint32_t num_kmod_refs
= 0;
5609 if (!sUnloadEnabled
) {
5611 kOSKextLogErrorLevel
|
5613 "Kext unloading is disabled (%s).",
5614 this->getIdentifierCString());
5616 result
= kOSKextReturnDisabled
;
5620 /* Refuse to unload if we have clients or instances. It is up to
5621 * the caller to make sure those aren't true.
5623 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
5624 // xxx - Don't log under errors? this is more of an info thing
5626 kOSKextLogErrorLevel
|
5627 kOSKextLogKextBookkeepingFlag
,
5628 "Can't unload kext %s; outstanding references (linkage or tracking object).",
5629 getIdentifierCString());
5630 result
= kOSKextReturnInUse
;
5634 if (hasOSMetaClassInstances()) {
5636 kOSKextLogErrorLevel
|
5637 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5638 "Can't unload kext %s; classes have instances:",
5639 getIdentifierCString());
5640 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
5641 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
5642 result
= kOSKextReturnInUse
;
5647 result
= kOSReturnSuccess
;
5651 if (isKernelComponent()) {
5652 result
= kOSKextReturnInvalidArgument
;
5656 /* Note that the kext is unloading before running any code that
5657 * might be in the kext (request callbacks, module stop function).
5658 * We will deny certain requests made against a kext in the process
5661 flags
.unloading
= 1;
5663 /* Update the string describing the last kext to unload in case we panic.
5665 savePanicString(/* isLoading */ false);
5669 if (result
!= KERN_SUCCESS
) {
5671 kOSKextLogErrorLevel
|
5673 "Kext %s can't unload - module stop returned 0x%x.",
5674 getIdentifierCString(), (unsigned)result
);
5675 result
= kOSKextReturnStartStopError
;
5681 kOSKextLogProgressLevel
|
5683 "Kext %s unloading.",
5684 getIdentifierCString());
5686 /* Even if we don't call the stop function, we want to be sure we
5687 * have no OSMetaClass references before unloading the kext executable
5688 * from memory. OSMetaClasses may have pointers into the kext executable
5689 * and that would cause a panic on OSKext::free() when metaClasses is freed.
5692 metaClasses
->flushCollection();
5695 /* Remove the kext from the list of loaded kexts, patch the gap
5696 * in the kmod_info_t linked list, and reset "kmod" to point to the
5697 * last loaded kext that isn't the fake kernel kext (sKernelKext).
5699 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
5700 if (index
!= (unsigned int)-1) {
5702 sLoadedKexts
->removeObject(index
);
5704 OSKext
* nextKext
= OSDynamicCast(OSKext
,
5705 sLoadedKexts
->getObject(index
));
5709 OSKext
* gapKext
= OSDynamicCast(OSKext
,
5710 sLoadedKexts
->getObject(index
- 1));
5712 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
5714 } else /* index == 0 */ {
5715 nextKext
->kmod_info
->next
= NULL
;
5719 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5720 if (lastKext
&& !lastKext
->isKernel()) {
5721 kmod
= lastKext
->kmod_info
;
5723 kmod
= NULL
; // clear the global kmod variable
5727 /* Clear out the kmod references that we're keeping for compatibility
5728 * with current panic backtrace code & kgmacros.
5729 * xxx - will want to update those bits sometime and remove this.
5731 num_kmod_refs
= getNumDependencies();
5732 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
5733 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
5734 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
5735 ref
->info
->reference_count
--;
5737 kfree(kmod_info
->reference_list
,
5738 num_kmod_refs
* sizeof(kmod_reference_t
));
5742 unregisterWithDTrace();
5743 #endif /* CONFIG_DTRACE */
5745 notifyKextUnloadObservers(this);
5747 /* Unwire and free the linked executable.
5749 if (linkedExecutable
) {
5750 if (!isInterface()) {
5751 kernel_segment_command_t
*seg
= NULL
;
5752 vm_map_t kext_map
= kext_get_vm_map(kmod_info
);
5756 kOSKextLogErrorLevel
|
5758 "Failed to free kext %s; couldn't find the kext map.",
5759 getIdentifierCString());
5760 result
= kOSKextReturnInternalError
;
5765 kOSKextLogProgressLevel
|
5767 "Kext %s unwiring and unmapping linked executable.",
5768 getIdentifierCString());
5770 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
5772 if (segmentShouldBeWired(seg
)) {
5773 result
= vm_map_unwire(kext_map
, seg
->vmaddr
,
5774 seg
->vmaddr
+ seg
->vmsize
, FALSE
);
5775 if (result
!= KERN_SUCCESS
) {
5777 kOSKextLogErrorLevel
|
5779 "Failed to unwire kext %s.",
5780 getIdentifierCString());
5781 result
= kOSKextReturnInternalError
;
5786 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
5790 OSSafeReleaseNULL(linkedExecutable
);
5793 /* An interface kext has a fake kmod_info that was allocated,
5794 * so we have to free it.
5796 if (isInterface()) {
5797 kfree(kmod_info
, sizeof(kmod_info_t
));
5802 flags
.loaded
= false;
5803 flushDependencies();
5805 /* save a copy of the bundle ID for us to check when deciding to
5806 * rebuild the kernel cache file. If a kext was already in the kernel
5807 * cache and unloaded then later loaded we do not need to rebuild the
5808 * kernel cache. 9055303
5810 if (isPrelinked()) {
5811 sUnloadedPrelinkedKexts
->setObject(bundleID
);
5815 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5816 "Kext %s unloaded.", getIdentifierCString());
5818 queueKextNotification(kKextRequestPredicateUnloadNotification
,
5819 OSDynamicCast(OSString
, bundleID
));
5822 OSKext::saveLoadedKextPanicList();
5823 OSKext::updateLoadedKextSummaries();
5825 flags
.unloading
= 0;
5829 /*********************************************************************
5830 * Assumes sKextLock is held.
5831 *********************************************************************/
5834 OSKext::queueKextNotification(
5835 const char * notificationName
,
5836 OSString
* kextIdentifier
)
5838 OSReturn result
= kOSReturnError
;
5839 OSDictionary
* loadRequest
= NULL
; // must release
5841 if (!kextIdentifier
) {
5842 result
= kOSKextReturnInvalidArgument
;
5846 /* Create a new request unless one is already sitting
5847 * in sKernelRequests for this bundle identifier
5849 result
= _OSKextCreateRequest(notificationName
, &loadRequest
);
5850 if (result
!= kOSReturnSuccess
) {
5853 if (!_OSKextSetRequestArgument(loadRequest
,
5854 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
5856 result
= kOSKextReturnNoMemory
;
5859 if (!sKernelRequests
->setObject(loadRequest
)) {
5860 result
= kOSKextReturnNoMemory
;
5864 /* We might want to only queue the notification if kextd is active,
5865 * but that wouldn't work for embedded. Note that we don't care if
5866 * the ping immediately succeeds here so don't do anything with the
5867 * result of this call.
5869 OSKext::pingKextd();
5871 result
= kOSReturnSuccess
;
5874 OSSafeRelease(loadRequest
);
5879 /*********************************************************************
5880 *********************************************************************/
5882 _OSKextConsiderDestroyingLinkContext(
5883 __unused thread_call_param_t p0
,
5884 __unused thread_call_param_t p1
)
5886 /* Take multiple locks in the correct order.
5888 IORecursiveLockLock(sKextLock
);
5889 IORecursiveLockLock(sKextInnerLock
);
5891 /* The first time we destroy the kxldContext is in the first
5892 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
5893 * before calling this function. Thereafter any call to this function
5894 * will actually destroy the context.
5896 if (sConsiderUnloadsCalled
&& sKxldContext
) {
5897 kxld_destroy_context(sKxldContext
);
5898 sKxldContext
= NULL
;
5901 /* Free the thread_call that was allocated to execute this function.
5903 if (sDestroyLinkContextThread
) {
5904 if (!thread_call_free(sDestroyLinkContextThread
)) {
5905 OSKextLog(/* kext */ NULL
,
5906 kOSKextLogErrorLevel
|
5907 kOSKextLogGeneralFlag
,
5908 "thread_call_free() failed for kext link context.");
5910 sDestroyLinkContextThread
= 0;
5913 IORecursiveLockUnlock(sKextInnerLock
);
5914 IORecursiveLockUnlock(sKextLock
);
5919 /*********************************************************************
5920 * Destroying the kxldContext requires checking variables under both
5921 * sKextInnerLock and sKextLock, so we do it on a separate thread
5922 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
5923 * call relationship.
5925 * This function must be invoked with sKextInnerLock held.
5926 * Do not call any function that takes sKextLock here!
5927 *********************************************************************/
5930 OSKext::considerDestroyingLinkContext(void)
5932 IORecursiveLockLock(sKextInnerLock
);
5934 /* If we have already queued a thread to destroy the link context,
5935 * don't bother resetting; that thread will take care of it.
5937 if (sDestroyLinkContextThread
) {
5941 /* The function to be invoked in the thread will deallocate
5942 * this thread_call, so don't share it around.
5944 sDestroyLinkContextThread
= thread_call_allocate(
5945 &_OSKextConsiderDestroyingLinkContext
, 0);
5946 if (!sDestroyLinkContextThread
) {
5947 OSKextLog(/* kext */ NULL
,
5948 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
5949 "Can't create thread to destroy kext link context.");
5953 thread_call_enter(sDestroyLinkContextThread
);
5956 IORecursiveLockUnlock(sKextInnerLock
);
5961 #pragma mark Autounload
5963 /*********************************************************************
5964 * This is a static method because the kext will be deallocated if it
5966 *********************************************************************/
5969 OSKext::autounloadKext(OSKext
* aKext
)
5971 OSReturn result
= kOSKextReturnInUse
;
5973 /* Check for external references to this kext (usu. dependents),
5974 * instances of defined classes (or classes derived from them),
5975 * outstanding requests.
5977 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
5978 !aKext
->flags
.autounloadEnabled
||
5979 aKext
->isKernelComponent()) {
5984 /* Skip a delay-autounload kext, once.
5986 if (aKext
->flags
.delayAutounload
) {
5988 kOSKextLogProgressLevel
|
5989 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5990 "Kext %s has delayed autounload set; skipping and clearing flag.",
5991 aKext
->getIdentifierCString());
5992 aKext
->flags
.delayAutounload
= 0;
5996 if (aKext
->hasOSMetaClassInstances() ||
5997 aKext
->countRequestCallbacks()) {
6001 result
= OSKext::removeKext(aKext
);
6008 /*********************************************************************
6009 *********************************************************************/
6011 _OSKextConsiderUnloads(
6012 __unused thread_call_param_t p0
,
6013 __unused thread_call_param_t p1
)
6015 bool didUnload
= false;
6016 unsigned int count
, i
;
6018 /* Take multiple locks in the correct order
6019 * (note also sKextSummaries lock further down).
6021 IORecursiveLockLock(sKextLock
);
6022 IORecursiveLockLock(sKextInnerLock
);
6024 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
6026 IOLockLock(sKextSummariesLock
);
6028 /* If there is an old kext summary, free that now.
6030 if (sPrevLoadedKextSummaries
) {
6031 kmem_free(kernel_map
, (vm_offset_t
)sPrevLoadedKextSummaries
,
6032 sPrevLoadedKextSummariesAllocSize
);
6033 sPrevLoadedKextSummaries
= NULL
;
6034 sPrevLoadedKextSummariesAllocSize
= 0;
6037 IOLockUnlock(sKextSummariesLock
);
6039 /* If the system is powering down, don't try to unload anything.
6045 OSKextLog(/* kext */ NULL
,
6046 kOSKextLogProgressLevel
|
6048 "Checking for unused kexts to autounload.");
6051 * Remove any request callbacks marked as stale,
6052 * and mark as stale any currently in flight.
6054 count
= sRequestCallbackRecords
->getCount();
6058 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
6059 sRequestCallbackRecords
->getObject(i
));
6060 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
6061 callbackRecord
->getObject(kKextRequestStaleKey
));
6063 if (stale
== kOSBooleanTrue
) {
6064 OSKext::invokeRequestCallback(callbackRecord
,
6065 kOSKextReturnTimeout
);
6067 callbackRecord
->setObject(kKextRequestStaleKey
,
6074 * Make multiple passes through the array of loaded kexts until
6075 * we don't unload any. This handles unwinding of dependency
6076 * chains. We have to go *backwards* through the array because
6077 * kexts are removed from it when unloaded, and we cannot make
6078 * a copy or we'll mess up the retain counts we rely on to
6079 * check whether a kext will unload. If only we could have
6080 * nonretaining collections like CF has....
6085 count
= sLoadedKexts
->getCount();
6089 OSKext
* thisKext
= OSDynamicCast(OSKext
,
6090 sLoadedKexts
->getObject(i
));
6091 didUnload
= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
6094 } while (didUnload
);
6097 sConsiderUnloadsPending
= false;
6098 sConsiderUnloadsExecuted
= true;
6100 (void) OSKext::considerRebuildOfPrelinkedKernel(NULL
);
6102 IORecursiveLockUnlock(sKextInnerLock
);
6103 IORecursiveLockUnlock(sKextLock
);
6108 /*********************************************************************
6109 * Do not call any function that takes sKextLock here!
6110 *********************************************************************/
6111 void OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
6115 IORecursiveLockLock(sKextInnerLock
);
6117 if (!sUnloadCallout
) {
6118 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, 0);
6121 /* we only reset delay value for unloading if we already have something
6122 * pending. rescheduleOnlyFlag should not start the count down.
6124 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
6128 thread_call_cancel(sUnloadCallout
);
6129 if (OSKext::getAutounloadEnabled() && !sSystemSleep
) {
6130 clock_interval_to_deadline(sConsiderUnloadDelay
,
6131 1000 * 1000 * 1000, &when
);
6133 OSKextLog(/* kext */ NULL
,
6134 kOSKextLogProgressLevel
|
6136 "%scheduling %sscan for unused kexts in %lu seconds.",
6137 sConsiderUnloadsPending
? "Res" : "S",
6138 sConsiderUnloadsCalled
? "" : "initial ",
6139 (unsigned long)sConsiderUnloadDelay
);
6141 sConsiderUnloadsPending
= true;
6142 thread_call_enter_delayed(sUnloadCallout
, when
);
6146 /* The kxld context should be reused throughout boot. We mark the end of
6147 * period as the first time considerUnloads() is called, and we destroy
6148 * the first kxld context in that function. Afterwards, it will be
6149 * destroyed in flushNonloadedKexts.
6151 if (!sConsiderUnloadsCalled
) {
6152 sConsiderUnloadsCalled
= true;
6153 OSKext::considerDestroyingLinkContext();
6156 IORecursiveLockUnlock(sKextInnerLock
);
6160 /*********************************************************************
6161 * Do not call any function that takes sKextLock here!
6162 *********************************************************************/
6165 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
)
6167 IORecursiveLockLock(sKextInnerLock
);
6169 /* If the system is going to sleep, cancel the reaper thread timer,
6170 * and note that we're in a sleep state in case it just fired but hasn't
6171 * taken the lock yet. If we are coming back from sleep, just
6172 * clear the sleep flag; IOService's normal operation will cause
6173 * unloads to be considered soon enough.
6175 if (messageType
== kIOMessageSystemWillSleep
) {
6176 if (sUnloadCallout
) {
6177 thread_call_cancel(sUnloadCallout
);
6179 sSystemSleep
= true;
6180 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
6181 sSystemSleep
= false;
6183 IORecursiveLockUnlock(sKextInnerLock
);
6185 return kIOReturnSuccess
;
6192 #pragma mark Prelinked Kernel
6194 /*********************************************************************
6195 * Do not access sConsiderUnloads... variables other than
6196 * sConsiderUnloadsExecuted in this function. They are guarded by a
6198 *********************************************************************/
6201 OSKext::considerRebuildOfPrelinkedKernel(OSString
* moduleName
)
6203 OSReturn checkResult
= kOSReturnError
;
6204 static bool requestedPrelink
= false;
6205 OSDictionary
* prelinkRequest
= NULL
; // must release
6207 IORecursiveLockLock(sKextLock
);
6209 /* moduleName is only passed when we see a load come in. We are only
6210 * interested in rebuilding the kernel cache if the kext we are loading
6211 * is not already in the original kernel cache. 9055303
6214 int count
= sUnloadedPrelinkedKexts
->getCount();
6217 for (i
= 0; i
< count
; i
++) {
6218 const OSSymbol
* myBundleID
; // do not release
6220 myBundleID
= OSDynamicCast(OSSymbol
, sUnloadedPrelinkedKexts
->getObject(i
));
6221 if (!myBundleID
) continue;
6222 if (moduleName
->isEqualTo(myBundleID
->getCStringNoCopy())) {
6223 OSKextLog(/* kext */ NULL
,
6224 kOSKextLogDetailLevel
|
6225 kOSKextLogArchiveFlag
,
6226 "bundleID %s already in cache skipping rebuild.",
6227 myBundleID
->getCStringNoCopy());
6229 /* no need to rebuild, already in kernel cache */
6233 (void) OSKext::setDeferredLoadSucceeded();
6236 if (!sDeferredLoadSucceeded
|| !sConsiderUnloadsExecuted
||
6237 sSafeBoot
|| requestedPrelink
)
6242 OSKextLog(/* kext */ NULL
,
6243 kOSKextLogProgressLevel
|
6244 kOSKextLogArchiveFlag
,
6245 "Requesting build of prelinked kernel.");
6247 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
6249 if (checkResult
!= kOSReturnSuccess
) {
6253 if (!sKernelRequests
->setObject(prelinkRequest
)) {
6257 OSKext::pingKextd();
6258 requestedPrelink
= true;
6261 IORecursiveLockUnlock(sKextLock
);
6262 OSSafeRelease(prelinkRequest
);
6267 #pragma mark Dependencies
6269 /*********************************************************************
6270 *********************************************************************/
6272 OSKext::resolveDependencies(
6273 OSArray
* loopStack
)
6275 bool result
= false;
6276 OSArray
* localLoopStack
= NULL
; // must release
6277 bool addedToLoopStack
= false;
6278 OSDictionary
* libraries
= NULL
; // do not release
6279 OSCollectionIterator
* libraryIterator
= NULL
; // must release
6280 OSString
* libraryID
= NULL
; // do not release
6281 OSString
* infoString
= NULL
; // do not release
6282 OSString
* readableString
= NULL
; // do not release
6283 OSKext
* libraryKext
= NULL
; // do not release
6284 bool hasRawKernelDependency
= false;
6285 bool hasKernelDependency
= false;
6286 bool hasKPIDependency
= false;
6287 bool hasPrivateKPIDependency
= false;
6290 /* A kernel component will automatically have this flag set,
6291 * and a loaded kext should also have it set (as should all its
6292 * loaded dependencies).
6294 if (flags
.hasAllDependencies
) {
6299 /* Check for loops in the dependency graph.
6302 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
6304 kOSKextLogErrorLevel
|
6305 kOSKextLogDependenciesFlag
,
6306 "Kext %s has a dependency loop; can't resolve dependencies.",
6307 getIdentifierCString());
6312 kOSKextLogStepLevel
|
6313 kOSKextLogDependenciesFlag
,
6314 "Kext %s resolving dependencies.",
6315 getIdentifierCString());
6317 loopStack
= OSArray::withCapacity(6); // any small capacity will do
6320 kOSKextLogErrorLevel
|
6321 kOSKextLogDependenciesFlag
,
6322 "Kext %s can't create bookkeeping stack to resolve dependencies.",
6323 getIdentifierCString());
6326 localLoopStack
= loopStack
;
6328 if (!loopStack
->setObject(this)) {
6330 kOSKextLogErrorLevel
|
6331 kOSKextLogDependenciesFlag
,
6332 "Kext %s - internal error resolving dependencies.",
6333 getIdentifierCString());
6336 addedToLoopStack
= true;
6338 /* Purge any existing kexts in the dependency list and start over.
6340 flushDependencies();
6343 kOSKextLogErrorLevel
|
6344 kOSKextLogDependenciesFlag
,
6345 "Kext %s - internal error resolving dependencies.",
6346 getIdentifierCString());
6349 libraries
= OSDynamicCast(OSDictionary
,
6350 getPropertyForHostArch(kOSBundleLibrariesKey
));
6351 if (libraries
== NULL
|| libraries
->getCount() == 0) {
6353 kOSKextLogErrorLevel
|
6354 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6355 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
6356 getIdentifierCString(), kOSBundleLibrariesKey
);
6360 /* Make a new array to hold the dependencies (flush freed the old one).
6362 dependencies
= OSArray::withCapacity(libraries
->getCount());
6363 if (!dependencies
) {
6365 kOSKextLogErrorLevel
|
6366 kOSKextLogDependenciesFlag
,
6367 "Kext %s - can't allocate dependencies array.",
6368 getIdentifierCString());
6372 // xxx - compat: We used to add an implicit dependency on kernel 6.0
6373 // xxx - compat: if none were declared.
6375 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
6376 if (!libraryIterator
) {
6378 kOSKextLogErrorLevel
|
6379 kOSKextLogDependenciesFlag
,
6380 "Kext %s - can't allocate dependencies iterator.",
6381 getIdentifierCString());
6385 while ((libraryID
= OSDynamicCast(OSString
,
6386 libraryIterator
->getNextObject()))) {
6388 const char * library_id
= libraryID
->getCStringNoCopy();
6390 OSString
* libraryVersion
= OSDynamicCast(OSString
,
6391 libraries
->getObject(libraryID
));
6392 if (libraryVersion
== NULL
) {
6394 kOSKextLogErrorLevel
|
6395 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6396 "Kext %s - illegal type in OSBundleLibraries.",
6397 getIdentifierCString());
6401 OSKextVersion libraryVers
=
6402 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
6403 if (libraryVers
== -1) {
6405 kOSKextLogErrorLevel
|
6406 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6407 "Kext %s - invalid library version %s.",
6408 getIdentifierCString(),
6409 libraryVersion
->getCStringNoCopy());
6413 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
6414 if (libraryKext
== NULL
) {
6416 kOSKextLogErrorLevel
|
6417 kOSKextLogDependenciesFlag
,
6418 "Kext %s - library kext %s not found.",
6419 getIdentifierCString(), library_id
);
6423 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
6425 kOSKextLogErrorLevel
|
6426 kOSKextLogDependenciesFlag
,
6427 "Kext %s - library kext %s not compatible "
6428 "with requested version %s.",
6429 getIdentifierCString(), library_id
,
6430 libraryVersion
->getCStringNoCopy());
6434 /* If a nonprelinked library somehow got into the mix for a
6435 * prelinked kext, at any point in the chain, we must fail
6436 * because the prelinked relocs for the library will be all wrong.
6438 if (this->isPrelinked() &&
6439 libraryKext
->declaresExecutable() &&
6440 !libraryKext
->isPrelinked()) {
6443 kOSKextLogErrorLevel
|
6444 kOSKextLogDependenciesFlag
,
6445 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
6446 getIdentifierCString(), library_id
,
6447 libraryVersion
->getCStringNoCopy());
6451 if (!libraryKext
->resolveDependencies(loopStack
)) {
6455 /* Add the library directly only if it has an executable to link.
6456 * Otherwise it's just used to collect other dependencies, so put
6457 * *its* dependencies on the list for this kext.
6459 // xxx - We are losing info here; would like to make fake entries or
6460 // xxx - keep these in the dependency graph for loaded kexts.
6461 // xxx - I really want to make kernel components not a special case!
6462 if (libraryKext
->declaresExecutable() ||
6463 libraryKext
->isInterface()) {
6465 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
6466 dependencies
->setObject(libraryKext
);
6469 kOSKextLogDetailLevel
|
6470 kOSKextLogDependenciesFlag
,
6471 "Kext %s added dependency %s.",
6472 getIdentifierCString(),
6473 libraryKext
->getIdentifierCString());
6476 int numLibDependencies
= libraryKext
->getNumDependencies();
6477 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
6480 if (numLibDependencies
) {
6481 // xxx - this msg level should be 1 lower than the per-kext one
6483 kOSKextLogDetailLevel
|
6484 kOSKextLogDependenciesFlag
,
6485 "Kext %s pulling %d dependencies from codeless library %s.",
6486 getIdentifierCString(),
6488 libraryKext
->getIdentifierCString());
6490 for (index
= 0; index
< numLibDependencies
; index
++) {
6491 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
6492 libraryDependencies
->getObject(index
));
6493 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
6494 dependencies
->setObject(thisLibDependency
);
6496 kOSKextLogDetailLevel
|
6497 kOSKextLogDependenciesFlag
,
6498 "Kext %s added dependency %s from codeless library %s.",
6499 getIdentifierCString(),
6500 thisLibDependency
->getIdentifierCString(),
6501 libraryKext
->getIdentifierCString());
6506 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
6507 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
)-1)) {
6509 hasRawKernelDependency
= true;
6510 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
6511 hasKernelDependency
= true;
6512 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
6513 hasKPIDependency
= true;
6514 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
)-1)) {
6515 hasPrivateKPIDependency
= true;
6520 if (hasRawKernelDependency
) {
6522 kOSKextLogErrorLevel
|
6523 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6524 "Error - kext %s declares a dependency on %s, which is not permitted.",
6525 getIdentifierCString(), KERNEL_LIB
);
6529 if (hasKernelDependency
) {
6531 kOSKextLogErrorLevel
|
6532 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
6533 "Error - kext %s declares %s dependencies. "
6534 "Only %s* dependencies are supported for 64-bit kexts.",
6535 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
6538 if (!hasKPIDependency
) {
6540 kOSKextLogWarningLevel
|
6541 kOSKextLogDependenciesFlag
,
6542 "Warning - kext %s declares no %s* dependencies. "
6543 "If it uses any KPIs, the link may fail with undefined symbols.",
6544 getIdentifierCString(), KPI_LIB_PREFIX
);
6546 #else /* __LP64__ */
6547 // xxx - will change to flatly disallow "kernel" dependencies at some point
6548 // xxx - is it invalid to do both "com.apple.kernel" and any
6549 // xxx - "com.apple.kernel.*"?
6551 if (hasKernelDependency
&& hasKPIDependency
) {
6553 kOSKextLogWarningLevel
|
6554 kOSKextLogDependenciesFlag
,
6555 "Warning - kext %s has immediate dependencies on both "
6556 "%s* and %s* components; use only one style.",
6557 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
6560 if (!hasKernelDependency
&& !hasKPIDependency
) {
6561 // xxx - do we want to use validation flag for these too?
6563 kOSKextLogWarningLevel
|
6564 kOSKextLogDependenciesFlag
,
6565 "Warning - %s declares no kernel dependencies; using %s.",
6566 getIdentifierCString(), KERNEL6_LIB
);
6567 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
6568 sKextsByID
->getObject(KERNEL6_LIB
));
6570 dependencies
->setObject(kernelKext
);
6573 kOSKextLogErrorLevel
|
6574 kOSKextLogDependenciesFlag
,
6575 "Error - Library %s not found for %s.",
6576 KERNEL6_LIB
, getIdentifierCString());
6580 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
6581 * its indirect dependencies to simulate old-style linking. XXX - Should
6582 * check for duplicates.
6584 if (!hasKPIDependency
) {
6587 flags
.hasBleedthrough
= true;
6589 count
= getNumDependencies();
6591 /* We add to the dependencies array in this loop, but do not iterate
6592 * past its original count.
6594 for (i
= 0; i
< count
; i
++) {
6595 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
6596 dependencies
->getObject(i
));
6597 dependencyKext
->addBleedthroughDependencies(dependencies
);
6600 #endif /* __LP64__ */
6602 if (hasPrivateKPIDependency
) {
6603 bool hasApplePrefix
= false;
6604 bool infoCopyrightIsValid
= false;
6605 bool readableCopyrightIsValid
= false;
6607 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
6610 infoString
= OSDynamicCast(OSString
,
6611 getPropertyForHostArch("CFBundleGetInfoString"));
6613 infoCopyrightIsValid
=
6614 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
6617 readableString
= OSDynamicCast(OSString
,
6618 getPropertyForHostArch("NSHumanReadableCopyright"));
6619 if (readableString
) {
6620 readableCopyrightIsValid
=
6621 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
6624 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
6626 kOSKextLogErrorLevel
|
6627 kOSKextLogDependenciesFlag
,
6628 "Error - kext %s declares a dependency on %s. "
6629 "Only Apple kexts may declare a dependency on %s.",
6630 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
6636 flags
.hasAllDependencies
= 1;
6640 if (addedToLoopStack
) {
6641 count
= loopStack
->getCount();
6642 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
6643 loopStack
->removeObject(count
- 1);
6646 kOSKextLogErrorLevel
|
6647 kOSKextLogDependenciesFlag
,
6648 "Kext %s - internal error resolving dependencies.",
6649 getIdentifierCString());
6653 if (result
&& localLoopStack
) {
6655 kOSKextLogStepLevel
|
6656 kOSKextLogDependenciesFlag
,
6657 "Kext %s successfully resolved dependencies.",
6658 getIdentifierCString());
6661 OSSafeRelease(localLoopStack
);
6662 OSSafeRelease(libraryIterator
);
6667 /*********************************************************************
6668 *********************************************************************/
6670 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
6672 bool result
= false;
6673 unsigned int dependencyIndex
, dependencyCount
;
6675 dependencyCount
= getNumDependencies();
6677 for (dependencyIndex
= 0;
6678 dependencyIndex
< dependencyCount
;
6679 dependencyIndex
++) {
6681 OSKext
* dependency
= OSDynamicCast(OSKext
,
6682 dependencies
->getObject(dependencyIndex
));
6685 kOSKextLogErrorLevel
|
6686 kOSKextLogDependenciesFlag
,
6687 "Kext %s - internal error propagating compatibility dependencies.",
6688 getIdentifierCString());
6691 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
6692 anArray
->setObject(dependency
);
6694 dependency
->addBleedthroughDependencies(anArray
);
6703 /*********************************************************************
6704 *********************************************************************/
6706 OSKext::flushDependencies(bool forceFlag
)
6708 bool result
= false;
6710 /* Only clear the dependencies if the kext isn't loaded;
6711 * we need the info for loaded kexts to track references.
6713 if (!isLoaded() || forceFlag
) {
6715 // xxx - check level
6717 kOSKextLogProgressLevel
|
6718 kOSKextLogDependenciesFlag
,
6719 "Kext %s flushing dependencies.",
6720 getIdentifierCString());
6721 OSSafeReleaseNULL(dependencies
);
6724 if (!isKernelComponent()) {
6725 flags
.hasAllDependencies
= 0;
6733 /*********************************************************************
6734 *********************************************************************/
6736 OSKext::getNumDependencies(void)
6738 if (!dependencies
) {
6741 return dependencies
->getCount();
6744 /*********************************************************************
6745 *********************************************************************/
6747 OSKext::getDependencies(void)
6749 return dependencies
;
6753 #pragma mark OSMetaClass Support
6755 /*********************************************************************
6756 *********************************************************************/
6759 OSMetaClass
* aClass
,
6760 uint32_t numClasses
)
6762 OSReturn result
= kOSMetaClassNoInsKModSet
;
6765 metaClasses
= OSSet::withCapacity(numClasses
);
6771 if (metaClasses
->containsObject(aClass
)) {
6773 kOSKextLogWarningLevel
|
6775 "Notice - kext %s has already registered class %s.",
6776 getIdentifierCString(),
6777 aClass
->getClassName());
6778 result
= kOSReturnSuccess
;
6782 if (!metaClasses
->setObject(aClass
)) {
6786 kOSKextLogDetailLevel
|
6788 "Kext %s registered class %s.",
6789 getIdentifierCString(),
6790 aClass
->getClassName());
6793 if (!flags
.autounloadEnabled
) {
6794 const OSMetaClass
* metaScan
= NULL
; // do not release
6796 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
6797 if (metaScan
== OSTypeID(IOService
)) {
6800 kOSKextLogProgressLevel
|
6802 "Kext %s has IOService subclass %s; enabling autounload.",
6803 getIdentifierCString(),
6804 aClass
->getClassName());
6806 flags
.autounloadEnabled
= 1;
6812 notifyAddClassObservers(this, aClass
, flags
);
6814 result
= kOSReturnSuccess
;
6817 if (result
!= kOSReturnSuccess
) {
6819 kOSKextLogErrorLevel
|
6821 "Kext %s failed to register class %s.",
6822 getIdentifierCString(),
6823 aClass
->getClassName());
6829 /*********************************************************************
6830 *********************************************************************/
6832 OSKext::removeClass(
6833 OSMetaClass
* aClass
)
6835 OSReturn result
= kOSMetaClassNoKModSet
;
6841 if (!metaClasses
->containsObject(aClass
)) {
6843 kOSKextLogWarningLevel
|
6845 "Notice - kext %s asked to unregister unknown class %s.",
6846 getIdentifierCString(),
6847 aClass
->getClassName());
6848 result
= kOSReturnSuccess
;
6853 kOSKextLogDetailLevel
|
6855 "Kext %s unregistering class %s.",
6856 getIdentifierCString(),
6857 aClass
->getClassName());
6859 metaClasses
->removeObject(aClass
);
6861 notifyRemoveClassObservers(this, aClass
, flags
);
6863 result
= kOSReturnSuccess
;
6866 if (result
!= kOSReturnSuccess
) {
6868 kOSKextLogErrorLevel
|
6870 "Failed to unregister kext %s class %s.",
6871 getIdentifierCString(),
6872 aClass
->getClassName());
6877 /*********************************************************************
6878 *********************************************************************/
6880 OSKext::getMetaClasses(void)
6885 /*********************************************************************
6886 *********************************************************************/
6888 OSKext::hasOSMetaClassInstances(void)
6890 bool result
= false;
6891 OSCollectionIterator
* classIterator
= NULL
; // must release
6892 OSMetaClass
* checkClass
= NULL
; // do not release
6898 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6899 if (!classIterator
) {
6900 // xxx - log alloc failure?
6903 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6904 if (checkClass
->getInstanceCount()) {
6912 OSSafeRelease(classIterator
);
6916 /*********************************************************************
6917 *********************************************************************/
6920 OSKext::reportOSMetaClassInstances(
6921 const char * kextIdentifier
,
6922 OSKextLogSpec msgLogSpec
)
6924 OSKext
* theKext
= NULL
; // must release
6926 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
6931 theKext
->reportOSMetaClassInstances(msgLogSpec
);
6933 OSSafeRelease(theKext
);
6937 /*********************************************************************
6938 *********************************************************************/
6940 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
6942 OSCollectionIterator
* classIterator
= NULL
; // must release
6943 OSMetaClass
* checkClass
= NULL
; // do not release
6949 classIterator
= OSCollectionIterator::withCollection(metaClasses
);
6950 if (!classIterator
) {
6953 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
6954 if (checkClass
->getInstanceCount()) {
6957 " Kext %s class %s has %d instance%s.",
6958 getIdentifierCString(),
6959 checkClass
->getClassName(),
6960 checkClass
->getInstanceCount(),
6961 checkClass
->getInstanceCount() == 1 ? "" : "s");
6966 OSSafeRelease(classIterator
);
6971 #pragma mark User-Space Requests
6973 /*********************************************************************
6974 * XXX - this function is a big ugly mess
6975 *********************************************************************/
6978 OSKext::handleRequest(
6979 host_priv_t hostPriv
,
6980 OSKextLogSpec clientLogFilter
,
6981 char * requestBuffer
,
6982 uint32_t requestLength
,
6983 char ** responseOut
,
6984 uint32_t * responseLengthOut
,
6986 uint32_t * logInfoLengthOut
)
6988 OSReturn result
= kOSReturnError
;
6989 kern_return_t kmem_result
= KERN_FAILURE
;
6991 char * response
= NULL
; // returned by reference
6992 uint32_t responseLength
= 0;
6994 OSObject
* parsedXML
= NULL
; // must release
6995 OSDictionary
* requestDict
= NULL
; // do not release
6996 OSString
* errorString
= NULL
; // must release
6998 OSData
* responseData
= NULL
; // must release
6999 OSObject
* responseObject
= NULL
; // must release
7001 OSSerialize
* serializer
= NULL
; // must release
7003 OSArray
* logInfoArray
= NULL
; // must release
7005 OSString
* predicate
= NULL
; // do not release
7006 OSString
* kextIdentifier
= NULL
; // do not release
7007 OSArray
* kextIdentifiers
= NULL
; // do not release
7008 OSKext
* theKext
= NULL
; // do not release
7009 OSBoolean
* boolArg
= NULL
; // do not release
7011 IORecursiveLockLock(sKextLock
);
7014 *responseOut
= NULL
;
7015 *responseLengthOut
= 0;
7019 *logInfoLengthOut
= 0;
7022 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
7024 /* XML must be nul-terminated.
7026 if (requestBuffer
[requestLength
- 1] != '\0') {
7027 OSKextLog(/* kext */ NULL
,
7028 kOSKextLogErrorLevel
|
7030 "Invalid request from user space (not nul-terminated).");
7031 result
= kOSKextReturnBadData
;
7034 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, &errorString
);
7036 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
);
7039 const char * errorCString
= "(unknown error)";
7041 if (errorString
&& errorString
->getCStringNoCopy()) {
7042 errorCString
= errorString
->getCStringNoCopy();
7043 } else if (parsedXML
) {
7044 errorCString
= "not a dictionary";
7046 OSKextLog(/* kext */ NULL
,
7047 kOSKextLogErrorLevel
|
7049 "Error unserializing request from user space: %s.",
7051 result
= kOSKextReturnSerialization
;
7055 predicate
= _OSKextGetRequestPredicate(requestDict
);
7057 OSKextLog(/* kext */ NULL
,
7058 kOSKextLogErrorLevel
|
7060 "Recieved kext request from user space with no predicate.");
7061 result
= kOSKextReturnInvalidArgument
;
7065 OSKextLog(/* kext */ NULL
,
7066 kOSKextLogDebugLevel
|
7068 "Received '%s' request from user space.",
7069 predicate
->getCStringNoCopy());
7071 result
= kOSKextReturnNotPrivileged
;
7072 if (hostPriv
== HOST_PRIV_NULL
) {
7073 if (!predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) &&
7074 !predicate
->isEqualTo(kKextRequestPredicateGetKernelImage
) &&
7075 !predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
7081 /* Get common args in anticipation of use.
7083 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
7084 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
7085 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
7086 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
7087 if (kextIdentifier
) {
7088 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
7090 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
7091 requestDict
, kKextRequestArgumentValueKey
));
7093 result
= kOSKextReturnInvalidArgument
;
7095 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
7096 if (!kextIdentifier
) {
7097 OSKextLog(/* kext */ NULL
,
7098 kOSKextLogErrorLevel
|
7100 "Invalid arguments to kext start request.");
7101 } else if (!theKext
) {
7102 OSKextLog(/* kext */ NULL
,
7103 kOSKextLogErrorLevel
|
7105 "Kext %s not found for start request.",
7106 kextIdentifier
->getCStringNoCopy());
7107 result
= kOSKextReturnNotFound
;
7109 result
= theKext
->start();
7112 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
7113 if (!kextIdentifier
) {
7114 OSKextLog(/* kext */ NULL
,
7115 kOSKextLogErrorLevel
|
7117 "Invalid arguments to kext stop request.");
7118 } else if (!theKext
) {
7119 OSKextLog(/* kext */ NULL
,
7120 kOSKextLogErrorLevel
|
7122 "Kext %s not found for stop request.",
7123 kextIdentifier
->getCStringNoCopy());
7124 result
= kOSKextReturnNotFound
;
7126 result
= theKext
->stop();
7129 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
7130 if (!kextIdentifier
) {
7131 OSKextLog(/* kext */ NULL
,
7132 kOSKextLogErrorLevel
|
7134 "Invalid arguments to kext unload request.");
7135 } else if (!theKext
) {
7136 OSKextLog(/* kext */ NULL
,
7137 kOSKextLogErrorLevel
|
7139 "Kext %s not found for unload request.",
7140 kextIdentifier
->getCStringNoCopy());
7141 result
= kOSKextReturnNotFound
;
7143 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
7144 _OSKextGetRequestArgument(requestDict
,
7145 kKextRequestArgumentTerminateIOServicesKey
));
7146 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
7149 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
7150 result
= OSKext::dispatchResource(requestDict
);
7152 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
7153 OSBoolean
* delayAutounloadBool
= NULL
;
7154 OSObject
* infoKeysRaw
= NULL
;
7155 OSArray
* infoKeys
= NULL
;
7156 uint32_t infoKeysCount
= 0;
7158 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
7159 _OSKextGetRequestArgument(requestDict
,
7160 kKextRequestArgumentDelayAutounloadKey
));
7162 /* If asked to delay autounload, reset the timer if it's currently set.
7163 * (That is, don't schedule an unload if one isn't already pending.
7165 if (delayAutounloadBool
== kOSBooleanTrue
) {
7166 OSKext::considerUnloads(/* rescheduleOnly? */ true);
7169 infoKeysRaw
= _OSKextGetRequestArgument(requestDict
,
7170 kKextRequestArgumentInfoKeysKey
);
7171 infoKeys
= OSDynamicCast(OSArray
, infoKeysRaw
);
7172 if (infoKeysRaw
&& !infoKeys
) {
7173 OSKextLog(/* kext */ NULL
,
7174 kOSKextLogErrorLevel
|
7176 "Invalid arguments to kext info request.");
7181 infoKeysCount
= infoKeys
->getCount();
7182 for (uint32_t i
= 0; i
< infoKeysCount
; i
++) {
7183 if (!OSDynamicCast(OSString
, infoKeys
->getObject(i
))) {
7184 OSKextLog(/* kext */ NULL
,
7185 kOSKextLogErrorLevel
|
7187 "Invalid arguments to kext info request.");
7193 responseObject
= OSKext::copyLoadedKextInfo(kextIdentifiers
, infoKeys
);
7194 if (!responseObject
) {
7195 result
= kOSKextReturnInternalError
;
7197 OSKextLog(/* kext */ NULL
,
7198 kOSKextLogDebugLevel
|
7200 "Returning loaded kext info.");
7201 result
= kOSReturnSuccess
;
7204 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelLoadAddress
)) {
7205 OSNumber
* addressNum
= NULL
; // released as responseObject
7206 kernel_segment_command_t
* textseg
= getsegbyname("__TEXT");
7209 OSKextLog(/* kext */ NULL
,
7210 kOSKextLogErrorLevel
|
7211 kOSKextLogGeneralFlag
| kOSKextLogIPCFlag
,
7212 "Can't find text segment for kernel load address.");
7213 result
= kOSReturnError
;
7217 OSKextLog(/* kext */ NULL
,
7218 kOSKextLogDebugLevel
|
7220 "Returning kernel load address 0x%llx.",
7221 (unsigned long long)textseg
->vmaddr
);
7222 addressNum
= OSNumber::withNumber((long long unsigned int)textseg
->vmaddr
,
7223 8 * sizeof(long long unsigned int));
7224 responseObject
= addressNum
;
7225 result
= kOSReturnSuccess
;
7227 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelImage
)) {
7228 OSKextLog(/* kext */ NULL
,
7229 kOSKextLogDebugLevel
|
7231 "Returning kernel image.");
7232 responseData
= OSKext::copySanitizedKernelImage();
7233 result
= kOSReturnSuccess
;
7235 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
7237 /* Hand the current sKernelRequests array to the caller
7238 * (who must release it), and make a new one.
7240 responseObject
= sKernelRequests
;
7241 sKernelRequests
= OSArray::withCapacity(0);
7242 sPostedKextLoadIdentifiers
->flushCollection();
7243 OSKextLog(/* kext */ NULL
,
7244 kOSKextLogDebugLevel
|
7246 "Returning kernel requests.");
7247 result
= kOSReturnSuccess
;
7249 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
7251 /* Return the set of all requested bundle identifiers */
7252 responseObject
= sAllKextLoadIdentifiers
;
7253 responseObject
->retain();
7254 OSKextLog(/* kext */ NULL
,
7255 kOSKextLogDebugLevel
|
7257 "Returning load requests.");
7258 result
= kOSReturnSuccess
;
7262 * Now we have handle the request, or not. Gather up the response & logging
7263 * info to ship to user space.
7266 /* Note: Nothing in OSKext is supposed to retain requestDict,
7267 * but you never know....
7269 if (requestDict
->getRetainCount() > 1) {
7270 OSKextLog(/* kext */ NULL
,
7271 kOSKextLogWarningLevel
|
7273 "Request from user space still retained by a kext; "
7274 "probable memory leak.");
7277 if (responseData
&& responseObject
) {
7278 OSKextLog(/* kext */ NULL
,
7279 kOSKextLogErrorLevel
|
7281 "Mistakenly generated both data & plist responses to user request "
7282 "(returning only data).");
7285 if (responseData
&& responseData
->getLength() && responseOut
) {
7287 response
= (char *)responseData
->getBytesNoCopy();
7288 responseLength
= responseData
->getLength();
7289 } else if (responseOut
&& responseObject
) {
7290 serializer
= OSSerialize::withCapacity(0);
7292 result
= kOSKextReturnNoMemory
;
7296 if (!responseObject
->serialize(serializer
)) {
7297 OSKextLog(/* kext */ NULL
,
7298 kOSKextLogErrorLevel
|
7300 "Failed to serialize response to request from user space.");
7301 result
= kOSKextReturnSerialization
;
7305 response
= (char *)serializer
->text();
7306 responseLength
= serializer
->getLength();
7309 if (responseOut
&& response
) {
7312 /* This kmem_alloc sets the return value of the function.
7314 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
7316 if (kmem_result
!= KERN_SUCCESS
) {
7317 OSKextLog(/* kext */ NULL
,
7318 kOSKextLogErrorLevel
|
7320 "Failed to copy response to request from user space.");
7321 result
= kmem_result
;
7324 memcpy(buffer
, response
, responseLength
);
7325 *responseOut
= buffer
;
7326 *responseLengthOut
= responseLength
;
7332 /* Gather up the collected log messages for user space. Any messages
7333 * messages past this call will not make it up as log messages but
7334 * will be in the system log. Note that we ignore the return of the
7335 * serialize; it has no bearing on the operation at hand even if we
7336 * fail to get the log messages.
7338 logInfoArray
= OSKext::clearUserSpaceLogFilter();
7340 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
7341 (void)OSKext::serializeLogInfo(logInfoArray
,
7342 logInfoOut
, logInfoLengthOut
);
7345 IORecursiveLockUnlock(sKextLock
);
7347 OSSafeRelease(parsedXML
);
7348 OSSafeRelease(errorString
);
7349 OSSafeRelease(responseData
);
7350 OSSafeRelease(responseObject
);
7351 OSSafeRelease(serializer
);
7352 OSSafeRelease(logInfoArray
);
7357 /*********************************************************************
7358 *********************************************************************/
7361 OSKext::copyLoadedKextInfo(
7362 OSArray
* kextIdentifiers
,
7365 OSDictionary
* result
= NULL
;
7366 OSDictionary
* kextInfo
= NULL
; // must release
7368 uint32_t idCount
= 0;
7369 uint32_t idIndex
= 0;
7371 IORecursiveLockLock(sKextLock
);
7373 /* Empty list of bundle ids is equivalent to no list (get all).
7375 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
7376 kextIdentifiers
= NULL
;
7377 } else if (kextIdentifiers
) {
7378 idCount
= kextIdentifiers
->getCount();
7383 if (infoKeys
&& !infoKeys
->getCount()) {
7387 count
= sLoadedKexts
->getCount();
7388 result
= OSDictionary::withCapacity(count
);
7392 for (i
= 0; i
< count
; i
++) {
7393 OSKext
* thisKext
= NULL
; // do not release
7394 Boolean includeThis
= true;
7397 kextInfo
->release();
7400 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
7405 /* Skip current kext if we have a list of bundle IDs and
7406 * it isn't in the list.
7408 if (kextIdentifiers
) {
7409 const OSString
* thisKextID
= thisKext
->getIdentifier();
7411 includeThis
= false;
7413 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
7414 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
7415 kextIdentifiers
->getObject(idIndex
));
7416 if (thisKextID
->isEqualTo(thisRequestID
)) {
7427 kextInfo
= thisKext
->copyInfo(infoKeys
);
7429 result
->setObject(thisKext
->getIdentifier(), kextInfo
);
7434 IORecursiveLockUnlock(sKextLock
);
7436 if (kextInfo
) kextInfo
->release();
7441 /*********************************************************************
7442 * Any info that needs to do allocations must goto finish on alloc
7443 * failure. Info that is just a lookup should just not set the object
7444 * if the info does not exist.
7445 *********************************************************************/
7446 #define _OSKextLoadInfoDictCapacity (12)
7449 OSKext::copyInfo(OSArray
* infoKeys
)
7451 OSDictionary
* result
= NULL
;
7452 bool success
= false;
7453 OSData
* headerData
= NULL
; // must release
7454 OSNumber
* cpuTypeNumber
= NULL
; // must release
7455 OSNumber
* cpuSubtypeNumber
= NULL
; // must release
7456 OSString
* versionString
= NULL
; // do not release
7457 uint32_t executablePathCStringSize
= 0;
7458 char * executablePathCString
= NULL
; // must release
7459 OSString
* executablePathString
= NULL
; // must release
7460 OSData
* uuid
= NULL
; // must release
7461 OSNumber
* scratchNumber
= NULL
; // must release
7462 OSArray
* dependencyLoadTags
= NULL
; // must release
7463 OSCollectionIterator
* metaClassIterator
= NULL
; // must release
7464 OSArray
* metaClassInfo
= NULL
; // must release
7465 OSDictionary
* metaClassDict
= NULL
; // must release
7466 OSMetaClass
* thisMetaClass
= NULL
; // do not release
7467 OSString
* metaClassName
= NULL
; // must release
7468 OSString
* superclassName
= NULL
; // must release
7471 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
7477 /* Empty keys means no keys, but NULL is quicker to check.
7479 if (infoKeys
&& !infoKeys
->getCount()) {
7483 /* Headers, CPU type, and CPU subtype.
7486 _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
) ||
7487 _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
) ||
7488 _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
))
7491 if (linkedExecutable
&& !isInterface()) {
7493 kernel_mach_header_t
*kext_mach_hdr
= (kernel_mach_header_t
*)
7494 linkedExecutable
->getBytesNoCopy();
7496 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
)) {
7497 headerData
= OSData::withBytes(kext_mach_hdr
,
7498 (u_int
) (sizeof(*kext_mach_hdr
) + kext_mach_hdr
->sizeofcmds
));
7502 result
->setObject(kOSBundleMachOHeadersKey
, headerData
);
7505 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
)) {
7506 cpuTypeNumber
= OSNumber::withNumber(
7507 (uint64_t) kext_mach_hdr
->cputype
,
7508 8 * sizeof(kext_mach_hdr
->cputype
));
7509 if (!cpuTypeNumber
) {
7512 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
);
7515 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
7516 cpuSubtypeNumber
= OSNumber::withNumber(
7517 (uint64_t) kext_mach_hdr
->cpusubtype
,
7518 8 * sizeof(kext_mach_hdr
->cpusubtype
));
7519 if (!cpuSubtypeNumber
) {
7522 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
);
7527 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
7529 result
->setObject(kCFBundleIdentifierKey
, bundleID
);
7533 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kCFBundleVersionKey
)) {
7534 versionString
= OSDynamicCast(OSString
,
7535 getPropertyForHostArch(kCFBundleVersionKey
));
7536 if (versionString
) {
7537 result
->setObject(kCFBundleVersionKey
, versionString
);
7541 /* OSBundleCompatibleVersion.
7543 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCompatibleVersionKey
)) {
7544 versionString
= OSDynamicCast(OSString
,
7545 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
7546 if (versionString
) {
7547 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
7553 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePathKey
)) {
7555 result
->setObject(kOSBundlePathKey
, path
);
7560 /* OSBundleExecutablePath.
7562 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecutablePathKey
)) {
7563 if (path
&& executableRelPath
) {
7565 uint32_t pathLength
= path
->getLength(); // gets incremented below
7567 // +1 for slash, +1 for \0
7568 executablePathCStringSize
= pathLength
+ executableRelPath
->getLength() + 2;
7570 executablePathCString
= (char *)kalloc((executablePathCStringSize
) *
7571 sizeof(char)); // +1 for \0
7572 if (!executablePathCString
) {
7575 strlcpy(executablePathCString
, path
->getCStringNoCopy(),
7576 executablePathCStringSize
);
7577 executablePathCString
[pathLength
++] = '/';
7578 executablePathCString
[pathLength
++] = '\0';
7579 strlcat(executablePathCString
, executableRelPath
->getCStringNoCopy(),
7580 executablePathCStringSize
);
7582 executablePathString
= OSString::withCString(executablePathCString
);
7584 if (!executablePathCString
) {
7588 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
);
7592 /* UUID, if the kext has one.
7594 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
7597 result
->setObject(kOSBundleUUIDKey
, uuid
);
7602 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
7604 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
7605 result
->setObject(kOSKernelResourceKey
,
7606 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
7609 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleIsInterfaceKey
)) {
7610 result
->setObject(kOSBundleIsInterfaceKey
,
7611 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
7614 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePrelinkedKey
)) {
7615 result
->setObject(kOSBundlePrelinkedKey
,
7616 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
7619 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleStartedKey
)) {
7620 result
->setObject(kOSBundleStartedKey
,
7621 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
7626 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadTagKey
)) {
7627 scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
7628 /* numBits */ 8 * sizeof(loadTag
));
7629 if (!scratchNumber
) {
7632 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
);
7633 OSSafeReleaseNULL(scratchNumber
);
7636 /* LoadAddress, LoadSize.
7639 _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
) ||
7640 _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
) ||
7641 _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
))
7643 if (isInterface() || linkedExecutable
) {
7644 /* These go to userspace via serialization, so we don't want any doubts
7647 uint64_t loadAddress
= 0;
7648 uint32_t loadSize
= 0;
7649 uint32_t wiredSize
= 0;
7651 /* Interfaces always report 0 load address & size.
7652 * Just the way they roll.
7654 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
7655 * xxx - shouldn't have one!
7657 if (linkedExecutable
/* && !isInterface() */) {
7658 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
7659 loadSize
= linkedExecutable
->getLength();
7661 /* If we have a kmod_info struct, calculated the wired size
7662 * from that. Otherwise it's the full load size.
7665 wiredSize
= loadSize
- kmod_info
->hdr_size
;
7667 wiredSize
= loadSize
;
7671 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
)) {
7672 scratchNumber
= OSNumber::withNumber(
7673 (unsigned long long)(loadAddress
),
7674 /* numBits */ 8 * sizeof(loadAddress
));
7675 if (!scratchNumber
) {
7678 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
);
7679 OSSafeReleaseNULL(scratchNumber
);
7681 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
)) {
7682 scratchNumber
= OSNumber::withNumber(
7683 (unsigned long long)(loadSize
),
7684 /* numBits */ 8 * sizeof(loadSize
));
7685 if (!scratchNumber
) {
7688 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
);
7689 OSSafeReleaseNULL(scratchNumber
);
7691 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
7692 scratchNumber
= OSNumber::withNumber(
7693 (unsigned long long)(wiredSize
),
7694 /* numBits */ 8 * sizeof(wiredSize
));
7695 if (!scratchNumber
) {
7698 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
);
7699 OSSafeReleaseNULL(scratchNumber
);
7704 /* OSBundleDependencies. In descending order for
7705 * easy compatibility with kextstat(8).
7707 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleDependenciesKey
)) {
7708 if ((count
= getNumDependencies())) {
7709 dependencyLoadTags
= OSArray::withCapacity(count
);
7710 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
);
7714 OSKext
* dependency
= OSDynamicCast(OSKext
,
7715 dependencies
->getObject(i
));
7717 OSSafeReleaseNULL(scratchNumber
);
7722 scratchNumber
= OSNumber::withNumber(
7723 (unsigned long long)dependency
->getLoadTag(),
7724 /* numBits*/ 8 * sizeof(loadTag
));
7725 if (!scratchNumber
) {
7728 dependencyLoadTags
->setObject(scratchNumber
);
7733 OSSafeReleaseNULL(scratchNumber
);
7735 /* OSBundleMetaClasses.
7737 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleClassesKey
)) {
7738 if (metaClasses
&& metaClasses
->getCount()) {
7739 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
);
7740 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
7741 if (!metaClassIterator
|| !metaClassInfo
) {
7744 result
->setObject(kOSBundleClassesKey
, metaClassInfo
);
7746 while ( (thisMetaClass
= OSDynamicCast(OSMetaClass
,
7747 metaClassIterator
->getNextObject())) ) {
7749 OSSafeReleaseNULL(metaClassDict
);
7750 OSSafeReleaseNULL(scratchNumber
);
7751 OSSafeReleaseNULL(metaClassName
);
7752 OSSafeReleaseNULL(superclassName
);
7754 metaClassDict
= OSDictionary::withCapacity(3);
7755 if (!metaClassDict
) {
7759 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
7760 if (thisMetaClass
->getSuperClass()) {
7761 superclassName
= OSString::withCString(
7762 thisMetaClass
->getSuperClass()->getClassName());
7764 scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
7765 8 * sizeof(unsigned int));
7767 /* Bail if any of the essentials is missing. The root class lacks a superclass,
7770 if (!metaClassDict
|| !metaClassName
|| !scratchNumber
) {
7774 metaClassInfo
->setObject(metaClassDict
);
7775 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
);
7776 if (superclassName
) {
7777 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
);
7779 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
);
7784 /* OSBundleRetainCount.
7786 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleRetainCountKey
)) {
7787 OSSafeReleaseNULL(scratchNumber
);
7789 int kextRetainCount
= getRetainCount() - 1;
7793 scratchNumber
= OSNumber::withNumber(
7794 (int)kextRetainCount
,
7795 /* numBits*/ 8 * sizeof(int));
7796 if (scratchNumber
) {
7797 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
);
7805 OSSafeRelease(headerData
);
7806 OSSafeRelease(cpuTypeNumber
);
7807 OSSafeRelease(cpuSubtypeNumber
);
7808 OSSafeRelease(executablePathString
);
7809 if (executablePathString
) kfree(executablePathCString
, executablePathCStringSize
);
7810 OSSafeRelease(uuid
);
7811 OSSafeRelease(scratchNumber
);
7812 OSSafeRelease(dependencyLoadTags
);
7813 OSSafeRelease(metaClassIterator
);
7814 OSSafeRelease(metaClassInfo
);
7815 OSSafeRelease(metaClassDict
);
7816 OSSafeRelease(metaClassName
);
7817 OSSafeRelease(superclassName
);
7819 OSSafeReleaseNULL(result
);
7824 /********************************************************************/
7825 static struct symtab_command
* getKernelSymtab(void)
7827 struct symtab_command
* result
= NULL
;
7828 struct load_command
* load_cmd
= NULL
;
7831 load_cmd
= (struct load_command
*)
7832 ((uintptr_t)&_mh_execute_header
+ sizeof(_mh_execute_header
));
7833 for(i
= 0; i
< _mh_execute_header
.ncmds
; i
++){
7834 if (load_cmd
->cmd
== LC_SYMTAB
) {
7835 result
= (struct symtab_command
*)load_cmd
;
7838 load_cmd
= (struct load_command
*)
7839 ((uintptr_t)load_cmd
+ load_cmd
->cmdsize
);
7846 /*********************************************************************
7847 *********************************************************************/
7850 OSKext::copySanitizedKernelImage(void)
7852 OSData
* result
= NULL
;
7854 kernel_mach_header_t
* kernelHeader
= NULL
;
7855 uint32_t sizeofcmds
= 0;
7857 /* These start out pointing to running kernel but
7858 * after copying point to the copied info.
7860 kernel_segment_command_t
* text_seg
= NULL
;
7861 kernel_segment_command_t
* data_seg
= NULL
;
7862 kernel_segment_command_t
* linkedit_seg
= NULL
;
7863 struct symtab_command
* symtab_cmd
= NULL
;
7864 kernel_section_t
* text_const_sect
= NULL
;
7865 kernel_section_t
* data_const_sect
= NULL
;
7867 kern_return_t kern_result
= 0;
7868 u_long kernelCopyLength
= 0;
7869 vm_offset_t kernelCopyAddr
= 0;
7870 u_char
* kernelCopy
= NULL
;
7872 vm_offset_t contentOffset
= 0;
7873 struct load_command
* scan_cmd
= NULL
;
7874 kernel_section_t
* scan_sect
= NULL
;
7875 int64_t stroff_shift
= 0;
7879 text_seg
= getsegbyname("__TEXT");
7880 data_seg
= getsegbyname("__DATA");
7881 linkedit_seg
= getsegbyname("__LINKEDIT");
7882 symtab_cmd
= getKernelSymtab();
7884 text_const_sect
= getsectbyname("__TEXT", "__const");
7885 data_const_sect
= getsectbyname("__DATA", "__const");
7887 if (!text_seg
|| !data_seg
|| !linkedit_seg
|| !symtab_cmd
||
7888 !text_const_sect
|| ! data_const_sect
) {
7890 OSKextLog(/* kext */ NULL
,
7891 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
7892 "Can't provide kernel image for linking; missing component.");
7896 /* Figure the size of the kernel image to build. We don't use the sizes of
7897 * the __TEXT & __DATA segments overall as we only use the __const sections,
7898 * so add those in manually. We're going to round each part to page size
7899 * multiples too, just to be extra cautious.
7901 sizeofcmds
= text_seg
->cmdsize
+ data_seg
->cmdsize
+
7902 linkedit_seg
->cmdsize
+ symtab_cmd
->cmdsize
;
7903 kernelCopyLength
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
) +
7904 round_page(text_const_sect
->size
) +
7905 round_page(data_const_sect
->size
) +
7906 round_page(linkedit_seg
->filesize
);
7908 kern_result
= kmem_alloc(kernel_map
, &kernelCopyAddr
, kernelCopyLength
);
7909 if (kern_result
!= KERN_SUCCESS
) {
7913 kernelCopy
= (u_char
*)kernelCopyAddr
;
7914 bzero(kernelCopy
, kernelCopyLength
); // ??? - is this really necessary?
7917 * Copy the kernel Mach header and the load commands we want.
7919 memcpy(kernelCopy
, &_mh_execute_header
, sizeof(_mh_execute_header
));
7920 kernelHeader
= (kernel_mach_header_t
*)kernelCopy
;
7921 kernelHeader
->ncmds
= 0;
7922 kernelHeader
->sizeofcmds
= sizeofcmds
;
7923 contentOffset
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
);
7925 /* __TEXT segment load command and sections.
7926 * Note that the __TEXT segment's 'offset' and 'filesize' include
7927 * the data from the beginning of the mach header.
7929 * Don't muck with the __TEXT segment's vmsize here;
7930 * user-space linking requires it to match what is in the running kernel.
7931 * We'll just have to live with it not being accurate
7932 * (not like we can run the sanitized image after all).
7934 scan_cmd
= (struct load_command
*)&kernelHeader
[1]; // just past mach header
7935 memcpy(scan_cmd
, text_seg
, text_seg
->cmdsize
);
7936 kernelHeader
->ncmds
++;
7937 text_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
7938 text_seg
->fileoff
= 0;
7939 text_seg
->filesize
= round_page(sizeof(_mh_execute_header
) + sizeofcmds
);
7941 scan_sect
= (kernel_section_t
*)(text_seg
+ 1);
7942 for (i
= 0; i
< text_seg
->nsects
; i
++, scan_sect
++) {
7943 if (0 == strncmp("__const", scan_sect
->sectname
, sizeof("__const"))) {
7944 text_const_sect
= scan_sect
; // retarget to constructed section
7946 text_seg
->filesize
+= scan_sect
->size
;
7948 scan_sect
->offset
= contentOffset
;
7949 contentOffset
+= scan_sect
->size
;
7951 memcpy(kernelCopy
+ scan_sect
->offset
, (void *)(uintptr_t)scan_sect
->addr
,
7954 scan_sect
->addr
= 0;
7955 scan_sect
->size
= 0;
7956 scan_sect
->offset
= contentOffset
;
7957 scan_sect
->nreloc
= 0;
7961 contentOffset
= round_page(contentOffset
);
7963 /* __DATA segment load command and sections.
7964 * Leave the vmsize as in the running kernel here, too.
7966 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
7967 memcpy(scan_cmd
, data_seg
, data_seg
->cmdsize
);
7968 kernelHeader
->ncmds
++;
7969 data_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
7970 data_seg
->fileoff
= contentOffset
;
7971 data_seg
->filesize
= 0;
7973 scan_sect
= (kernel_section_t
*)(data_seg
+ 1);
7974 for (i
= 0; i
< data_seg
->nsects
; i
++, scan_sect
++) {
7975 if (0 == strncmp("__const", scan_sect
->sectname
, sizeof("__const"))) {
7976 data_const_sect
= scan_sect
; // retarget to constructed section
7978 data_seg
->filesize
+= scan_sect
->size
;
7980 scan_sect
->offset
= contentOffset
;
7981 contentOffset
+= scan_sect
->size
;
7983 memcpy(kernelCopy
+ scan_sect
->offset
, (void *)(uintptr_t)scan_sect
->addr
,
7986 scan_sect
->addr
= 0;
7987 scan_sect
->size
= 0;
7988 scan_sect
->offset
= contentOffset
;
7989 scan_sect
->nreloc
= 0;
7993 contentOffset
= round_page(contentOffset
);
7995 /* __LINKEDIT segment load command.
7996 * Leave the vmsize as in the running kernel here, too.
7998 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
7999 memcpy(scan_cmd
, linkedit_seg
, linkedit_seg
->cmdsize
);
8000 kernelHeader
->ncmds
++;
8001 linkedit_seg
= (kernel_segment_command_t
*)scan_cmd
; // retarget to constructed segment
8002 linkedit_seg
->fileoff
= contentOffset
;
8003 linkedit_seg
->filesize
= linkedit_seg
->vmsize
;
8005 contentOffset
+= round_page(linkedit_seg
->vmsize
);
8007 memcpy(kernelCopy
+ linkedit_seg
->fileoff
, (void *)(uintptr_t)linkedit_seg
->vmaddr
,
8008 linkedit_seg
->vmsize
);
8010 /* __SYMTAB load command (contents shared with __LINKEDIT).
8012 scan_cmd
= (struct load_command
*)((uintptr_t)scan_cmd
+ scan_cmd
->cmdsize
);
8013 memcpy(scan_cmd
, symtab_cmd
, symtab_cmd
->cmdsize
);
8014 kernelHeader
->ncmds
++;
8015 symtab_cmd
= (struct symtab_command
*)scan_cmd
; // retarget to constructed cmd
8016 stroff_shift
= symtab_cmd
->stroff
- symtab_cmd
->symoff
;
8017 symtab_cmd
->symoff
= linkedit_seg
->fileoff
;
8018 symtab_cmd
->stroff
= symtab_cmd
->symoff
+ stroff_shift
;
8020 /* Wrap the thing up in an OSData.
8022 result
= OSData::withBytesNoCopy(kernelCopy
, kernelCopyLength
);
8024 result
->setDeallocFunction(osdata_kmem_free
);
8029 if (kernelCopy
) kmem_free(kernel_map
, kernelCopyAddr
, kernelCopyLength
);
8034 /*********************************************************************
8035 *********************************************************************/
8038 OSKext::requestResource(
8039 const char * kextIdentifierCString
,
8040 const char * resourceNameCString
,
8041 OSKextRequestResourceCallback callback
,
8043 OSKextRequestTag
* requestTagOut
)
8045 OSReturn result
= kOSReturnError
;
8046 OSKext
* callbackKext
= NULL
; // must release (looked up)
8048 OSKextRequestTag requestTag
= -1;
8049 OSNumber
* requestTagNum
= NULL
; // must release
8051 OSDictionary
* requestDict
= NULL
; // must release
8052 OSString
* kextIdentifier
= NULL
; // must release
8053 OSString
* resourceName
= NULL
; // must release
8055 OSDictionary
* callbackRecord
= NULL
; // must release
8056 OSData
* callbackWrapper
= NULL
; // must release
8058 OSData
* contextWrapper
= NULL
; // must release
8060 IORecursiveLockLock(sKextLock
);
8062 if (requestTagOut
) {
8063 *requestTagOut
= kOSKextRequestTagInvalid
;
8066 /* If requests to user space are disabled, don't go any further */
8067 if (!sKernelRequestsEnabled
) {
8068 OSKextLog(/* kext */ NULL
,
8069 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8070 "Can't request resource %s for %s - requests to user space are disabled.",
8071 resourceNameCString
,
8072 kextIdentifierCString
);
8073 result
= kOSKextReturnDisabled
;
8077 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
8078 result
= kOSKextReturnInvalidArgument
;
8082 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
8083 if (!callbackKext
) {
8084 OSKextLog(/* kext */ NULL
,
8085 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8086 "Resource request has bad callback address.");
8087 result
= kOSKextReturnInvalidArgument
;
8090 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
8091 OSKextLog(/* kext */ NULL
,
8092 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8093 "Resource request callback is in a kext that is not started.");
8094 result
= kOSKextReturnInvalidArgument
;
8098 /* Do not allow any new requests to be made on a kext that is unloading.
8100 if (callbackKext
->flags
.stopping
) {
8101 result
= kOSKextReturnStopping
;
8105 /* If we're wrapped the next available request tag around to the negative
8106 * numbers, we can't service any more requests.
8108 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
8109 OSKextLog(/* kext */ NULL
,
8110 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8111 "No more request tags available; restart required.");
8112 result
= kOSKextReturnNoResources
;
8115 requestTag
= sNextRequestTag
++;
8117 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
8119 if (result
!= kOSReturnSuccess
) {
8123 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
8124 resourceName
= OSString::withCString(resourceNameCString
);
8125 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
8126 8 * sizeof(requestTag
));
8127 if (!kextIdentifier
||
8130 !_OSKextSetRequestArgument(requestDict
,
8131 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
8132 !_OSKextSetRequestArgument(requestDict
,
8133 kKextRequestArgumentNameKey
, resourceName
) ||
8134 !_OSKextSetRequestArgument(requestDict
,
8135 kKextRequestArgumentRequestTagKey
, requestTagNum
)) {
8137 result
= kOSKextReturnNoMemory
;
8141 callbackRecord
= OSDynamicCast(OSDictionary
, requestDict
->copyCollection());
8142 if (!callbackRecord
) {
8143 result
= kOSKextReturnNoMemory
;
8146 // we validate callback address at call time
8147 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
8149 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
8151 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
8152 kKextRequestArgumentCallbackKey
, callbackWrapper
)) {
8154 result
= kOSKextReturnNoMemory
;
8159 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
,
8160 kKextRequestArgumentContextKey
, contextWrapper
)) {
8162 result
= kOSKextReturnNoMemory
;
8167 /* Only post the requests after all the other potential failure points
8170 if (!sKernelRequests
->setObject(requestDict
) ||
8171 !sRequestCallbackRecords
->setObject(callbackRecord
)) {
8173 result
= kOSKextReturnNoMemory
;
8177 OSKext::pingKextd();
8179 result
= kOSReturnSuccess
;
8180 if (requestTagOut
) {
8181 *requestTagOut
= requestTag
;
8186 /* If we didn't succeed, yank the request & callback
8187 * from their holding arrays.
8189 if (result
!= kOSReturnSuccess
) {
8192 index
= sKernelRequests
->getNextIndexOfObject(requestDict
, 0);
8193 if (index
!= (unsigned int)-1) {
8194 sKernelRequests
->removeObject(index
);
8196 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
, 0);
8197 if (index
!= (unsigned int)-1) {
8198 sRequestCallbackRecords
->removeObject(index
);
8202 OSKext::considerUnloads(/* rescheduleOnly? */ true);
8204 IORecursiveLockUnlock(sKextLock
);
8206 if (callbackKext
) callbackKext
->release();
8207 if (requestTagNum
) requestTagNum
->release();
8209 if (requestDict
) requestDict
->release();
8210 if (kextIdentifier
) kextIdentifier
->release();
8211 if (resourceName
) resourceName
->release();
8213 if (callbackRecord
) callbackRecord
->release();
8214 if (callbackWrapper
) callbackWrapper
->release();
8215 if (contextWrapper
) contextWrapper
->release();
8220 /*********************************************************************
8221 * Assumes sKextLock is held.
8222 *********************************************************************/
8225 OSKext::dequeueCallbackForRequestTag(
8226 OSKextRequestTag requestTag
,
8227 OSDictionary
** callbackRecordOut
)
8229 OSReturn result
= kOSReturnError
;
8230 OSNumber
* requestTagNum
= NULL
; // must release
8232 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
8233 8 * sizeof(requestTag
));
8234 if (!requestTagNum
) {
8238 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
,
8242 OSSafeRelease(requestTagNum
);
8247 /*********************************************************************
8248 * Assumes sKextLock is held.
8249 *********************************************************************/
8252 OSKext::dequeueCallbackForRequestTag(
8253 OSNumber
* requestTagNum
,
8254 OSDictionary
** callbackRecordOut
)
8256 OSReturn result
= kOSKextReturnInvalidArgument
;
8257 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
8258 OSNumber
* callbackTagNum
= NULL
; // do not release
8259 unsigned int count
, i
;
8261 result
= kOSReturnError
;
8262 count
= sRequestCallbackRecords
->getCount();
8263 for (i
= 0; i
< count
; i
++) {
8264 callbackRecord
= OSDynamicCast(OSDictionary
,
8265 sRequestCallbackRecords
->getObject(i
));
8266 if (!callbackRecord
) {
8270 /* If we don't find a tag, we basically have a leak here. Maybe
8271 * we should just remove it.
8273 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
8274 callbackRecord
, kKextRequestArgumentRequestTagKey
));
8275 if (!callbackTagNum
) {
8279 /* We could be even more paranoid and check that all the incoming
8280 * args match what's in the callback record.
8282 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
8283 if (callbackRecordOut
) {
8284 *callbackRecordOut
= callbackRecord
;
8285 callbackRecord
->retain();
8287 sRequestCallbackRecords
->removeObject(i
);
8288 result
= kOSReturnSuccess
;
8292 result
= kOSKextReturnNotFound
;
8298 /*********************************************************************
8299 * Assumes sKextLock is held.
8300 *********************************************************************/
8303 OSKext::dispatchResource(OSDictionary
* requestDict
)
8305 OSReturn result
= kOSReturnError
;
8306 OSDictionary
* callbackRecord
= NULL
; // must release
8307 OSNumber
* requestTag
= NULL
; // do not release
8308 OSNumber
* requestResult
= NULL
; // do not release
8309 OSData
* dataObj
= NULL
; // do not release
8310 uint32_t dataLength
= 0;
8311 const void * dataPtr
= NULL
; // do not free
8312 OSData
* callbackWrapper
= NULL
; // do not release
8313 OSKextRequestResourceCallback callback
= NULL
;
8314 OSData
* contextWrapper
= NULL
; // do not release
8315 void * context
= NULL
; // do not free
8316 OSKext
* callbackKext
= NULL
; // must release (looked up)
8318 /* Get the args from the request. Right now we need the tag
8319 * to look up the callback record, and the result for invoking the callback.
8321 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
8322 kKextRequestArgumentRequestTagKey
));
8323 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
8324 kKextRequestArgumentResultKey
));
8325 if (!requestTag
|| !requestResult
) {
8326 result
= kOSKextReturnInvalidArgument
;
8330 /* Look for a callback record matching this request's tag.
8332 result
= dequeueCallbackForRequestTag(requestTag
, &callbackRecord
);
8333 if (result
!= kOSReturnSuccess
) {
8338 * Get the context pointer of the callback record (if there is one).
8340 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
,
8341 kKextRequestArgumentContextKey
));
8342 context
= _OSKextExtractPointer(contextWrapper
);
8343 if (contextWrapper
&& !context
) {
8347 callbackWrapper
= OSDynamicCast(OSData
,
8348 _OSKextGetRequestArgument(callbackRecord
,
8349 kKextRequestArgumentCallbackKey
));
8350 callback
= (OSKextRequestResourceCallback
)
8351 _OSKextExtractPointer(callbackWrapper
);
8356 /* Check for a data obj. We might not have one and that's ok, that means
8357 * we didn't find the requested resource, and we still have to tell the
8358 * caller that via the callback.
8360 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
8361 kKextRequestArgumentValueKey
));
8363 dataPtr
= dataObj
->getBytesNoCopy();
8364 dataLength
= dataObj
->getLength();
8367 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
8368 if (!callbackKext
) {
8369 OSKextLog(/* kext */ NULL
,
8370 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8371 "Can't invoke callback for resource request; "
8372 "no kext loaded at callback address %p.",
8376 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
8377 OSKextLog(/* kext */ NULL
,
8378 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
8379 "Can't invoke kext resource callback; "
8380 "kext at callback address %p is not running.",
8385 (void)callback(requestTag
->unsigned32BitValue(),
8386 (OSReturn
)requestResult
->unsigned32BitValue(),
8387 dataPtr
, dataLength
, context
);
8389 result
= kOSReturnSuccess
;
8392 if (callbackKext
) callbackKext
->release();
8393 if (callbackRecord
) callbackRecord
->release();
8398 /*********************************************************************
8399 *********************************************************************/
8402 OSKext::invokeRequestCallback(
8403 OSDictionary
* callbackRecord
,
8404 OSReturn callbackResult
)
8406 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
8407 OSNumber
* resultNum
= NULL
; // must release
8413 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
8414 8 * sizeof(callbackResult
));
8419 /* Insert the result into the callback record and dispatch it as if it
8420 * were the reply coming down from user space.
8422 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
8425 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
8426 /* This removes the pending callback record.
8428 OSKext::dispatchResource(callbackRecord
);
8432 if (resultNum
) resultNum
->release();
8436 /*********************************************************************
8437 * Assumes sKextLock is held.
8438 *********************************************************************/
8441 OSKext::cancelRequest(
8442 OSKextRequestTag requestTag
,
8445 OSReturn result
= kOSKextReturnNoMemory
;
8446 OSDictionary
* callbackRecord
= NULL
; // must release
8447 OSData
* contextWrapper
= NULL
; // do not release
8449 IORecursiveLockLock(sKextLock
);
8450 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
8452 IORecursiveLockUnlock(sKextLock
);
8454 if (result
== kOSReturnSuccess
&& contextOut
) {
8455 contextWrapper
= OSDynamicCast(OSData
,
8456 _OSKextGetRequestArgument(callbackRecord
,
8457 kKextRequestArgumentContextKey
));
8458 *contextOut
= _OSKextExtractPointer(contextWrapper
);
8461 if (callbackRecord
) callbackRecord
->release();
8466 /*********************************************************************
8467 * Assumes sKextLock is held.
8468 *********************************************************************/
8470 OSKext::invokeOrCancelRequestCallbacks(
8471 OSReturn callbackResult
,
8474 unsigned int count
, i
;
8476 count
= sRequestCallbackRecords
->getCount();
8483 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
8484 sRequestCallbackRecords
->getObject(i
));
8489 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
8490 _OSKextGetRequestArgument(request
,
8491 kKextRequestArgumentCallbackKey
));
8493 if (!callbackWrapper
) {
8494 sRequestCallbackRecords
->removeObject(i
);
8498 vm_address_t callbackAddress
= (vm_address_t
)
8499 _OSKextExtractPointer(callbackWrapper
);
8501 if ((kmod_info
->address
<= callbackAddress
) &&
8502 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
8505 /* This removes the callback record.
8507 invokeRequestCallback(request
, callbackResult
);
8509 sRequestCallbackRecords
->removeObject(i
);
8518 /*********************************************************************
8519 * Assumes sKextLock is held.
8520 *********************************************************************/
8522 OSKext::countRequestCallbacks(void)
8524 uint32_t result
= 0;
8525 unsigned int count
, i
;
8527 count
= sRequestCallbackRecords
->getCount();
8534 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
8535 sRequestCallbackRecords
->getObject(i
));
8540 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
8541 _OSKextGetRequestArgument(request
,
8542 kKextRequestArgumentCallbackKey
));
8544 if (!callbackWrapper
) {
8548 vm_address_t callbackAddress
= (vm_address_t
)
8549 _OSKextExtractPointer(callbackWrapper
);
8551 if ((kmod_info
->address
<= callbackAddress
) &&
8552 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
8562 /*********************************************************************
8563 *********************************************************************/
8564 static OSReturn
_OSKextCreateRequest(
8565 const char * predicate
,
8566 OSDictionary
** requestP
)
8568 OSReturn result
= kOSKextReturnNoMemory
;
8569 OSDictionary
* request
= NULL
; // must release on error
8570 OSDictionary
* args
= NULL
; // must release
8572 request
= OSDictionary::withCapacity(2);
8576 result
= _OSDictionarySetCStringValue(request
,
8577 kKextRequestPredicateKey
, predicate
);
8578 if (result
!= kOSReturnSuccess
) {
8581 result
= kOSReturnSuccess
;
8584 if (result
!= kOSReturnSuccess
) {
8585 if (request
) request
->release();
8587 *requestP
= request
;
8589 if (args
) args
->release();
8594 /*********************************************************************
8595 *********************************************************************/
8596 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
8598 return OSDynamicCast(OSString
,
8599 requestDict
->getObject(kKextRequestPredicateKey
));
8602 /*********************************************************************
8603 *********************************************************************/
8604 static OSObject
* _OSKextGetRequestArgument(
8605 OSDictionary
* requestDict
,
8606 const char * argName
)
8608 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
8609 requestDict
->getObject(kKextRequestArgumentsKey
));
8611 return args
->getObject(argName
);
8616 /*********************************************************************
8617 *********************************************************************/
8618 static bool _OSKextSetRequestArgument(
8619 OSDictionary
* requestDict
,
8620 const char * argName
,
8623 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
8624 requestDict
->getObject(kKextRequestArgumentsKey
));
8626 args
= OSDictionary::withCapacity(2);
8630 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
8634 return args
->setObject(argName
, value
);
8640 /*********************************************************************
8641 *********************************************************************/
8642 static void * _OSKextExtractPointer(OSData
* wrapper
)
8644 void * result
= NULL
;
8645 const void * resultPtr
= NULL
;
8650 resultPtr
= wrapper
->getBytesNoCopy();
8651 result
= *(void **)resultPtr
;
8656 /*********************************************************************
8657 *********************************************************************/
8658 static OSReturn
_OSDictionarySetCStringValue(
8659 OSDictionary
* dict
,
8661 const char * cValue
)
8663 OSReturn result
= kOSKextReturnNoMemory
;
8664 const OSSymbol
* key
= NULL
; // must release
8665 OSString
* value
= NULL
; // must release
8667 key
= OSSymbol::withCString(cKey
);
8668 value
= OSString::withCString(cValue
);
8669 if (!key
|| !value
) {
8672 if (dict
->setObject(key
, value
)) {
8673 result
= kOSReturnSuccess
;
8677 if (key
) key
->release();
8678 if (value
) value
->release();
8683 /*********************************************************************
8684 *********************************************************************/
8685 static bool _OSArrayContainsCString(
8687 const char * cString
)
8689 bool result
= false;
8690 const OSSymbol
* symbol
= NULL
;
8693 if (!array
|| !cString
) {
8697 symbol
= OSSymbol::withCStringNoCopy(cString
);
8702 count
= array
->getCount();
8703 for (i
= 0; i
< count
; i
++) {
8704 OSObject
* thisObject
= array
->getObject(i
);
8705 if (symbol
->isEqualTo(thisObject
)) {
8712 if (symbol
) symbol
->release();
8717 #pragma mark Personalities (IOKit Drivers)
8719 /*********************************************************************
8720 *********************************************************************/
8723 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
8725 OSArray
* result
= NULL
; // returned
8726 OSCollectionIterator
* kextIterator
= NULL
; // must release
8727 OSArray
* personalities
= NULL
; // must release
8728 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
8730 OSString
* kextID
= NULL
; // do not release
8731 OSKext
* theKext
= NULL
; // do not release
8733 IORecursiveLockLock(sKextLock
);
8735 /* Let's conservatively guess that any given kext has around 3
8736 * personalities for now.
8738 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
8743 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
);
8744 if (!kextIterator
) {
8748 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
8749 if (personalitiesIterator
) {
8750 personalitiesIterator
->release();
8751 personalitiesIterator
= NULL
;
8753 if (personalities
) {
8754 personalities
->release();
8755 personalities
= NULL
;
8758 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
8759 if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
8760 personalities
= theKext
->copyPersonalitiesArray();
8761 if (!personalities
) {
8764 result
->merge(personalities
);
8766 // xxx - check for better place to put this log msg
8768 kOSKextLogWarningLevel
|
8770 "Kext %s is not loadable during safe boot; "
8771 "omitting its personalities.",
8772 theKext
->getIdentifierCString());
8778 IORecursiveLockUnlock(sKextLock
);
8780 if (kextIterator
) kextIterator
->release();
8781 if (personalitiesIterator
) personalitiesIterator
->release();
8782 if (personalities
) personalities
->release();
8787 /*********************************************************************
8788 *********************************************************************/
8791 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
8793 int numPersonalities
= 0;
8795 OSKextLog(/* kext */ NULL
,
8796 kOSKextLogStepLevel
|
8798 "Sending all eligible registered kexts' personalities "
8799 "to the IOCatalogue %s.",
8800 startMatching
? "and starting matching" : "but not starting matching");
8802 OSArray
* personalities
= OSKext::copyAllKextPersonalities(
8803 /* filterSafeBootFlag */ true);
8805 if (personalities
) {
8806 gIOCatalogue
->addDrivers(personalities
, startMatching
);
8807 numPersonalities
= personalities
->getCount();
8808 personalities
->release();
8811 OSKextLog(/* kext */ NULL
,
8812 kOSKextLogStepLevel
|
8814 "%d kext personalit%s sent to the IOCatalogue; %s.",
8815 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
8816 startMatching
? "matching started" : "matching not started");
8820 /*********************************************************************
8821 * Do not make a deep copy, just convert the IOKitPersonalities dict
8822 * to an array for sending to the IOCatalogue.
8823 *********************************************************************/
8825 OSKext::copyPersonalitiesArray(void)
8827 OSArray
* result
= NULL
;
8828 OSDictionary
* personalities
= NULL
; // do not release
8829 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
8831 OSString
* personalityName
= NULL
; // do not release
8832 OSString
* personalityBundleIdentifier
= NULL
; // do not release
8834 personalities
= OSDynamicCast(OSDictionary
,
8835 getPropertyForHostArch(kIOKitPersonalitiesKey
));
8836 if (!personalities
) {
8840 result
= OSArray::withCapacity(personalities
->getCount());
8845 personalitiesIterator
=
8846 OSCollectionIterator::withCollection(personalities
);
8847 if (!personalitiesIterator
) {
8850 while ((personalityName
= OSDynamicCast(OSString
,
8851 personalitiesIterator
->getNextObject()))) {
8853 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
8854 personalities
->getObject(personalityName
));
8857 * If the personality doesn't have a CFBundleIdentifier, or if it
8858 * differs from the kext's, insert the kext's ID so we can find it.
8859 * The publisher ID is used to remove personalities from bundles
8862 personalityBundleIdentifier
= OSDynamicCast(OSString
,
8863 personality
->getObject(kCFBundleIdentifierKey
));
8865 if (!personalityBundleIdentifier
) {
8866 personality
->setObject(kCFBundleIdentifierKey
, bundleID
);
8867 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
)) {
8868 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
);
8871 result
->setObject(personality
);
8875 if (personalitiesIterator
) personalitiesIterator
->release();
8880 /*********************************************************************
8881 Might want to change this to a bool return?
8882 *********************************************************************/
8884 OSKext::sendPersonalitiesToCatalog(
8886 OSArray
* personalityNames
)
8888 OSReturn result
= kOSReturnSuccess
;
8889 OSArray
* personalitiesToSend
= NULL
; // must release
8890 OSDictionary
* kextPersonalities
= NULL
; // do not release
8893 if (!sLoadEnabled
) {
8895 kOSKextLogErrorLevel
|
8897 "Kext loading is disabled (attempt to start matching for kext %s).",
8898 getIdentifierCString());
8899 result
= kOSKextReturnDisabled
;
8903 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
8905 kOSKextLogErrorLevel
|
8907 "Kext %s is not loadable during safe boot; "
8908 "not sending personalities to the IOCatalogue.",
8909 getIdentifierCString());
8910 result
= kOSKextReturnNotLoadable
;
8914 if (!personalityNames
|| !personalityNames
->getCount()) {
8915 personalitiesToSend
= copyPersonalitiesArray();
8917 kextPersonalities
= OSDynamicCast(OSDictionary
,
8918 getPropertyForHostArch(kIOKitPersonalitiesKey
));
8919 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
8923 personalitiesToSend
= OSArray::withCapacity(0);
8924 if (!personalitiesToSend
) {
8925 result
= kOSKextReturnNoMemory
;
8928 count
= personalityNames
->getCount();
8929 for (i
= 0; i
< count
; i
++) {
8930 OSString
* name
= OSDynamicCast(OSString
,
8931 personalityNames
->getObject(i
));
8935 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
8936 kextPersonalities
->getObject(name
));
8938 personalitiesToSend
->setObject(personality
);
8942 if (personalitiesToSend
) {
8943 unsigned numPersonalities
= personalitiesToSend
->getCount();
8945 kOSKextLogStepLevel
|
8947 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
8948 getIdentifierCString(),
8950 numPersonalities
> 1 ? "ies" : "y",
8951 startMatching
? " and starting matching" : " but not starting matching");
8952 gIOCatalogue
->addDrivers(personalitiesToSend
, startMatching
);
8955 if (personalitiesToSend
) {
8956 personalitiesToSend
->release();
8961 /*********************************************************************
8962 * xxx - We should allow removing the kext's declared personalities,
8963 * xxx - even with other bundle identifiers.
8964 *********************************************************************/
8966 OSKext::removePersonalitiesFromCatalog(void)
8968 OSDictionary
* personality
= NULL
; // do not release
8970 personality
= OSDictionary::withCapacity(1);
8974 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
8977 kOSKextLogStepLevel
|
8979 "Kext %s removing all personalities naming it from the IOCatalogue.",
8980 getIdentifierCString());
8982 /* Have the IOCatalog remove all personalities matching this kext's
8983 * bundle ID and trigger matching anew.
8985 gIOCatalogue
->removeDrivers(personality
, /* startMatching */ true);
8988 if (personality
) personality
->release();
8995 #pragma mark Logging
8997 /*********************************************************************
8998 * Do not call any function that takes sKextLock here!
8999 *********************************************************************/
9002 OSKext::setUserSpaceLogFilter(
9003 OSKextLogSpec newUserLogFilter
,
9006 OSKextLogSpec result
;
9007 bool allocError
= false;
9009 /* Do not call any function that takes sKextLoggingLock during
9010 * this critical block. That means do logging after.
9012 IOLockLock(sKextLoggingLock
);
9014 result
= sUserSpaceKextLogFilter
;
9015 sUserSpaceKextLogFilter
= newUserLogFilter
;
9017 if (newUserLogFilter
&& captureFlag
&&
9018 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
9020 // xxx - do some measurements for a good initial capacity?
9021 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
9022 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
9024 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
9025 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
9026 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
9031 IOLockUnlock(sKextLoggingLock
);
9033 /* If the config flag itself is changing, log the state change
9034 * going both ways, before setting up the user-space log arrays,
9035 * so that this is only logged in the kernel.
9037 if (result
!= newUserLogFilter
) {
9038 OSKextLog(/* kext */ NULL
,
9039 kOSKextLogDebugLevel
|
9040 kOSKextLogGeneralFlag
,
9041 "User-space log flags changed from 0x%x to 0x%x.",
9042 result
, newUserLogFilter
);
9045 OSKextLog(/* kext */ NULL
,
9046 kOSKextLogErrorLevel
|
9047 kOSKextLogGeneralFlag
,
9048 "Failed to allocate user-space log message arrays.");
9054 /*********************************************************************
9055 * Do not call any function that takes sKextLock here!
9056 *********************************************************************/
9059 OSKext::clearUserSpaceLogFilter(void)
9061 OSArray
* result
= NULL
;
9062 OSKextLogSpec oldLogFilter
;
9063 OSKextLogSpec newLogFilter
= kOSKextLogSilentFilter
;
9065 /* Do not call any function that takes sKextLoggingLock during
9066 * this critical block. That means do logging after.
9068 IOLockLock(sKextLoggingLock
);
9070 result
= OSArray::withCapacity(2);
9072 result
->setObject(sUserSpaceLogSpecArray
);
9073 result
->setObject(sUserSpaceLogMessageArray
);
9075 OSSafeReleaseNULL(sUserSpaceLogSpecArray
);
9076 OSSafeReleaseNULL(sUserSpaceLogMessageArray
);
9078 oldLogFilter
= sUserSpaceKextLogFilter
;
9079 sUserSpaceKextLogFilter
= newLogFilter
;
9081 IOLockUnlock(sKextLoggingLock
);
9083 /* If the config flag itself is changing, log the state change
9084 * going both ways, after tearing down the user-space log
9085 * arrays, so this is only logged within the kernel.
9087 if (oldLogFilter
!= newLogFilter
) {
9088 OSKextLog(/* kext */ NULL
,
9089 kOSKextLogDebugLevel
|
9090 kOSKextLogGeneralFlag
,
9091 "User-space log flags changed from 0x%x to 0x%x.",
9092 oldLogFilter
, newLogFilter
);
9099 /*********************************************************************
9100 * Do not call any function that takes sKextLock here!
9101 *********************************************************************/
9104 OSKext::getUserSpaceLogFilter(void)
9106 OSKextLogSpec result
;
9108 IOLockLock(sKextLoggingLock
);
9109 result
= sUserSpaceKextLogFilter
;
9110 IOLockUnlock(sKextLoggingLock
);
9115 /*********************************************************************
9116 * This function is called by OSMetaClass during kernel C++ setup.
9117 * Be careful what you access here; assume only OSKext::initialize()
9120 * Do not call any function that takes sKextLock here!
9121 *********************************************************************/
9122 #define VTRESET "\033[0m"
9124 #define VTBOLD "\033[1m"
9125 #define VTUNDER "\033[4m"
9127 #define VTRED "\033[31m"
9128 #define VTGREEN "\033[32m"
9129 #define VTYELLOW "\033[33m"
9130 #define VTBLUE "\033[34m"
9131 #define VTMAGENTA "\033[35m"
9132 #define VTCYAN "\033[36m"
9134 inline const char * colorForFlags(OSKextLogSpec flags
)
9136 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
9139 case kOSKextLogErrorLevel
:
9140 return VTRED VTBOLD
;
9142 case kOSKextLogWarningLevel
:
9145 case kOSKextLogBasicLevel
:
9146 return VTYELLOW VTUNDER
;
9148 case kOSKextLogProgressLevel
:
9151 case kOSKextLogStepLevel
:
9154 case kOSKextLogDetailLevel
:
9157 case kOSKextLogDebugLevel
:
9167 inline bool logSpecMatch(
9168 OSKextLogSpec msgLogSpec
,
9169 OSKextLogSpec logFilter
)
9171 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
9172 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
9173 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
9175 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
9176 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
9177 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
9179 /* Explicit messages always get logged.
9181 if (msgLevel
== kOSKextLogExplicitLevel
) {
9185 /* Warnings and errors are logged regardless of the flags.
9187 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
9191 /* A verbose message that isn't for a logging-enabled kext and isn't global
9192 * does *not* get logged.
9194 if (!msgKextGlobal
&& !filterKextGlobal
) {
9198 /* Warnings and errors are logged regardless of the flags.
9199 * All other messages must fit the flags and
9200 * have a level at or below the filter.
9203 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
9214 OSKextLogSpec msgLogSpec
,
9215 const char * format
, ...)
9219 va_start(argList
, format
);
9220 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
9227 OSKextLogSpec msgLogSpec
,
9228 const char * format
,
9231 extern int disableConsoleOutput
;
9233 bool logForKernel
= false;
9234 bool logForUser
= false;
9236 char stackBuffer
[120];
9237 uint32_t length
= 0;
9238 char * allocBuffer
= NULL
; // must kfree
9239 OSNumber
* logSpecNum
= NULL
; // must release
9240 OSString
* logString
= NULL
; // must release
9241 char * buffer
= stackBuffer
; // do not free
9243 IOLockLock(sKextLoggingLock
);
9245 /* Set the kext/global bit in the message spec if we have no
9246 * kext or if the kext requests logging.
9248 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
9249 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
9252 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
9253 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
9254 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
9257 if (! (logForKernel
|| logForUser
) ) {
9261 /* No goto from here until past va_end()!
9263 va_copy(argList
, srcArgList
);
9264 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
9267 if (length
+ 1 >= sizeof(stackBuffer
)) {
9268 allocBuffer
= (char *)kalloc((length
+ 1) * sizeof(char));
9273 /* No goto from here until past va_end()!
9275 va_copy(argList
, srcArgList
);
9276 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
9279 buffer
= allocBuffer
;
9282 /* If user space wants the log message, queue it up.
9284 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
9285 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
9286 logString
= OSString::withCString(buffer
);
9287 if (logSpecNum
&& logString
) {
9288 sUserSpaceLogSpecArray
->setObject(logSpecNum
);
9289 sUserSpaceLogMessageArray
->setObject(logString
);
9293 /* Always log messages from the kernel according to the kernel's
9298 /* If we are in console mode and have a custom log filter,
9299 * colorize the log message.
9301 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
9302 const char * color
= ""; // do not free
9303 color
= colorForFlags(msgLogSpec
);
9304 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
9305 buffer
, color
[0] ? VTRESET
: "");
9307 printf("%s\n", buffer
);
9312 IOLockUnlock(sKextLoggingLock
);
9315 kfree(allocBuffer
, (length
+ 1) * sizeof(char));
9317 OSSafeRelease(logString
);
9318 OSSafeRelease(logSpecNum
);
9325 #pragma mark Backtrace Dump & kmod_get_info() support
9327 /*********************************************************************
9328 * This function must be safe to call in panic context.
9329 *********************************************************************/
9332 OSKext::printKextsInBacktrace(
9335 int (* printf_func
)(const char *fmt
, ...),
9338 addr64_t summary_page
= 0;
9339 addr64_t last_summary_page
= 0;
9340 bool found_kmod
= false;
9344 IOLockLock(sKextSummariesLock
);
9347 if (!gLoadedKextSummaries
) {
9348 (*printf_func
)(" can't perform kext scan: no kext summary");
9352 summary_page
= trunc_page((addr64_t
)(uintptr_t)gLoadedKextSummaries
);
9353 last_summary_page
= round_page(summary_page
+ sLoadedKextSummariesAllocSize
);
9354 for (; summary_page
< last_summary_page
; summary_page
+= PAGE_SIZE
) {
9355 if (pmap_find_phys(kernel_pmap
, summary_page
) == 0) {
9356 (*printf_func
)(" can't perform kext scan: "
9357 "missing kext summary page %p", summary_page
);
9362 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
9363 OSKextLoadedKextSummary
* summary
;
9365 summary
= gLoadedKextSummaries
->summaries
+ i
;
9366 if (!summary
->address
) {
9370 if (!summaryIsInBacktrace(summary
, addr
, cnt
)) {
9375 (*printf_func
)(" Kernel Extensions in backtrace:\n");
9379 printSummary(summary
, printf_func
);
9384 IOLockUnlock(sKextSummariesLock
);
9390 /*********************************************************************
9391 * This function must be safe to call in panic context.
9392 *********************************************************************/
9395 OSKext::summaryIsInBacktrace(
9396 OSKextLoadedKextSummary
* summary
,
9402 for (i
= 0; i
< cnt
; i
++) {
9403 vm_offset_t kscan_addr
= addr
[i
];
9404 if ((kscan_addr
>= summary
->address
) &&
9405 (kscan_addr
< (summary
->address
+ summary
->size
)))
9414 /*********************************************************************
9415 * scan list of loaded kext summaries looking for a load address match and if
9416 * found return the UUID C string. If not found then set empty string.
9417 *********************************************************************/
9418 static void findSummaryUUID(
9420 uuid_string_t uuid
);
9422 static void findSummaryUUID(
9428 uuid
[0] = 0x00; // default to no UUID
9430 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
9431 OSKextLoadedKextSummary
* summary
;
9433 summary
= gLoadedKextSummaries
->summaries
+ i
;
9435 if (summary
->loadTag
== tag_ID
) {
9436 (void) uuid_unparse(summary
->uuid
, uuid
);
9443 /*********************************************************************
9444 * This function must be safe to call in panic context.
9445 *********************************************************************/
9446 void OSKext::printSummary(
9447 OSKextLoadedKextSummary
* summary
,
9448 int (* printf_func
)(const char *fmt
, ...))
9450 kmod_reference_t
* kmod_ref
= NULL
;
9452 char version
[kOSKextVersionMaxLength
];
9454 if (!OSKextVersionGetString(summary
->version
, version
, sizeof(version
))) {
9455 strlcpy(version
, "unknown version", sizeof(version
));
9457 (void) uuid_unparse(summary
->uuid
, uuid
);
9459 (*printf_func
)(" %s(%s)[%s]@0x%llx->0x%llx\n",
9460 summary
->name
, version
, uuid
,
9461 summary
->address
, summary
->address
+ summary
->size
- 1);
9463 /* print dependency info */
9464 for (kmod_ref
= (kmod_reference_t
*) summary
->reference_list
;
9466 kmod_ref
= kmod_ref
->next
) {
9467 kmod_info_t
* rinfo
;
9469 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_ref
)) == 0) {
9470 (*printf_func
)(" kmod dependency scan stopped "
9471 "due to missing dependency page: %p\n", kmod_ref
);
9474 rinfo
= kmod_ref
->info
;
9476 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
9477 (*printf_func
)(" kmod dependency scan stopped "
9478 "due to missing kmod page: %p\n", rinfo
);
9482 if (!rinfo
->address
) {
9483 continue; // skip fake entries for built-ins
9486 /* locate UUID in gLoadedKextSummaries */
9487 findSummaryUUID(rinfo
->id
, uuid
);
9489 (*printf_func
)(" dependency: %s(%s)[%s]@%p\n",
9490 rinfo
->name
, rinfo
->version
, uuid
, rinfo
->address
);
9496 /*******************************************************************************
9497 * substitute() looks at an input string (a pointer within a larger buffer)
9498 * for a match to a substring, and on match it writes the marker & substitution
9499 * character to an output string, updating the scan (from) and
9500 * output (to) indexes as appropriate.
9501 *******************************************************************************/
9502 static int substitute(
9503 const char * scan_string
,
9505 uint32_t * to_index
,
9506 uint32_t * from_index
,
9507 const char * substring
,
9511 /* string_out must be at least KMOD_MAX_NAME bytes.
9515 const char * scan_string
,
9517 uint32_t * to_index
,
9518 uint32_t * from_index
,
9519 const char * substring
,
9523 uint32_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
9525 /* On a substring match, append the marker (if there is one) and then
9526 * the substitution character, updating the output (to) index accordingly.
9527 * Then update the input (from) length by the length of the substring
9528 * that got replaced.
9530 if (!strncmp(scan_string
, substring
, substring_length
)) {
9532 string_out
[(*to_index
)++] = marker
;
9534 string_out
[(*to_index
)++] = substitution
;
9535 (*from_index
) += substring_length
;
9541 /*******************************************************************************
9542 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
9543 * KMOD_MAX_NAME characters and performs various substitutions of common
9544 * prefixes & substrings as defined by tables in kext_panic_report.h.
9545 *******************************************************************************/
9546 static void compactIdentifier(
9547 const char * identifier
,
9548 char * identifier_out
,
9549 char ** identifier_out_end
);
9553 const char * identifier
,
9554 char * identifier_out
,
9555 char ** identifier_out_end
)
9557 uint32_t from_index
, to_index
;
9558 uint32_t scan_from_index
= 0;
9559 uint32_t scan_to_index
= 0;
9560 subs_entry_t
* subs_entry
= NULL
;
9563 from_index
= to_index
= 0;
9564 identifier_out
[0] = '\0';
9566 /* Replace certain identifier prefixes with shorter @+character sequences.
9567 * Check the return value of substitute() so we only replace the prefix.
9569 for (subs_entry
= &kext_identifier_prefix_subs
[0];
9570 subs_entry
->substring
&& !did_sub
;
9573 did_sub
= substitute(identifier
, identifier_out
,
9574 &scan_to_index
, &scan_from_index
,
9575 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
9579 /* Now scan through the identifier looking for the common substrings
9580 * and replacing them with shorter !+character sequences via substitute().
9582 for (/* see above */;
9583 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
9586 const char * scan_string
= &identifier
[scan_from_index
];
9590 if (scan_from_index
) {
9591 for (subs_entry
= &kext_identifier_substring_subs
[0];
9592 subs_entry
->substring
&& !did_sub
;
9595 did_sub
= substitute(scan_string
, identifier_out
,
9596 &scan_to_index
, &scan_from_index
,
9597 subs_entry
->substring
, '!', subs_entry
->substitute
);
9601 /* If we didn't substitute, copy the input character to the output.
9604 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
9608 identifier_out
[scan_to_index
] = '\0';
9609 if (identifier_out_end
) {
9610 *identifier_out_end
= &identifier_out
[scan_to_index
];
9616 /*******************************************************************************
9617 * assemble_identifier_and_version() adds to a string buffer a compacted
9618 * bundle identifier followed by a version string.
9619 *******************************************************************************/
9621 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
9623 static int assemble_identifier_and_version(
9624 kmod_info_t
* kmod_info
,
9625 char * identPlusVers
);
9627 assemble_identifier_and_version(
9628 kmod_info_t
* kmod_info
,
9629 char * identPlusVers
)
9633 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
9634 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
9635 identPlusVers
[result
++] = '\t'; // increment for real char
9636 identPlusVers
[result
] = '\0'; // don't increment for nul char
9637 result
= strlcat(identPlusVers
, kmod_info
->version
, KMOD_MAX_NAME
);
9642 /*******************************************************************************
9643 * Assumes sKextLock is held.
9644 *******************************************************************************/
9647 OSKext::saveLoadedKextPanicListTyped(
9648 const char * prefix
,
9653 uint32_t * list_length_ptr
)
9655 uint32_t result
= 0;
9657 unsigned int count
, i
;
9659 count
= sLoadedKexts
->getCount();
9666 OSObject
* rawKext
= sLoadedKexts
->getObject(i
);
9667 OSKext
* theKext
= OSDynamicCast(OSKext
, rawKext
);
9669 char identPlusVers
[2*KMOD_MAX_NAME
];
9670 uint32_t identPlusVersLength
;
9673 printf("OSKext::saveLoadedKextPanicListTyped - "
9674 "NULL kext in loaded kext list; continuing\n");
9679 printf("OSKext::saveLoadedKextPanicListTyped - "
9680 "Kext type cast failed in loaded kext list; continuing\n");
9684 /* Skip all built-in kexts.
9686 if (theKext
->isKernelComponent()) {
9690 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
9692 /* Filter for kmod name (bundle identifier).
9694 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
9695 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
9699 /* Filter for libraries (kexts that have a compatible version).
9701 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
9702 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
9708 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
9710 printf("kext scan stopped due to missing kmod_info page: %p\n",
9716 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
9718 if (!identPlusVersLength
) {
9719 printf("error saving loaded kext info\n");
9723 /* Adding 1 for the newline.
9725 if (*list_length_ptr
+ identPlusVersLength
+ 1 >= list_size
) {
9729 *list_length_ptr
= strlcat(paniclist
, identPlusVers
, list_size
);
9730 *list_length_ptr
= strlcat(paniclist
, "\n", list_size
);
9736 if (*list_length_ptr
+ 1 <= list_size
) {
9737 result
= list_size
- (*list_length_ptr
+ 1);
9744 /*********************************************************************
9745 *********************************************************************/
9748 OSKext::saveLoadedKextPanicList(void)
9750 char * newlist
= NULL
;
9751 uint32_t newlist_size
= 0;
9752 uint32_t newlist_length
= 0;
9755 newlist_size
= KEXT_PANICLIST_SIZE
;
9756 newlist
= (char *)kalloc(newlist_size
);
9759 OSKextLog(/* kext */ NULL
,
9760 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
9761 "Couldn't allocate kext panic log buffer.");
9767 // non-"com.apple." kexts
9768 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
9769 /* libs? */ -1, newlist
, newlist_size
, &newlist_length
)) {
9773 // "com.apple." nonlibrary kexts
9774 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
9775 /* libs? */ 0, newlist
, newlist_size
, &newlist_length
)) {
9779 // "com.apple." library kexts
9780 if (!OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
9781 /* libs? */ 1, newlist
, newlist_size
, &newlist_length
)) {
9786 if (loaded_kext_paniclist
) {
9787 kfree(loaded_kext_paniclist
, loaded_kext_paniclist_size
);
9789 loaded_kext_paniclist
= newlist
;
9790 loaded_kext_paniclist_size
= newlist_size
;
9791 loaded_kext_paniclist_length
= newlist_length
;
9797 /*********************************************************************
9798 * Assumes sKextLock is held.
9799 *********************************************************************/
9801 OSKext::savePanicString(bool isLoading
)
9806 return; // do not goto finish here b/c of lock
9809 len
= assemble_identifier_and_version(kmod_info
,
9810 (isLoading
) ? last_loaded_str
: last_unloaded_str
);
9812 printf("error saving unloaded kext info\n");
9817 last_loaded_strlen
= len
;
9818 last_loaded_address
= (void *)kmod_info
->address
;
9819 last_loaded_size
= kmod_info
->size
;
9820 clock_get_uptime(&last_loaded_timestamp
);
9822 last_unloaded_strlen
= len
;
9823 last_unloaded_address
= (void *)kmod_info
->address
;
9824 last_unloaded_size
= kmod_info
->size
;
9825 clock_get_uptime(&last_unloaded_timestamp
);
9832 /*********************************************************************
9833 *********************************************************************/
9836 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
9838 if (last_loaded_strlen
) {
9839 printf_func("last loaded kext at %llu: %.*s (addr %p, size %lu)\n",
9840 AbsoluteTime_to_scalar(&last_loaded_timestamp
),
9841 last_loaded_strlen
, last_loaded_str
,
9842 last_loaded_address
, last_loaded_size
);
9845 if (last_unloaded_strlen
) {
9846 printf_func("last unloaded kext at %llu: %.*s (addr %p, size %lu)\n",
9847 AbsoluteTime_to_scalar(&last_unloaded_timestamp
),
9848 last_unloaded_strlen
, last_unloaded_str
,
9849 last_unloaded_address
, last_unloaded_size
);
9852 printf_func("loaded kexts:\n");
9853 if (loaded_kext_paniclist
&&
9854 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
9855 loaded_kext_paniclist
[0]) {
9857 printf_func("%.*s", loaded_kext_paniclist_length
, loaded_kext_paniclist
);
9859 printf_func("(none)\n");
9864 /*********************************************************************
9865 * Assumes sKextLock is held.
9866 *********************************************************************/
9869 OSKext::updateLoadedKextSummaries(void)
9871 kern_return_t result
= KERN_FAILURE
;
9872 OSKextLoadedKextSummaryHeader
*summaryHeader
= NULL
;
9873 OSKextLoadedKextSummaryHeader
*summaryHeaderAlloc
= NULL
;
9875 vm_map_offset_t start
, end
;
9876 size_t summarySize
= 0;
9882 IOLockLock(sKextSummariesLock
);
9884 count
= sLoadedKexts
->getCount();
9885 for (i
= 0, numKexts
= 0; i
< count
; ++i
) {
9886 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
9887 numKexts
+= (aKext
&& aKext
->isExecutable());
9890 if (!numKexts
) goto finish
;
9892 /* Calculate the size needed for the new summary headers.
9895 size
= sizeof(*gLoadedKextSummaries
);
9896 size
+= numKexts
* sizeof(*gLoadedKextSummaries
->summaries
);
9897 size
= round_page(size
);
9899 /* If the previous summary is large enough, use it (and be sure to make
9900 * it writable). If it's too small, free it and allocate a new buffer.
9903 if (sPrevLoadedKextSummariesAllocSize
< size
) {
9904 if (sPrevLoadedKextSummaries
) {
9905 kmem_free(kernel_map
, (vm_offset_t
)sPrevLoadedKextSummaries
,
9906 sPrevLoadedKextSummariesAllocSize
);
9907 sPrevLoadedKextSummaries
= NULL
;
9908 sPrevLoadedKextSummariesAllocSize
= 0;
9911 result
= kmem_alloc(kernel_map
,
9912 (vm_offset_t
*)&summaryHeaderAlloc
, size
);
9913 if (result
!= KERN_SUCCESS
) goto finish
;
9915 summaryHeader
= summaryHeaderAlloc
;
9918 summaryHeader
= sPrevLoadedKextSummaries
;
9919 summarySize
= sPrevLoadedKextSummariesAllocSize
;
9921 start
= (vm_map_offset_t
) summaryHeader
;
9922 end
= start
+ summarySize
;
9923 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_DEFAULT
, FALSE
);
9924 if (result
!= KERN_SUCCESS
) goto finish
;
9927 /* Populate the summary header.
9930 bzero(summaryHeader
, summarySize
);
9931 summaryHeader
->version
= kOSKextLoadedKextSummaryVersion
;
9932 summaryHeader
->entry_size
= sizeof(OSKextLoadedKextSummary
);
9933 summaryHeader
->numSummaries
= numKexts
;
9935 /* Populate each kext summary.
9938 count
= sLoadedKexts
->getCount();
9939 for (i
= 0, j
= 0; i
< count
; ++i
) {
9940 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
9941 if (!aKext
|| !aKext
->isExecutable()) continue;
9943 aKext
->updateLoadedKextSummary(&summaryHeader
->summaries
[j
++]);
9946 /* Write protect the buffer and move it into place.
9949 start
= (vm_map_offset_t
) summaryHeader
;
9950 end
= start
+ summarySize
;
9951 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_READ
, FALSE
);
9952 if (result
!= KERN_SUCCESS
) goto finish
;
9954 sPrevLoadedKextSummaries
= gLoadedKextSummaries
;
9955 sPrevLoadedKextSummariesAllocSize
= sLoadedKextSummariesAllocSize
;
9957 gLoadedKextSummaries
= summaryHeader
;
9958 sLoadedKextSummariesAllocSize
= summarySize
;
9960 summaryHeaderAlloc
= NULL
;
9962 /* Call the magic breakpoint function through a static function pointer so
9963 * the compiler can't optimize the function away.
9965 if (sLoadedKextSummariesUpdated
) (*sLoadedKextSummariesUpdated
)();
9968 IOLockUnlock(sKextSummariesLock
);
9970 /* If we had to allocate a new buffer but failed to generate the summaries,
9973 if (summaryHeaderAlloc
) {
9974 kmem_free(kernel_map
, (vm_offset_t
)summaryHeaderAlloc
, summarySize
);
9980 /*********************************************************************
9981 *********************************************************************/
9983 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary
*summary
)
9987 strlcpy(summary
->name
, getIdentifierCString(),
9988 sizeof(summary
->name
));
9992 memcpy(summary
->uuid
, uuid
->getBytesNoCopy(), sizeof(summary
->uuid
));
9993 OSSafeRelease(uuid
);
9996 summary
->address
= kmod_info
->address
;
9997 summary
->size
= kmod_info
->size
;
9998 summary
->version
= getVersion();
9999 summary
->loadTag
= kmod_info
->id
;
10000 summary
->flags
= 0;
10001 summary
->reference_list
= (uint64_t) kmod_info
->reference_list
;
10006 /*********************************************************************
10007 *********************************************************************/
10011 OSKext::getKmodInfo(
10012 kmod_info_array_t
* kmodList
,
10013 mach_msg_type_number_t
* kmodCount
)
10015 kern_return_t result
= KERN_FAILURE
;
10016 vm_offset_t data
= 0;
10017 kmod_info_t
* k
, * kmod_info_scan_ptr
;
10018 kmod_reference_t
* r
, * ref_scan_ptr
;
10022 *kmodList
= (kmod_info_t
*)0;
10025 IORecursiveLockLock(sKextLock
);
10029 size
+= sizeof(kmod_info_t
);
10030 r
= k
->reference_list
;
10032 size
+=sizeof(kmod_reference_t
);
10038 result
= KERN_SUCCESS
;
10042 result
= kmem_alloc(kernel_map
, &data
, size
);
10043 if (result
!= KERN_SUCCESS
) {
10047 /* Copy each kmod_info struct sequentially into the data buffer.
10048 * Set each struct's nonzero 'next' pointer back to itself as a sentinel;
10049 * the kernel space address is used to match refs, and a zero 'next' flags
10050 * the end of kmod_infos in the data buffer and the beginning of references.
10053 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
10055 *kmod_info_scan_ptr
= *k
;
10057 kmod_info_scan_ptr
->next
= k
;
10059 kmod_info_scan_ptr
++;
10063 /* Now add references after the kmod_info structs in the same buffer.
10064 * Update each kmod_info with the ref_count so we can associate
10065 * references with kmod_info structs.
10068 ref_scan_ptr
= (kmod_reference_t
*)kmod_info_scan_ptr
;
10069 kmod_info_scan_ptr
= (kmod_info_t
*)data
;
10071 r
= k
->reference_list
;
10074 /* Note the last kmod_info in the data buffer has its next == 0.
10075 * Since there can only be one like that,
10076 * this case is handled by the caller.
10078 *ref_scan_ptr
= *r
;
10083 /* Stuff the # of refs into the 'reference_list' field of the kmod_info
10084 * struct for the client to interpret.
10086 kmod_info_scan_ptr
->reference_list
= (kmod_reference_t
*)(long)ref_count
;
10087 kmod_info_scan_ptr
++;
10091 result
= vm_map_copyin(kernel_map
, data
, size
, TRUE
, (vm_map_copy_t
*)kmodList
);
10092 if (result
!= KERN_SUCCESS
) {
10097 result
= KERN_SUCCESS
;
10100 IORecursiveLockUnlock(sKextLock
);
10102 if (result
!= KERN_SUCCESS
&& data
) {
10103 kmem_free(kernel_map
, data
, size
);
10104 *kmodList
= (kmod_info_t
*)0;
10109 #endif /* __i386__ */
10111 #pragma mark MAC Framework Support
10113 /*********************************************************************
10114 *********************************************************************/
10115 #if CONFIG_MACF_KEXT
10116 /* MAC Framework support */
10119 * define IOC_DEBUG to display run-time debugging information
10120 * #define IOC_DEBUG 1
10124 #define DPRINTF(x) printf x
10130 /*********************************************************************
10131 *********************************************************************/
10133 MACFObjectIsPrimitiveType(OSObject
* obj
)
10135 const OSMetaClass
* typeID
= NULL
; // do not release
10137 typeID
= OSTypeIDInst(obj
);
10138 if (typeID
== OSTypeID(OSString
) || typeID
== OSTypeID(OSNumber
) ||
10139 typeID
== OSTypeID(OSBoolean
) || typeID
== OSTypeID(OSData
)) {
10146 /*********************************************************************
10147 *********************************************************************/
10149 MACFLengthForObject(OSObject
* obj
)
10151 const OSMetaClass
* typeID
= NULL
; // do not release
10154 typeID
= OSTypeIDInst(obj
);
10155 if (typeID
== OSTypeID(OSString
)) {
10156 OSString
* stringObj
= OSDynamicCast(OSString
, obj
);
10157 len
= stringObj
->getLength() + 1;
10158 } else if (typeID
== OSTypeID(OSNumber
)) {
10159 len
= sizeof("4294967295"); /* UINT32_MAX */
10160 } else if (typeID
== OSTypeID(OSBoolean
)) {
10161 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, obj
);
10162 len
= (boolObj
== kOSBooleanTrue
) ? sizeof("true") : sizeof("false");
10163 } else if (typeID
== OSTypeID(OSData
)) {
10164 OSData
* dataObj
= OSDynamicCast(OSData
, obj
);
10165 len
= dataObj
->getLength();
10172 /*********************************************************************
10173 *********************************************************************/
10175 MACFInitElementFromObject(
10176 struct mac_module_data_element
* element
,
10179 const OSMetaClass
* typeID
= NULL
; // do not release
10181 typeID
= OSTypeIDInst(value
);
10182 if (typeID
== OSTypeID(OSString
)) {
10183 OSString
* stringObj
= OSDynamicCast(OSString
, value
);
10184 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10185 element
->value_size
= stringObj
->getLength() + 1;
10186 DPRINTF(("osdict: string %s size %d\n",
10187 stringObj
->getCStringNoCopy(), element
->value_size
));
10188 memcpy(element
->value
, stringObj
->getCStringNoCopy(),
10189 element
->value_size
);
10190 } else if (typeID
== OSTypeID(OSNumber
)) {
10191 OSNumber
* numberObj
= OSDynamicCast(OSNumber
, value
);
10192 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10193 element
->value_size
= sprintf(element
->value
, "%u",
10194 numberObj
->unsigned32BitValue()) + 1;
10195 } else if (typeID
== OSTypeID(OSBoolean
)) {
10196 OSBoolean
* boolObj
= OSDynamicCast(OSBoolean
, value
);
10197 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10198 if (boolObj
== kOSBooleanTrue
) {
10199 strcpy(element
->value
, "true");
10200 element
->value_size
= 5;
10202 strcpy(element
->value
, "false");
10203 element
->value_size
= 6;
10205 } else if (typeID
== OSTypeID(OSData
)) {
10206 OSData
* dataObj
= OSDynamicCast(OSData
, value
);
10207 element
->value_type
= MAC_DATA_TYPE_PRIMITIVE
;
10208 element
->value_size
= dataObj
->getLength();
10209 DPRINTF(("osdict: data size %d\n", dataObj
->getLength()));
10210 memcpy(element
->value
, dataObj
->getBytesNoCopy(),
10211 element
->value_size
);
10216 /*********************************************************************
10217 * This function takes an OSDictionary and returns a struct mac_module_data
10219 *********************************************************************/
10220 static struct mac_module_data
*
10221 MACFEncodeOSDictionary(OSDictionary
* dict
)
10223 struct mac_module_data
* result
= NULL
; // do not free
10224 const OSMetaClass
* typeID
= NULL
; // do not release
10225 OSString
* key
= NULL
; // do not release
10226 OSCollectionIterator
* keyIterator
= NULL
; // must release
10227 struct mac_module_data_element
* element
= NULL
; // do not free
10228 unsigned int strtabsize
= 0;
10229 unsigned int listtabsize
= 0;
10230 unsigned int dicttabsize
= 0;
10231 unsigned int nkeys
= 0;
10232 unsigned int datalen
= 0;
10233 char * strtab
= NULL
; // do not free
10234 char * listtab
= NULL
; // do not free
10235 char * dicttab
= NULL
; // do not free
10236 vm_offset_t data_addr
= 0;
10238 keyIterator
= OSCollectionIterator::withCollection(dict
);
10239 if (!keyIterator
) {
10243 /* Iterate over OSModuleData to figure out total size */
10244 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
10246 // Get the key's value and determine its type
10247 OSObject
* value
= dict
->getObject(key
);
10252 typeID
= OSTypeIDInst(value
);
10253 if (MACFObjectIsPrimitiveType(value
)) {
10254 strtabsize
+= MACFLengthForObject(value
);
10256 else if (typeID
== OSTypeID(OSArray
)) {
10257 unsigned int k
, cnt
, nents
;
10258 OSArray
* arrayObj
= OSDynamicCast(OSArray
, value
);
10261 cnt
= arrayObj
->getCount();
10262 for (k
= 0; k
< cnt
; k
++) {
10263 value
= arrayObj
->getObject(k
);
10264 typeID
= OSTypeIDInst(value
);
10265 if (MACFObjectIsPrimitiveType(value
)) {
10266 listtabsize
+= MACFLengthForObject(value
);
10269 else if (typeID
== OSTypeID(OSDictionary
)) {
10270 unsigned int dents
= 0;
10271 OSDictionary
* dictObj
= NULL
; // do not release
10272 OSString
* dictkey
= NULL
; // do not release
10273 OSCollectionIterator
* dictIterator
= NULL
; // must release
10275 dictObj
= OSDynamicCast(OSDictionary
, value
);
10276 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
10277 if (!dictIterator
) {
10280 while ((dictkey
= OSDynamicCast(OSString
,
10281 dictIterator
->getNextObject()))) {
10283 OSObject
* dictvalue
= NULL
; // do not release
10285 dictvalue
= dictObj
->getObject(dictkey
);
10289 if (MACFObjectIsPrimitiveType(dictvalue
)) {
10290 strtabsize
+= MACFLengthForObject(dictvalue
);
10292 continue; /* Only handle primitive types here. */
10295 * Allow for the "arraynnn/" prefix in the key length.
10297 strtabsize
+= dictkey
->getLength() + 1;
10300 dictIterator
->release();
10302 dicttabsize
+= sizeof(struct mac_module_data_list
) +
10303 dents
* sizeof(struct mac_module_data_element
);
10308 continue; /* Skip everything else. */
10314 listtabsize
+= sizeof(struct mac_module_data_list
) +
10315 (nents
- 1) * sizeof(struct mac_module_data_element
);
10317 continue; /* skip anything else */
10319 strtabsize
+= key
->getLength() + 1;
10327 * Allocate and fill in the module data structures.
10329 datalen
= sizeof(struct mac_module_data
) +
10330 sizeof(mac_module_data_element
) * (nkeys
- 1) +
10331 strtabsize
+ listtabsize
+ dicttabsize
;
10332 DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n",
10333 datalen
, strtabsize
, listtabsize
, dicttabsize
));
10334 if (kmem_alloc(kernel_map
, &data_addr
, datalen
) != KERN_SUCCESS
) {
10337 result
= (mac_module_data
*)data_addr
;
10338 result
->base_addr
= data_addr
;
10339 result
->size
= datalen
;
10340 result
->count
= nkeys
;
10341 strtab
= (char *)&result
->data
[nkeys
];
10342 listtab
= strtab
+ strtabsize
;
10343 dicttab
= listtab
+ listtabsize
;
10344 DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n",
10345 data_addr
, strtab
, listtab
, dicttab
, data_addr
+ datalen
));
10347 keyIterator
->reset();
10349 element
= &result
->data
[0];
10350 DPRINTF(("osdict: element %p\n", element
));
10351 while ( (key
= OSDynamicCast(OSString
, keyIterator
->getNextObject())) ) {
10353 // Get the key's value and determine its type
10354 OSObject
* value
= dict
->getObject(key
);
10360 DPRINTF(("osdict: element @%p\n", element
));
10361 element
->key
= strtab
;
10362 element
->key_size
= key
->getLength() + 1;
10363 DPRINTF(("osdict: key %s size %d @%p\n", key
->getCStringNoCopy(),
10364 element
->key_size
, strtab
));
10365 memcpy(element
->key
, key
->getCStringNoCopy(), element
->key_size
);
10367 typeID
= OSTypeIDInst(value
);
10368 if (MACFObjectIsPrimitiveType(value
)) {
10370 element
->value
= element
->key
+ element
->key_size
;
10371 DPRINTF(("osdict: primitive element value %p\n", element
->value
));
10372 MACFInitElementFromObject(element
, value
);
10373 strtab
+= element
->key_size
+ element
->value_size
;
10374 DPRINTF(("osdict: new strtab %p\n", strtab
));
10375 } else if (typeID
== OSTypeID(OSArray
)) {
10376 unsigned int k
, cnt
, nents
;
10378 struct mac_module_data_list
*arrayhd
;
10379 struct mac_module_data_element
*ele
;
10380 OSArray
*arrayObj
= OSDynamicCast(OSArray
, value
);
10382 element
->value
= listtab
;
10383 DPRINTF(("osdict: array element value %p\n", element
->value
));
10384 element
->value_type
= MAC_DATA_TYPE_ARRAY
;
10385 arrayhd
= (struct mac_module_data_list
*)element
->value
;
10387 DPRINTF(("osdict: arrayhd %p\n", arrayhd
));
10389 astrtab
= strtab
+ element
->key_size
;
10390 ele
= &(arrayhd
->list
[0]);
10391 cnt
= arrayObj
->getCount();
10392 for (k
= 0; k
< cnt
; k
++) {
10393 value
= arrayObj
->getObject(k
);
10394 DPRINTF(("osdict: array ele %d @%p\n", nents
, ele
));
10397 typeID
= OSTypeIDInst(value
);
10398 if (MACFObjectIsPrimitiveType(value
)) {
10399 if (arrayhd
->type
!= 0 &&
10400 arrayhd
->type
!= MAC_DATA_TYPE_PRIMITIVE
) {
10404 arrayhd
->type
= MAC_DATA_TYPE_PRIMITIVE
;
10405 ele
->value
= astrtab
;
10406 MACFInitElementFromObject(ele
, value
);
10407 astrtab
+= ele
->value_size
;
10408 DPRINTF(("osdict: array new astrtab %p\n", astrtab
));
10409 } else if (typeID
== OSTypeID(OSDictionary
)) {
10410 unsigned int dents
;
10411 char * dstrtab
= NULL
; // do not free
10412 OSDictionary
* dictObj
= NULL
; // do not release
10413 OSString
* dictkey
= NULL
; // do not release
10414 OSCollectionIterator
* dictIterator
= NULL
; // must release
10415 struct mac_module_data_list
* dicthd
= NULL
; // do not free
10416 struct mac_module_data_element
* dele
= NULL
; // do not free
10418 if (arrayhd
->type
!= 0 &&
10419 arrayhd
->type
!= MAC_DATA_TYPE_DICT
) {
10423 dictObj
= OSDynamicCast(OSDictionary
, value
);
10424 dictIterator
= OSCollectionIterator::withCollection(dictObj
);
10425 if (!dictIterator
) {
10428 DPRINTF(("osdict: dict\n"));
10429 ele
->value
= dicttab
;
10430 ele
->value_type
= MAC_DATA_TYPE_DICT
;
10431 dicthd
= (struct mac_module_data_list
*)ele
->value
;
10432 DPRINTF(("osdict: dicthd %p\n", dicthd
));
10435 while ((dictkey
= OSDynamicCast(OSString
,
10436 dictIterator
->getNextObject()))) {
10438 OSObject
* dictvalue
= NULL
; // do not release
10440 dictvalue
= dictObj
->getObject(dictkey
);
10444 dele
= &(dicthd
->list
[dents
]);
10445 DPRINTF(("osdict: dict ele %d @%p\n", dents
, dele
));
10446 if (MACFObjectIsPrimitiveType(dictvalue
)) {
10447 dele
->key
= dstrtab
;
10448 dele
->key_size
= dictkey
->getLength() + 1;
10449 DPRINTF(("osdict: dictkey %s size %d @%p\n",
10450 dictkey
->getCStringNoCopy(), dictkey
->getLength(), dstrtab
));
10451 memcpy(dele
->key
, dictkey
->getCStringNoCopy(),
10453 dele
->value
= dele
->key
+ dele
->key_size
;
10454 MACFInitElementFromObject(dele
, dictvalue
);
10455 dstrtab
+= dele
->key_size
+ dele
->value_size
;
10456 DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab
));
10458 continue; /* Only handle primitive types here. */
10462 dictIterator
->release();
10466 arrayhd
->type
= MAC_DATA_TYPE_DICT
;
10467 ele
->value_size
= sizeof(struct mac_module_data_list
) +
10468 (dents
- 1) * sizeof(struct mac_module_data_element
);
10469 DPRINTF(("osdict: dict ele size %d ents %d\n", ele
->value_size
, dents
));
10470 dicttab
+= ele
->value_size
;
10471 DPRINTF(("osdict: new dicttab %p\n", dicttab
));
10472 dicthd
->count
= dents
;
10475 continue; /* Skip everything else. */
10483 element
->value_size
= sizeof(struct mac_module_data_list
) +
10484 (nents
- 1) * sizeof(struct mac_module_data_element
);
10485 listtab
+= element
->value_size
;
10486 DPRINTF(("osdict: new listtab %p\n", listtab
));
10487 arrayhd
->count
= nents
;
10489 DPRINTF(("osdict: new strtab %p\n", strtab
));
10491 continue; /* skip anything else */
10495 DPRINTF(("result list @%p, key %p value %p\n",
10496 result
, result
->data
[0].key
, result
->data
[0].value
));
10498 if (keyIterator
) keyIterator
->release();
10502 /*********************************************************************
10503 * This function takes a plist and looks for an OSModuleData dictionary.
10504 * If it is found, an encoded copy is returned. The value must be
10506 *********************************************************************/
10508 MACFCopyModuleDataForKext(
10510 mach_msg_type_number_t
* datalen
)
10513 struct mac_module_data
* result
= NULL
;
10514 OSDictionary
* kextModuleData
= NULL
; // do not release
10515 vm_map_copy_t copy
= 0;
10517 kextModuleData
= OSDynamicCast(OSDictionary
,
10518 theKext
->getPropertyForHostArch("OSModuleData"));
10519 if (!kextModuleData
) {
10523 result
= MACFEncodeOSDictionary(kextModuleData
);
10527 *datalen
= module_data
->size
;
10530 return (void *)result
;
10532 #endif /* CONFIG_MACF_KEXT */