2 * Copyright (c) 2008-2016 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@
29 #define IOKIT_ENABLE_SHARED_PTR
33 #include <kern/clock.h>
34 #include <kern/host.h>
35 #include <kern/kext_alloc.h>
36 #include <firehose/tracepoint_private.h>
37 #include <firehose/chunk_private.h>
38 #include <os/firehose_buffer_private.h>
39 #include <vm/vm_kern.h>
40 #include <vm/vm_map.h>
41 #include <kextd/kextd_mach.h>
42 #include <libkern/kernel_mach_header.h>
43 #include <libkern/kext_panic_report.h>
44 #include <libkern/kext_request_keys.h>
45 #include <libkern/mkext.h>
46 #include <libkern/prelink.h>
47 #include <libkern/version.h>
48 #include <libkern/zlib.h>
49 #include <mach/host_special_ports.h>
50 #include <mach/mach_vm.h>
51 #include <mach/mach_time.h>
52 #include <sys/sysctl.h>
53 #include <uuid/uuid.h>
54 #include <sys/random.h>
55 #include <pexpert/pexpert.h>
60 #include <sys/kauth.h>
61 #include <security/mac_framework.h>
67 #include <sys/vnode.h>
68 #endif /* CONFIG_CSR */
71 #include <os/cpp_util.h>
73 #include <libkern/OSKextLibPrivate.h>
74 #include <libkern/c++/OSKext.h>
75 #include <libkern/c++/OSLib.h>
77 #include <IOKit/IOLib.h>
78 #include <IOKit/IOCatalogue.h>
79 #include <IOKit/IORegistryEntry.h>
80 #include <IOKit/IOService.h>
81 #include <IOKit/IOUserServer.h>
83 #include <IOKit/IOStatisticsPrivate.h>
84 #include <IOKit/IOBSD.h>
85 #include <IOKit/IOPlatformExpert.h>
87 #include <san/kasan.h>
90 #pragma mark External & Internal Function Protos
92 /*********************************************************************
93 *********************************************************************/
95 extern int IODTGetLoaderInfo(const char * key
, void ** infoAddr
, int * infoSize
);
96 extern void IODTFreeLoaderInfo(const char * key
, void * infoAddr
, int infoSize
);
98 extern ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
); /* osfmk/machine/pmap.h */
99 extern int dtrace_keep_kernel_symbols(void);
101 #if defined(__x86_64__) || defined(__i386__)
102 extern kern_return_t
i386_slide_individual_kext(kernel_mach_header_t
*mh
, uintptr_t slide
);
103 extern kern_return_t
i386_slide_kext_collection_mh_addrs(kernel_mach_header_t
*mh
, uintptr_t slide
, bool adjust_mach_headers
);
104 extern void *ubc_getobject_from_filename(const char *filename
, struct vnode
**, off_t
*file_size
);
105 static void *allocate_kcfileset_map_entry_list(void);
106 static void add_kcfileset_map_entry(void *map_entry_list
, vm_map_offset_t start
, vm_map_offset_t size
);
107 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list
, boolean_t unmap_entries
, bool pageable
);
108 int vnode_put(struct vnode
*vp
);
109 kern_return_t
vm_map_kcfileset_segment(vm_map_offset_t
*start
, vm_map_offset_t size
,
110 void *control
, vm_object_offset_t fileoffset
, vm_prot_t max_prot
);
111 kern_return_t
vm_unmap_kcfileset_segment(vm_map_offset_t
*start
, vm_map_offset_t size
);
112 void * ubc_getobject(struct vnode
*vp
, __unused
int flags
);
113 #endif //(__x86_64__) || defined(__i386__)
116 extern unsigned long gVirtBase
;
117 extern unsigned long gPhysBase
;
118 extern vm_map_t g_kext_map
;
120 bool pageableKCloaded
= false;
121 bool auxKCloaded
= false;
122 bool resetAuxKCSegmentOnUnload
= false;
124 extern boolean_t pageablekc_uuid_valid
;
125 extern uuid_t pageablekc_uuid
;
126 extern uuid_string_t pageablekc_uuid_string
;
128 extern boolean_t auxkc_uuid_valid
;
129 extern uuid_t auxkc_uuid
;
130 extern uuid_string_t auxkc_uuid_string
;
132 static OSReturn
_OSKextCreateRequest(
133 const char * predicate
,
134 OSSharedPtr
<OSDictionary
> & requestP
);
135 static OSString
* _OSKextGetRequestPredicate(OSDictionary
* requestDict
);
136 static OSObject
* _OSKextGetRequestArgument(
137 OSDictionary
* requestDict
,
138 const char * argName
);
139 static bool _OSKextSetRequestArgument(
140 OSDictionary
* requestDict
,
141 const char * argName
,
143 static void * _OSKextExtractPointer(OSData
* wrapper
);
144 static OSKextRequestResourceCallback
_OSKextExtractCallbackPointer(OSData
* wrapper
);
145 static OSReturn
_OSDictionarySetCStringValue(
149 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol
* theBundleID
);
151 static bool _OSKextInPrelinkRebuildWindow(void);
154 // We really should add containsObject() & containsCString to OSCollection & subclasses.
155 // So few pad slots, though....
156 static bool _OSArrayContainsCString(OSArray
* array
, const char * cString
);
157 static void OSKextLogKextInfo(OSKext
*aKext
, uint64_t address
, uint64_t size
, firehose_tracepoint_code_t code
);
159 /* Prelinked arm kexts do not have VM entries because the method we use to
160 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
161 * not work on ARM. To get around that, we must free prelinked kext
162 * executables with ml_static_mfree() instead of kext_free().
164 #if __i386__ || __x86_64__
165 #define VM_MAPPED_KEXTS 1
166 #define KASLR_KEXT_DEBUG 0
167 #define KASLR_IOREG_DEBUG 0
168 #elif __arm__ || __arm64__
169 #define VM_MAPPED_KEXTS 0
170 #define KASLR_KEXT_DEBUG 0
172 #error Unsupported architecture
176 #pragma mark Constants & Macros
178 /*********************************************************************
180 *********************************************************************/
182 /* Use this number to create containers.
184 #define kOSKextTypicalLoadCount (150)
186 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
187 * A loaded kext will no dependents or external retains will have 2 retains.
189 #define kOSKextMinRetainCount (1)
190 #define kOSKextMinLoadedRetainCount (2)
193 * Strings and substrings used in dependency resolution.
195 #define APPLE_KEXT_PREFIX "com.apple."
196 #define KERNEL_LIB "com.apple.kernel"
198 #define PRIVATE_KPI "com.apple.kpi.private"
200 /* Version for compatbility pseudokexts (com.apple.kernel.*),
201 * compatible back to v6.0.
203 #define KERNEL6_LIB "com.apple.kernel.6.0"
204 #define KERNEL6_VERSION "7.9.9"
206 #define KERNEL_LIB_PREFIX "com.apple.kernel."
207 #define KPI_LIB_PREFIX "com.apple.kpi."
209 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
211 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
212 #define MINIMUM_WAKEUP_SECONDS (30)
214 /*********************************************************************
215 * infoDict keys for internally-stored data. Saves on ivar slots for
216 * objects we don't keep around past boot time or during active load.
217 *********************************************************************/
219 /* A usable, uncompressed file is stored under this key.
221 #define _kOSKextExecutableKey "_OSKextExecutable"
223 /* An indirect reference to the executable file from an mkext
224 * is stored under this key.
226 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
228 /* If the file is contained in a larger buffer laid down by the booter or
229 * sent from user space, the OSKext stores that OSData under this key so that
230 * references are properly tracked. This is always an mkext, right now.
232 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
234 #define OS_LOG_HDR_VERSION 1
235 #define NUM_OS_LOG_SECTIONS 2
237 #define OS_LOG_SECT_IDX 0
238 #define CSTRING_SECT_IDX 1
241 #pragma mark Typedefs
243 /*********************************************************************
245 *********************************************************************/
247 /*********************************************************************
248 * osLogDataHeaderRef describes the header information of an OSData
249 * object that is returned when querying for kOSBundleLogStringsKey.
250 * We currently return information regarding 2 sections - os_log and
251 * cstring. In the case that the os_log section doesn't exist, we just
252 * return an offset and length of 0 for that section.
253 *********************************************************************/
254 typedef struct osLogDataHeader
{
258 uint32_t sect_offset
;
261 } osLogDataHeaderRef
;
263 /*********************************************************************
264 * MkextEntryRef describes the contents of an OSData object
265 * referencing a file entry from an mkext so that we can uncompress
266 * (if necessary) and extract it on demand.
268 * It contains the mkextVersion in case we ever wind up supporting
269 * multiple mkext formats. Mkext format 1 is officially retired as of
271 *********************************************************************/
272 typedef struct MkextEntryRef
{
273 mkext_basic_header
* mkext
; // beginning of whole mkext file
274 void * fileinfo
;// mkext2_file_entry or equiv; see mkext.h
278 #pragma mark Global and static Module Variables
280 /*********************************************************************
281 * Global & static variables, used to keep track of kexts.
282 *********************************************************************/
284 static bool sPrelinkBoot
= false;
285 static bool sSafeBoot
= false;
286 static bool sKeepSymbols
= false;
287 static bool sPanicOnKCMismatch
= false;
288 static bool sOSKextWasResetAfterUserspaceReboot
= false;
290 /*********************************************************************
291 * sKextLock is the principal lock for OSKext, and guards all static
292 * and global variables not owned by other locks (declared further
293 * below). It must be taken by any entry-point method or function,
294 * including internal functions called on scheduled threads.
296 * sKextLock and sKextInnerLock are recursive due to multiple functions
297 * that are called both externally and internally. The other locks are
300 * Which locks are taken depends on what they protect, but if more than
301 * one must be taken, they must always be locked in this order
302 * (and unlocked in reverse order) to prevent deadlocks:
306 * 3. sKextSummariesLock
307 * 4. sKextLoggingLock
309 static IORecursiveLock
* sKextLock
= NULL
;
311 static OSSharedPtr
<OSDictionary
> sKextsByID
;
312 static OSSharedPtr
<OSDictionary
> sExcludeListByID
;
313 static OSKextVersion sExcludeListVersion
= 0;
314 static OSSharedPtr
<OSArray
> sLoadedKexts
;
315 static OSSharedPtr
<OSDictionary
> sNonLoadableKextsByID
;
316 static OSSharedPtr
<OSArray
> sUnloadedPrelinkedKexts
;
317 static OSSharedPtr
<OSArray
> sLoadedDriverKitKexts
;
319 // Requests to the IOKit daemon waiting to be picked up.
320 static OSSharedPtr
<OSArray
> sKernelRequests
;
321 // Identifier of kext load requests in sKernelRequests
322 static OSSharedPtr
<OSSet
> sPostedKextLoadIdentifiers
;
323 static OSSharedPtr
<OSArray
> sRequestCallbackRecords
;
325 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
326 static OSSharedPtr
<OSSet
> sAllKextLoadIdentifiers
;
328 static KXLDContext
* sKxldContext
= NULL
;
330 static uint32_t sNextLoadTag
= 0;
331 static uint32_t sNextRequestTag
= 0;
333 static bool sUserLoadsActive
= false;
334 static bool sIOKitDaemonActive
= false;
335 static bool sDeferredLoadSucceeded
= false;
336 static bool sConsiderUnloadsExecuted
= false;
339 static bool sKernelRequestsEnabled
= false;
341 static bool sKernelRequestsEnabled
= true;
343 static bool sLoadEnabled
= true;
344 static bool sUnloadEnabled
= true;
346 /*********************************************************************
347 * Stuff for the OSKext representing the kernel itself.
349 static OSKext
* sKernelKext
= NULL
;
351 /* Set up a fake kmod_info struct for the kernel.
352 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
353 * before OSKext is initialized; that call only needs the name
354 * and address to be set correctly.
356 * We don't do much else with the kerne's kmod_info; we never
357 * put it into the kmod list, never adjust the reference count,
358 * and never have kernel components reference it.
359 * For that matter, we don't do much with kmod_info structs
360 * at all anymore! We just keep them filled in for gdb and
361 * binary compability.
363 kmod_info_t g_kernel_kmod_info
= {
365 .info_version
= KMOD_INFO_VERSION
,
366 .id
= 0, // loadTag: kernel is always 0
367 .name
= kOSKextKernelIdentifier
,// bundle identifier
368 .version
= "0", // filled in in OSKext::initialize()
369 .reference_count
= -1, // never adjusted; kernel never unloads
370 .reference_list
= NULL
,
372 .size
= 0, // filled in in OSKext::initialize()
378 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
380 kmod_info_t invalid_kmod_info
= {
382 .info_version
= KMOD_INFO_VERSION
,
386 .reference_count
= -1,
387 .reference_list
= NULL
,
396 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
397 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
398 // misc_protos.h, db_low_trace.c, kgmacros
399 // 'kmod' is a holdover from the old kmod system, we can't rename it.
400 kmod_info_t
* kmod
= NULL
;
402 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
405 static char * loaded_kext_paniclist
= NULL
;
406 static uint32_t loaded_kext_paniclist_size
= 0;
408 AbsoluteTime last_loaded_timestamp
;
409 static char last_loaded_str_buf
[2 * KMOD_MAX_NAME
];
410 static u_long last_loaded_strlen
= 0;
411 static void * last_loaded_address
= NULL
;
412 static u_long last_loaded_size
= 0;
414 AbsoluteTime last_unloaded_timestamp
;
415 static char last_unloaded_str_buf
[2 * KMOD_MAX_NAME
];
416 static u_long last_unloaded_strlen
= 0;
417 static void * last_unloaded_address
= NULL
;
418 static u_long last_unloaded_size
= 0;
420 // Statically linked kmods described by several mach-o sections:
422 // kPrelinkInfoSegment:kBuiltinInfoSection
423 // Array of pointers to kmod_info_t structs.
425 // kPrelinkInfoSegment:kBuiltinInfoSection
426 // Array of pointers to an embedded mach-o header.
428 // __DATA:kBuiltinInitSection, kBuiltinTermSection
429 // Structors for all kmods. Has to be filtered by proc address.
432 static uint32_t gBuiltinKmodsCount
;
433 static kernel_section_t
* gBuiltinKmodsSectionInfo
;
434 static kernel_section_t
* gBuiltinKmodsSectionStart
;
436 const OSSymbol
* gIOSurfaceIdentifier
;
437 vm_tag_t gIOSurfaceTag
;
439 /*********************************************************************
440 * sKextInnerLock protects against cross-calls with IOService and
441 * IOCatalogue, and owns the variables declared immediately below.
443 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
445 * When both sKextLock and sKextInnerLock need to be taken,
446 * always lock sKextLock first and unlock it second. Never take both
447 * locks in an entry point to OSKext; if you need to do so, you must
448 * spawn an independent thread to avoid potential deadlocks for threads
449 * calling into OSKext.
451 static IORecursiveLock
* sKextInnerLock
= NULL
;
453 static bool sAutounloadEnabled
= true;
454 static bool sConsiderUnloadsCalled
= false;
455 static bool sConsiderUnloadsPending
= false;
457 static unsigned int sConsiderUnloadDelay
= 60; // seconds
458 static thread_call_t sUnloadCallout
= NULL
;
460 static thread_call_t sDestroyLinkContextThread
= NULL
; // one-shot, one-at-a-time thread
461 #endif // CONFIG_KXLD
462 static bool sSystemSleep
= false; // true when system going to sleep
463 static AbsoluteTime sLastWakeTime
; // last time we woke up
465 /*********************************************************************
466 * Backtraces can be printed at various times so we need a tight lock
467 * on data used for that. sKextSummariesLock protects the variables
468 * declared immediately below.
470 * gLoadedKextSummaries is accessed by other modules, but only during
471 * a panic so the lock isn't needed then.
473 * gLoadedKextSummaries has the "used" attribute in order to ensure
474 * that it remains visible even when we are performing extremely
475 * aggressive optimizations, as it is needed to allow the debugger
476 * to automatically parse the list of loaded kexts.
478 static IOLock
* sKextSummariesLock
= NULL
;
479 extern "C" lck_spin_t vm_allocation_sites_lock
;
480 static IOSimpleLock
* sKextAccountsLock
= &vm_allocation_sites_lock
;
482 void(*const sLoadedKextSummariesUpdated
)(void) = OSKextLoadedKextSummariesUpdated
;
483 OSKextLoadedKextSummaryHeader
* gLoadedKextSummaries
__attribute__((used
)) = NULL
;
484 uint64_t gLoadedKextSummariesTimestamp
__attribute__((used
)) = 0;
485 static size_t sLoadedKextSummariesAllocSize
= 0;
487 static OSKextActiveAccount
* sKextAccounts
;
488 static uint32_t sKextAccountsCount
;
491 /*********************************************************************
492 * sKextLoggingLock protects the logging variables declared immediately below.
494 static IOLock
* sKextLoggingLock
= NULL
;
496 static const OSKextLogSpec kDefaultKernelLogFilter
= kOSKextLogBasicLevel
|
497 kOSKextLogVerboseFlagsMask
;
498 static OSKextLogSpec sKernelLogFilter
= kDefaultKernelLogFilter
;
499 static bool sBootArgLogFilterFound
= false;
500 SYSCTL_UINT(_debug
, OID_AUTO
, kextlog
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &sKernelLogFilter
,
501 0, "kernel kext logging");
503 static OSKextLogSpec sUserSpaceKextLogFilter
= kOSKextLogSilentFilter
;
504 static OSSharedPtr
<OSArray
> sUserSpaceLogSpecArray
;
505 static OSSharedPtr
<OSArray
> sUserSpaceLogMessageArray
;
508 * End scope for sKextInnerLock-protected variables.
509 *********************************************************************/
512 /*********************************************************************
513 * helper function used for collecting PGO data upon unload of a kext
516 static int OSKextGrabPgoDataLocked(OSKext
*kext
,
518 uuid_t instance_uuid
,
521 uint64_t bufferSize
);
523 /**********************************************************************/
528 #pragma mark OSData callbacks (need to move to OSData)
530 /*********************************************************************
531 * C functions used for callbacks.
532 *********************************************************************/
535 osdata_kmem_free(void * ptr
, unsigned int length
)
537 kmem_free(kernel_map
, (vm_address_t
)ptr
, length
);
542 osdata_phys_free(void * ptr
, unsigned int length
)
544 ml_static_mfree((vm_offset_t
)ptr
, length
);
549 osdata_vm_deallocate(void * ptr
, unsigned int length
)
551 (void)vm_deallocate(kernel_map
, (vm_offset_t
)ptr
, length
);
556 osdata_kext_free(void * ptr
, unsigned int length
)
558 (void)kext_free((vm_offset_t
)ptr
, length
);
563 #pragma mark KXLD Allocation Callback
566 /*********************************************************************
567 * KXLD Allocation Callback
568 *********************************************************************/
572 KXLDAllocateFlags
* flags
,
575 vm_address_t result
= 0; // returned
576 kern_return_t mach_result
= KERN_FAILURE
;
577 bool success
= false;
578 OSKext
* theKext
= (OSKext
*)user_data
;
579 unsigned int roundSize
= 0;
580 OSSharedPtr
<OSData
> linkBuffer
;
582 if (round_page(size
) > UINT_MAX
) {
584 kOSKextLogErrorLevel
|
585 kOSKextLogGeneralFlag
,
586 "%s: Requested memory size is greater than UINT_MAX.",
587 theKext
->getIdentifierCString());
591 roundSize
= (unsigned int)round_page(size
);
593 mach_result
= kext_alloc(&result
, roundSize
, /* fixed */ FALSE
);
594 if (mach_result
!= KERN_SUCCESS
) {
596 kOSKextLogErrorLevel
|
597 kOSKextLogGeneralFlag
,
598 "Can't allocate kernel memory to link %s.",
599 theKext
->getIdentifierCString());
603 /* Create an OSData wrapper for the allocated buffer.
605 linkBuffer
= OSData::withBytesNoCopy((void *)result
, roundSize
);
608 kOSKextLogErrorLevel
|
609 kOSKextLogGeneralFlag
,
610 "Can't allocate linked executable wrapper for %s.",
611 theKext
->getIdentifierCString());
614 linkBuffer
->setDeallocFunction(osdata_kext_free
);
616 kOSKextLogProgressLevel
|
617 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
618 "Allocated link buffer for kext %s at %p (%lu bytes).",
619 theKext
->getIdentifierCString(),
620 (void *)result
, (unsigned long)roundSize
);
622 theKext
->setLinkedExecutable(linkBuffer
.get());
624 *flags
= kKxldAllocateWritable
;
628 if (!success
&& result
) {
629 kext_free(result
, roundSize
);
633 return (kxld_addr_t
)result
;
636 /*********************************************************************
637 *********************************************************************/
640 KXLDLogSubsystem subsystem
,
646 OSKext
*theKext
= (OSKext
*) user_data
;
647 OSKextLogSpec logSpec
= 0;
650 case kKxldLogLinking
:
651 logSpec
|= kOSKextLogLinkFlag
;
653 case kKxldLogPatching
:
654 logSpec
|= kOSKextLogPatchFlag
;
659 case kKxldLogExplicit
:
660 logSpec
|= kOSKextLogExplicitLevel
;
663 logSpec
|= kOSKextLogErrorLevel
;
666 logSpec
|= kOSKextLogWarningLevel
;
669 logSpec
|= kOSKextLogProgressLevel
;
672 logSpec
|= kOSKextLogDetailLevel
;
675 logSpec
|= kOSKextLogDebugLevel
;
679 OSKextVLog(theKext
, logSpec
, format
, argList
);
681 #endif // CONFIG_KXLD
684 #pragma mark IOStatistics defines
689 #define notifyKextLoadObservers(kext, kmod_info) \
691 IOStatistics::onKextLoad(kext, kmod_info); \
694 #define notifyKextUnloadObservers(kext) \
696 IOStatistics::onKextUnload(kext); \
699 #define notifyAddClassObservers(kext, addedClass, flags) \
701 IOStatistics::onClassAdded(kext, addedClass); \
704 #define notifyRemoveClassObservers(kext, removedClass, flags) \
706 IOStatistics::onClassRemoved(kext, removedClass); \
711 #define notifyKextLoadObservers(kext, kmod_info)
712 #define notifyKextUnloadObservers(kext)
713 #define notifyAddClassObservers(kext, addedClass, flags)
714 #define notifyRemoveClassObservers(kext, removedClass, flags)
716 #endif /* IOKITSTATS */
719 #pragma mark Module Config (Startup & Shutdown)
721 /*********************************************************************
722 * Module Config (Class Definition & Class Methods)
723 *********************************************************************/
724 #define super OSObject
725 OSDefineMetaClassAndStructors(OSKext
, OSObject
)
727 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment
, OSObject
);
729 /*********************************************************************
730 *********************************************************************/
733 OSKext::initialize(void)
735 OSSharedPtr
<OSData
> kernelExecutable
= NULL
;// do not release
736 u_char
* kernelStart
= NULL
;// do not free
737 size_t kernelLength
= 0;
738 IORegistryEntry
* registryRoot
= NULL
;// do not release
739 OSSharedPtr
<OSNumber
> kernelCPUType
;
740 OSSharedPtr
<OSNumber
> kernelCPUSubtype
;
741 OSKextLogSpec bootLogFilter
= kOSKextLogSilentFilter
;
742 bool setResult
= false;
743 uint64_t * timestamp
= NULL
;
744 __unused
char bootArgBuffer
[16];// for PE_parse_boot_argn w/strings
746 /* This must be the first thing allocated. Everything else grabs this lock.
748 sKextLock
= IORecursiveLockAlloc();
749 sKextInnerLock
= IORecursiveLockAlloc();
750 sKextSummariesLock
= IOLockAlloc();
751 sKextLoggingLock
= IOLockAlloc();
753 assert(sKextInnerLock
);
754 assert(sKextSummariesLock
);
755 assert(sKextLoggingLock
);
757 sKextsByID
= OSDictionary::withCapacity(kOSKextTypicalLoadCount
);
758 sLoadedKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
);
759 sLoadedDriverKitKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
);
760 sUnloadedPrelinkedKexts
= OSArray::withCapacity(kOSKextTypicalLoadCount
/ 10);
761 sKernelRequests
= OSArray::withCapacity(0);
762 sPostedKextLoadIdentifiers
= OSSet::withCapacity(0);
763 sAllKextLoadIdentifiers
= OSSet::withCapacity(kOSKextTypicalLoadCount
);
764 sRequestCallbackRecords
= OSArray::withCapacity(0);
765 assert(sKextsByID
&& sLoadedKexts
&& sLoadedDriverKitKexts
&& sKernelRequests
&&
766 sPostedKextLoadIdentifiers
&& sAllKextLoadIdentifiers
&&
767 sRequestCallbackRecords
&& sUnloadedPrelinkedKexts
);
769 /* Read the log flag boot-args and set the log flags.
771 if (PE_parse_boot_argn("kextlog", &bootLogFilter
, sizeof(bootLogFilter
))) {
772 sBootArgLogFilterFound
= true;
773 sKernelLogFilter
= bootLogFilter
;
774 // log this if any flags are set
775 OSKextLog(/* kext */ NULL
,
776 kOSKextLogBasicLevel
|
778 "Kernel kext log filter 0x%x per kextlog boot arg.",
779 (unsigned)sKernelLogFilter
);
782 #if !defined(__arm__) && !defined(__arm64__)
784 * On our ARM targets, the kernelcache/boot kernel collection contains
785 * the set of kexts required to boot, as specified by KCB. Safeboot is
786 * either unsupported, or is supported by the bootloader only loading
787 * the boot kernel collection; as a result OSKext has no role to play
788 * in safeboot policy on ARM.
790 sSafeBoot
= PE_parse_boot_argn("-x", bootArgBuffer
,
791 sizeof(bootArgBuffer
)) ? true : false;
792 #endif /* defined(__arm__) && defined(__arm64__) */
795 OSKextLog(/* kext */ NULL
,
796 kOSKextLogWarningLevel
|
797 kOSKextLogGeneralFlag
,
798 "SAFE BOOT DETECTED - "
799 "only valid OSBundleRequired kexts will be loaded.");
802 PE_parse_boot_argn("keepsyms", &sKeepSymbols
, sizeof(sKeepSymbols
));
804 if (dtrace_keep_kernel_symbols()) {
807 #endif /* CONFIG_DTRACE */
808 #if KASAN_DYNAMIC_BLACKLIST
809 /* needed for function lookup */
814 * Should we panic when the SystemKC is not linked against the
815 * BootKC that was loaded by the booter? By default: yes, if the
816 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
817 * on mis-match and instead just print an error and continue.
819 sPanicOnKCMismatch
= PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer
,
820 sizeof(bootArgBuffer
)) ? false : true;
822 /* Set up an OSKext instance to represent the kernel itself.
824 sKernelKext
= new OSKext
;
827 kernelStart
= (u_char
*)&_mh_execute_header
;
828 kernelLength
= getlastaddr() - (vm_offset_t
)kernelStart
;
829 assert(kernelLength
<= UINT_MAX
);
830 kernelExecutable
= OSData::withBytesNoCopy(
831 kernelStart
, (unsigned int)kernelLength
);
832 assert(kernelExecutable
);
835 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
836 (unsigned long)kernelStart
,
837 (unsigned long)getlastaddr(),
839 (unsigned long)vm_kernel_slide
,
840 (unsigned long)vm_kernel_slide
);
843 sKernelKext
->loadTag
= sNextLoadTag
++; // the kernel is load tag 0
844 sKernelKext
->bundleID
= OSSymbol::withCString(kOSKextKernelIdentifier
);
846 sKernelKext
->version
= OSKextParseVersionString(osrelease
);
847 sKernelKext
->compatibleVersion
= sKernelKext
->version
;
848 sKernelKext
->linkedExecutable
= os::move(kernelExecutable
);
849 sKernelKext
->interfaceUUID
= sKernelKext
->copyUUID();
851 sKernelKext
->flags
.hasAllDependencies
= 1;
852 sKernelKext
->flags
.kernelComponent
= 1;
853 sKernelKext
->flags
.prelinked
= 0;
854 sKernelKext
->flags
.loaded
= 1;
855 sKernelKext
->flags
.started
= 1;
856 sKernelKext
->flags
.CPPInitialized
= 0;
857 sKernelKext
->flags
.jettisonLinkeditSeg
= 0;
859 sKernelKext
->kmod_info
= &g_kernel_kmod_info
;
860 strlcpy(g_kernel_kmod_info
.version
, osrelease
,
861 sizeof(g_kernel_kmod_info
.version
));
862 g_kernel_kmod_info
.size
= kernelLength
;
863 g_kernel_kmod_info
.id
= sKernelKext
->loadTag
;
865 /* Cons up an info dict, so we don't have to have special-case
868 sKernelKext
->infoDict
= OSDictionary::withCapacity(5);
869 assert(sKernelKext
->infoDict
);
870 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleIdentifierKey
,
871 sKernelKext
->bundleID
.get());
873 setResult
= sKernelKext
->infoDict
->setObject(kOSKernelResourceKey
,
878 OSSharedPtr
<OSString
> scratchString(OSString::withCStringNoCopy(osrelease
));
879 assert(scratchString
);
880 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleVersionKey
,
881 scratchString
.get());
886 OSSharedPtr
<OSString
> scratchString(OSString::withCStringNoCopy("mach_kernel"));
887 assert(scratchString
);
888 setResult
= sKernelKext
->infoDict
->setObject(kCFBundleNameKey
,
889 scratchString
.get());
893 /* Add the kernel kext to the bookkeeping dictionaries. Note that
894 * the kernel kext doesn't have a kmod_info struct. copyInfo()
895 * gathers info from other places anyhow.
897 setResult
= sKextsByID
->setObject(sKernelKext
->bundleID
.get(), sKernelKext
);
899 setResult
= sLoadedKexts
->setObject(sKernelKext
);
902 // XXX: better way with OSSharedPtr?
903 // sKernelKext remains a valid pointer even after the decref
904 sKernelKext
->release();
906 registryRoot
= IORegistryEntry::getRegistryRoot();
907 kernelCPUType
= OSNumber::withNumber(
908 (long long unsigned int)_mh_execute_header
.cputype
,
909 8 * sizeof(_mh_execute_header
.cputype
));
910 kernelCPUSubtype
= OSNumber::withNumber(
911 (long long unsigned int)_mh_execute_header
.cpusubtype
,
912 8 * sizeof(_mh_execute_header
.cpusubtype
));
913 assert(registryRoot
&& kernelCPUSubtype
&& kernelCPUType
);
915 registryRoot
->setProperty(kOSKernelCPUTypeKey
, kernelCPUType
.get());
916 registryRoot
->setProperty(kOSKernelCPUSubtypeKey
, kernelCPUSubtype
.get());
918 gBuiltinKmodsSectionInfo
= getsectbyname(kPrelinkInfoSegment
, kBuiltinInfoSection
);
919 if (gBuiltinKmodsSectionInfo
) {
922 assert(gBuiltinKmodsSectionInfo
->addr
);
923 assert(gBuiltinKmodsSectionInfo
->size
);
924 assert(gBuiltinKmodsSectionInfo
->size
/ sizeof(kmod_info_t
*) <= UINT_MAX
);
925 gBuiltinKmodsCount
= (unsigned int)(gBuiltinKmodsSectionInfo
->size
/ sizeof(kmod_info_t
*));
927 gBuiltinKmodsSectionStart
= getsectbyname(kPrelinkInfoSegment
, kBuiltinStartSection
);
928 assert(gBuiltinKmodsSectionStart
);
929 assert(gBuiltinKmodsSectionStart
->addr
);
930 assert(gBuiltinKmodsSectionStart
->size
);
931 assert(gBuiltinKmodsSectionStart
->size
/ sizeof(uintptr_t) <= UINT_MAX
);
932 count
= (unsigned int)(gBuiltinKmodsSectionStart
->size
/ sizeof(uintptr_t));
933 // one extra pointer for the end of last kmod
934 assert(count
== (gBuiltinKmodsCount
+ 1));
936 vm_kernel_builtinkmod_text
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[0];
937 vm_kernel_builtinkmod_text_end
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[count
- 1];
940 // Don't track this object -- it's never released
941 gIOSurfaceIdentifier
= OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
943 timestamp
= __OSAbsoluteTimePtr(&last_loaded_timestamp
);
945 timestamp
= __OSAbsoluteTimePtr(&last_unloaded_timestamp
);
947 timestamp
= __OSAbsoluteTimePtr(&sLastWakeTime
);
950 OSKextLog(/* kext */ NULL
,
951 kOSKextLogProgressLevel
|
952 kOSKextLogGeneralFlag
,
953 "Kext system initialized.");
955 notifyKextLoadObservers(sKernelKext
, sKernelKext
->kmod_info
);
960 /*********************************************************************
961 * This is expected to be called exactly once, from exactly one thread
962 * context, during kernel bootstrap.
963 *********************************************************************/
966 OSKext::removeKextBootstrap(void)
968 OSReturn result
= kOSReturnError
;
970 const char * dt_kernel_header_name
= "Kernel-__HEADER";
971 const char * dt_kernel_symtab_name
= "Kernel-__SYMTAB";
972 kernel_mach_header_t
* dt_mach_header
= NULL
;
973 int dt_mach_header_size
= 0;
974 struct symtab_command
* dt_symtab
= NULL
;
975 int dt_symtab_size
= 0;
978 kernel_segment_command_t
* seg_kld
= NULL
;
979 kernel_segment_command_t
* seg_klddata
= NULL
;
980 kernel_segment_command_t
* seg_linkedit
= NULL
;
982 const char __unused
* dt_segment_name
= NULL
;
983 void __unused
* segment_paddress
= NULL
;
984 int __unused segment_size
= 0;
986 OSKextLog(/* kext */ NULL
,
987 kOSKextLogProgressLevel
|
988 kOSKextLogGeneralFlag
,
989 "Jettisoning kext bootstrap segments.");
992 * keep the linkedit segment around when booted from a new MH_FILESET
993 * KC because all the kexts shared a linkedit segment.
995 kc_format_t kc_format
;
996 if (!PE_get_primary_kc_format(&kc_format
)) {
997 OSKextLog(/* kext */ NULL
,
998 kOSKextLogErrorLevel
|
999 kOSKextLogGeneralFlag
,
1000 "Unable to determine primary KC format");
1004 * Dispose of unnecessary stuff that the booter didn't need to load.
1006 dt_result
= IODTGetLoaderInfo(dt_kernel_header_name
,
1007 (void **)&dt_mach_header
, &dt_mach_header_size
);
1008 if (dt_result
== 0 && dt_mach_header
) {
1009 IODTFreeLoaderInfo(dt_kernel_header_name
, (void *)dt_mach_header
,
1010 round_page_32(dt_mach_header_size
));
1012 dt_result
= IODTGetLoaderInfo(dt_kernel_symtab_name
,
1013 (void **)&dt_symtab
, &dt_symtab_size
);
1014 if (dt_result
== 0 && dt_symtab
) {
1015 IODTFreeLoaderInfo(dt_kernel_symtab_name
, (void *)dt_symtab
,
1016 round_page_32(dt_symtab_size
));
1020 * KLD & KLDDATA bootstrap segments.
1022 // xxx - should rename KLD segment
1023 seg_kld
= getsegbyname("__KLD");
1024 seg_klddata
= getsegbyname("__KLDDATA");
1026 // __mod_term_func is part of __KLDDATA
1027 OSRuntimeUnloadCPPForSegment(seg_klddata
);
1030 #if __arm__ || __arm64__
1031 /* Free the memory that was set up by iBoot.
1033 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1034 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1035 * is covered by the contiguous rorgn.
1037 dt_segment_name
= "Kernel-__KLD";
1038 if (0 == IODTGetLoaderInfo(dt_segment_name
, &segment_paddress
, &segment_size
)) {
1039 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
1040 (int)segment_size
); // calls ml_static_mfree
1041 } else if (seg_kld
&& seg_kld
->vmaddr
&& seg_kld
->vmsize
) {
1042 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1043 ml_static_mfree(ml_static_ptovirt(seg_kld
->vmaddr
- gVirtBase
+ gPhysBase
),
1047 dt_segment_name
= "Kernel-__KLDDATA";
1048 if (0 == IODTGetLoaderInfo(dt_segment_name
, &segment_paddress
, &segment_size
)) {
1049 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
1050 (int)segment_size
); // calls ml_static_mfree
1051 } else if (seg_klddata
&& seg_klddata
->vmaddr
&& seg_klddata
->vmsize
) {
1052 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1053 ml_static_mfree(ml_static_ptovirt(seg_klddata
->vmaddr
- gVirtBase
+ gPhysBase
),
1054 seg_klddata
->vmsize
);
1056 #elif __i386__ || __x86_64__
1057 /* On x86, use the mapping data from the segment load command to
1058 * unload KLD & KLDDATA directly.
1059 * This may invalidate any assumptions about "avail_start"
1060 * defining the lower bound for valid physical addresses.
1062 if (seg_kld
&& seg_kld
->vmaddr
&& seg_kld
->vmsize
) {
1063 bzero((void *)seg_kld
->vmaddr
, seg_kld
->vmsize
);
1064 ml_static_mfree(seg_kld
->vmaddr
, seg_kld
->vmsize
);
1066 if (seg_klddata
&& seg_klddata
->vmaddr
&& seg_klddata
->vmsize
) {
1067 bzero((void *)seg_klddata
->vmaddr
, seg_klddata
->vmsize
);
1068 ml_static_mfree(seg_klddata
->vmaddr
, seg_klddata
->vmsize
);
1075 * Prelinked kernel's symtab (if there is one).
1077 if (kc_format
!= KCFormatFileset
) {
1078 kernel_section_t
* sect
;
1079 sect
= getsectbyname("__PRELINK", "__symtab");
1080 if (sect
&& sect
->addr
&& sect
->size
) {
1081 ml_static_mfree(sect
->addr
, sect
->size
);
1085 seg_linkedit
= (kernel_segment_command_t
*)getsegbyname("__LINKEDIT");
1087 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1088 * pageable, unless keepsyms is set. To do that, we have to copy it from
1089 * its booter-allocated memory, free the booter memory, reallocate proper
1090 * managed memory, then copy the segment back in.
1092 * NOTE: This optimization is not valid for fileset KCs because each
1093 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1094 * that points to one fileset-global LINKEDIT segment. This
1095 * optimization is also only valid for platforms that support vm
1096 * mapped kexts or mapped kext collections (pageable KCs)
1099 if (!sKeepSymbols
&& kc_format
!= KCFormatFileset
) {
1100 kern_return_t mem_result
;
1101 void *seg_copy
= NULL
;
1102 void *seg_data
= NULL
;
1103 vm_map_offset_t seg_offset
= 0;
1104 vm_map_offset_t seg_copy_offset
= 0;
1105 vm_map_size_t seg_length
= 0;
1107 seg_data
= (void *) seg_linkedit
->vmaddr
;
1108 seg_offset
= (vm_map_offset_t
) seg_linkedit
->vmaddr
;
1109 seg_length
= (vm_map_size_t
) seg_linkedit
->vmsize
;
1111 /* Allocate space for the LINKEDIT copy.
1113 mem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*) &seg_copy
,
1114 seg_length
, VM_KERN_MEMORY_KEXT
);
1115 if (mem_result
!= KERN_SUCCESS
) {
1116 OSKextLog(/* kext */ NULL
,
1117 kOSKextLogErrorLevel
|
1118 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1119 "Can't copy __LINKEDIT segment for VM reassign.");
1122 seg_copy_offset
= (vm_map_offset_t
) seg_copy
;
1126 memcpy(seg_copy
, seg_data
, seg_length
);
1128 /* Dump the booter memory.
1130 ml_static_mfree(seg_offset
, seg_length
);
1132 /* Set up the VM region.
1134 mem_result
= vm_map_enter_mem_object(
1137 seg_length
, /* mask */ 0,
1138 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
1139 VM_MAP_KERNEL_FLAGS_NONE
,
1140 VM_KERN_MEMORY_NONE
,
1142 (vm_object_offset_t
) 0,
1144 /* cur_protection */ VM_PROT_READ
| VM_PROT_WRITE
,
1145 /* max_protection */ VM_PROT_ALL
,
1146 /* inheritance */ VM_INHERIT_DEFAULT
);
1147 if ((mem_result
!= KERN_SUCCESS
) ||
1148 (seg_offset
!= (vm_map_offset_t
) seg_data
)) {
1149 OSKextLog(/* kext */ NULL
,
1150 kOSKextLogErrorLevel
|
1151 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1152 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1153 seg_data
, seg_length
, mem_result
);
1157 /* And copy it back.
1159 memcpy(seg_data
, seg_copy
, seg_length
);
1163 kmem_free(kernel_map
, seg_copy_offset
, seg_length
);
1164 } else if (!sKeepSymbols
&& kc_format
== KCFormatFileset
) {
1165 /* Remove the linkedit segment of the Boot KC */
1166 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)PE_get_kc_header(KCKindPrimary
);
1167 OSKext::jettisonFileSetLinkeditSegment(mh
);
1169 #else // !VM_MAPPED_KEXTS
1171 * Dump the LINKEDIT segment, unless keepsyms is set.
1173 if (!sKeepSymbols
&& kc_format
!= KCFormatFileset
) {
1174 dt_segment_name
= "Kernel-__LINKEDIT";
1175 if (0 == IODTGetLoaderInfo(dt_segment_name
,
1176 &segment_paddress
, &segment_size
)) {
1177 #ifdef SECURE_KERNEL
1178 vm_offset_t vmaddr
= ml_static_ptovirt((vm_offset_t
)segment_paddress
);
1179 bzero((void*)vmaddr
, segment_size
);
1181 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
1185 OSKextLog(/* kext */ NULL
,
1186 kOSKextLogBasicLevel
|
1187 kOSKextLogGeneralFlag
,
1188 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1190 #endif // VM_MAPPED_KEXTS
1192 result
= kOSReturnSuccess
;
1198 /*********************************************************************
1199 *********************************************************************/
1201 OSKext::flushNonloadedKexts(
1202 Boolean flushPrelinkedKexts
)
1204 OSSharedPtr
<OSSet
> keepKexts
;
1206 /* TODO: make this more efficient with MH_FILESET kexts */
1208 // Do not unload prelinked kexts on arm because the kernelcache is not
1209 // structured in a way that allows them to be unmapped
1210 #if !defined(__x86_64__)
1211 flushPrelinkedKexts
= false;
1212 #endif /* defined(__x86_64__) */
1214 IORecursiveLockLock(sKextLock
);
1216 OSKextLog(/* kext */ NULL
,
1217 kOSKextLogProgressLevel
|
1218 kOSKextLogKextBookkeepingFlag
,
1219 "Flushing nonloaded kexts and other unused data.");
1221 OSKext::considerDestroyingLinkContext();
1223 /* If we aren't flushing unused prelinked kexts, we have to put them
1224 * aside while we flush everything else so make a container for them.
1226 keepKexts
= OSSet::withCapacity(16);
1231 /* Set aside prelinked kexts (in-use or not) and break
1232 * any lingering inter-kext references for nonloaded kexts
1233 * so they have min. retain counts.
1236 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisID __unused
, OSObject
* obj
) {
1237 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1241 if (!flushPrelinkedKexts
&& thisKext
->isPrelinked()) {
1242 keepKexts
->setObject(thisKext
);
1243 } else if (!thisKext
->declaresExecutable()) {
1245 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1246 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1247 * flushNonloadedKexts().
1248 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1250 keepKexts
->setObject(thisKext
);
1251 } else if (thisKext
->isInFileset()) {
1252 /* keep all kexts in the new MH_FILESET KC */
1253 keepKexts
->setObject(thisKext
);
1256 thisKext
->flushDependencies(/* forceIfLoaded */ false);
1260 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1262 sKextsByID
->flushCollection();
1264 /* Now put the loaded kexts back into the ID dictionary.
1266 sLoadedKexts
->iterateObjects(^bool (OSObject
* obj
) {
1267 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1271 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
1275 /* Finally, put back the kept kexts if we saved any.
1277 keepKexts
->iterateObjects(^bool (OSObject
* obj
) {
1278 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1282 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
1287 IORecursiveLockUnlock(sKextLock
);
1290 #else /* !CONFIG_KXLD */
1293 OSKext::flushNonloadedKexts(
1294 Boolean flushPrelinkedKexts __unused
)
1296 IORecursiveLockLock(sKextLock
);
1298 OSKextLog(/* kext */ NULL
,
1299 kOSKextLogProgressLevel
|
1300 kOSKextLogKextBookkeepingFlag
,
1301 "Flushing dependency info for non-loaded kexts.");
1304 * In a world where we don't dynamically link kexts, they all come
1305 * from a kext collection that's either in wired memory, or
1306 * wire-on-demand. We don't need to mess around with moving kexts in
1307 * and out of the sKextsByID array - they can all just stay there.
1308 * Here we just flush the dependency list for kexts that are not
1311 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisID __unused
, OSObject
* obj
) {
1312 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1316 thisKext
->flushDependencies(/* forceIfLoaded */ false);
1320 IORecursiveLockUnlock(sKextLock
);
1324 #endif /* CONFIG_KXLD */
1326 /*********************************************************************
1327 *********************************************************************/
1330 OSKext::setIOKitDaemonActive(bool active
)
1332 IOServiceTrace(IOSERVICE_KEXTD_ALIVE
, 0, 0, 0, 0);
1333 IORecursiveLockLock(sKextLock
);
1334 sIOKitDaemonActive
= active
;
1335 if (sKernelRequests
->getCount()) {
1336 OSKext::pingIOKitDaemon();
1338 IORecursiveLockUnlock(sKextLock
);
1343 /*********************************************************************
1344 * OSKextLib.cpp might need access to this someday but for now it's
1346 *********************************************************************/
1348 extern void ipc_port_release_send(ipc_port_t
);
1353 OSKext::pingIOKitDaemon(void)
1355 OSReturn result
= kOSReturnError
;
1357 mach_port_t kextd_port
= IPC_PORT_NULL
;
1359 if (!sIOKitDaemonActive
) {
1360 result
= kOSKextReturnDisabled
; // basically unavailable
1364 result
= host_get_kextd_port(host_priv_self(), &kextd_port
);
1365 if (result
!= KERN_SUCCESS
|| !IPC_PORT_VALID(kextd_port
)) {
1366 OSKextLog(/* kext */ NULL
,
1367 kOSKextLogErrorLevel
|
1369 "Can't get " kIOKitDaemonName
" port.");
1373 result
= kextd_ping(kextd_port
);
1374 if (result
!= KERN_SUCCESS
) {
1375 OSKextLog(/* kext */ NULL
,
1376 kOSKextLogErrorLevel
|
1378 kIOKitDaemonName
" ping failed (0x%x).", (int)result
);
1383 if (IPC_PORT_VALID(kextd_port
)) {
1384 ipc_port_release_send(kextd_port
);
1391 /*********************************************************************
1392 *********************************************************************/
1395 OSKext::setDeferredLoadSucceeded(Boolean succeeded
)
1397 IORecursiveLockLock(sKextLock
);
1398 sDeferredLoadSucceeded
= succeeded
;
1399 IORecursiveLockUnlock(sKextLock
);
1404 /*********************************************************************
1405 * Called from IOSystemShutdownNotification.
1406 *********************************************************************/
1409 OSKext::willShutdown(void)
1412 OSReturn checkResult
= kOSReturnError
;
1414 OSSharedPtr
<OSDictionary
> exitRequest
;
1416 IORecursiveLockLock(sKextLock
);
1418 OSKext::setLoadEnabled(false);
1419 OSKext::setUnloadEnabled(false);
1420 OSKext::setAutounloadsEnabled(false);
1421 OSKext::setKernelRequestsEnabled(false);
1423 #if defined(__x86_64__) || defined(__i386__)
1424 if (IOPMRootDomainGetWillShutdown()) {
1425 OSKext::freeKCFileSetcontrol();
1427 #endif // (__x86_64__) || defined(__i386__)
1430 OSKextLog(/* kext */ NULL
,
1431 kOSKextLogProgressLevel
|
1432 kOSKextLogGeneralFlag
,
1433 "System shutdown; requesting immediate " kIOKitDaemonName
" exit.");
1435 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit
,
1437 if (checkResult
!= kOSReturnSuccess
) {
1440 if (!sKernelRequests
->setObject(exitRequest
.get())) {
1444 OSKext::pingIOKitDaemon();
1449 IORecursiveLockUnlock(sKextLock
);
1454 OSKext::willUserspaceReboot(void)
1456 OSKext::willShutdown();
1457 IOService::userSpaceWillReboot();
1458 gIOCatalogue
->terminateDriversForUserspaceReboot();
1462 OSKext::resetAfterUserspaceReboot(void)
1464 OSSharedPtr
<OSArray
> arr
= OSArray::withCapacity(1);
1465 IOService::updateConsoleUsers(arr
.get(), 0, true /* after_userspace_reboot */);
1467 IORecursiveLockLock(sKextLock
);
1468 gIOCatalogue
->resetAfterUserspaceReboot();
1469 IOService::userSpaceDidReboot();
1470 OSKext::setLoadEnabled(true);
1471 OSKext::setUnloadEnabled(true);
1472 OSKext::setAutounloadsEnabled(true);
1473 OSKext::setKernelRequestsEnabled(true);
1474 sOSKextWasResetAfterUserspaceReboot
= true;
1475 IORecursiveLockUnlock(sKextLock
);
1479 OSKextResetAfterUserspaceReboot(void)
1481 OSKext::resetAfterUserspaceReboot();
1484 /*********************************************************************
1485 *********************************************************************/
1488 OSKext::getLoadEnabled(void)
1492 IORecursiveLockLock(sKextLock
);
1493 result
= sLoadEnabled
;
1494 IORecursiveLockUnlock(sKextLock
);
1498 /*********************************************************************
1499 *********************************************************************/
1502 OSKext::setLoadEnabled(bool flag
)
1506 IORecursiveLockLock(sKextLock
);
1507 result
= sLoadEnabled
;
1508 sLoadEnabled
= (flag
? true : false);
1510 if (sLoadEnabled
!= result
) {
1511 OSKextLog(/* kext */ NULL
,
1512 kOSKextLogBasicLevel
|
1514 "Kext loading now %sabled.", sLoadEnabled
? "en" : "dis");
1517 IORecursiveLockUnlock(sKextLock
);
1522 /*********************************************************************
1523 *********************************************************************/
1526 OSKext::getUnloadEnabled(void)
1530 IORecursiveLockLock(sKextLock
);
1531 result
= sUnloadEnabled
;
1532 IORecursiveLockUnlock(sKextLock
);
1536 /*********************************************************************
1537 *********************************************************************/
1540 OSKext::setUnloadEnabled(bool flag
)
1544 IORecursiveLockLock(sKextLock
);
1545 result
= sUnloadEnabled
;
1546 sUnloadEnabled
= (flag
? true : false);
1547 IORecursiveLockUnlock(sKextLock
);
1549 if (sUnloadEnabled
!= result
) {
1550 OSKextLog(/* kext */ NULL
,
1551 kOSKextLogBasicLevel
|
1552 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1553 "Kext unloading now %sabled.", sUnloadEnabled
? "en" : "dis");
1559 /*********************************************************************
1560 * Do not call any function that takes sKextLock here!
1561 *********************************************************************/
1564 OSKext::getAutounloadEnabled(void)
1568 IORecursiveLockLock(sKextInnerLock
);
1569 result
= sAutounloadEnabled
? true : false;
1570 IORecursiveLockUnlock(sKextInnerLock
);
1574 /*********************************************************************
1575 * Do not call any function that takes sKextLock here!
1576 *********************************************************************/
1579 OSKext::setAutounloadsEnabled(bool flag
)
1583 IORecursiveLockLock(sKextInnerLock
);
1585 result
= sAutounloadEnabled
;
1586 sAutounloadEnabled
= (flag
? true : false);
1587 if (!sAutounloadEnabled
&& sUnloadCallout
) {
1588 thread_call_cancel(sUnloadCallout
);
1591 if (sAutounloadEnabled
!= result
) {
1592 OSKextLog(/* kext */ NULL
,
1593 kOSKextLogBasicLevel
|
1594 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1595 "Kext autounloading now %sabled.",
1596 sAutounloadEnabled
? "en" : "dis");
1599 IORecursiveLockUnlock(sKextInnerLock
);
1604 /*********************************************************************
1605 *********************************************************************/
1606 /* instance method operating on OSKext field */
1608 OSKext::setAutounloadEnabled(bool flag
)
1610 bool result
= flags
.autounloadEnabled
? true : false;
1611 flags
.autounloadEnabled
= flag
? (0 == flags
.unloadUnsupported
) : 0;
1613 if (result
!= (flag
? true : false)) {
1615 kOSKextLogProgressLevel
|
1616 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
1617 "Autounloading for kext %s now %sabled.",
1618 getIdentifierCString(),
1619 flags
.autounloadEnabled
? "en" : "dis");
1624 /*********************************************************************
1625 *********************************************************************/
1628 OSKext::setKernelRequestsEnabled(bool flag
)
1632 IORecursiveLockLock(sKextLock
);
1633 result
= sKernelRequestsEnabled
;
1634 sKernelRequestsEnabled
= flag
? true : false;
1636 if (sKernelRequestsEnabled
!= result
) {
1637 OSKextLog(/* kext */ NULL
,
1638 kOSKextLogBasicLevel
|
1639 kOSKextLogGeneralFlag
,
1640 "Kernel requests now %sabled.",
1641 sKernelRequestsEnabled
? "en" : "dis");
1643 IORecursiveLockUnlock(sKextLock
);
1647 /*********************************************************************
1648 *********************************************************************/
1651 OSKext::getKernelRequestsEnabled(void)
1655 IORecursiveLockLock(sKextLock
);
1656 result
= sKernelRequestsEnabled
;
1657 IORecursiveLockUnlock(sKextLock
);
1662 segmentIsMutable(kernel_segment_command_t
*seg
)
1664 /* Mutable segments have to have VM_PROT_WRITE */
1665 if ((seg
->maxprot
& VM_PROT_WRITE
) == 0) {
1668 /* Exclude the __DATA_CONST segment */
1669 if (strncmp(seg
->segname
, "__DATA_CONST", sizeof(seg
->segname
)) == 0) {
1672 /* Exclude __LINKEDIT */
1673 if (strncmp(seg
->segname
, "__LINKEDIT", sizeof(seg
->segname
)) == 0) {
1680 #pragma mark Kext Life Cycle
1682 /*********************************************************************
1683 *********************************************************************/
1685 OSKext::withPrelinkedInfoDict(
1686 OSDictionary
* anInfoDict
,
1687 bool doCoalescedSlides
,
1690 OSSharedPtr
<OSKext
> newKext(OSMakeShared
<OSKext
>());
1692 if (newKext
&& !newKext
->initWithPrelinkedInfoDict(anInfoDict
, doCoalescedSlides
, type
)) {
1699 /*********************************************************************
1700 *********************************************************************/
1702 OSKext::initWithPrelinkedInfoDict(
1703 OSDictionary
* anInfoDict
,
1704 bool doCoalescedSlides
,
1707 bool result
= false;
1708 OSString
* kextPath
= NULL
; // do not release
1709 OSNumber
* addressNum
= NULL
; // reused; do not release
1710 OSNumber
* lengthNum
= NULL
; // reused; do not release
1711 OSBoolean
* scratchBool
= NULL
; // do not release
1712 void * data
= NULL
; // do not free
1713 void * srcData
= NULL
; // do not free
1714 OSSharedPtr
<OSData
> prelinkedExecutable
;
1715 uint32_t length
= 0; // reused
1716 uintptr_t kext_slide
= PE_get_kc_slide(type
);
1717 bool shouldSaveSegments
= false;
1719 if (!super::init()) {
1723 /* Get the path. Don't look for an arch-specific path property.
1725 kextPath
= OSDynamicCast(OSString
,
1726 anInfoDict
->getObject(kPrelinkBundlePathKey
));
1728 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
1732 #if KASLR_KEXT_DEBUG
1733 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides
, getIdentifierCString());
1736 /* Also get the executable's bundle-relative path if present.
1737 * Don't look for an arch-specific path property.
1739 executableRelPath
.reset(OSDynamicCast(OSString
,
1740 anInfoDict
->getObject(kPrelinkExecutableRelativePathKey
)), OSRetain
);
1741 userExecutableRelPath
.reset(OSDynamicCast(OSString
,
1742 anInfoDict
->getObject(kCFBundleDriverKitExecutableKey
)), OSRetain
);
1744 /* Don't need the paths to be in the info dictionary any more.
1746 anInfoDict
->removeObject(kPrelinkBundlePathKey
);
1747 anInfoDict
->removeObject(kPrelinkExecutableRelativePathKey
);
1749 scratchBool
= OSDynamicCast(OSBoolean
,
1750 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey
));
1751 if (scratchBool
== kOSBooleanTrue
) {
1752 flags
.requireExplicitLoad
= 1;
1755 /* Create an OSData wrapper around the linked executable.
1757 addressNum
= OSDynamicCast(OSNumber
,
1758 anInfoDict
->getObject(kPrelinkExecutableLoadKey
));
1759 if (addressNum
&& addressNum
->unsigned64BitValue() != kOSKextCodelessKextLoadAddr
) {
1760 lengthNum
= OSDynamicCast(OSNumber
,
1761 anInfoDict
->getObject(kPrelinkExecutableSizeKey
));
1764 kOSKextLogErrorLevel
|
1765 kOSKextLogArchiveFlag
,
1766 "Kext %s can't find prelinked kext executable size.",
1767 getIdentifierCString());
1771 data
= (void *) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1772 length
= (uint32_t) (lengthNum
->unsigned32BitValue());
1774 #if KASLR_KEXT_DEBUG
1775 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1776 (unsigned long)ml_static_unslide((vm_offset_t
)data
),
1777 (unsigned long)data
,
1781 anInfoDict
->removeObject(kPrelinkExecutableLoadKey
);
1782 anInfoDict
->removeObject(kPrelinkExecutableSizeKey
);
1784 /* If the kext's load address differs from its source address, allocate
1785 * space in the kext map at the load address and copy the kext over.
1787 addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject(kPrelinkExecutableSourceKey
));
1789 srcData
= (void *) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1791 #if KASLR_KEXT_DEBUG
1792 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1793 (unsigned long)ml_static_unslide((vm_offset_t
)srcData
),
1794 (unsigned long)srcData
);
1797 if (data
!= srcData
) {
1799 kern_return_t alloc_result
;
1801 alloc_result
= kext_alloc((vm_offset_t
*)&data
, length
, /* fixed */ TRUE
);
1802 if (alloc_result
!= KERN_SUCCESS
) {
1804 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1805 "Failed to allocate space for prelinked kext %s.",
1806 getIdentifierCString());
1809 memcpy(data
, srcData
, length
);
1812 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1813 "Error: prelinked kext %s - source and load addresses "
1814 "differ on ILP32 architecture.",
1815 getIdentifierCString());
1817 #endif /* __LP64__ */
1820 anInfoDict
->removeObject(kPrelinkExecutableSourceKey
);
1823 prelinkedExecutable
= OSData::withBytesNoCopy(data
, length
);
1824 if (!prelinkedExecutable
) {
1826 kOSKextLogErrorLevel
|
1827 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1828 "Kext %s failed to create executable wrapper.",
1829 getIdentifierCString());
1834 prelinkedExecutable
->setDeallocFunction(osdata_kext_free
);
1836 prelinkedExecutable
->setDeallocFunction(osdata_phys_free
);
1838 setLinkedExecutable(prelinkedExecutable
.get());
1839 addressNum
= OSDynamicCast(OSNumber
,
1840 anInfoDict
->getObject(kPrelinkKmodInfoKey
));
1843 kOSKextLogErrorLevel
|
1844 kOSKextLogArchiveFlag
,
1845 "Kext %s can't find prelinked kext kmod_info address.",
1846 getIdentifierCString());
1850 if (addressNum
->unsigned64BitValue() != 0) {
1851 kmod_info
= (kmod_info_t
*) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1852 if (kmod_info
->address
) {
1853 kmod_info
->address
= (((uintptr_t)(kmod_info
->address
)) + kext_slide
);
1855 kmod_info
->address
= (uintptr_t)data
;
1856 kmod_info
->size
= length
;
1858 #if KASLR_KEXT_DEBUG
1859 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1860 (unsigned long)((vm_offset_t
)kmod_info
) - kext_slide
,
1861 (unsigned long)kmod_info
);
1862 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1863 (unsigned long)((vm_offset_t
)kmod_info
->address
) - kext_slide
,
1864 (unsigned long)kmod_info
->address
);
1868 anInfoDict
->removeObject(kPrelinkKmodInfoKey
);
1871 if ((addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject("ModuleIndex")))) {
1872 uintptr_t builtinTextStart
;
1873 uintptr_t builtinTextEnd
;
1875 flags
.builtin
= true;
1876 builtinKmodIdx
= addressNum
->unsigned32BitValue();
1877 assert(builtinKmodIdx
< gBuiltinKmodsCount
);
1879 builtinTextStart
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[builtinKmodIdx
];
1880 builtinTextEnd
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[builtinKmodIdx
+ 1];
1882 kmod_info
= ((kmod_info_t
**)gBuiltinKmodsSectionInfo
->addr
)[builtinKmodIdx
];
1883 kmod_info
->address
= builtinTextStart
;
1884 kmod_info
->size
= builtinTextEnd
- builtinTextStart
;
1887 /* If the plist has a UUID for an interface, save that off.
1889 if (isInterface()) {
1890 interfaceUUID
.reset(OSDynamicCast(OSData
,
1891 anInfoDict
->getObject(kPrelinkInterfaceUUIDKey
)), OSRetain
);
1892 if (interfaceUUID
) {
1893 anInfoDict
->removeObject(kPrelinkInterfaceUUIDKey
);
1897 result
= (kOSReturnSuccess
== slidePrelinkedExecutable(doCoalescedSlides
));
1903 /* Exclude builtin and codeless kexts */
1904 if (prelinkedExecutable
&& kmod_info
) {
1907 shouldSaveSegments
= (
1908 getPropertyForHostArch(kOSMutableSegmentCopy
) == kOSBooleanTrue
||
1909 getPropertyForHostArch(kOSBundleAllowUserLoadKey
) == kOSBooleanTrue
);
1910 if (shouldSaveSegments
) {
1911 flags
.resetSegmentsFromImmutableCopy
= 1;
1913 flags
.unloadUnsupported
= 1;
1916 case KCKindPageable
:
1917 flags
.resetSegmentsFromVnode
= 1;
1919 case KCKindAuxiliary
:
1920 if (!pageableKCloaded
) {
1921 flags
.resetSegmentsFromImmutableCopy
= 1;
1922 } else if (resetAuxKCSegmentOnUnload
) {
1923 flags
.resetSegmentsFromVnode
= 1;
1925 flags
.unloadUnsupported
= 1;
1933 if (flags
.resetSegmentsFromImmutableCopy
) {
1934 /* Save a pristine copy of the mutable segments */
1935 kernel_segment_command_t
*seg
= NULL
;
1936 kernel_mach_header_t
*k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
1938 savedMutableSegments
= OSArray::withCapacity(0);
1940 for (seg
= firstsegfromheader(k_mh
); seg
; seg
= nextsegfromheader(k_mh
, seg
)) {
1941 if (!segmentIsMutable(seg
)) {
1944 uint64_t unslid_vmaddr
= seg
->vmaddr
- kext_slide
;
1945 uint64_t vmsize
= seg
->vmsize
;
1946 OSKextLog(this, kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
1947 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg
->segname
, sizeof(seg
->segname
)), seg
->segname
, unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
1948 OSSharedPtr
<OSKextSavedMutableSegment
> savedSegment
= OSKextSavedMutableSegment::withSegment(seg
);
1949 if (!savedSegment
) {
1951 kOSKextLogErrorLevel
|
1952 kOSKextLogGeneralFlag
,
1953 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
1954 result
= kOSKextReturnInternalError
;
1957 savedMutableSegments
->setObject(savedSegment
);
1961 if (doCoalescedSlides
== false && !flags
.resetSegmentsFromVnode
) {
1963 * set VM protections now, wire pages for the old style Aux KC now,
1964 * wire pages for the rest of the KC types at load time.
1966 result
= (kOSReturnSuccess
== setVMAttributes(true, (type
== KCKindAuxiliary
) ? true : false));
1972 flags
.prelinked
= true;
1974 /* If we created a kext from prelink info,
1975 * we must be booting from a prelinked kernel.
1977 sPrelinkBoot
= true;
1979 result
= registerIdentifier();
1985 /*********************************************************************
1986 *********************************************************************/
1989 OSKext::withCodelessInfo(OSDictionary
* anInfoDict
)
1991 OSSharedPtr
<OSKext
> newKext
= OSMakeShared
<OSKext
>();
1993 if (newKext
&& !newKext
->initWithCodelessInfo(anInfoDict
)) {
2000 /*********************************************************************
2001 *********************************************************************/
2003 OSKext::initWithCodelessInfo(OSDictionary
* anInfoDict
)
2005 bool result
= false;
2006 OSString
* kextPath
= NULL
; // do not release
2007 OSBoolean
* scratchBool
= NULL
; // do not release
2009 if (anInfoDict
== NULL
|| !super::init()) {
2014 * Get the path. Don't look for an arch-specific path property.
2016 kextPath
= OSDynamicCast(OSString
,
2017 anInfoDict
->getObject(kKextRequestArgumentCodelessInfoBundlePathKey
));
2020 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
2021 "Requested codeless kext dictionary does not contain the '%s' key",
2022 kKextRequestArgumentCodelessInfoBundlePathKey
);
2026 uniquePersonalityProperties(anInfoDict
);
2028 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
2033 * This path is meant to initialize codeless kexts only. Refuse
2034 * anything that looks like it has an executable and/or declares
2035 * itself as a kernel component.
2037 if (declaresExecutable() || isKernelComponent()) {
2039 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
2040 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2041 getIdentifierCString());
2045 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID
) == 0) {
2046 boolean_t updated
= updateExcludeList(infoDict
.get());
2049 kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
2050 "KextExcludeList was updated to version: %lld", sExcludeListVersion
);
2054 kc_type
= KCKindNone
;
2056 scratchBool
= OSDynamicCast(OSBoolean
,
2057 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey
));
2058 if (scratchBool
== kOSBooleanTrue
) {
2059 flags
.requireExplicitLoad
= 1;
2062 /* Also get the executable's bundle-relative path if present.
2063 * Don't look for an arch-specific path property.
2065 userExecutableRelPath
.reset(OSDynamicCast(OSString
,
2066 anInfoDict
->getObject(kCFBundleDriverKitExecutableKey
)), OSRetain
);
2068 /* remove unnecessary paths from the info dict */
2069 anInfoDict
->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey
);
2071 result
= registerIdentifier();
2077 /*********************************************************************
2078 *********************************************************************/
2081 OSKext::setAllVMAttributes(void)
2083 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
2084 const OSSymbol
* thisID
= NULL
; // do not release
2086 IORecursiveLockLock(sKextLock
);
2088 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
2089 if (!kextIterator
) {
2093 while ((thisID
= OSDynamicCast(OSSymbol
, kextIterator
->getNextObject()))) {
2094 OSKext
* thisKext
; // do not release
2096 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
2097 if (!thisKext
|| thisKext
->isInterface() || !thisKext
->declaresExecutable()) {
2101 if (!thisKext
->flags
.resetSegmentsFromVnode
) {
2103 * set VM protections now, wire pages for the old style Aux KC now,
2104 * wire pages for the rest of the KC types at load time.
2106 thisKext
->setVMAttributes(true, (thisKext
->kc_type
== KCKindAuxiliary
) ? true : false);
2111 IORecursiveLockUnlock(sKextLock
);
2116 /*********************************************************************
2117 *********************************************************************/
2119 OSKext::withBooterData(
2120 OSString
* deviceTreeName
,
2121 OSData
* booterData
)
2123 OSSharedPtr
<OSKext
> newKext(OSMakeShared
<OSKext
>());
2125 if (newKext
&& !newKext
->initWithBooterData(deviceTreeName
, booterData
)) {
2132 /*********************************************************************
2133 *********************************************************************/
2134 typedef struct _BooterKextFileInfo
{
2135 uint32_t infoDictPhysAddr
;
2136 uint32_t infoDictLength
;
2137 uint32_t executablePhysAddr
;
2138 uint32_t executableLength
;
2139 uint32_t bundlePathPhysAddr
;
2140 uint32_t bundlePathLength
;
2141 } _BooterKextFileInfo
;
2144 OSKext::initWithBooterData(
2145 OSString
* deviceTreeName
,
2146 OSData
* booterData
)
2148 bool result
= false;
2149 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not free
2150 char * infoDictAddr
= NULL
; // do not free
2151 void * executableAddr
= NULL
; // do not free
2152 char * bundlePathAddr
= NULL
; // do not free
2154 OSDictionary
* theInfoDict
= NULL
; // do not release
2155 OSSharedPtr
<OSObject
> parsedXML
;
2156 OSSharedPtr
<OSString
> kextPath
;
2158 OSSharedPtr
<OSString
> errorString
;
2159 OSSharedPtr
<OSData
> executable
;
2161 if (!super::init()) {
2165 kextFileInfo
= (_BooterKextFileInfo
*)booterData
->getBytesNoCopy();
2166 if (!kextFileInfo
) {
2168 kOSKextLogErrorLevel
|
2169 kOSKextLogGeneralFlag
,
2170 "No booter-provided data for kext device tree entry %s.",
2171 deviceTreeName
->getCStringNoCopy());
2175 /* The info plist must exist or we can't read the kext.
2177 if (!kextFileInfo
->infoDictPhysAddr
|| !kextFileInfo
->infoDictLength
) {
2179 kOSKextLogErrorLevel
|
2180 kOSKextLogGeneralFlag
,
2181 "No kext info dictionary for booter device tree entry %s.",
2182 deviceTreeName
->getCStringNoCopy());
2186 infoDictAddr
= (char *)ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
2187 if (!infoDictAddr
) {
2189 kOSKextLogErrorLevel
|
2190 kOSKextLogGeneralFlag
,
2191 "Can't translate physical address 0x%x of kext info dictionary "
2192 "for device tree entry %s.",
2193 (int)kextFileInfo
->infoDictPhysAddr
,
2194 deviceTreeName
->getCStringNoCopy());
2198 parsedXML
= OSUnserializeXML(infoDictAddr
, errorString
);
2200 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
2203 const char * errorCString
= "(unknown error)";
2205 if (errorString
&& errorString
->getCStringNoCopy()) {
2206 errorCString
= errorString
->getCStringNoCopy();
2207 } else if (parsedXML
) {
2208 errorCString
= "not a dictionary";
2211 kOSKextLogErrorLevel
|
2212 kOSKextLogGeneralFlag
,
2213 "Error unserializing info dictionary for device tree entry %s: %s.",
2214 deviceTreeName
->getCStringNoCopy(), errorCString
);
2218 /* A bundle path is not mandatory.
2220 if (kextFileInfo
->bundlePathPhysAddr
&& kextFileInfo
->bundlePathLength
) {
2221 bundlePathAddr
= (char *)ml_static_ptovirt(kextFileInfo
->bundlePathPhysAddr
);
2222 if (!bundlePathAddr
) {
2224 kOSKextLogErrorLevel
|
2225 kOSKextLogGeneralFlag
,
2226 "Can't translate physical address 0x%x of kext bundle path "
2227 "for device tree entry %s.",
2228 (int)kextFileInfo
->bundlePathPhysAddr
,
2229 deviceTreeName
->getCStringNoCopy());
2232 bundlePathAddr
[kextFileInfo
->bundlePathLength
- 1] = '\0'; // just in case!
2234 kextPath
= OSString::withCString(bundlePathAddr
);
2237 kOSKextLogErrorLevel
|
2238 kOSKextLogGeneralFlag
,
2239 "Failed to create wrapper for device tree entry %s kext path %s.",
2240 deviceTreeName
->getCStringNoCopy(), bundlePathAddr
);
2245 if (!setInfoDictionaryAndPath(theInfoDict
, kextPath
.get())) {
2249 /* An executable is not mandatory.
2251 if (kextFileInfo
->executablePhysAddr
&& kextFileInfo
->executableLength
) {
2252 executableAddr
= (void *)ml_static_ptovirt(kextFileInfo
->executablePhysAddr
);
2253 if (!executableAddr
) {
2255 kOSKextLogErrorLevel
|
2256 kOSKextLogGeneralFlag
,
2257 "Can't translate physical address 0x%x of kext executable "
2258 "for device tree entry %s.",
2259 (int)kextFileInfo
->executablePhysAddr
,
2260 deviceTreeName
->getCStringNoCopy());
2264 executable
= OSData::withBytesNoCopy(executableAddr
,
2265 kextFileInfo
->executableLength
);
2268 kOSKextLogErrorLevel
|
2269 kOSKextLogGeneralFlag
,
2270 "Failed to create executable wrapper for device tree entry %s.",
2271 deviceTreeName
->getCStringNoCopy());
2275 /* A kext with an executable needs to retain the whole booterData
2276 * object to keep the executable in memory.
2278 if (!setExecutable(executable
.get(), booterData
)) {
2280 kOSKextLogErrorLevel
|
2281 kOSKextLogGeneralFlag
,
2282 "Failed to set kext executable for device tree entry %s.",
2283 deviceTreeName
->getCStringNoCopy());
2288 result
= registerIdentifier();
2294 /*********************************************************************
2295 *********************************************************************/
2297 OSKext::registerIdentifier(void)
2299 bool result
= false;
2300 OSKext
* existingKext
= NULL
; // do not release
2301 bool existingIsLoaded
= false;
2302 bool existingIsPrelinked
= false;
2303 bool existingIsCodeless
= false;
2304 bool existingIsDext
= false;
2305 OSKextVersion newVersion
= -1;
2306 OSKextVersion existingVersion
= -1;
2307 char newVersionCString
[kOSKextVersionMaxLength
];
2308 char existingVersionCString
[kOSKextVersionMaxLength
];
2309 OSSharedPtr
<OSData
> newUUID
;
2310 OSSharedPtr
<OSData
> existingUUID
;
2312 IORecursiveLockLock(sKextLock
);
2314 /* Get the new kext's version for checks & log messages.
2316 newVersion
= getVersion();
2317 OSKextVersionGetString(newVersion
, newVersionCString
,
2318 kOSKextVersionMaxLength
);
2320 /* If we don't have an existing kext with this identifier,
2321 * just record the new kext and we're done!
2323 existingKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
.get()));
2324 if (!existingKext
) {
2325 sKextsByID
->setObject(bundleID
.get(), this);
2330 /* Get the existing kext's version for checks & log messages.
2332 existingVersion
= existingKext
->getVersion();
2333 OSKextVersionGetString(existingVersion
,
2334 existingVersionCString
, kOSKextVersionMaxLength
);
2336 existingIsLoaded
= existingKext
->isLoaded();
2337 existingIsPrelinked
= existingKext
->isPrelinked();
2338 existingIsDext
= existingKext
->isDriverKit();
2339 existingIsCodeless
= !existingKext
->declaresExecutable() && !existingIsDext
;
2341 /* If we have a non-codeless kext with this identifier that's already
2342 * loaded/prelinked, we can't use the new one, but let's be really
2343 * thorough and check how the two are related for a precise diagnostic
2346 * This check is valid for kexts that declare an executable and for
2347 * dexts, but not for codeless kexts - we can just replace those.
2349 if ((!existingIsCodeless
|| existingIsDext
) &&
2350 (existingIsLoaded
|| existingIsPrelinked
)) {
2351 bool sameVersion
= (newVersion
== existingVersion
);
2352 bool sameExecutable
= true; // assume true unless we have UUIDs
2354 /* Only get the UUID if the existing kext is loaded. Doing so
2355 * might have to uncompress an mkext executable and we shouldn't
2356 * take that hit when neither kext is loaded.
2358 * Note: there is no decompression that happens when all kexts
2359 * are loaded from kext collecitons.
2361 newUUID
= copyUUID();
2362 existingUUID
= existingKext
->copyUUID();
2364 if (existingIsDext
&& !isDriverKit()) {
2366 kOSKextLogWarningLevel
|
2367 kOSKextLogKextBookkeepingFlag
,
2368 "Notice - new kext %s, v%s matches a %s dext"
2369 "with the same bundle ID, v%s.",
2370 getIdentifierCString(), newVersionCString
,
2371 (existingIsLoaded
? "loaded" : "prelinked"),
2372 existingVersionCString
);
2376 /* I'm entirely too paranoid about checking equivalence of executables,
2377 * but I remember nasty problems with it in the past.
2379 * - If we have UUIDs for both kexts, compare them.
2380 * - If only one kext has a UUID, they're definitely different.
2382 if (newUUID
&& existingUUID
) {
2383 sameExecutable
= newUUID
->isEqualTo(existingUUID
.get());
2384 } else if (newUUID
|| existingUUID
) {
2385 sameExecutable
= false;
2388 if (!newUUID
&& !existingUUID
) {
2389 /* If there are no UUIDs, we can't really tell that the executables
2390 * are *different* without a lot of work; the loaded kext's
2391 * unrelocated executable is no longer around (and we never had it
2392 * in-kernel for a prelinked kext). We certainly don't want to do
2393 * a whole fake link for the new kext just to compare, either.
2396 kOSKextLogWarningLevel
|
2397 kOSKextLogKextBookkeepingFlag
,
2398 "Notice - new kext %s, v%s matches %s kext "
2399 "but can't determine if executables are the same (no UUIDs).",
2400 getIdentifierCString(),
2402 (existingIsLoaded
? "loaded" : "prelinked"));
2405 if (sameVersion
&& sameExecutable
) {
2407 (existingIsLoaded
? kOSKextLogWarningLevel
: kOSKextLogStepLevel
) |
2408 kOSKextLogKextBookkeepingFlag
,
2409 "Refusing new kext %s, v%s: a %s copy is already present "
2410 "(same version and executable).",
2411 getIdentifierCString(), newVersionCString
,
2412 (existingIsLoaded
? "loaded" : "prelinked"));
2415 /* This condition is significant so log it under warnings.
2418 kOSKextLogWarningLevel
|
2419 kOSKextLogKextBookkeepingFlag
,
2420 "Refusing new kext %s, v%s: already have %s v%s.",
2421 getIdentifierCString(),
2423 (existingIsLoaded
? "loaded" : "prelinked"),
2424 existingVersionCString
);
2426 /* This condition is significant so log it under warnings.
2429 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
2430 "Refusing new kext %s, v%s: a %s copy with a different "
2431 "executable UUID is already present.",
2432 getIdentifierCString(), newVersionCString
,
2433 (existingIsLoaded
? "loaded" : "prelinked"));
2437 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2439 /* Refuse to allow an existing loaded codeless kext be replaced by a
2440 * normal kext with the same bundle ID.
2442 if (existingIsCodeless
&& declaresExecutable()) {
2444 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
2445 "Refusing new kext %s, v%s: a codeless copy is already %s",
2446 getIdentifierCString(), newVersionCString
,
2447 (existingIsLoaded
? "loaded" : "prelinked"));
2451 /* Dexts packaged in the BootKC will be protected against replacement
2452 * by non-dexts by the logic above which checks if they are prelinked.
2453 * Dexts which are prelinked into the System KC will be registered
2454 * before any other kexts in the AuxKC are registered, and we never
2455 * put dexts in the AuxKC. Therefore, there is no need to check if an
2456 * existing object is a dext and is being replaced by a non-dext.
2457 * The scenario cannot happen by construction.
2459 * See: OSKext::loadFileSetKexts()
2462 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2463 * user loads are happening or if we're still in early boot. User agents are
2464 * supposed to resolve dependencies topside and include only the exact
2465 * kexts needed; so we always accept the new kext (in fact we should never
2466 * see an older unloaded copy hanging around).
2468 if (sUserLoadsActive
) {
2469 sKextsByID
->setObject(bundleID
.get(), this);
2473 kOSKextLogStepLevel
|
2474 kOSKextLogKextBookkeepingFlag
,
2475 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2476 getIdentifierCString(),
2477 existingVersionCString
,
2483 /* During early boot, the kext with the highest version always wins out.
2484 * Prelinked kernels will never hit this, but mkexts and booter-read
2485 * kexts might have duplicates.
2487 if (newVersion
> existingVersion
) {
2488 sKextsByID
->setObject(bundleID
.get(), this);
2492 kOSKextLogStepLevel
|
2493 kOSKextLogKextBookkeepingFlag
,
2494 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2495 existingVersionCString
,
2496 getIdentifierCString(),
2500 kOSKextLogStepLevel
|
2501 kOSKextLogKextBookkeepingFlag
,
2502 "Kext %s is already registered with a higher/same version (v%s); "
2503 "dropping newly-added (v%s).",
2504 getIdentifierCString(),
2505 existingVersionCString
,
2509 /* result has been set appropriately by now. */
2513 IORecursiveLockUnlock(sKextLock
);
2517 kOSKextLogStepLevel
|
2518 kOSKextLogKextBookkeepingFlag
,
2519 "Kext %s, v%s registered and available for loading.",
2520 getIdentifierCString(), newVersionCString
);
2526 /*********************************************************************
2527 * Does the bare minimum validation to look up a kext.
2528 * All other validation is done on the spot as needed.
2529 **********************************************************************/
2531 OSKext::setInfoDictionaryAndPath(
2532 OSDictionary
* aDictionary
,
2535 bool result
= false;
2536 OSString
* bundleIDString
= NULL
; // do not release
2537 OSString
* versionString
= NULL
; // do not release
2538 OSString
* compatibleVersionString
= NULL
; // do not release
2539 const char * versionCString
= NULL
; // do not free
2540 const char * compatibleVersionCString
= NULL
; // do not free
2541 OSBoolean
* scratchBool
= NULL
; // do not release
2542 OSDictionary
* scratchDict
= NULL
; // do not release
2545 panic("Attempt to set info dictionary on a kext "
2546 "that already has one (%s).",
2547 getIdentifierCString());
2550 if (!aDictionary
|| !OSDynamicCast(OSDictionary
, aDictionary
)) {
2554 infoDict
.reset(aDictionary
, OSRetain
);
2556 /* Check right away if the info dictionary has any log flags.
2558 scratchBool
= OSDynamicCast(OSBoolean
,
2559 getPropertyForHostArch(kOSBundleEnableKextLoggingKey
));
2560 if (scratchBool
== kOSBooleanTrue
) {
2561 flags
.loggingEnabled
= 1;
2564 /* The very next thing to get is the bundle identifier. Unlike
2565 * in user space, a kext with no bundle identifier gets axed
2568 bundleIDString
= OSDynamicCast(OSString
,
2569 getPropertyForHostArch(kCFBundleIdentifierKey
));
2570 if (!bundleIDString
) {
2572 kOSKextLogErrorLevel
|
2573 kOSKextLogValidationFlag
,
2574 "CFBundleIdentifier missing/invalid type in kext %s.",
2575 aPath
? aPath
->getCStringNoCopy() : "(unknown)");
2578 bundleID
= OSSymbol::withString(bundleIDString
);
2581 kOSKextLogErrorLevel
|
2582 kOSKextLogValidationFlag
,
2583 "Can't copy bundle identifier as symbol for kext %s.",
2584 bundleIDString
->getCStringNoCopy());
2588 /* Save the path if we got one (it should always be available but it's
2589 * just something nice to have for bookkeeping).
2592 path
.reset(aPath
, OSRetain
);
2596 * Minimal validation to initialize. We'll do other validation on the spot.
2598 if (bundleID
->getLength() >= KMOD_MAX_NAME
) {
2600 kOSKextLogErrorLevel
|
2601 kOSKextLogValidationFlag
,
2602 "Kext %s error - CFBundleIdentifier over max length %d.",
2603 getIdentifierCString(), KMOD_MAX_NAME
- 1);
2607 version
= compatibleVersion
= -1;
2609 versionString
= OSDynamicCast(OSString
,
2610 getPropertyForHostArch(kCFBundleVersionKey
));
2611 if (!versionString
) {
2613 kOSKextLogErrorLevel
|
2614 kOSKextLogValidationFlag
,
2615 "Kext %s error - CFBundleVersion missing/invalid type.",
2616 getIdentifierCString());
2619 versionCString
= versionString
->getCStringNoCopy();
2620 version
= OSKextParseVersionString(versionCString
);
2623 kOSKextLogErrorLevel
|
2624 kOSKextLogValidationFlag
,
2625 "Kext %s error - CFBundleVersion bad value '%s'.",
2626 getIdentifierCString(), versionCString
);
2630 compatibleVersion
= -1; // set to illegal value for kexts that don't have
2632 compatibleVersionString
= OSDynamicCast(OSString
,
2633 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
2634 if (compatibleVersionString
) {
2635 compatibleVersionCString
= compatibleVersionString
->getCStringNoCopy();
2636 compatibleVersion
= OSKextParseVersionString(compatibleVersionCString
);
2637 if (compatibleVersion
< 0) {
2639 kOSKextLogErrorLevel
|
2640 kOSKextLogValidationFlag
,
2641 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2642 getIdentifierCString(), compatibleVersionCString
);
2646 if (compatibleVersion
> version
) {
2648 kOSKextLogErrorLevel
|
2649 kOSKextLogValidationFlag
,
2650 "Kext %s error - %s %s > %s %s (must be <=).",
2651 getIdentifierCString(),
2652 kOSBundleCompatibleVersionKey
, compatibleVersionCString
,
2653 kCFBundleVersionKey
, versionCString
);
2658 /* Check to see if this kext is in exclude list */
2659 if (isInExcludeList()) {
2661 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
2662 "Kext %s is in exclude list, not loadable",
2663 getIdentifierCString());
2667 /* Set flags for later use if the infoDict gets flushed. We only
2668 * check for true values, not false ones(!)
2670 scratchBool
= OSDynamicCast(OSBoolean
,
2671 getPropertyForHostArch(kOSBundleIsInterfaceKey
));
2672 if (scratchBool
== kOSBooleanTrue
) {
2673 flags
.interface
= 1;
2676 scratchBool
= OSDynamicCast(OSBoolean
,
2677 getPropertyForHostArch(kOSKernelResourceKey
));
2678 if (scratchBool
== kOSBooleanTrue
) {
2679 flags
.kernelComponent
= 1;
2680 flags
.interface
= 1; // xxx - hm. the kernel itself isn't an interface...
2683 /* A kernel component has one implicit dependency on the kernel.
2685 flags
.hasAllDependencies
= 1;
2688 /* Make sure common string values in personalities are uniqued to OSSymbols.
2690 scratchDict
= OSDynamicCast(OSDictionary
,
2691 getPropertyForHostArch(kIOKitPersonalitiesKey
));
2693 uniquePersonalityProperties(scratchDict
);
2703 /*********************************************************************
2704 * Not used for prelinked kernel boot as there is no unrelocated
2706 *********************************************************************/
2708 OSKext::setExecutable(
2709 OSData
* anExecutable
,
2710 OSData
* externalData
,
2711 bool externalDataIsMkext
)
2713 bool result
= false;
2714 const char * executableKey
= NULL
; // do not free
2716 if (!anExecutable
) {
2717 infoDict
->removeObject(_kOSKextExecutableKey
);
2718 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
2719 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
2724 if (infoDict
->getObject(_kOSKextExecutableKey
) ||
2725 infoDict
->getObject(_kOSKextMkextExecutableReferenceKey
)) {
2726 panic("Attempt to set an executable on a kext "
2727 "that already has one (%s).",
2728 getIdentifierCString());
2732 if (externalDataIsMkext
) {
2733 executableKey
= _kOSKextMkextExecutableReferenceKey
;
2735 executableKey
= _kOSKextExecutableKey
;
2739 infoDict
->setObject(executableKey
, anExecutable
);
2741 infoDict
->setObject(_kOSKextExecutableExternalDataKey
, externalData
);
2751 /*********************************************************************
2752 *********************************************************************/
2754 uniqueStringPlistProperty(OSDictionary
* dict
, const char * key
)
2756 OSObject
* value
= NULL
; // do not release
2757 OSString
* stringValue
= NULL
; // do not release
2758 OSSharedPtr
<const OSSymbol
> symbolValue
;
2760 value
= dict
->getObject(key
);
2764 if (OSDynamicCast(OSSymbol
, value
)) {
2765 /* this is already an OSSymbol: we're good */
2769 stringValue
= OSDynamicCast(OSString
, value
);
2774 symbolValue
= OSSymbol::withString(stringValue
);
2779 dict
->setObject(key
, symbolValue
.get());
2785 /*********************************************************************
2786 *********************************************************************/
2788 uniqueStringPlistProperty(OSDictionary
* dict
, const OSString
* key
)
2790 OSObject
* value
= NULL
; // do not release
2791 OSString
* stringValue
= NULL
; // do not release
2792 OSSharedPtr
<const OSSymbol
> symbolValue
;
2794 value
= dict
->getObject(key
);
2798 if (OSDynamicCast(OSSymbol
, value
)) {
2799 /* this is already an OSSymbol: we're good */
2803 stringValue
= OSDynamicCast(OSString
, value
);
2808 symbolValue
= OSSymbol::withString(stringValue
);
2813 dict
->setObject(key
, symbolValue
.get());
2820 OSKext::uniquePersonalityProperties(OSDictionary
* personalityDict
)
2822 OSKext::uniquePersonalityProperties(personalityDict
, true);
2825 /*********************************************************************
2826 * Replace common personality property values with uniqued instances
2827 * to save on wired memory.
2828 *********************************************************************/
2831 OSKext::uniquePersonalityProperties(OSDictionary
* personalityDict
, bool defaultAddKernelBundleIdentifier
)
2833 /* Properties every personality has.
2835 uniqueStringPlistProperty(personalityDict
, kCFBundleIdentifierKey
);
2836 uniqueStringPlistProperty(personalityDict
, kIOProviderClassKey
);
2837 uniqueStringPlistProperty(personalityDict
, gIOClassKey
.get());
2838 if (personalityDict
->getObject(kCFBundleIdentifierKernelKey
)) {
2839 uniqueStringPlistProperty(personalityDict
, kCFBundleIdentifierKernelKey
);
2840 } else if (defaultAddKernelBundleIdentifier
) {
2841 personalityDict
->setObject(kCFBundleIdentifierKernelKey
, personalityDict
->getObject(kCFBundleIdentifierKey
));
2844 /* Other commonly used properties.
2846 uniqueStringPlistProperty(personalityDict
, gIOMatchCategoryKey
);
2847 uniqueStringPlistProperty(personalityDict
, gIOResourceMatchKey
);
2848 uniqueStringPlistProperty(personalityDict
, gIOUserClientClassKey
);
2850 uniqueStringPlistProperty(personalityDict
, "HIDDefaultBehavior");
2851 uniqueStringPlistProperty(personalityDict
, "HIDPointerAccelerationType");
2852 uniqueStringPlistProperty(personalityDict
, "HIDRemoteControlType");
2853 uniqueStringPlistProperty(personalityDict
, "HIDScrollAccelerationType");
2854 uniqueStringPlistProperty(personalityDict
, "IOPersonalityPublisher");
2855 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect");
2856 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect Location");
2857 uniqueStringPlistProperty(personalityDict
, "Vendor");
2858 uniqueStringPlistProperty(personalityDict
, "Vendor Identification");
2859 uniqueStringPlistProperty(personalityDict
, "Vendor Name");
2860 uniqueStringPlistProperty(personalityDict
, "bConfigurationValue");
2861 uniqueStringPlistProperty(personalityDict
, "bInterfaceNumber");
2862 uniqueStringPlistProperty(personalityDict
, "idProduct");
2867 /*********************************************************************
2868 *********************************************************************/
2873 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2879 executableRelPath
.reset();
2880 userExecutableRelPath
.reset();
2881 dependencies
.reset();
2882 linkedExecutable
.reset();
2883 metaClasses
.reset();
2884 interfaceUUID
.reset();
2885 driverKitUUID
.reset();
2887 if (isInterface() && kmod_info
) {
2888 kfree(kmod_info
, sizeof(kmod_info_t
));
2896 #pragma mark Mkext files
2901 * mkext archives are really only relevant on kxld-enabled kernels.
2902 * Without a dynamic kernel linker, we don't need to support any mkexts.
2905 /*********************************************************************
2906 *********************************************************************/
2908 OSKext::readMkextArchive(OSData
* mkextData
,
2909 uint32_t * checksumPtr
)
2911 OSReturn result
= kOSKextReturnBadData
;
2912 uint32_t mkextLength
= 0;
2913 mkext_header
* mkextHeader
= NULL
; // do not free
2914 uint32_t mkextVersion
= 0;
2916 /* Note default return of kOSKextReturnBadData above.
2918 mkextLength
= mkextData
->getLength();
2919 if (mkextLength
< sizeof(mkext_basic_header
)) {
2920 OSKextLog(/* kext */ NULL
,
2921 kOSKextLogErrorLevel
|
2922 kOSKextLogArchiveFlag
,
2923 "Mkext archive too small to be valid.");
2927 mkextHeader
= (mkext_header
*)mkextData
->getBytesNoCopy();
2929 if (MKEXT_GET_MAGIC(mkextHeader
) != MKEXT_MAGIC
||
2930 MKEXT_GET_SIGNATURE(mkextHeader
) != MKEXT_SIGN
) {
2931 OSKextLog(/* kext */ NULL
,
2932 kOSKextLogErrorLevel
|
2933 kOSKextLogArchiveFlag
,
2934 "Mkext archive has invalid magic or signature.");
2938 if (MKEXT_GET_LENGTH(mkextHeader
) != mkextLength
) {
2939 OSKextLog(/* kext */ NULL
,
2940 kOSKextLogErrorLevel
|
2941 kOSKextLogArchiveFlag
,
2942 "Mkext archive recorded length doesn't match actual file length.");
2946 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2948 if (mkextVersion
== MKEXT_VERS_2
) {
2949 result
= OSKext::readMkext2Archive(mkextData
, NULL
, checksumPtr
);
2951 OSKextLog(/* kext */ NULL
,
2952 kOSKextLogErrorLevel
|
2953 kOSKextLogArchiveFlag
,
2954 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion
);
2955 result
= kOSKextReturnUnsupported
;
2962 /*********************************************************************
2963 * Assumes magic, signature, version, length have been checked.
2964 * xxx - need to add further bounds checking for each file entry
2966 * Should keep track of all kexts created so far, and if we hit a
2967 * fatal error halfway through, remove those kexts. If we've dropped
2968 * an older version that had already been read, whoops! Might want to
2969 * add a level of buffering?
2970 *********************************************************************/
2973 OSKext::readMkext2Archive(
2975 OSDictionary
** mkextPlistOut
,
2976 uint32_t * checksumPtr
)
2978 OSReturn result
= kOSReturnError
;
2979 uint32_t mkextLength
;
2980 mkext2_header
* mkextHeader
= NULL
; // do not free
2981 void * mkextEnd
= NULL
; // do not free
2982 uint32_t mkextVersion
;
2983 uint8_t * crc_address
= NULL
;
2984 size_t crc_buffer_size
= 0;
2986 uint32_t mkextPlistOffset
;
2987 uint32_t mkextPlistCompressedSize
;
2988 char * mkextPlistEnd
= NULL
; // do not free
2989 uint32_t mkextPlistFullSize
;
2990 OSSharedPtr
<OSString
> errorString
;
2991 OSSharedPtr
<OSData
> mkextPlistUncompressedData
;
2992 const char * mkextPlistDataBuffer
= NULL
; // do not free
2993 OSSharedPtr
<OSObject
> parsedXML
;
2994 OSDictionary
* mkextPlist
= NULL
; // do not release
2995 OSArray
* mkextInfoDictArray
= NULL
; // do not release
2997 kc_format_t kc_format
;
2999 if (!PE_get_primary_kc_format(&kc_format
)) {
3000 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
3001 "Unable to determine primary KC format");
3005 mkextLength
= mkextData
->getLength();
3006 mkextHeader
= (mkext2_header
*)mkextData
->getBytesNoCopy();
3007 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
3008 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
3010 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
3011 crc_buffer_size
= (uintptr_t)mkextHeader
+
3012 MKEXT_GET_LENGTH(mkextHeader
) - (uintptr_t)crc_address
;
3013 if (crc_buffer_size
> INT32_MAX
) {
3014 OSKextLog(/* kext */ NULL
,
3015 kOSKextLogErrorLevel
|
3016 kOSKextLogArchiveFlag
,
3017 "Mkext archive size is too large (%lu > INT32_MAX).",
3019 result
= kOSKextReturnBadData
;
3022 checksum
= mkext_adler32(crc_address
, (int32_t)crc_buffer_size
);
3024 if (MKEXT_GET_CHECKSUM(mkextHeader
) != checksum
) {
3025 OSKextLog(/* kext */ NULL
,
3026 kOSKextLogErrorLevel
|
3027 kOSKextLogArchiveFlag
,
3028 "Mkext archive has bad checksum.");
3029 result
= kOSKextReturnBadData
;
3034 *checksumPtr
= checksum
;
3037 /* Check that the CPU type & subtype match that of the running kernel. */
3038 if (MKEXT_GET_CPUTYPE(mkextHeader
) == (UInt32
)CPU_TYPE_ANY
) {
3039 OSKextLog(/* kext */ NULL
,
3040 kOSKextLogErrorLevel
|
3041 kOSKextLogArchiveFlag
,
3042 "Mkext archive must have a specific CPU type.");
3043 result
= kOSKextReturnBadData
;
3046 if ((UInt32
)_mh_execute_header
.cputype
!=
3047 MKEXT_GET_CPUTYPE(mkextHeader
)) {
3048 OSKextLog(/* kext */ NULL
,
3049 kOSKextLogErrorLevel
|
3050 kOSKextLogArchiveFlag
,
3051 "Mkext archive does not match the running kernel's CPU type.");
3052 result
= kOSKextReturnArchNotFound
;
3057 mkextPlistOffset
= MKEXT2_GET_PLIST(mkextHeader
);
3058 mkextPlistCompressedSize
= MKEXT2_GET_PLIST_COMPSIZE(mkextHeader
);
3059 mkextPlistEnd
= (char *)mkextHeader
+ mkextPlistOffset
+
3060 mkextPlistCompressedSize
;
3061 if (mkextPlistEnd
> mkextEnd
) {
3062 OSKextLog(/* kext */ NULL
,
3063 kOSKextLogErrorLevel
|
3064 kOSKextLogArchiveFlag
,
3065 "Mkext archive file overrun.");
3066 result
= kOSKextReturnBadData
;
3069 mkextPlistFullSize
= MKEXT2_GET_PLIST_FULLSIZE(mkextHeader
);
3070 if (mkextPlistCompressedSize
) {
3071 mkextPlistUncompressedData
= sKernelKext
->extractMkext2FileData(
3072 (UInt8
*)mkextHeader
+ mkextPlistOffset
,
3074 mkextPlistCompressedSize
, mkextPlistFullSize
);
3075 if (!mkextPlistUncompressedData
) {
3078 mkextPlistDataBuffer
= (const char *)
3079 mkextPlistUncompressedData
->getBytesNoCopy();
3081 mkextPlistDataBuffer
= (const char *)mkextHeader
+ mkextPlistOffset
;
3084 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3086 parsedXML
= OSUnserializeXML(mkextPlistDataBuffer
, errorString
);
3088 mkextPlist
= OSDynamicCast(OSDictionary
, parsedXML
.get());
3091 const char * errorCString
= "(unknown error)";
3093 if (errorString
&& errorString
->getCStringNoCopy()) {
3094 errorCString
= errorString
->getCStringNoCopy();
3095 } else if (parsedXML
) {
3096 errorCString
= "not a dictionary";
3098 OSKextLog(/* kext */ NULL
,
3099 kOSKextLogErrorLevel
|
3100 kOSKextLogArchiveFlag
,
3101 "Error unserializing mkext plist: %s.", errorCString
);
3105 mkextInfoDictArray
= OSDynamicCast(OSArray
,
3106 mkextPlist
->getObject(kMKEXTInfoDictionariesKey
));
3107 if (!mkextInfoDictArray
) {
3108 OSKextLog(/* kext */ NULL
,
3109 kOSKextLogErrorLevel
|
3110 kOSKextLogArchiveFlag
,
3111 "Mkext archive contains no kext info dictionaries.");
3115 count
= mkextInfoDictArray
->getCount();
3116 for (i
= 0; i
< count
; i
++) {
3117 OSDictionary
* infoDict
;
3120 infoDict
= OSDynamicCast(OSDictionary
,
3121 mkextInfoDictArray
->getObject(i
));
3123 /* Create the kext for the entry, then release it, because the
3124 * kext system keeps them around until explicitly removed.
3125 * Any creation/registration failures are already logged for us.
3128 OSSharedPtr
<OSKext
> newKext
= OSKext::withMkext2Info(infoDict
, mkextData
);
3130 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3131 if (kc_format
== KCFormatFileset
&&
3133 !(newKext
->isPrelinked()) &&
3134 newKext
->declaresExecutable()) {
3135 result
= kOSReturnError
;
3136 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3137 newKext
->getIdentifier() ? newKext
->getIdentifierCString() : "unknown kext");
3139 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
3140 "Dynamic loading of kext denied for kext %s\n",
3141 newKext
->getIdentifier() ? newKext
->getIdentifierCString() : "unknown kext");
3147 /* If the caller needs the plist, hand them back our copy
3149 if (mkextPlistOut
) {
3150 *mkextPlistOut
= mkextPlist
;
3154 /* Even if we didn't keep any kexts from the mkext, we may have a load
3155 * request to process, so we are successful (no errors occurred).
3157 result
= kOSReturnSuccess
;
3165 OSKext::readMkext2Archive(
3167 OSSharedPtr
<OSDictionary
> &mkextPlistOut
,
3168 uint32_t * checksumPtr
)
3170 OSDictionary
* mkextPlist
= NULL
;
3173 if (kOSReturnSuccess
== (ret
= readMkext2Archive(mkextData
,
3176 mkextPlistOut
.reset(mkextPlist
, OSNoRetain
);
3181 /*********************************************************************
3182 *********************************************************************/
3185 OSKext::withMkext2Info(
3186 OSDictionary
* anInfoDict
,
3189 OSSharedPtr
<OSKext
> newKext
= OSMakeShared
<OSKext
>();
3191 if (newKext
&& !newKext
->initWithMkext2Info(anInfoDict
, mkextData
)) {
3198 /*********************************************************************
3199 *********************************************************************/
3201 OSKext::initWithMkext2Info(
3202 OSDictionary
* anInfoDict
,
3205 bool result
= false;
3206 OSString
* kextPath
= NULL
; // do not release
3207 OSNumber
* executableOffsetNum
= NULL
; // do not release
3208 OSSharedPtr
<OSData
> executable
;
3210 if (anInfoDict
== NULL
|| !super::init()) {
3214 /* Get the path. Don't look for an arch-specific path property.
3216 kextPath
= OSDynamicCast(OSString
,
3217 anInfoDict
->getObject(kMKEXTBundlePathKey
));
3219 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
3223 /* If we have a path to the executable, save it.
3225 executableRelPath
.reset(OSDynamicCast(OSString
,
3226 anInfoDict
->getObject(kMKEXTExecutableRelativePathKey
)), OSRetain
);
3228 /* Don't need the paths to be in the info dictionary any more.
3230 anInfoDict
->removeObject(kMKEXTBundlePathKey
);
3231 anInfoDict
->removeObject(kMKEXTExecutableRelativePathKey
);
3233 executableOffsetNum
= OSDynamicCast(OSNumber
,
3234 infoDict
->getObject(kMKEXTExecutableKey
));
3235 if (executableOffsetNum
) {
3236 executable
= createMkext2FileEntry(mkextData
,
3237 executableOffsetNum
, "executable");
3238 infoDict
->removeObject(kMKEXTExecutableKey
);
3242 if (!setExecutable(executable
.get(), mkextData
, true)) {
3247 result
= registerIdentifier();
3253 /*********************************************************************
3254 *********************************************************************/
3256 OSKext::createMkext2FileEntry(
3258 OSNumber
* offsetNum
,
3261 OSSharedPtr
<OSData
> result
;
3262 MkextEntryRef entryRef
;
3263 uint8_t * mkextBuffer
= (uint8_t *)mkextData
->getBytesNoCopy();
3264 uint32_t entryOffset
= offsetNum
->unsigned32BitValue();
3266 result
= OSData::withCapacity(sizeof(entryRef
));
3271 entryRef
.mkext
= (mkext_basic_header
*)mkextBuffer
;
3272 entryRef
.fileinfo
= mkextBuffer
+ entryOffset
;
3273 if (!result
->appendBytes(&entryRef
, sizeof(entryRef
))) {
3281 kOSKextLogErrorLevel
|
3282 kOSKextLogArchiveFlag
,
3283 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3284 name
, getIdentifierCString());
3289 /*********************************************************************
3290 *********************************************************************/
3292 static void * z_alloc(void *, u_int items
, u_int size
);
3293 static void z_free(void *, void *ptr
);
3295 typedef struct z_mem
{
3296 uint32_t alloc_size
;
3301 * Space allocation and freeing routines for use by zlib routines.
3304 z_alloc(void * notused __unused
, u_int num_items
, u_int size
)
3306 void * result
= NULL
;
3307 z_mem
* zmem
= NULL
;
3309 uint64_t total
= ((uint64_t)num_items
) * ((uint64_t)size
);
3310 //Check for overflow due to multiplication
3311 if (total
> UINT32_MAX
) {
3312 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3313 notused
, num_items
, size
, num_items
, size
);
3316 uint64_t allocSize64
= total
+ ((uint64_t)sizeof(zmem
));
3317 //Check for overflow due to addition
3318 if (allocSize64
> UINT32_MAX
) {
3319 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3320 notused
, num_items
, size
, (uint32_t)total
, sizeof(zmem
));
3322 uint32_t allocSize
= (uint32_t)allocSize64
;
3324 zmem
= (z_mem
*)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, allocSize
,
3325 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
3329 zmem
->alloc_size
= allocSize
;
3330 result
= (void *)&(zmem
->data
);
3336 z_free(void * notused __unused
, void * ptr
)
3338 uint32_t * skipper
= (uint32_t *)ptr
- 1;
3339 z_mem
* zmem
= (z_mem
*)skipper
;
3340 kheap_free(KHEAP_DATA_BUFFERS
, zmem
, zmem
->alloc_size
);
3346 OSKext::extractMkext2FileData(
3349 uint32_t compressedSize
,
3352 OSSharedPtr
<OSData
> result
;
3353 OSSharedPtr
<OSData
> uncompressedData
; // release on error
3355 uint8_t * uncompressedDataBuffer
= NULL
; // do not free
3356 unsigned long uncompressedSize
;
3358 bool zstream_inited
= false;
3361 /* If the file isn't compressed, we want to make a copy
3362 * so that we don't have the tie to the larger mkext file buffer any more.
3364 if (!compressedSize
) {
3365 uncompressedData
= OSData::withBytes(data
, fullSize
);
3366 // xxx - no check for failure?
3367 result
= uncompressedData
;
3371 if (KERN_SUCCESS
!= kmem_alloc(kernel_map
,
3372 (vm_offset_t
*)&uncompressedDataBuffer
, fullSize
, VM_KERN_MEMORY_OSKEXT
)) {
3373 /* How's this for cheesy? The kernel is only asked to extract
3374 * kext plists so we tailor the log messages.
3378 kOSKextLogErrorLevel
|
3379 kOSKextLogArchiveFlag
,
3380 "Allocation failure extracting %s from mkext.", name
);
3383 kOSKextLogErrorLevel
|
3384 kOSKextLogArchiveFlag
,
3385 "Allocation failure extracting %s from mkext for kext %s.",
3386 name
, getIdentifierCString());
3391 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
, fullSize
);
3392 if (!uncompressedData
) {
3395 kOSKextLogErrorLevel
|
3396 kOSKextLogArchiveFlag
,
3397 "Allocation failure extracting %s from mkext.", name
);
3400 kOSKextLogErrorLevel
|
3401 kOSKextLogArchiveFlag
,
3402 "Allocation failure extracting %s from mkext for kext %s.",
3403 name
, getIdentifierCString());
3407 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
3411 kOSKextLogDetailLevel
|
3412 kOSKextLogArchiveFlag
,
3413 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3414 name
, compressedSize
, fullSize
);
3417 kOSKextLogDetailLevel
|
3418 kOSKextLogArchiveFlag
,
3419 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3420 getIdentifierCString(), name
, compressedSize
, fullSize
);
3423 bzero(&zstream
, sizeof(zstream
));
3424 zstream
.next_in
= (UInt8
*)data
;
3425 zstream
.avail_in
= compressedSize
;
3427 zstream
.next_out
= uncompressedDataBuffer
;
3428 zstream
.avail_out
= fullSize
;
3430 zstream
.zalloc
= z_alloc
;
3431 zstream
.zfree
= z_free
;
3433 zlib_result
= inflateInit(&zstream
);
3434 if (Z_OK
!= zlib_result
) {
3437 kOSKextLogErrorLevel
|
3438 kOSKextLogArchiveFlag
,
3439 "Mkext error; zlib inflateInit failed (%d) for %s.",
3443 kOSKextLogErrorLevel
|
3444 kOSKextLogArchiveFlag
,
3445 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3446 getIdentifierCString(), zlib_result
, name
);
3450 zstream_inited
= true;
3453 zlib_result
= inflate(&zstream
, Z_FINISH
);
3455 if (zlib_result
== Z_STREAM_END
|| zlib_result
== Z_OK
) {
3456 uncompressedSize
= zstream
.total_out
;
3460 kOSKextLogErrorLevel
|
3461 kOSKextLogArchiveFlag
,
3462 "Mkext error; zlib inflate failed (%d) for %s.",
3466 kOSKextLogErrorLevel
|
3467 kOSKextLogArchiveFlag
,
3468 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3469 getIdentifierCString(), zlib_result
, name
);
3473 kOSKextLogErrorLevel
|
3474 kOSKextLogArchiveFlag
,
3475 "zlib error: %s.", zstream
.msg
);
3480 if (uncompressedSize
!= fullSize
) {
3483 kOSKextLogErrorLevel
|
3484 kOSKextLogArchiveFlag
,
3485 "Mkext error; zlib inflate discrepancy for %s, "
3486 "uncompressed size != original size.", name
);
3489 kOSKextLogErrorLevel
|
3490 kOSKextLogArchiveFlag
,
3491 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3492 "uncompressed size != original size.",
3493 getIdentifierCString(), name
);
3498 result
= os::move(uncompressedData
);
3501 /* Don't bother checking return, nothing we can do on fail.
3503 if (zstream_inited
) {
3504 inflateEnd(&zstream
);
3510 /*********************************************************************
3511 *********************************************************************/
3514 OSKext::loadFromMkext(
3515 OSKextLogSpec clientLogFilter
,
3517 uint32_t mkextBufferLength
,
3519 uint32_t * logInfoLengthOut
)
3521 OSReturn result
= kOSReturnError
;
3522 OSReturn tempResult
= kOSReturnError
;
3524 OSSharedPtr
<OSData
> mkextData
;
3525 OSSharedPtr
<OSDictionary
> mkextPlist
;
3527 OSSharedPtr
<OSArray
> logInfoArray
;
3528 OSSharedPtr
<OSSerialize
> serializer
;
3530 OSString
* predicate
= NULL
; // do not release
3531 OSDictionary
* requestArgs
= NULL
; // do not release
3533 OSString
* kextIdentifier
= NULL
; // do not release
3534 OSNumber
* startKextExcludeNum
= NULL
; // do not release
3535 OSNumber
* startMatchingExcludeNum
= NULL
; // do not release
3536 OSBoolean
* delayAutounloadBool
= NULL
; // do not release
3537 OSArray
* personalityNames
= NULL
; // do not release
3539 /* Default values for these two options: regular autounload behavior,
3540 * load all kexts, send no personalities.
3542 Boolean delayAutounload
= false;
3543 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
3544 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeAll
;
3546 IORecursiveLockLock(sKextLock
);
3550 *logInfoLengthOut
= 0;
3553 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
3555 OSKextLog(/* kext */ NULL
,
3556 kOSKextLogDebugLevel
|
3558 "Received kext load request from user space.");
3560 /* Regardless of processing, the fact that we have gotten here means some
3561 * user-space program is up and talking to us, so we'll switch our kext
3562 * registration to reflect that.
3564 if (!sUserLoadsActive
) {
3565 OSKextLog(/* kext */ NULL
,
3566 kOSKextLogProgressLevel
|
3567 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
3568 "Switching to late startup (user-space) kext loading policy.");
3570 sUserLoadsActive
= true;
3573 if (!sLoadEnabled
) {
3574 OSKextLog(/* kext */ NULL
,
3575 kOSKextLogErrorLevel
|
3577 "Kext loading is disabled.");
3578 result
= kOSKextReturnDisabled
;
3582 /* Note that we do not set a dealloc function on this OSData
3583 * object! No references to it can remain after the loadFromMkext()
3584 * call since we are in a MIG function, and will vm_deallocate()
3587 mkextData
= OSData::withBytesNoCopy(mkextBuffer
,
3590 OSKextLog(/* kext */ NULL
,
3591 kOSKextLogErrorLevel
|
3592 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3593 "Failed to create wrapper for kext load request.");
3594 result
= kOSKextReturnNoMemory
;
3598 result
= readMkext2Archive(mkextData
.get(), mkextPlist
, NULL
);
3599 if (result
!= kOSReturnSuccess
) {
3600 OSKextLog(/* kext */ NULL
,
3601 kOSKextLogErrorLevel
|
3603 "Failed to read kext load request.");
3607 predicate
= _OSKextGetRequestPredicate(mkextPlist
.get());
3608 if (!predicate
|| !predicate
->isEqualTo(kKextRequestPredicateLoad
)) {
3609 OSKextLog(/* kext */ NULL
,
3610 kOSKextLogErrorLevel
|
3612 "Received kext load request with no predicate; skipping.");
3613 result
= kOSKextReturnInvalidArgument
;
3617 requestArgs
= OSDynamicCast(OSDictionary
,
3618 mkextPlist
->getObject(kKextRequestArgumentsKey
));
3619 if (!requestArgs
|| !requestArgs
->getCount()) {
3620 OSKextLog(/* kext */ NULL
,
3621 kOSKextLogErrorLevel
|
3623 "Received kext load request with no arguments.");
3624 result
= kOSKextReturnInvalidArgument
;
3628 kextIdentifier
= OSDynamicCast(OSString
,
3629 requestArgs
->getObject(kKextRequestArgumentBundleIdentifierKey
));
3631 if (!kextIdentifier
) {
3632 OSKextLog(/* kext */ NULL
,
3633 kOSKextLogErrorLevel
|
3635 "Received kext load request with no kext identifier.");
3636 result
= kOSKextReturnInvalidArgument
;
3640 startKextExcludeNum
= OSDynamicCast(OSNumber
,
3641 requestArgs
->getObject(kKextRequestArgumentStartExcludeKey
));
3642 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
3643 requestArgs
->getObject(kKextRequestArgumentStartMatchingExcludeKey
));
3644 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
3645 requestArgs
->getObject(kKextRequestArgumentDelayAutounloadKey
));
3646 personalityNames
= OSDynamicCast(OSArray
,
3647 requestArgs
->getObject(kKextRequestArgumentPersonalityNamesKey
));
3649 if (delayAutounloadBool
) {
3650 delayAutounload
= delayAutounloadBool
->getValue();
3652 if (startKextExcludeNum
) {
3653 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
3655 if (startMatchingExcludeNum
) {
3656 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
3659 OSKextLog(/* kext */ NULL
,
3660 kOSKextLogProgressLevel
|
3662 "Received request from user space to load kext %s.",
3663 kextIdentifier
->getCStringNoCopy());
3665 /* Load the kext, with no deferral, since this is a load from outside
3667 * xxx - Would like a better way to handle the default values for the
3668 * xxx - start/match opt args.
3670 result
= OSKext::loadKextWithIdentifier(
3673 /* allowDefer */ false,
3675 startKextExcludeLevel
,
3676 startMatchingExcludeLevel
,
3678 if (result
!= kOSReturnSuccess
) {
3681 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3682 * for matching via a separate IOKit calldown.
3687 /* Gather up the collected log messages for user space. Any
3688 * error messages past this call will not make it up as log messages
3689 * but will be in the system log.
3691 logInfoArray
= OSKext::clearUserSpaceLogFilter();
3693 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
3694 tempResult
= OSKext::serializeLogInfo(logInfoArray
.get(),
3695 logInfoOut
, logInfoLengthOut
);
3696 if (tempResult
!= kOSReturnSuccess
) {
3697 result
= tempResult
;
3701 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3703 IORecursiveLockUnlock(sKextLock
);
3705 /* Note: mkextDataObject will have been retained by every kext w/an
3706 * executable in it. That should all have been flushed out at the
3707 * and of the load operation, but you never know....
3709 if (mkextData
&& mkextData
->getRetainCount() > 1) {
3710 OSKextLog(/* kext */ NULL
,
3711 kOSKextLogErrorLevel
|
3712 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3713 "Kext load request buffer from user space still retained by a kext; "
3714 "probable memory leak.");
3720 #endif // CONFIG_KXLD
3722 /*********************************************************************
3723 *********************************************************************/
3726 OSKext::serializeLogInfo(
3727 OSArray
* logInfoArray
,
3729 uint32_t * logInfoLengthOut
)
3731 OSReturn result
= kOSReturnError
;
3732 char * buffer
= NULL
;
3733 kern_return_t kmem_result
= KERN_FAILURE
;
3734 OSSharedPtr
<OSSerialize
> serializer
;
3735 char * logInfo
= NULL
; // returned by reference
3736 uint32_t logInfoLength
= 0;
3738 if (!logInfoArray
|| !logInfoOut
|| !logInfoLengthOut
) {
3739 OSKextLog(/* kext */ NULL
,
3740 kOSKextLogErrorLevel
|
3742 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3743 /* Bad programmer. */
3744 result
= kOSKextReturnInvalidArgument
;
3748 serializer
= OSSerialize::withCapacity(0);
3750 OSKextLog(/* kext */ NULL
,
3751 kOSKextLogErrorLevel
|
3753 "Failed to create serializer on log info for request from user space.");
3754 /* Incidental error; we're going to (try to) allow the request
3755 * itself to succeed. */
3758 if (!logInfoArray
->serialize(serializer
.get())) {
3759 OSKextLog(/* kext */ NULL
,
3760 kOSKextLogErrorLevel
|
3762 "Failed to serialize log info for request from user space.");
3763 /* Incidental error; we're going to (try to) allow the request
3764 * itself to succeed. */
3766 logInfo
= serializer
->text();
3767 logInfoLength
= serializer
->getLength();
3769 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
, round_page(logInfoLength
), VM_KERN_MEMORY_OSKEXT
);
3770 if (kmem_result
!= KERN_SUCCESS
) {
3771 OSKextLog(/* kext */ NULL
,
3772 kOSKextLogErrorLevel
|
3774 "Failed to copy log info for request from user space.");
3775 /* Incidental error; we're going to (try to) allow the request
3778 /* 11981737 - clear uninitialized data in last page */
3779 bzero((void *)(buffer
+ logInfoLength
),
3780 (round_page(logInfoLength
) - logInfoLength
));
3781 memcpy(buffer
, logInfo
, logInfoLength
);
3782 *logInfoOut
= buffer
;
3783 *logInfoLengthOut
= logInfoLength
;
3787 result
= kOSReturnSuccess
;
3793 #pragma mark Instance Management Methods
3795 /*********************************************************************
3796 *********************************************************************/
3798 OSKext::lookupKextWithIdentifier(const char * kextIdentifier
)
3800 OSSharedPtr
<OSKext
> foundKext
;
3802 IORecursiveLockLock(sKextLock
);
3803 foundKext
.reset(OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
)), OSRetain
);
3804 IORecursiveLockUnlock(sKextLock
);
3809 /*********************************************************************
3810 *********************************************************************/
3812 OSKext::lookupKextWithIdentifier(OSString
* kextIdentifier
)
3814 return OSKext::lookupKextWithIdentifier(kextIdentifier
->getCStringNoCopy());
3817 /*********************************************************************
3818 *********************************************************************/
3820 OSKext::lookupKextWithLoadTag(uint32_t aTag
)
3822 OSSharedPtr
<OSKext
> foundKext
; // returned
3824 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
3825 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
3827 IORecursiveLockLock(sKextLock
);
3829 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
3830 for (i
= 0; i
< count
[j
]; i
++) {
3831 OSKext
* thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
3832 if (thisKext
->getLoadTag() == aTag
) {
3833 foundKext
.reset(thisKext
, OSRetain
);
3840 IORecursiveLockUnlock(sKextLock
);
3845 /*********************************************************************
3846 *********************************************************************/
3848 OSKext::lookupKextWithAddress(vm_address_t address
)
3850 OSSharedPtr
<OSKext
> foundKext
; // returned
3852 kmod_info_t
*kmod_info
;
3853 vm_address_t originalAddress
;
3854 #if defined(__arm64__)
3855 uint64_t textExecBase
;
3856 size_t textExecSize
;
3857 #endif /* defined(__arm64__) */
3859 originalAddress
= address
;
3860 #if __has_feature(ptrauth_calls)
3861 address
= (vm_address_t
)VM_KERNEL_STRIP_PTR(address
);
3862 #endif /* __has_feature(ptrauth_calls) */
3864 IORecursiveLockLock(sKextLock
);
3866 count
= sLoadedKexts
->getCount();
3867 for (i
= 0; i
< count
; i
++) {
3868 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3869 if (thisKext
== sKernelKext
) {
3872 if (thisKext
->kmod_info
&& thisKext
->kmod_info
->address
) {
3873 kmod_info
= thisKext
->kmod_info
;
3874 vm_address_t kext_start
= kmod_info
->address
;
3875 vm_address_t kext_end
= kext_start
+ kmod_info
->size
;
3876 if ((kext_start
<= address
) && (address
< kext_end
)) {
3877 foundKext
.reset(thisKext
, OSRetain
);
3880 #if defined(__arm64__)
3881 textExecBase
= (uintptr_t) getsegdatafromheader((kernel_mach_header_t
*)kmod_info
->address
, "__TEXT_EXEC", &textExecSize
);
3882 if ((textExecBase
<= address
) && (address
< textExecBase
+ textExecSize
)) {
3883 foundKext
.reset(thisKext
, OSRetain
);
3886 #endif /* defined (__arm64__) */
3889 if ((address
>= vm_kernel_stext
) && (address
< vm_kernel_etext
)) {
3890 foundKext
.reset(sKernelKext
, OSRetain
);
3894 * DriverKit userspace executables do not have a kernel linkedExecutable,
3895 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3896 * here, so use the original address passed to this method.
3898 * This is supposed to be used for logging reasons only. When logd
3899 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3900 * remove it here before checking it against the LoadTag.
3901 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3904 address
= originalAddress
& ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK
| FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT
);
3905 count
= sLoadedDriverKitKexts
->getCount();
3906 for (i
= 0; i
< count
; i
++) {
3907 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedDriverKitKexts
->getObject(i
));
3908 if (thisKext
->getLoadTag() == address
) {
3909 foundKext
.reset(thisKext
, OSRetain
);
3914 IORecursiveLockUnlock(sKextLock
);
3920 OSKext::copyKextUUIDForAddress(OSNumber
*address
)
3922 OSSharedPtr
<OSData
> uuid
;
3923 OSSharedPtr
<OSKext
> kext
;
3930 /* Is the calling process allowed to query kext info? */
3931 if (current_task() != kernel_task
) {
3932 int macCheckResult
= 0;
3933 kauth_cred_t cred
= NULL
;
3935 cred
= kauth_cred_get_with_ref();
3936 macCheckResult
= mac_kext_check_query(cred
);
3937 kauth_cred_unref(&cred
);
3939 if (macCheckResult
!= 0) {
3940 OSKextLog(/* kext */ NULL
,
3941 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
3942 "Failed to query kext UUID (MAC policy error 0x%x).",
3949 uintptr_t slidAddress
= ml_static_slide((uintptr_t)address
->unsigned64BitValue());
3950 if (slidAddress
!= 0) {
3951 kext
= lookupKextWithAddress(slidAddress
);
3953 uuid
= kext
->copyTextUUID();
3959 * If we still don't have a UUID, then we failed to match the slid + stripped address with
3960 * a kext. This might have happened because the log message came from a dext.
3962 * Try again with the original address.
3964 kext
= lookupKextWithAddress((vm_address_t
)address
->unsigned64BitValue());
3965 if (kext
&& kext
->isDriverKit()) {
3966 uuid
= kext
->copyTextUUID();
3973 /*********************************************************************
3974 *********************************************************************/
3976 OSKext::lookupKextWithUUID(uuid_t wanted
)
3978 OSSharedPtr
<OSKext
> foundKext
; // returned
3980 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
3981 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
3984 IORecursiveLockLock(sKextLock
);
3986 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
3987 for (i
= 0; i
< count
[j
]; i
++) {
3988 OSKext
* thisKext
= NULL
;
3990 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
3995 OSSharedPtr
<OSData
> uuid_data
= thisKext
->copyUUID();
4001 memcpy(&uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
4003 if (0 == uuid_compare(wanted
, uuid
)) {
4004 foundKext
.reset(thisKext
, OSRetain
);
4010 IORecursiveLockUnlock(sKextLock
);
4018 /*********************************************************************
4019 *********************************************************************/
4022 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
4024 bool result
= false;
4025 OSKext
* foundKext
= NULL
; // returned
4027 IORecursiveLockLock(sKextLock
);
4029 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4030 if (foundKext
&& foundKext
->isLoaded()) {
4034 IORecursiveLockUnlock(sKextLock
);
4039 /*********************************************************************
4040 * xxx - should spawn a separate thread so a kext can safely have
4041 * xxx - itself unloaded.
4042 *********************************************************************/
4050 bool terminateServicesAndRemovePersonalitiesFlag
)
4054 kOSKextLogErrorLevel
|
4055 kOSKextLogKextBookkeepingFlag
,
4056 "removeKext() called for %s, not supported on embedded",
4057 aKext
->getIdentifier() ? aKext
->getIdentifierCString() : "unknown kext");
4059 return kOSReturnSuccess
;
4060 #else /* CONFIG_EMBEDDED */
4062 OSReturn result
= kOSKextReturnInUse
;
4063 OSKext
* checkKext
= NULL
; // do not release
4065 int macCheckResult
= 0;
4066 kauth_cred_t cred
= NULL
;
4069 IORecursiveLockLock(sKextLock
);
4071 /* If the kext has no identifier, it failed to init
4072 * so isn't in sKextsByID and it isn't loaded.
4074 if (!aKext
->getIdentifier()) {
4075 result
= kOSReturnSuccess
;
4079 checkKext
= OSDynamicCast(OSKext
,
4080 sKextsByID
->getObject(aKext
->getIdentifier()));
4081 if (checkKext
!= aKext
) {
4082 result
= kOSKextReturnNotFound
;
4086 if (aKext
->isLoaded()) {
4088 if (current_task() != kernel_task
) {
4089 cred
= kauth_cred_get_with_ref();
4090 macCheckResult
= mac_kext_check_unload(cred
, aKext
->getIdentifierCString());
4091 kauth_cred_unref(&cred
);
4094 if (macCheckResult
!= 0) {
4095 result
= kOSReturnError
;
4097 kOSKextLogErrorLevel
|
4098 kOSKextLogKextBookkeepingFlag
,
4099 "Failed to remove kext %s (MAC policy error 0x%x).",
4100 aKext
->getIdentifierCString(), macCheckResult
);
4105 /* make sure there are no resource requests in flight - 17187548 */
4106 if (aKext
->countRequestCallbacks()) {
4109 if (aKext
->flags
.unloadUnsupported
) {
4110 result
= kOSKextReturnInUse
;
4112 kOSKextLogErrorLevel
|
4113 kOSKextLogKextBookkeepingFlag
,
4114 "Can't remove kext %s; unsupported by cache.",
4115 aKext
->getIdentifierCString());
4119 /* If we are terminating, send the request to the IOCatalogue
4120 * (which will actually call us right back but that's ok we have
4121 * a recursive lock don't you know) but do not ask the IOCatalogue
4122 * to call back with an unload, we'll do that right here.
4124 if (terminateServicesAndRemovePersonalitiesFlag
) {
4125 result
= gIOCatalogue
->terminateDriversForModule(
4126 aKext
->getIdentifierCString(), /* unload */ false);
4127 if (result
!= kOSReturnSuccess
) {
4129 kOSKextLogErrorLevel
|
4130 kOSKextLogKextBookkeepingFlag
,
4131 "Can't remove kext %s; services failed to terminate - 0x%x.",
4132 aKext
->getIdentifierCString(), result
);
4137 result
= aKext
->unload();
4138 if (result
!= kOSReturnSuccess
) {
4143 /* Remove personalities as requested. This is a bit redundant for a loaded
4144 * kext as IOCatalogue::terminateDriversForModule() removes driver
4145 * personalities, but it doesn't restart matching, which we always want
4146 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4149 if (terminateServicesAndRemovePersonalitiesFlag
) {
4150 aKext
->removePersonalitiesFromCatalog();
4153 if (aKext
->isInFileset()) {
4155 kOSKextLogProgressLevel
|
4156 kOSKextLogKextBookkeepingFlag
,
4157 "Fileset kext %s unloaded.",
4158 aKext
->getIdentifierCString());
4161 kOSKextLogProgressLevel
|
4162 kOSKextLogKextBookkeepingFlag
,
4163 "Removing kext %s.",
4164 aKext
->getIdentifierCString());
4166 sKextsByID
->removeObject(aKext
->getIdentifier());
4168 result
= kOSReturnSuccess
;
4171 IORecursiveLockUnlock(sKextLock
);
4173 #endif /* CONFIG_EMBEDDED */
4176 /*********************************************************************
4177 *********************************************************************/
4180 OSKext::removeKextWithIdentifier(
4181 const char * kextIdentifier
,
4182 bool terminateServicesAndRemovePersonalitiesFlag
)
4184 OSReturn result
= kOSReturnError
;
4186 IORecursiveLockLock(sKextLock
);
4188 OSKext
* aKext
= OSDynamicCast(OSKext
,
4189 sKextsByID
->getObject(kextIdentifier
));
4191 result
= kOSKextReturnNotFound
;
4192 OSKextLog(/* kext */ NULL
,
4193 kOSKextLogErrorLevel
|
4194 kOSKextLogKextBookkeepingFlag
,
4195 "Can't remove kext %s - not found.",
4200 result
= OSKext::removeKext(aKext
,
4201 terminateServicesAndRemovePersonalitiesFlag
);
4204 IORecursiveLockUnlock(sKextLock
);
4209 /*********************************************************************
4210 *********************************************************************/
4213 OSKext::removeKextWithLoadTag(
4214 OSKextLoadTag loadTag
,
4215 bool terminateServicesAndRemovePersonalitiesFlag
)
4217 OSReturn result
= kOSReturnError
;
4218 OSKext
* foundKext
= NULL
;
4220 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
4221 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
4224 IORecursiveLockLock(sKextLock
);
4226 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
4227 for (i
= 0; i
< count
[j
]; i
++) {
4228 OSKext
* thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
4229 if (thisKext
->loadTag
== loadTag
) {
4230 foundKext
= thisKext
;
4237 result
= kOSKextReturnNotFound
;
4238 OSKextLog(/* kext */ NULL
,
4239 kOSKextLogErrorLevel
|
4240 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
4241 "Can't remove kext with load tag %d - not found.",
4246 result
= OSKext::removeKext(foundKext
,
4247 terminateServicesAndRemovePersonalitiesFlag
);
4250 IORecursiveLockUnlock(sKextLock
);
4255 /*********************************************************************
4256 *********************************************************************/
4257 OSSharedPtr
<OSDictionary
>
4258 OSKext::copyKexts(void)
4260 OSSharedPtr
<OSDictionary
> result
;
4262 IORecursiveLockLock(sKextLock
);
4263 result
= OSDynamicPtrCast
<OSDictionary
>(sKextsByID
->copyCollection());
4264 IORecursiveLockUnlock(sKextLock
);
4269 /*********************************************************************
4270 *********************************************************************/
4271 #define BOOTER_KEXT_PREFIX "Driver-"
4273 typedef struct _DeviceTreeBuffer
{
4276 } _DeviceTreeBuffer
;
4278 /*********************************************************************
4279 * Create a dictionary of excluded kexts from the given booter data.
4280 *********************************************************************/
4283 OSKext::createExcludeListFromBooterData(
4284 OSDictionary
* theDictionary
,
4285 OSCollectionIterator
* theIterator
)
4287 OSString
* deviceTreeName
= NULL
; // do not release
4288 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not release
4289 char * booterDataPtr
= NULL
; // do not release
4290 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not release
4291 char * infoDictAddr
= NULL
; // do not release
4292 OSSharedPtr
<OSObject
> parsedXML
;
4293 OSDictionary
* theInfoDict
= NULL
; // do not release
4295 theIterator
->reset();
4297 /* look for AppleKextExcludeList.kext */
4298 while ((deviceTreeName
=
4299 OSDynamicCast(OSString
, theIterator
->getNextObject()))) {
4300 const char * devTreeNameCString
;
4301 OSData
* deviceTreeEntry
; // do not release
4302 OSString
* myBundleID
; // do not release
4305 OSDynamicCast(OSData
, theDictionary
->getObject(deviceTreeName
));
4306 if (!deviceTreeEntry
) {
4310 /* Make sure it is a kext */
4311 devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
4312 if (strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
4313 (sizeof(BOOTER_KEXT_PREFIX
) - 1)) != 0) {
4315 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4316 "\"%s\" not a kext",
4317 devTreeNameCString
);
4321 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
4322 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
4323 if (!deviceTreeBuffer
) {
4327 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
4328 if (!booterDataPtr
) {
4332 kextFileInfo
= (_BooterKextFileInfo
*) booterDataPtr
;
4333 if (!kextFileInfo
->infoDictPhysAddr
||
4334 !kextFileInfo
->infoDictLength
) {
4338 infoDictAddr
= (char *)
4339 ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
4340 if (!infoDictAddr
) {
4344 parsedXML
= OSUnserializeXML(infoDictAddr
);
4349 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
4355 OSDynamicCast(OSString
,
4356 theInfoDict
->getObject(kCFBundleIdentifierKey
));
4358 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4359 boolean_t updated
= updateExcludeList(theInfoDict
);
4362 panic("Missing OSKextExcludeList dictionary\n");
4366 } // while ( (deviceTreeName = ...) )
4371 /*********************************************************************
4372 * Create a dictionary of excluded kexts from the given prelink
4373 * info (kernelcache).
4374 *********************************************************************/
4377 OSKext::createExcludeListFromPrelinkInfo( OSArray
* theInfoArray
)
4379 OSDictionary
* myInfoDict
= NULL
; // do not release
4380 OSString
* myBundleID
; // do not release
4383 /* Find the Apple Kext Exclude List. */
4384 for (i
= 0; i
< theInfoArray
->getCount(); i
++) {
4385 myInfoDict
= OSDynamicCast(OSDictionary
, theInfoArray
->getObject(i
));
4390 OSDynamicCast(OSString
,
4391 myInfoDict
->getObject(kCFBundleIdentifierKey
));
4393 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4394 boolean_t updated
= updateExcludeList(myInfoDict
);
4397 panic("Missing OSKextExcludeList dictionary\n");
4401 } // for (i = 0; i < theInfoArray->getCount()...
4408 OSKext::updateExcludeList(OSDictionary
*infoDict
)
4410 OSDictionary
*myTempDict
= NULL
; // do not free
4411 OSString
*myTempString
= NULL
; // do not free
4412 OSKextVersion newVersion
= 0;
4413 boolean_t updated
= false;
4419 myTempDict
= OSDynamicCast(OSDictionary
, infoDict
->getObject("OSKextExcludeList"));
4424 myTempString
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundleVersionKey
));
4425 if (!myTempString
) {
4429 newVersion
= OSKextParseVersionString(myTempString
->getCStringNoCopy());
4430 if (newVersion
== 0) {
4434 IORecursiveLockLock(sKextLock
);
4436 if (newVersion
> sExcludeListVersion
) {
4437 sExcludeListByID
= OSDictionary::withDictionary(myTempDict
, 0);
4438 sExcludeListVersion
= newVersion
;
4442 IORecursiveLockUnlock(sKextLock
);
4447 #pragma mark Accessors
4449 /*********************************************************************
4450 *********************************************************************/
4452 OSKext::getIdentifier(void)
4454 return bundleID
.get();
4457 /*********************************************************************
4458 * A kext must have a bundle identifier to even survive initialization;
4459 * this is guaranteed to exist past then.
4460 *********************************************************************/
4462 OSKext::getIdentifierCString(void)
4464 return bundleID
->getCStringNoCopy();
4467 /*********************************************************************
4468 *********************************************************************/
4470 OSKext::getVersion(void)
4475 /*********************************************************************
4476 *********************************************************************/
4478 OSKext::getCompatibleVersion(void)
4480 return compatibleVersion
;
4483 /*********************************************************************
4484 *********************************************************************/
4486 OSKext::isLibrary(void)
4488 return getCompatibleVersion() > 0;
4491 /*********************************************************************
4492 *********************************************************************/
4494 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
4496 if ((compatibleVersion
> -1 && version
> -1) &&
4497 (compatibleVersion
<= version
&& aVersion
<= version
)) {
4503 /*********************************************************************
4504 *********************************************************************/
4506 OSKext::declaresExecutable(void)
4508 if (isDriverKit()) {
4511 return getPropertyForHostArch(kCFBundleExecutableKey
) != NULL
;
4514 /*********************************************************************
4515 *********************************************************************/
4517 OSKext::getExecutable(void)
4519 OSData
* result
= NULL
;
4520 OSSharedPtr
<OSData
> extractedExecutable
;
4522 if (flags
.builtin
) {
4523 return sKernelKext
->linkedExecutable
.get();
4526 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
4532 OSData
* mkextExecutableRef
= NULL
; // do not release
4533 mkextExecutableRef
= OSDynamicCast(OSData
,
4534 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
4536 if (mkextExecutableRef
) {
4537 MkextEntryRef
* mkextEntryRef
= (MkextEntryRef
*)
4538 mkextExecutableRef
->getBytesNoCopy();
4539 uint32_t mkextVersion
= MKEXT_GET_VERSION(mkextEntryRef
->mkext
);
4540 if (mkextVersion
== MKEXT_VERS_2
) {
4541 mkext2_file_entry
* fileinfo
=
4542 (mkext2_file_entry
*)mkextEntryRef
->fileinfo
;
4543 uint32_t compressedSize
= MKEXT2_GET_ENTRY_COMPSIZE(fileinfo
);
4544 uint32_t fullSize
= MKEXT2_GET_ENTRY_FULLSIZE(fileinfo
);
4545 extractedExecutable
= extractMkext2FileData(
4546 MKEXT2_GET_ENTRY_DATA(fileinfo
), "executable",
4547 compressedSize
, fullSize
);
4549 OSKextLog(this, kOSKextLogErrorLevel
|
4550 kOSKextLogArchiveFlag
,
4551 "Kext %s - unknown mkext version 0x%x for executable.",
4552 getIdentifierCString(), mkextVersion
);
4555 /* Regardless of success, remove the mkext executable,
4556 * and drop one reference on the mkext. (setExecutable() does not
4557 * replace, it removes, or panics if asked to replace.)
4559 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
4560 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
4562 if (extractedExecutable
&& extractedExecutable
->getLength()) {
4563 if (!setExecutable(extractedExecutable
.get())) {
4566 result
= extractedExecutable
.get();
4573 #endif // CONFIG_KXLD
4577 /*********************************************************************
4578 *********************************************************************/
4580 OSKext::isInterface(void)
4582 return flags
.interface
;
4585 /*********************************************************************
4586 *********************************************************************/
4588 OSKext::isKernel(void)
4590 return this == sKernelKext
;
4593 /*********************************************************************
4594 *********************************************************************/
4596 OSKext::isKernelComponent(void)
4598 return flags
.kernelComponent
? true : false;
4601 /*********************************************************************
4602 *********************************************************************/
4604 OSKext::isExecutable(void)
4606 return !isKernel() && !isInterface() && declaresExecutable();
4609 /*********************************************************************
4610 * We might want to check this recursively for all dependencies,
4611 * since a subtree of dependencies could get loaded before we hit
4612 * a dependency that isn't safe-boot-loadable.
4614 * xxx - Might want to return false if OSBundleEnableKextLogging or
4615 * OSBundleDebugLevel
4616 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4617 * the point except it's usually development drivers, which might
4618 * cause panics on startup, that have those properties). Heh; could
4619 * use a "kx" boot-arg!
4620 *********************************************************************/
4622 OSKext::isLoadableInSafeBoot(void)
4624 bool result
= false;
4625 OSString
* required
= NULL
; // do not release
4632 if (isDriverKit()) {
4637 required
= OSDynamicCast(OSString
,
4638 getPropertyForHostArch(kOSBundleRequiredKey
));
4642 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
4643 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
4644 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
4645 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
4646 required
->isEqualTo(kOSBundleRequiredConsole
)) {
4654 /*********************************************************************
4655 *********************************************************************/
4657 OSKext::isPrelinked(void)
4659 return flags
.prelinked
? true : false;
4662 /*********************************************************************
4663 *********************************************************************/
4665 OSKext::isLoaded(void)
4667 return flags
.loaded
? true : false;
4670 /*********************************************************************
4671 *********************************************************************/
4673 OSKext::isStarted(void)
4675 return flags
.started
? true : false;
4678 /*********************************************************************
4679 *********************************************************************/
4681 OSKext::isCPPInitialized(void)
4683 return flags
.CPPInitialized
;
4686 /*********************************************************************
4687 *********************************************************************/
4689 OSKext::setCPPInitialized(bool initialized
)
4691 flags
.CPPInitialized
= initialized
;
4694 /*********************************************************************
4695 *********************************************************************/
4697 OSKext::getLoadTag(void)
4702 /*********************************************************************
4703 *********************************************************************/
4705 OSKext::getSizeInfo(uint32_t *loadSize
, uint32_t *wiredSize
)
4707 if (linkedExecutable
) {
4708 *loadSize
= linkedExecutable
->getLength();
4710 /* If we have a kmod_info struct, calculated the wired size
4711 * from that. Otherwise it's the full load size.
4714 *wiredSize
= *loadSize
- (uint32_t)kmod_info
->hdr_size
;
4716 *wiredSize
= *loadSize
;
4724 /*********************************************************************
4725 *********************************************************************/
4727 OSKext::copyUUID(void)
4729 OSSharedPtr
<OSData
> result
;
4730 OSData
* theExecutable
= NULL
; // do not release
4731 const kernel_mach_header_t
* header
;
4733 /* An interface kext doesn't have a linked executable with an LC_UUID,
4734 * we create one when it's linked.
4736 if (interfaceUUID
) {
4737 result
= interfaceUUID
;
4741 if (flags
.builtin
|| isInterface()) {
4742 return sKernelKext
->copyUUID();
4745 if (isDriverKit() && infoDict
) {
4746 return driverKitUUID
;
4749 /* For real kexts, try to get the UUID from the linked executable,
4750 * or if is hasn't been linked yet, the unrelocated executable.
4752 theExecutable
= linkedExecutable
.get();
4753 if (!theExecutable
) {
4754 theExecutable
= getExecutable();
4757 if (!theExecutable
) {
4761 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
4762 result
= copyMachoUUID(header
);
4768 /*********************************************************************
4769 *********************************************************************/
4771 OSKext::copyTextUUID(void)
4773 if (flags
.builtin
) {
4774 return copyMachoUUID((const kernel_mach_header_t
*)kmod_info
->address
);
4779 /*********************************************************************
4780 *********************************************************************/
4782 OSKext::copyMachoUUID(const kernel_mach_header_t
* header
)
4784 OSSharedPtr
<OSData
> result
;
4785 const struct load_command
* load_cmd
= NULL
;
4786 const struct uuid_command
* uuid_cmd
= NULL
;
4789 load_cmd
= (const struct load_command
*)&header
[1];
4791 if (header
->magic
!= MH_MAGIC_KERNEL
) {
4793 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4794 "%s: bad header %p",
4800 for (i
= 0; i
< header
->ncmds
; i
++) {
4801 if (load_cmd
->cmd
== LC_UUID
) {
4802 uuid_cmd
= (struct uuid_command
*)load_cmd
;
4803 result
= OSData::withBytes(uuid_cmd
->uuid
, sizeof(uuid_cmd
->uuid
));
4806 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
4814 OSKext::setDriverKitUUID(OSData
*uuid
)
4816 if (!OSCompareAndSwapPtr(nullptr, uuid
, &driverKitUUID
)) {
4817 OSSafeReleaseNULL(uuid
);
4821 /*********************************************************************
4822 *********************************************************************/
4823 #if defined (__arm__)
4824 #include <arm/arch.h>
4827 #if defined (__x86_64__)
4828 #define ARCHNAME "x86_64"
4829 #elif defined (__arm64__)
4830 #define ARCHNAME "arm64"
4831 #elif defined (__arm__)
4833 #if defined (__ARM_ARCH_7S__)
4834 #define ARCHNAME "armv7s"
4835 #elif defined (__ARM_ARCH_7F__)
4836 #define ARCHNAME "armv7f"
4837 #elif defined (__ARM_ARCH_7K__)
4838 #define ARCHNAME "armv7k"
4839 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4840 #define ARCHNAME "armv7"
4841 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4842 #define ARCHNAME "armv6"
4845 #elif defined (__arm64__)
4846 #define ARCHNAME "arm64"
4848 #error architecture not supported
4851 #define ARCH_SEPARATOR_CHAR '_'
4854 makeHostArchKey(const char * key
, size_t * keySizeOut
)
4856 char * result
= NULL
;
4857 size_t keyLength
= strlen(key
);
4860 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4862 keySize
= 1 + 1 + keyLength
+ strlen(ARCHNAME
);
4863 result
= (char *)kheap_alloc_tag(KHEAP_TEMP
, keySize
,
4864 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
4869 strlcpy(result
, key
, keySize
);
4870 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
4871 result
[keyLength
] = '\0';
4872 strlcat(result
, ARCHNAME
, keySize
);
4873 *keySizeOut
= keySize
;
4879 /*********************************************************************
4880 *********************************************************************/
4882 OSKext::getPropertyForHostArch(const char * key
)
4884 OSObject
* result
= NULL
;// do not release
4885 size_t hostArchKeySize
= 0;
4886 char * hostArchKey
= NULL
;// must kfree
4888 if (!key
|| !infoDict
) {
4892 /* Some properties are not allowed to be arch-variant:
4893 * - Any CFBundle... property.
4894 * - OSBundleIsInterface.
4895 * - OSKernelResource.
4897 if (STRING_HAS_PREFIX(key
, "OS") ||
4898 STRING_HAS_PREFIX(key
, "IO")) {
4899 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
4901 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
4902 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4903 "Allocation failure.");
4906 result
= infoDict
->getObject(hostArchKey
);
4910 result
= infoDict
->getObject(key
);
4915 kheap_free(KHEAP_TEMP
, hostArchKey
, hostArchKeySize
);
4921 #pragma mark Load/Start/Stop/Unload
4924 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4926 /*********************************************************************
4927 * sExcludeListByID is a dictionary with keys / values of:
4928 * key = bundleID string of kext we will not allow to load
4929 * value = version string(s) of the kext that is to be denied loading.
4930 * The version strings can be comma delimited. For example if kext
4931 * com.foocompany.fookext has two versions that we want to deny
4932 * loading then the version strings might look like:
4934 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4935 * not load the kext.
4937 * Value may also be in the form of "LE 2.0.0" (version numbers
4938 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4939 * number less than 2.0.0 will not load)
4941 * NOTE - we cannot use the characters "<=" or "<" because we have code
4942 * that serializes plists and treats '<' as a special character.
4943 *********************************************************************/
4945 OSKext::isInExcludeList(void)
4947 OSString
* versionString
= NULL
; // do not release
4948 char * versionCString
= NULL
; // do not free
4950 boolean_t wantLessThan
= false;
4951 boolean_t wantLessThanEqualTo
= false;
4952 boolean_t isInExcludeList
= true;
4955 IORecursiveLockLock(sKextLock
);
4957 if (!sExcludeListByID
) {
4958 isInExcludeList
= false;
4960 /* look up by bundleID in our exclude list and if found get version
4961 * string (or strings) that we will not allow to load
4963 versionString
= OSDynamicCast(OSString
, sExcludeListByID
->getObject(bundleID
.get()));
4964 if (versionString
== NULL
|| versionString
->getLength() > (sizeof(myBuffer
) - 1)) {
4965 isInExcludeList
= false;
4969 IORecursiveLockUnlock(sKextLock
);
4971 if (!isInExcludeList
) {
4975 /* parse version strings */
4976 versionCString
= (char *) versionString
->getCStringNoCopy();
4978 /* look for "LT" or "LE" form of version string, must be in first two
4981 if (*versionCString
== 'L' && *(versionCString
+ 1) == 'T') {
4982 wantLessThan
= true;
4983 versionCString
+= 2;
4984 } else if (*versionCString
== 'L' && *(versionCString
+ 1) == 'E') {
4985 wantLessThanEqualTo
= true;
4986 versionCString
+= 2;
4989 for (i
= 0; *versionCString
!= 0x00; versionCString
++) {
4990 /* skip whitespace */
4991 if (isWhiteSpace(*versionCString
)) {
4995 /* peek ahead for version string separator or null terminator */
4996 if (*(versionCString
+ 1) == ',' || *(versionCString
+ 1) == 0x00) {
4997 /* OK, we have a version string */
4998 myBuffer
[i
++] = *versionCString
;
5001 OSKextVersion excludeVers
;
5002 excludeVers
= OSKextParseVersionString(myBuffer
);
5004 if (wantLessThanEqualTo
) {
5005 if (version
<= excludeVers
) {
5008 } else if (wantLessThan
) {
5009 if (version
< excludeVers
) {
5012 } else if (version
== excludeVers
) {
5016 /* reset for the next (if any) version string */
5018 wantLessThan
= false;
5019 wantLessThanEqualTo
= false;
5021 /* save valid version character */
5022 myBuffer
[i
++] = *versionCString
;
5024 /* make sure bogus version string doesn't overrun local buffer */
5025 if (i
>= sizeof(myBuffer
)) {
5034 /*********************************************************************
5035 * sNonLoadableKextsByID is a dictionary with keys / values of:
5036 * key = bundleID string of kext we will not allow to load
5037 * value = boolean (true == loadable, false == not loadable)
5039 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5040 * i.e., the value for the kext's bundleID will be false. All kexts in
5041 * the primary and system KCs will always be marked as "loadable."
5043 * This list ultimately comes from kexts which have been uninstalled
5044 * in user space by deleting the kext from disk, but which have not
5045 * yet been removed from the AuxKC. Because the user could choose to
5046 * re-install the exact same version of the kext, we need to keep
5047 * a dictionary of boolean values so that user space only needs to
5048 * keep a simple list of "uninstalled" or "missing" bundles. When
5049 * a bundle is re-installed, the iokit daemon can use the
5050 * AucKCBundleAvailable predicate to set the individual kext's
5051 * availability to true.
5052 *********************************************************************/
5054 OSKext::isLoadable(void)
5056 bool isLoadable
= true;
5058 if (kc_type
!= KCKindAuxiliary
) {
5059 /* this filtering only applies to kexts in the auxkc */
5063 IORecursiveLockLock(sKextLock
);
5065 if (sNonLoadableKextsByID
) {
5066 /* look up by bundleID in our exclude list and if found get version
5067 * string (or strings) that we will not allow to load
5069 OSBoolean
*loadableVal
;
5070 loadableVal
= OSDynamicCast(OSBoolean
, sNonLoadableKextsByID
->getObject(bundleID
.get()));
5071 if (loadableVal
&& !loadableVal
->getValue()) {
5075 IORecursiveLockUnlock(sKextLock
);
5080 /*********************************************************************
5081 *********************************************************************/
5084 OSKext::loadKextWithIdentifier(
5085 const char * kextIdentifierCString
,
5086 Boolean allowDeferFlag
,
5087 Boolean delayAutounloadFlag
,
5088 OSKextExcludeLevel startOpt
,
5089 OSKextExcludeLevel startMatchingOpt
,
5090 OSArray
* personalityNames
)
5092 OSReturn result
= kOSReturnError
;
5093 OSSharedPtr
<OSString
> kextIdentifier
;
5095 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
5096 if (!kextIdentifier
) {
5097 result
= kOSKextReturnNoMemory
;
5100 result
= OSKext::loadKextWithIdentifier(kextIdentifier
.get(),
5102 allowDeferFlag
, delayAutounloadFlag
,
5103 startOpt
, startMatchingOpt
, personalityNames
);
5110 OSKext::loadKextWithIdentifier(
5111 OSString
* kextIdentifier
,
5112 OSSharedPtr
<OSObject
> &kextRef
,
5113 Boolean allowDeferFlag
,
5114 Boolean delayAutounloadFlag
,
5115 OSKextExcludeLevel startOpt
,
5116 OSKextExcludeLevel startMatchingOpt
,
5117 OSArray
* personalityNames
)
5119 OSObject
* kextRefRaw
= NULL
;
5122 result
= loadKextWithIdentifier(kextIdentifier
,
5125 delayAutounloadFlag
,
5129 if ((kOSReturnSuccess
== result
) && kextRefRaw
) {
5130 kextRef
.reset(kextRefRaw
, OSNoRetain
);
5135 /*********************************************************************
5136 *********************************************************************/
5138 OSKext::loadKextWithIdentifier(
5139 OSString
* kextIdentifier
,
5140 OSObject
** kextRef
,
5141 Boolean allowDeferFlag
,
5142 Boolean delayAutounloadFlag
,
5143 OSKextExcludeLevel startOpt
,
5144 OSKextExcludeLevel startMatchingOpt
,
5145 OSArray
* personalityNames
)
5147 OSReturn result
= kOSReturnError
;
5148 OSReturn pingResult
= kOSReturnError
;
5149 OSKext
* theKext
= NULL
; // do not release
5150 OSSharedPtr
<OSDictionary
> loadRequest
;
5151 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5157 IORecursiveLockLock(sKextLock
);
5159 if (!kextIdentifier
) {
5160 result
= kOSKextReturnInvalidArgument
;
5164 OSKext::recordIdentifierRequest(kextIdentifier
);
5166 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
5168 if (!allowDeferFlag
) {
5169 OSKextLog(/* kext */ NULL
,
5170 kOSKextLogErrorLevel
|
5172 "Can't load kext %s - not found.",
5173 kextIdentifier
->getCStringNoCopy());
5177 if (!sKernelRequestsEnabled
) {
5179 kOSKextLogErrorLevel
|
5181 "Can't load kext %s - requests to user space are disabled.",
5182 kextIdentifier
->getCStringNoCopy());
5183 result
= kOSKextReturnDisabled
;
5187 /* Create a new request unless one is already sitting
5188 * in sKernelRequests for this bundle identifier
5190 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5191 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5192 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
5194 if (result
!= kOSReturnSuccess
) {
5197 if (!_OSKextSetRequestArgument(loadRequest
.get(),
5198 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
5199 result
= kOSKextReturnNoMemory
;
5202 if (!sKernelRequests
->setObject(loadRequest
.get())) {
5203 result
= kOSKextReturnNoMemory
;
5207 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5208 result
= kOSKextReturnNoMemory
;
5213 kOSKextLogDebugLevel
|
5215 "Kext %s not found; queued load request to user space.",
5216 kextIdentifier
->getCStringNoCopy());
5219 pingResult
= OSKext::pingIOKitDaemon();
5220 if (pingResult
== kOSKextReturnDisabled
) {
5221 OSKextLog(/* kext */ NULL
,
5222 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
5224 "Kext %s might not load - " kIOKitDaemonName
" is currently unavailable.",
5225 kextIdentifier
->getCStringNoCopy());
5228 result
= kOSKextReturnDeferred
;
5232 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
5234 if (result
!= kOSReturnSuccess
) {
5236 kOSKextLogErrorLevel
|
5238 "Failed to load kext %s (error 0x%x).",
5239 kextIdentifier
->getCStringNoCopy(), (int)result
);
5241 if (theKext
->kc_type
== KCKindUnknown
) {
5242 OSKext::removeKext(theKext
,
5243 /* terminateService/removePersonalities */ true);
5248 if (delayAutounloadFlag
) {
5250 kOSKextLogProgressLevel
|
5251 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5252 "Setting delayed autounload for %s.",
5253 kextIdentifier
->getCStringNoCopy());
5254 theKext
->flags
.delayAutounload
= 1;
5258 if ((kOSReturnSuccess
== result
) && kextRef
) {
5260 theKext
->matchingRefCount
++;
5264 IORecursiveLockUnlock(sKextLock
);
5269 /*********************************************************************
5270 *********************************************************************/
5273 OSKext::loadKextFromKC(OSKext
*theKext
, OSDictionary
*requestDict
)
5275 OSReturn result
= kOSReturnError
;
5277 OSBoolean
*delayAutounloadBool
= NULL
; // do not release
5278 OSNumber
*startKextExcludeNum
= NULL
; // do not release
5279 OSNumber
*startMatchingExcludeNum
= NULL
; // do not release
5280 OSArray
*personalityNames
= NULL
; // do not release
5283 * Default values for these options:
5284 * regular autounload behavior
5286 * send all personalities to the catalog
5288 Boolean delayAutounload
= false;
5289 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
5290 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeNone
;
5292 IORecursiveLockLock(sKextLock
);
5294 OSKextLog(/* kext */ NULL
,
5295 kOSKextLogDebugLevel
|
5297 "Received kext KC load request from user space.");
5299 /* Regardless of processing, the fact that we have gotten here means some
5300 * user-space program is up and talking to us, so we'll switch our kext
5301 * registration to reflect that.
5303 if (!sUserLoadsActive
) {
5304 OSKextLog(/* kext */ NULL
,
5305 kOSKextLogProgressLevel
|
5306 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5307 "Switching to late startup (user-space) kext loading policy.");
5308 sUserLoadsActive
= true;
5311 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
5312 _OSKextGetRequestArgument(requestDict
,
5313 kKextRequestArgumentDelayAutounloadKey
));
5314 startKextExcludeNum
= OSDynamicCast(OSNumber
,
5315 _OSKextGetRequestArgument(requestDict
,
5316 kKextRequestArgumentStartExcludeKey
));
5317 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
5318 _OSKextGetRequestArgument(requestDict
,
5319 kKextRequestArgumentStartMatchingExcludeKey
));
5320 personalityNames
= OSDynamicCast(OSArray
,
5321 _OSKextGetRequestArgument(requestDict
,
5322 kKextRequestArgumentPersonalityNamesKey
));
5324 if (delayAutounloadBool
) {
5325 delayAutounload
= delayAutounloadBool
->getValue();
5327 if (startKextExcludeNum
) {
5328 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
5330 if (startMatchingExcludeNum
) {
5331 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
5334 OSKextLog(/* kext */ NULL
,
5335 kOSKextLogProgressLevel
|
5337 "Received request from user space to load KC kext %s.",
5338 theKext
->getIdentifierCString());
5340 /* this could be in the Auxiliary KC, so record the load request */
5341 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, theKext
->getIdentifier()));
5346 result
= theKext
->load(startKextExcludeLevel
,
5347 startMatchingExcludeLevel
, personalityNames
);
5349 if (result
!= kOSReturnSuccess
) {
5351 kOSKextLogErrorLevel
|
5353 "Failed to load kext %s (error 0x%x).",
5354 theKext
->getIdentifierCString(), (int)result
);
5356 OSKext::removeKext(theKext
,
5357 /* terminateService/removePersonalities */ true);
5361 kOSKextLogProgressLevel
|
5363 "Kext %s Loaded successfully from %s KC",
5364 theKext
->getIdentifierCString(), theKext
->getKCTypeString());
5367 if (delayAutounload
) {
5369 kOSKextLogProgressLevel
|
5370 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5371 "Setting delayed autounload for %s.",
5372 theKext
->getIdentifierCString());
5373 theKext
->flags
.delayAutounload
= 1;
5377 IORecursiveLockUnlock(sKextLock
);
5382 /*********************************************************************
5383 *********************************************************************/
5386 OSKext::loadCodelessKext(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
5388 OSReturn result
= kOSReturnError
;
5389 OSDictionary
*anInfoDict
= NULL
; // do not release
5391 anInfoDict
= OSDynamicCast(OSDictionary
,
5392 _OSKextGetRequestArgument(requestDict
,
5393 kKextRequestArgumentCodelessInfoKey
));
5394 if (anInfoDict
== NULL
) {
5395 OSKextLog(/* kext */ NULL
,
5396 kOSKextLogErrorLevel
|
5397 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5398 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5399 kextIdentifier
->getCStringNoCopy());
5400 return kOSKextReturnInvalidArgument
;
5403 IORecursiveLockLock(sKextLock
);
5405 OSKextLog(/* kext */ NULL
,
5406 kOSKextLogProgressLevel
|
5408 "Received request from user space to load codeless kext %s.",
5409 kextIdentifier
->getCStringNoCopy());
5412 // instantiate a new kext, and don't hold a reference
5413 // (the kext subsystem will hold one implicitly)
5414 OSSharedPtr
<OSKext
> newKext
= OSKext::withCodelessInfo(anInfoDict
);
5416 OSKextLog(/* kext */ NULL
,
5417 kOSKextLogErrorLevel
|
5418 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5419 "Could not instantiate codeless kext.");
5420 result
= kOSKextReturnNotLoadable
;
5423 if (!kextIdentifier
->isEqualTo(newKext
->getIdentifierCString())) {
5424 OSKextLog(/* kext */ NULL
,
5425 kOSKextLogErrorLevel
|
5426 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5427 "Codeless kext identifiers don't match '%s' != '%s'",
5428 kextIdentifier
->getCStringNoCopy(), newKext
->getIdentifierCString());
5430 OSKext::removeKext(newKext
.get(), false);
5431 result
= kOSKextReturnInvalidArgument
;
5435 /* Record the request for the codeless kext */
5436 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, newKext
->getIdentifier()));
5438 result
= kOSReturnSuccess
;
5439 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5440 result
= newKext
->sendPersonalitiesToCatalog(true, NULL
);
5444 IORecursiveLockUnlock(sKextLock
);
5449 /*********************************************************************
5450 *********************************************************************/
5453 OSKext::dropMatchingReferences(
5456 IORecursiveLockLock(sKextLock
);
5457 kexts
->iterateObjects(^bool (OSObject
* obj
) {
5458 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
5462 thisKext
->matchingRefCount
--;
5465 IORecursiveLockUnlock(sKextLock
);
5468 /*********************************************************************
5469 *********************************************************************/
5472 OSKext::recordIdentifierRequest(
5473 OSString
* kextIdentifier
)
5475 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5478 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
5482 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5483 if (!kextIdentifierSymbol
) {
5484 // xxx - this is really a basic alloc failure
5489 IORecursiveLockLock(sKextLock
);
5490 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5491 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5494 // xxx - need to find a way to associate this whole func w/the kext
5495 OSKextLog(/* kext */ NULL
,
5496 // xxx - check level
5497 kOSKextLogStepLevel
|
5498 kOSKextLogArchiveFlag
,
5499 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5500 kextIdentifier
->getCStringNoCopy());
5503 IORecursiveLockUnlock(sKextLock
);
5508 OSKextLog(/* kext */ NULL
,
5509 kOSKextLogErrorLevel
|
5510 kOSKextLogArchiveFlag
,
5511 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5512 kextIdentifier
->getCStringNoCopy());
5517 /*********************************************************************
5518 *********************************************************************/
5521 OSKextExcludeLevel startOpt
,
5522 OSKextExcludeLevel startMatchingOpt
,
5523 OSArray
* personalityNames
)
5525 OSReturn result
= kOSReturnError
;
5526 OSKextExcludeLevel dependenciesStartOpt
= startOpt
;
5527 OSKextExcludeLevel dependenciesStartMatchingOpt
= startMatchingOpt
;
5528 unsigned int i
, count
;
5529 Boolean alreadyLoaded
= false;
5530 OSKext
* lastLoadedKext
= NULL
; // do not release
5532 if (isInExcludeList()) {
5534 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5536 "Kext %s is in exclude list, not loadable",
5537 getIdentifierCString());
5539 result
= kOSKextReturnNotLoadable
;
5542 if (!isLoadable()) {
5544 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5546 "Kext %s is not loadable",
5547 getIdentifierCString());
5549 result
= kOSKextReturnNotLoadable
;
5554 alreadyLoaded
= true;
5555 result
= kOSReturnSuccess
;
5558 kOSKextLogDebugLevel
|
5559 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5560 "Kext %s is already loaded.",
5561 getIdentifierCString());
5565 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5567 if (current_task() != kernel_task
) {
5570 * On non-kxld systems, only check the mac-hook for kexts in the
5571 * Pageable and Aux KCs. This means on Apple silicon devices that
5572 * the mac hook will only be useful to block 3rd party kexts.
5574 * Note that this should _not_ be called on kexts loaded from the
5575 * kernel bootstrap thread as the kernel proc's cred struct is not
5576 * yet initialized! This won't happen on macOS because all the kexts
5577 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5579 if (kc_type
!= KCKindPrimary
&& kc_type
!= KCKindUnknown
) {
5580 #endif /* CONFIG_KXLD */
5581 int macCheckResult
= 0;
5582 kauth_cred_t cred
= NULL
;
5584 cred
= kauth_cred_get_with_ref();
5585 macCheckResult
= mac_kext_check_load(cred
, getIdentifierCString());
5586 kauth_cred_unref(&cred
);
5588 if (macCheckResult
!= 0) {
5589 result
= kOSReturnError
;
5591 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5592 "Failed to load kext %s (MAC policy error 0x%x).",
5593 getIdentifierCString(), macCheckResult
);
5599 if (!sLoadEnabled
) {
5601 kOSKextLogErrorLevel
|
5603 "Kext loading is disabled (attempt to load kext %s).",
5604 getIdentifierCString());
5605 result
= kOSKextReturnDisabled
;
5609 /* If we've pushed the next available load tag to the invalid value,
5610 * we can't load any more kexts.
5612 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
5614 kOSKextLogErrorLevel
|
5616 "Can't load kext %s - no more load tags to assign.",
5617 getIdentifierCString());
5618 result
= kOSKextReturnNoResources
;
5622 /* This is a bit of a hack, because we shouldn't be handling
5623 * personalities within the load function.
5625 if (!declaresExecutable()) {
5626 /* There is a special case where a non-executable kext can be loaded: the
5627 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5628 * load its metadata into the global data structures, if appropriate
5630 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID
) == 0) {
5631 boolean_t updated
= updateExcludeList(infoDict
.get());
5634 kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
5635 "KextExcludeList was updated to version: %lld", sExcludeListVersion
);
5639 if (isDriverKit()) {
5641 sLoadedDriverKitKexts
->setObject(this);
5642 loadTag
= sNextLoadTag
++;
5645 result
= kOSReturnSuccess
;
5649 /* Are we in safe boot?
5651 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
5653 kOSKextLogErrorLevel
|
5655 "Can't load kext %s - not loadable during safe boot.",
5656 getIdentifierCString());
5657 result
= kOSKextReturnBootLevel
;
5662 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5664 getIdentifierCString());
5666 #if !VM_MAPPED_KEXTS
5667 if (isPrelinked() == false) {
5669 kOSKextLogErrorLevel
|
5671 "Can't load kext %s - not in a kext collection.",
5672 getIdentifierCString());
5673 result
= kOSKextReturnDisabled
;
5676 #endif /* defined(__x86_64__) */
5679 if (!sKxldContext
) {
5680 kern_return_t kxldResult
;
5681 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
5682 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
5683 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5686 kOSKextLogErrorLevel
|
5687 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
5688 "Can't load kext %s - failed to create link context.",
5689 getIdentifierCString());
5690 result
= kOSKextReturnNoMemory
;
5694 #endif // CONFIG_KXLD
5696 /* We only need to resolve dependencies once for the whole graph, but
5697 * resolveDependencies will just return if there's no work to do, so it's
5698 * safe to call it more than once.
5700 if (!resolveDependencies()) {
5701 // xxx - check resolveDependencies() for log msg
5703 kOSKextLogErrorLevel
|
5704 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5705 "Can't load kext %s - failed to resolve library dependencies.",
5706 getIdentifierCString());
5707 result
= kOSKextReturnDependencies
;
5711 /* If we are excluding just the kext being loaded now (and not its
5712 * dependencies), drop the exclusion level to none so dependencies
5713 * start and/or add their personalities.
5715 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
5716 dependenciesStartOpt
= kOSKextExcludeNone
;
5719 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
5720 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
5723 /* Load the dependencies, recursively.
5725 count
= getNumDependencies();
5726 for (i
= 0; i
< count
; i
++) {
5727 OSKext
* dependency
= OSDynamicCast(OSKext
,
5728 dependencies
->getObject(i
));
5729 if (dependency
== NULL
) {
5731 kOSKextLogErrorLevel
|
5732 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5733 "Internal error loading kext %s; dependency disappeared.",
5734 getIdentifierCString());
5735 result
= kOSKextReturnInternalError
;
5739 /* Dependencies must be started accorting to the opt,
5740 * but not given the personality names of the main kext.
5742 result
= dependency
->load(dependenciesStartOpt
,
5743 dependenciesStartMatchingOpt
,
5744 /* personalityNames */ NULL
);
5745 if (result
!= KERN_SUCCESS
) {
5747 kOSKextLogErrorLevel
|
5748 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5749 "Dependency %s of kext %s failed to load.",
5750 dependency
->getIdentifierCString(),
5751 getIdentifierCString());
5753 OSKext::removeKext(dependency
,
5754 /* terminateService/removePersonalities */ true);
5755 result
= kOSKextReturnDependencyLoadError
;
5761 result
= loadExecutable();
5762 if (result
!= KERN_SUCCESS
) {
5766 pendingPgoHead
.next
= &pendingPgoHead
;
5767 pendingPgoHead
.prev
= &pendingPgoHead
;
5769 // The kernel PRNG is not initialized when the first kext is
5770 // loaded, so use early random
5771 uuid_generate_early_random(instance_uuid
);
5772 account
= IONew(OSKextAccount
, 1);
5774 result
= KERN_MEMORY_ERROR
;
5777 bzero(account
, sizeof(*account
));
5778 account
->loadTag
= kmod_info
->id
;
5779 account
->site
.refcount
= 0;
5780 account
->site
.flags
= VM_TAG_KMOD
;
5781 account
->kext
= this;
5782 if (gIOSurfaceIdentifier
== bundleID
) {
5783 vm_tag_alloc(&account
->site
);
5784 gIOSurfaceTag
= account
->site
.tag
;
5787 flags
.loaded
= true;
5789 /* Add the kext to the list of loaded kexts and update the kmod_info
5790 * struct to point to that of the last loaded kext (which is the way
5791 * it's always been done, though I'd rather do them in order now).
5793 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5794 sLoadedKexts
->setObject(this);
5796 /* Keep the kernel itself out of the kmod list.
5798 if (lastLoadedKext
->isKernel()) {
5799 lastLoadedKext
= NULL
;
5802 if (lastLoadedKext
) {
5803 kmod_info
->next
= lastLoadedKext
->kmod_info
;
5806 notifyKextLoadObservers(this, kmod_info
);
5808 /* Make the global kmod list point at the just-loaded kext. Note that the
5809 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5810 * although we do report it in kextstat these days by using the newer
5811 * OSArray of loaded kexts, which does contain it.
5813 * (The OSKext object representing the kernel doesn't even have a kmod_info
5814 * struct, though I suppose we could stick a pointer to it from the
5815 * static struct in OSRuntime.cpp.)
5819 /* Save the list of loaded kexts in case we panic.
5821 OSKext::saveLoadedKextPanicList();
5823 if (isExecutable()) {
5824 OSKext::updateLoadedKextSummaries();
5825 savePanicString(/* isLoading */ true);
5828 registerWithDTrace();
5830 jettisonLinkeditSegment();
5831 #endif /* CONFIG_DTRACE */
5833 #if !VM_MAPPED_KEXTS
5834 /* If there is a page (or more) worth of padding after the end
5835 * of the last data section but before the end of the data segment
5836 * then free it in the same manner the LinkeditSegment is freed
5838 jettisonDATASegmentPadding();
5843 if (isExecutable() && !flags
.started
) {
5844 if (startOpt
== kOSKextExcludeNone
) {
5846 if (result
!= kOSReturnSuccess
) {
5848 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5849 "Kext %s start failed (result 0x%x).",
5850 getIdentifierCString(), result
);
5851 result
= kOSKextReturnStartStopError
;
5856 /* If not excluding matching, send the personalities to the kernel.
5857 * This never affects the result of the load operation.
5858 * This is a bit of a hack, because we shouldn't be handling
5859 * personalities within the load function.
5861 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
5862 result
= sendPersonalitiesToCatalog(true, personalityNames
);
5867 if (result
!= kOSReturnSuccess
) {
5869 kOSKextLogErrorLevel
|
5871 "Kext %s failed to load (0x%x).",
5872 getIdentifierCString(), (int)result
);
5873 } else if (!alreadyLoaded
) {
5875 kOSKextLogProgressLevel
|
5878 getIdentifierCString());
5880 queueKextNotification(kKextRequestPredicateLoadNotification
,
5881 OSDynamicCast(OSString
, bundleID
.get()));
5887 /*********************************************************************
5889 *********************************************************************/
5891 strdup(const char * string
)
5893 char * result
= NULL
;
5900 size
= 1 + strlen(string
);
5901 result
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, size
,
5902 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
5907 memcpy(result
, string
, size
);
5912 #endif // CONFIG_KXLD
5914 /*********************************************************************
5916 *********************************************************************/
5919 OSKext::lookupSection(const char *segname
, const char *secname
)
5921 kernel_section_t
* found_section
= NULL
;
5922 kernel_mach_header_t
* mh
= NULL
;
5923 kernel_segment_command_t
* seg
= NULL
;
5924 kernel_section_t
* sec
= NULL
;
5926 if (!linkedExecutable
) {
5930 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5932 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5933 if (0 != strncmp(seg
->segname
, segname
, sizeof(seg
->segname
))) {
5937 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
5938 if (0 == strncmp(sec
->sectname
, secname
, sizeof(sec
->sectname
))) {
5939 found_section
= sec
;
5946 return found_section
;
5949 /*********************************************************************
5951 *********************************************************************/
5954 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides
)
5956 OSReturn result
= kOSKextReturnBadData
;
5957 kernel_mach_header_t
* mh
= NULL
;
5958 kernel_segment_command_t
* seg
= NULL
;
5959 kernel_segment_command_t
* linkeditSeg
= NULL
;
5960 kernel_section_t
* sec
= NULL
;
5961 char * linkeditBase
= NULL
;
5962 bool haveLinkeditBase
= false;
5963 char * relocBase
= NULL
;
5964 bool haveRelocBase
= false;
5965 struct dysymtab_command
* dysymtab
= NULL
;
5966 struct linkedit_data_command
* segmentSplitInfo
= NULL
;
5967 struct symtab_command
* symtab
= NULL
;
5968 kernel_nlist_t
* sym
= NULL
;
5969 struct relocation_info
* reloc
= NULL
;
5972 vm_offset_t new_kextsize
;
5974 if (linkedExecutable
== NULL
|| flags
.builtin
) {
5975 result
= kOSReturnSuccess
;
5979 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5980 if (kernel_mach_header_is_in_fileset(mh
)) {
5981 // kexts in filesets are slid as part of collection sliding
5982 result
= kOSReturnSuccess
;
5986 segmentSplitInfo
= (struct linkedit_data_command
*) getcommandfromheader(mh
, LC_SEGMENT_SPLIT_INFO
);
5988 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5993 seg
->vmaddr
= ml_static_slide(seg
->vmaddr
);
5995 #if KASLR_KEXT_DEBUG
5996 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5998 (unsigned long)ml_static_unslide(seg
->vmaddr
),
5999 (unsigned long)seg
->vmaddr
);
6002 if (!haveRelocBase
) {
6003 relocBase
= (char *) seg
->vmaddr
;
6004 haveRelocBase
= true;
6006 if (!strcmp(seg
->segname
, "__LINKEDIT")) {
6007 linkeditBase
= (char *) seg
->vmaddr
- seg
->fileoff
;
6008 haveLinkeditBase
= true;
6011 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
6012 sec
->addr
= ml_static_slide(sec
->addr
);
6014 #if KASLR_KEXT_DEBUG
6015 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6017 (unsigned long)ml_static_unslide(sec
->addr
),
6018 (unsigned long)sec
->addr
);
6023 dysymtab
= (struct dysymtab_command
*) getcommandfromheader(mh
, LC_DYSYMTAB
);
6025 symtab
= (struct symtab_command
*) getcommandfromheader(mh
, LC_SYMTAB
);
6027 if (symtab
!= NULL
&& doCoalescedSlides
== false) {
6028 /* Some pseudo-kexts have symbol tables without segments.
6030 if (symtab
->nsyms
> 0 && haveLinkeditBase
) {
6031 sym
= (kernel_nlist_t
*) (linkeditBase
+ symtab
->symoff
);
6032 for (i
= 0; i
< symtab
->nsyms
; i
++) {
6033 if (sym
[i
].n_type
& N_STAB
) {
6036 sym
[i
].n_value
= ml_static_slide(sym
[i
].n_value
);
6038 #if KASLR_KEXT_DEBUG
6039 #define MAX_SYMS_TO_LOG 5
6040 if (i
< MAX_SYMS_TO_LOG
) {
6041 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6042 (unsigned long)ml_static_unslide(sym
[i
].n_value
),
6043 (unsigned long)sym
[i
].n_value
);
6050 if (dysymtab
!= NULL
&& doCoalescedSlides
== false) {
6051 if (dysymtab
->nextrel
> 0) {
6053 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6055 "Sliding kext %s: External relocations found.",
6056 getIdentifierCString());
6060 if (dysymtab
->nlocrel
> 0) {
6061 if (!haveLinkeditBase
) {
6063 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6065 "Sliding kext %s: No linkedit segment.",
6066 getIdentifierCString());
6070 if (!haveRelocBase
) {
6072 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6075 "Sliding kext %s: No writable segments.",
6077 "Sliding kext %s: No segments.",
6079 getIdentifierCString());
6083 reloc
= (struct relocation_info
*) (linkeditBase
+ dysymtab
->locreloff
);
6084 reloc_size
= dysymtab
->nlocrel
* sizeof(struct relocation_info
);
6086 for (i
= 0; i
< dysymtab
->nlocrel
; i
++) {
6087 if (reloc
[i
].r_extern
!= 0
6088 || reloc
[i
].r_type
!= 0
6089 || reloc
[i
].r_length
!= (sizeof(void *) == 8 ? 3 : 2)
6092 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6094 "Sliding kext %s: Unexpected relocation found.",
6095 getIdentifierCString());
6098 if (reloc
[i
].r_pcrel
!= 0) {
6101 uintptr_t *relocAddr
= (uintptr_t*)(relocBase
+ reloc
[i
].r_address
);
6102 *relocAddr
= ml_static_slide(*relocAddr
);
6104 #if KASLR_KEXT_DEBUG
6105 #define MAX_DYSYMS_TO_LOG 5
6106 if (i
< MAX_DYSYMS_TO_LOG
) {
6107 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6108 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr
))),
6109 (unsigned long)*((uintptr_t *)(relocBase
+ reloc
[i
].r_address
)));
6114 /* We should free these relocations, not just delete the reference to them.
6115 * <rdar://problem/10535549> Free relocations from PIE kexts.
6117 * For now, we do not free LINKEDIT for kexts with split segments.
6119 new_kextsize
= round_page(kmod_info
->size
- reloc_size
);
6120 if (new_kextsize
> UINT_MAX
) {
6122 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6124 "Kext %s: new kext size is too large.",
6125 getIdentifierCString());
6128 if (((kmod_info
->size
- new_kextsize
) > PAGE_SIZE
) && (!segmentSplitInfo
)) {
6129 vm_offset_t endofkext
= kmod_info
->address
+ kmod_info
->size
;
6130 vm_offset_t new_endofkext
= kmod_info
->address
+ new_kextsize
;
6131 vm_offset_t endofrelocInfo
= (vm_offset_t
) (((uint8_t *)reloc
) + reloc_size
);
6132 size_t bytes_remaining
= endofkext
- endofrelocInfo
;
6133 OSSharedPtr
<OSData
> new_osdata
;
6135 /* fix up symbol offsets if they are after the dsymtab local relocs */
6137 if (dysymtab
->locreloff
< symtab
->symoff
) {
6138 symtab
->symoff
-= reloc_size
;
6140 if (dysymtab
->locreloff
< symtab
->stroff
) {
6141 symtab
->stroff
-= reloc_size
;
6144 if (dysymtab
->locreloff
< dysymtab
->extreloff
) {
6145 dysymtab
->extreloff
-= reloc_size
;
6148 /* move data behind reloc info down to new offset */
6149 if (endofrelocInfo
< endofkext
) {
6150 memcpy(reloc
, (void *)endofrelocInfo
, bytes_remaining
);
6153 /* Create a new OSData for the smaller kext object and reflect
6154 * new linkedit segment size.
6156 linkeditSeg
->vmsize
= round_page(linkeditSeg
->vmsize
- reloc_size
);
6157 linkeditSeg
->filesize
= linkeditSeg
->vmsize
;
6159 new_osdata
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)new_kextsize
);
6161 /* Fix up kmod info and linkedExecutable.
6163 kmod_info
->size
= new_kextsize
;
6165 new_osdata
->setDeallocFunction(osdata_kext_free
);
6167 new_osdata
->setDeallocFunction(osdata_phys_free
);
6169 linkedExecutable
->setDeallocFunction(NULL
);
6170 linkedExecutable
= os::move(new_osdata
);
6173 kext_free(new_endofkext
, (endofkext
- new_endofkext
));
6175 ml_static_mfree(new_endofkext
, (endofkext
- new_endofkext
));
6179 dysymtab
->nlocrel
= 0;
6180 dysymtab
->locreloff
= 0;
6184 result
= kOSReturnSuccess
;
6189 /*********************************************************************
6190 * called only by load()
6191 *********************************************************************/
6193 OSKext::loadExecutable()
6195 OSReturn result
= kOSReturnError
;
6196 OSSharedPtr
<OSArray
> linkDependencies
;
6197 uint32_t num_kmod_refs
= 0;
6198 OSData
* theExecutable
= NULL
; // do not release
6199 OSString
* versString
= NULL
; // do not release
6200 const char * versCString
= NULL
; // do not free
6201 const char * string
= NULL
; // do not free
6205 uint32_t numDirectDependencies
= 0;
6206 kern_return_t kxldResult
;
6207 KXLDDependency
* kxlddeps
= NULL
; // must kfree
6208 uint32_t num_kxlddeps
= 0;
6209 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
6210 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
6211 #endif // CONFIG_KXLD
6213 /* We need the version string for a variety of bits below.
6215 versString
= OSDynamicCast(OSString
,
6216 getPropertyForHostArch(kCFBundleVersionKey
));
6220 versCString
= versString
->getCStringNoCopy();
6222 if (isKernelComponent()) {
6223 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
6224 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
6226 kOSKextLogErrorLevel
|
6228 "Kernel component %s has incorrect version %s; "
6230 getIdentifierCString(),
6231 versCString
, KERNEL6_VERSION
);
6232 result
= kOSKextReturnInternalError
;
6234 } else if (strcmp(versCString
, osrelease
)) {
6236 kOSKextLogErrorLevel
|
6238 "Kernel component %s has incorrect version %s; "
6240 getIdentifierCString(),
6241 versCString
, osrelease
);
6242 result
= kOSKextReturnInternalError
;
6248 #if defined(__x86_64__) || defined(__i386__)
6249 if (flags
.resetSegmentsFromVnode
) {
6250 /* Fixup the chains and slide the mach headers */
6251 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6253 if (i386_slide_individual_kext(mh
, PE_get_kc_slide(kc_type
)) != KERN_SUCCESS
) {
6254 result
= kOSKextReturnValidation
;
6258 #endif //(__x86_64__) || defined(__i386__)
6260 if (isPrelinked()) {
6264 /* <rdar://problem/21444003> all callers must be entitled */
6265 if (FALSE
== IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
)) {
6267 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6268 "Not entitled to link kext '%s'",
6269 getIdentifierCString());
6270 result
= kOSKextReturnNotPrivileged
;
6274 theExecutable
= getExecutable();
6275 if (!theExecutable
) {
6276 if (declaresExecutable()) {
6278 kOSKextLogErrorLevel
|
6280 "Can't load kext %s - executable is missing.",
6281 getIdentifierCString());
6282 result
= kOSKextReturnValidation
;
6288 if (isInterface()) {
6289 OSSharedPtr
<OSData
> executableCopy
= OSData::withData(theExecutable
);
6290 if (executableCopy
) {
6291 setLinkedExecutable(executableCopy
.get());
6297 numDirectDependencies
= getNumDependencies();
6299 if (flags
.hasBleedthrough
) {
6300 linkDependencies
= dependencies
;
6302 linkDependencies
= OSArray::withArray(dependencies
.get());
6303 if (!linkDependencies
) {
6305 kOSKextLogErrorLevel
|
6306 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6307 "Can't allocate link dependencies to load kext %s.",
6308 getIdentifierCString());
6312 for (i
= 0; i
< numDirectDependencies
; ++i
) {
6313 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
6314 dependencies
->getObject(i
));
6315 dependencyKext
->addBleedthroughDependencies(linkDependencies
.get());
6319 num_kxlddeps
= linkDependencies
->getCount();
6320 if (!num_kxlddeps
) {
6322 kOSKextLogErrorLevel
|
6323 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
6324 "Can't load kext %s - it has no library dependencies.",
6325 getIdentifierCString());
6329 kxlddeps
= (KXLDDependency
*)kalloc_tag(num_kxlddeps
* sizeof(*kxlddeps
), VM_KERN_MEMORY_OSKEXT
);
6332 kOSKextLogErrorLevel
|
6333 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6334 "Can't allocate link context to load kext %s.",
6335 getIdentifierCString());
6338 bzero(kxlddeps
, num_kxlddeps
* sizeof(*kxlddeps
));
6340 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6341 OSKext
* dependency
= OSDynamicCast(OSKext
, linkDependencies
->getObject(i
));
6343 if (dependency
->isInterface()) {
6344 OSKext
*interfaceTargetKext
= NULL
; //do not release
6345 OSData
* interfaceTarget
= NULL
; //do not release
6347 if (dependency
->isKernelComponent()) {
6348 interfaceTargetKext
= sKernelKext
;
6349 interfaceTarget
= sKernelKext
->linkedExecutable
.get();
6351 interfaceTargetKext
= OSDynamicCast(OSKext
,
6352 dependency
->dependencies
->getObject(0));
6354 interfaceTarget
= interfaceTargetKext
->linkedExecutable
.get();
6357 if (!interfaceTarget
) {
6362 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6363 * it will be useful to have them in the debugger.
6364 * strdup() failing isn't critical right here so we don't check that.
6366 kxlddeps
[i
].kext
= (u_char
*) interfaceTarget
->getBytesNoCopy();
6367 kxlddeps
[i
].kext_size
= interfaceTarget
->getLength();
6368 kxlddeps
[i
].kext_name
= strdup(interfaceTargetKext
->getIdentifierCString());
6370 if (dependency
->linkedExecutable
!= NULL
) {
6371 kxlddeps
[i
].interface
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6372 kxlddeps
[i
].interface_size
= dependency
->linkedExecutable
->getLength();
6374 kxlddeps
[i
].interface
= (u_char
*) NULL
;
6375 kxlddeps
[i
].interface_size
= 0;
6377 kxlddeps
[i
].interface_name
= strdup(dependency
->getIdentifierCString());
6379 kxlddeps
[i
].kext
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6380 kxlddeps
[i
].kext_size
= dependency
->linkedExecutable
->getLength();
6381 kxlddeps
[i
].kext_name
= strdup(dependency
->getIdentifierCString());
6384 kxlddeps
[i
].is_direct_dependency
= (i
< numDirectDependencies
);
6387 kxldHeaderPtr
= &kxld_header
;
6391 kOSKextLogExplicitLevel
|
6392 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6393 "Kext %s - calling kxld_link_file:\n"
6394 " kxld_context: %p\n"
6395 " executable: %p executable_length: %d\n"
6397 " kxld_dependencies: %p num_dependencies: %d\n"
6398 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6399 getIdentifierCString(), sKxldContext
,
6400 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
6401 this, kxlddeps
, num_kxlddeps
,
6402 kxldHeaderPtr
, &kmod_info
);
6405 /* After this call, the linkedExecutable instance variable
6408 kxldResult
= kxld_link_file(sKxldContext
,
6409 (u_char
*)theExecutable
->getBytesNoCopy(),
6410 theExecutable
->getLength(),
6411 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
6412 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
);
6414 if (kxldResult
!= KERN_SUCCESS
) {
6415 // xxx - add kxldResult here?
6417 kOSKextLogErrorLevel
|
6419 "Can't load kext %s - link failed.",
6420 getIdentifierCString());
6421 result
= kOSKextReturnLinkError
;
6425 /* We've written data & instructions into kernel memory, so flush the data
6426 * cache and invalidate the instruction cache.
6427 * I/D caches are coherent on x86
6429 #if !defined(__i386__) && !defined(__x86_64__)
6430 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
6431 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
6434 #else // !CONFIG_KXLD
6435 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6436 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6437 result
= kOSKextReturnLinkError
;
6439 #endif // CONFIG_KXLD
6443 if (isInterface()) {
6444 /* Whip up a fake kmod_info entry for the interface kext.
6446 kmod_info
= (kmod_info_t
*)kalloc_tag(sizeof(kmod_info_t
), VM_KERN_MEMORY_OSKEXT
);
6448 result
= KERN_MEMORY_ERROR
;
6452 /* A pseudokext has almost nothing in its kmod_info struct.
6454 bzero(kmod_info
, sizeof(kmod_info_t
));
6456 kmod_info
->info_version
= KMOD_INFO_VERSION
;
6458 /* An interface kext doesn't have a linkedExecutable, so save a
6459 * copy of the UUID out of the original executable via copyUUID()
6460 * while we still have the original executable.
6462 interfaceUUID
= copyUUID();
6465 kmod_info
->id
= loadTag
= sNextLoadTag
++;
6466 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
6468 /* Stamp the bundle ID and version from the OSKext over anything
6469 * resident inside the kmod_info.
6471 string
= getIdentifierCString();
6472 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
6474 string
= versCString
;
6475 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
6477 /* Add the dependencies' kmod_info structs as kmod_references.
6479 num_kmod_refs
= getNumDependencies();
6480 if (num_kmod_refs
) {
6481 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc_tag(
6482 num_kmod_refs
* sizeof(kmod_reference_t
), VM_KERN_MEMORY_OSKEXT
);
6483 if (!kmod_info
->reference_list
) {
6484 result
= KERN_MEMORY_ERROR
;
6487 bzero(kmod_info
->reference_list
,
6488 num_kmod_refs
* sizeof(kmod_reference_t
));
6489 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
6490 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
6491 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
6492 ref
->info
= refKext
->kmod_info
;
6493 ref
->info
->reference_count
++;
6495 if (refIndex
+ 1 < num_kmod_refs
) {
6496 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
6501 if (kmod_info
->hdr_size
> UINT32_MAX
) {
6503 kOSKextLogErrorLevel
|
6506 "Kext %s header size is too large (%lu > UINT32_MAX).",
6508 "Kext %s header size is too large (%u > UINT32_MAX).",
6511 kmod_info
->hdr_size
);
6512 result
= KERN_FAILURE
;
6516 if (kmod_info
->size
> UINT32_MAX
) {
6518 kOSKextLogErrorLevel
|
6521 "Kext %s size is too large (%lu > UINT32_MAX).",
6523 "Kext %s size is too large (%u > UINT32_MAX).",
6527 result
= KERN_FAILURE
;
6531 if (!isInterface() && linkedExecutable
) {
6533 kOSKextLogProgressLevel
|
6535 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6537 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
6538 (unsigned long)ml_static_unslide(kmod_info
->address
),
6539 (unsigned)kmod_info
->id
);
6542 /* VM protections and wiring for the Aux KC are done at collection loading time */
6543 if (kc_type
!= KCKindAuxiliary
|| flags
.resetSegmentsFromVnode
) {
6544 /* if prelinked and primary KC, VM protections are already set */
6545 result
= setVMAttributes(!isPrelinked() || flags
.resetSegmentsFromVnode
, true);
6546 if (result
!= KERN_SUCCESS
) {
6552 if (linkedExecutable
) {
6553 kasan_load_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(),
6554 linkedExecutable
->getLength(), getIdentifierCString());
6557 if (lookupSection(KASAN_GLOBAL_SEGNAME
, KASAN_GLOBAL_SECTNAME
)) {
6559 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6560 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6561 getIdentifierCString()
6563 result
= KERN_FAILURE
;
6568 result
= kOSReturnSuccess
;
6573 /* Clear up locally allocated dependency info.
6575 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6578 if (kxlddeps
[i
].kext_name
) {
6579 size
= 1 + strlen(kxlddeps
[i
].kext_name
);
6580 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].kext_name
, size
);
6582 if (kxlddeps
[i
].interface_name
) {
6583 size
= 1 + strlen(kxlddeps
[i
].interface_name
);
6584 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].interface_name
, size
);
6588 kfree(kxlddeps
, (num_kxlddeps
* sizeof(*kxlddeps
)));
6590 #endif // CONFIG_KXLD
6592 /* We no longer need the unrelocated executable (which the linker
6593 * has altered anyhow).
6595 setExecutable(NULL
);
6597 if (result
!= kOSReturnSuccess
) {
6599 kOSKextLogErrorLevel
|
6601 "Failed to load executable for kext %s.",
6602 getIdentifierCString());
6604 if (kmod_info
&& kmod_info
->reference_list
) {
6605 kfree(kmod_info
->reference_list
,
6606 num_kmod_refs
* sizeof(kmod_reference_t
));
6608 if (isInterface()) {
6609 kfree(kmod_info
, sizeof(kmod_info_t
));
6612 if (kc_type
== KCKindUnknown
) {
6614 if (linkedExecutable
) {
6615 linkedExecutable
.reset();
6626 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t
*mh
)
6628 kernel_segment_command_t
*linkeditseg
= NULL
;
6630 linkeditseg
= getsegbynamefromheader(mh
, SEG_LINKEDIT
);
6631 assert(linkeditseg
!= NULL
);
6633 /* BootKC on x86_64 is not vm mapped */
6634 ml_static_mfree(linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6636 OSKextLog(/* kext */ NULL
,
6637 kOSKextLogProgressLevel
|
6638 kOSKextLogGeneralFlag
,
6639 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6640 linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6642 #endif /* VM_MAPPED_KEXTS */
6644 /*********************************************************************
6645 * The linkedit segment is used by the kext linker for dependency
6646 * resolution, and by dtrace for probe initialization. We can free it
6647 * for non-library kexts, since no kexts depend on non-library kexts
6648 * by definition, once dtrace has been initialized.
6649 *********************************************************************/
6651 OSKext::jettisonLinkeditSegment(void)
6653 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
6654 kernel_segment_command_t
* linkedit
= NULL
;
6656 vm_size_t linkeditsize
, kextsize
;
6657 OSSharedPtr
<OSData
> data
;
6659 if (isInFileset()) {
6664 /* We can free symbol tables for all embedded kexts because we don't
6665 * support runtime kext linking.
6667 if (sKeepSymbols
|| !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6669 if (sKeepSymbols
|| isLibrary() || !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6674 /* Find the linkedit segment. If it's not the last segment, then freeing
6675 * it will fragment the kext into multiple VM regions, which OSKext is not
6676 * designed to handle, so we'll have to skip it.
6678 linkedit
= getsegbynamefromheader(machhdr
, SEG_LINKEDIT
);
6683 if (round_page(kmod_info
->address
+ kmod_info
->size
) !=
6684 round_page(linkedit
->vmaddr
+ linkedit
->vmsize
)) {
6688 /* Create a new OSData for the smaller kext object.
6690 linkeditsize
= round_page(linkedit
->vmsize
);
6691 kextsize
= kmod_info
->size
- linkeditsize
;
6692 start
= linkedit
->vmaddr
;
6694 if (kextsize
> UINT_MAX
) {
6697 data
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)kextsize
);
6702 /* Fix the kmod info and linkedExecutable.
6704 kmod_info
->size
= kextsize
;
6707 data
->setDeallocFunction(osdata_kext_free
);
6709 data
->setDeallocFunction(osdata_phys_free
);
6711 linkedExecutable
->setDeallocFunction(NULL
);
6712 linkedExecutable
= os::move(data
);
6713 flags
.jettisonLinkeditSeg
= 1;
6715 /* Free the linkedit segment.
6718 kext_free(start
, linkeditsize
);
6720 ml_static_mfree(start
, linkeditsize
);
6727 /*********************************************************************
6728 * If there are whole pages that are unused betweem the last section
6729 * of the DATA segment and the end of the DATA segment then we can free
6731 *********************************************************************/
6733 OSKext::jettisonDATASegmentPadding(void)
6735 kernel_mach_header_t
* mh
;
6736 kernel_segment_command_t
* dataSeg
;
6737 kernel_section_t
* sec
, * lastSec
;
6738 vm_offset_t dataSegEnd
, lastSecEnd
;
6741 if (flags
.builtin
) {
6744 mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6746 if (isInFileset()) {
6750 dataSeg
= getsegbynamefromheader(mh
, SEG_DATA
);
6751 if (dataSeg
== NULL
) {
6756 sec
= firstsect(dataSeg
);
6757 while (sec
!= NULL
) {
6759 sec
= nextsect(dataSeg
, sec
);
6762 if (lastSec
== NULL
) {
6766 if ((dataSeg
->vmaddr
!= round_page(dataSeg
->vmaddr
)) ||
6767 (dataSeg
->vmsize
!= round_page(dataSeg
->vmsize
))) {
6771 dataSegEnd
= dataSeg
->vmaddr
+ dataSeg
->vmsize
;
6772 lastSecEnd
= round_page(lastSec
->addr
+ lastSec
->size
);
6774 if (dataSegEnd
<= lastSecEnd
) {
6778 padSize
= dataSegEnd
- lastSecEnd
;
6780 if (padSize
>= PAGE_SIZE
) {
6782 kext_free(lastSecEnd
, padSize
);
6784 ml_static_mfree(lastSecEnd
, padSize
);
6789 /*********************************************************************
6790 *********************************************************************/
6792 OSKext::setLinkedExecutable(OSData
* anExecutable
)
6794 if (linkedExecutable
) {
6795 panic("Attempt to set linked executable on kext "
6796 "that already has one (%s).\n",
6797 getIdentifierCString());
6799 linkedExecutable
.reset(anExecutable
, OSRetain
);
6804 /*********************************************************************
6805 * Go through all loaded kexts and tell them to register with dtrace.
6806 * The instance method only registers if necessary.
6807 *********************************************************************/
6810 OSKext::registerKextsWithDTrace(void)
6812 uint32_t count
= sLoadedKexts
->getCount();
6815 IORecursiveLockLock(sKextLock
);
6817 for (i
= 0; i
< count
; i
++) {
6818 OSKext
* thisKext
= NULL
; // do not release
6820 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6821 if (!thisKext
|| !thisKext
->isExecutable()) {
6825 thisKext
->registerWithDTrace();
6828 IORecursiveLockUnlock(sKextLock
);
6834 extern int (*dtrace_modload
)(struct kmod_info
*, uint32_t);
6835 extern int (*dtrace_modunload
)(struct kmod_info
*);
6838 /*********************************************************************
6839 *********************************************************************/
6841 OSKext::registerWithDTrace(void)
6843 /* Register kext with dtrace. A dtrace_modload failure should not
6844 * prevent a kext from loading, so we ignore the return code.
6846 if (!flags
.dtraceInitialized
&& (dtrace_modload
!= NULL
)) {
6847 uint32_t modflag
= 0;
6848 OSObject
* forceInit
= getPropertyForHostArch("OSBundleForceDTraceInit");
6851 if (!sKeepSymbols
&& kc_type
== KCKindPrimary
) {
6852 if (forceInit
== kOSBooleanTrue
) {
6853 /* Make sure the kext is not from the Boot KC */
6854 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6856 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6857 modflag
|= KMOD_DTRACE_NO_KERNEL_SYMS
;
6860 #endif /* VM_MAPPED_KEXTS */
6861 if (forceInit
== kOSBooleanTrue
) {
6862 modflag
|= KMOD_DTRACE_FORCE_INIT
;
6864 if (flags
.builtin
) {
6865 modflag
|= KMOD_DTRACE_STATIC_KEXT
;
6868 (void)(*dtrace_modload
)(kmod_info
, modflag
);
6869 flags
.dtraceInitialized
= true;
6870 jettisonLinkeditSegment();
6874 /*********************************************************************
6875 *********************************************************************/
6877 OSKext::unregisterWithDTrace(void)
6879 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6880 * prevent a kext from loading, so we ignore the return code.
6882 if (flags
.dtraceInitialized
&& (dtrace_modunload
!= NULL
)) {
6883 (void)(*dtrace_modunload
)(kmod_info
);
6884 flags
.dtraceInitialized
= false;
6888 #endif /* CONFIG_DTRACE */
6891 /*********************************************************************
6892 * called only by loadExecutable()
6893 *********************************************************************/
6894 #if !VM_MAPPED_KEXTS
6895 #if defined(__arm__) || defined(__arm64__)
6896 static inline kern_return_t
6898 kernel_mach_header_t
*kext_mh
,
6900 vm_map_offset_t start
,
6901 vm_map_offset_t end
,
6906 #pragma unused(kext_mh,map,kc_type)
6907 assert(map
== kernel_map
); // we can handle KEXTs arising from the PRELINK segment and no others
6908 assert(start
<= end
);
6910 return KERN_SUCCESS
; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6911 } else if (set_max
) {
6912 return KERN_SUCCESS
; // Punt set_max, as there's no mechanism to record that state
6914 return ml_static_protect(start
, end
- start
, new_prot
);
6918 static inline kern_return_t
6920 kernel_mach_header_t
*kext_mh
,
6922 vm_map_offset_t start
,
6923 vm_map_offset_t end
,
6924 vm_prot_t access_type
,
6925 boolean_t user_wire
,
6928 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6929 return KERN_SUCCESS
; // No-op as PRELINK kexts are cemented into physical memory at boot
6932 #error Unrecognized architecture
6935 static inline kern_return_t
6937 kernel_mach_header_t
*kext_mh
,
6939 vm_map_offset_t start
,
6940 vm_map_offset_t end
,
6945 if (start
== end
) { // 10538581
6946 return KERN_SUCCESS
;
6948 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6950 * XXX: This will probably need to be different for AuxKC and
6953 return ml_static_protect(start
, end
- start
, new_prot
);
6955 return vm_map_protect(map
, start
, end
, new_prot
, set_max
);
6958 static inline kern_return_t
6960 kernel_mach_header_t
*kext_mh
,
6962 vm_map_offset_t start
,
6963 vm_map_offset_t end
,
6964 vm_prot_t access_type
,
6965 boolean_t user_wire
,
6968 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6969 /* TODO: we may need to hook this for the pageableKC */
6970 return KERN_SUCCESS
;
6972 return vm_map_wire_kernel(map
, start
, end
, access_type
, VM_KERN_MEMORY_KEXT
, user_wire
);
6977 OSKext::setVMAttributes(bool protect
, bool wire
)
6979 vm_map_t kext_map
= NULL
;
6980 kernel_segment_command_t
* seg
= NULL
;
6981 vm_map_offset_t start_protect
= 0;
6982 vm_map_offset_t start_wire
= 0;
6983 vm_map_offset_t end_protect
= 0;
6984 vm_map_offset_t end_wire
= 0;
6985 OSReturn result
= kOSReturnError
;
6987 if (isInterface() || !declaresExecutable() || flags
.builtin
) {
6988 result
= kOSReturnSuccess
;
6992 /* Get the kext's vm map */
6993 kext_map
= kext_get_vm_map(kmod_info
);
6995 result
= KERN_MEMORY_ERROR
;
6999 #if !VM_MAPPED_KEXTS
7000 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
)) {
7001 /* This is a split kext in a prelinked kernelcache; we'll let the
7002 * platform code take care of protecting it. It is already wired.
7004 /* TODO: Should this still allow protections for the first segment
7005 * to go through, in the event that we have a mix of split and
7008 result
= KERN_SUCCESS
;
7012 if (isInFileset() && kc_type
!= KCKindPageable
) {
7013 // kexts in filesets have protections setup as part of collection loading
7014 result
= KERN_SUCCESS
;
7019 /* Protect the headers as read-only; they do not need to be wired */
7020 result
= (protect
) ? OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7021 kext_map
, kmod_info
->address
,
7022 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
, kc_type
)
7024 if (result
!= KERN_SUCCESS
) {
7028 /* Set the VM protections and wire down each of the segments */
7029 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7032 /* We build all ARM kexts, so we can ensure they are aligned */
7033 assert((seg
->vmaddr
& PAGE_MASK
) == 0);
7034 assert((seg
->vmsize
& PAGE_MASK
) == 0);
7038 * For the non page aligned segments, the range calculation for protection
7039 * and wiring differ as follows:
7041 * Protection: The non page aligned data at the start or at the end of the
7042 * segment is excluded from the protection. This exclusion is needed to make
7043 * sure OSKext_protect is not called twice on same page, if the page is shared
7044 * between two segments.
7046 * Wiring: The non page aligned data at the start or at the end of the
7047 * segment is included in the wiring range, this inclusion is needed to make sure
7048 * all the data of the segment is wired.
7050 start_protect
= round_page(seg
->vmaddr
);
7051 end_protect
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
7053 start_wire
= trunc_page(seg
->vmaddr
);
7054 end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7057 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7058 * across kexts and data from kexts is not page aligned
7060 if (protect
&& (end_protect
> start_protect
) &&
7061 ((strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0 &&
7062 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) != 0) ||
7063 (kc_type
!= KCKindPageable
&& kc_type
!= KCKindAuxiliary
))) {
7064 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7065 kext_map
, start_protect
, end_protect
, seg
->maxprot
, TRUE
, kc_type
);
7066 if (result
!= KERN_SUCCESS
) {
7068 kOSKextLogErrorLevel
|
7070 "Kext %s failed to set maximum VM protections "
7071 "for segment %s - 0x%x.",
7072 getIdentifierCString(), seg
->segname
, (int)result
);
7076 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7077 kext_map
, start_protect
, end_protect
, seg
->initprot
, FALSE
, kc_type
);
7078 if (result
!= KERN_SUCCESS
) {
7080 kOSKextLogErrorLevel
|
7082 "Kext %s failed to set initial VM protections "
7083 "for segment %s - 0x%x.",
7084 getIdentifierCString(), seg
->segname
, (int)result
);
7089 if (segmentShouldBeWired(seg
) && wire
) {
7090 result
= OSKext_wire((kernel_mach_header_t
*)kmod_info
->address
,
7091 kext_map
, start_wire
, end_wire
, seg
->initprot
, FALSE
, kc_type
);
7092 if (result
!= KERN_SUCCESS
) {
7097 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7104 /*********************************************************************
7105 *********************************************************************/
7107 OSKext::segmentShouldBeWired(kernel_segment_command_t
*seg
)
7109 return sKeepSymbols
|| (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) &&
7110 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)));
7113 /*********************************************************************
7114 *********************************************************************/
7116 OSKext::validateKextMapping(bool startFlag
)
7118 OSReturn result
= kOSReturnError
;
7119 const char * whichOp
= startFlag
? "start" : "stop";
7120 kern_return_t kern_result
= 0;
7121 vm_map_t kext_map
= NULL
;
7122 kernel_segment_command_t
* seg
= NULL
;
7123 mach_vm_address_t address
= 0;
7124 mach_vm_size_t size
= 0;
7126 uint64_t kext_segbase
= 0;
7127 uint64_t kext_segsize
= 0;
7128 mach_msg_type_number_t count
;
7129 vm_region_submap_short_info_data_64_t info
;
7130 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
7132 if (flags
.builtin
) {
7133 return kOSReturnSuccess
;
7136 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
7137 bzero(&info
, sizeof(info
));
7139 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7140 // xxx - sufficient?
7142 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7146 kOSKextLogErrorLevel
|
7148 "Kext %s - NULL kmod_info pointer.",
7149 getIdentifierCString());
7150 result
= kOSKextReturnBadData
;
7155 address
= (mach_vm_address_t
)kmod_info
->start
;
7157 address
= (mach_vm_address_t
)kmod_info
->stop
;
7162 kOSKextLogErrorLevel
|
7164 "Kext %s - NULL module %s pointer.",
7165 getIdentifierCString(), whichOp
);
7166 result
= kOSKextReturnBadData
;
7170 kext_map
= kext_get_vm_map(kmod_info
);
7171 depth
= (kernel_map
== kext_map
) ? 1 : 2;
7172 if (isInFileset()) {
7173 #if defined(HAS_APPLE_PAC)
7174 address
= (mach_vm_address_t
)ptrauth_auth_data((void*)address
, ptrauth_key_function_pointer
, 0);
7175 #endif /* defined(HAS_APPLE_PAC) */
7178 /* Verify that the start/stop function lies within the kext's address range.
7180 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
) ||
7182 /* This will likely be how we deal with split kexts; walk the segments to
7183 * check that the function lies inside one of the segments of this kext.
7185 for (seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7187 seg
= nextsegfromheader((kernel_mach_header_t
*)kmod_info
->address
, seg
)) {
7188 if ((address
>= seg
->vmaddr
) && address
< (seg
->vmaddr
+ seg
->vmsize
)) {
7189 kext_segbase
= seg
->vmaddr
;
7190 kext_segsize
= seg
->vmsize
;
7197 kOSKextLogErrorLevel
|
7199 "Kext %s module %s pointer is outside of kext range "
7200 "(%s %p - kext starts at %p).",
7201 getIdentifierCString(),
7204 (void *)(((uintptr_t)address
) - kext_slide
),
7205 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
));
7206 result
= kOSKextReturnBadData
;
7212 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
7213 kmod_info
->address
+ kmod_info
->size
<= address
) {
7215 kOSKextLogErrorLevel
|
7217 "Kext %s module %s pointer is outside of kext range "
7218 "(%s %p - kext at %p-%p).",
7219 getIdentifierCString(),
7222 (void *)(((uintptr_t)address
) - kext_slide
),
7223 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
),
7224 (void *)((((uintptr_t)kmod_info
->address
) - kext_slide
) + kmod_info
->size
));
7225 result
= kOSKextReturnBadData
;
7230 /* Only do these checks before calling the start function;
7231 * If anything goes wrong with the mapping while the kext is running,
7232 * we'll likely have panicked well before any attempt to stop the kext.
7235 if (!isInFileset() || kc_type
!= KCKindPrimary
) {
7237 * Verify that the start/stop function is executable.
7239 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
7240 (vm_region_recurse_info_t
)&info
, &count
);
7241 if (kern_result
!= KERN_SUCCESS
) {
7243 kOSKextLogErrorLevel
|
7245 "Kext %s - bad %s pointer %p.",
7246 getIdentifierCString(),
7247 whichOp
, (void *)ml_static_unslide(address
));
7248 result
= kOSKextReturnBadData
;
7253 * Since kexts loaded from the primary KC are held in memory
7254 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7255 * discover that memory's protection flags. Instead, we need to
7256 * get that information from the kernel pmap itself. Above, we
7257 * (potentially) saved the size of the segment in which the address
7258 * in question was located. If we have a non-zero size, verify
7259 * that all pages in the (address, address + kext_segsize) range
7260 * are marked executable. If we somehow did not record the size
7261 * (or the base) just verify the single page that includes the address.
7263 if (kext_segbase
== 0 || kext_segsize
== 0) {
7264 kext_segbase
= address
& ~(uint64_t)PAGE_MASK
;
7265 kext_segsize
= PAGE_SIZE
;
7270 if (((!isInFileset() || kc_type
!= KCKindPrimary
) && !(info
.protection
& VM_PROT_EXECUTE
)) ||
7271 ((isInFileset() && kc_type
== KCKindPrimary
) &&
7272 ml_static_verify_page_protections(kext_segbase
, kext_segsize
, VM_PROT_EXECUTE
) != KERN_SUCCESS
)) {
7274 kOSKextLogErrorLevel
|
7276 "Kext %s - memory region containing module %s function "
7277 "is not executable.",
7278 getIdentifierCString(), whichOp
);
7279 result
= kOSKextReturnBadData
;
7284 /* Verify that the kext's segments are backed by physical memory.
7286 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7288 if (!verifySegmentMapping(seg
)) {
7289 result
= kOSKextReturnBadData
;
7293 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7297 result
= kOSReturnSuccess
;
7302 /*********************************************************************
7303 *********************************************************************/
7305 OSKext::verifySegmentMapping(kernel_segment_command_t
*seg
)
7307 mach_vm_address_t address
= 0;
7309 if (seg
->vmsize
> UINT32_MAX
) {
7313 if (!segmentShouldBeWired(seg
)) {
7317 for (address
= seg
->vmaddr
;
7318 address
< round_page(seg
->vmaddr
+ seg
->vmsize
);
7319 address
+= PAGE_SIZE
) {
7320 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
7322 kOSKextLogErrorLevel
|
7324 "Kext %s - page %p is not backed by physical memory.",
7325 getIdentifierCString(),
7334 /*********************************************************************
7335 *********************************************************************/
7337 OSKextLogKextInfo(OSKext
*aKext
, uint64_t address
, uint64_t size
, firehose_tracepoint_code_t code
)
7340 firehose_tracepoint_id_u trace_id
;
7341 struct firehose_trace_uuid_info_s uuid_info_s
;
7342 firehose_trace_uuid_info_t uuid_info
= &uuid_info_s
;
7343 size_t uuid_info_len
= sizeof(struct firehose_trace_uuid_info_s
);
7344 OSSharedPtr
<OSData
> uuid_data
;
7346 stamp
= firehose_tracepoint_time(firehose_activity_flags_default
);
7347 trace_id
.ftid_value
= FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata
, _firehose_tracepoint_type_metadata_kext
, (firehose_tracepoint_flags_t
)0, code
);
7349 uuid_data
= aKext
->copyTextUUID();
7351 memcpy(uuid_info
->ftui_uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_info
->ftui_uuid
));
7354 uuid_info
->ftui_size
= size
;
7355 if (aKext
->isDriverKit()) {
7356 uuid_info
->ftui_address
= address
;
7358 uuid_info
->ftui_address
= ml_static_unslide(address
);
7360 firehose_trace_metadata(firehose_stream_metadata
, trace_id
, stamp
, uuid_info
, uuid_info_len
);
7365 OSKext::OSKextLogDriverKitInfoLoad(OSKext
*kext
)
7367 OSKextLogKextInfo(kext
, kext
->getLoadTag(), 1, firehose_tracepoint_code_load
);
7370 /*********************************************************************
7371 *********************************************************************/
7373 OSKext::start(bool startDependenciesFlag
)
7375 OSReturn result
= kOSReturnError
;
7376 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
7377 unsigned int i
, count
;
7378 void * kmodStartData
= NULL
;
7380 if (isStarted() || isInterface() || isKernelComponent()) {
7381 result
= kOSReturnSuccess
;
7387 kOSKextLogErrorLevel
|
7389 "Attempt to start nonloaded kext %s.",
7390 getIdentifierCString());
7391 result
= kOSKextReturnInvalidArgument
;
7395 if (!sLoadEnabled
) {
7397 kOSKextLogErrorLevel
|
7399 "Kext loading is disabled (attempt to start kext %s).",
7400 getIdentifierCString());
7401 result
= kOSKextReturnDisabled
;
7405 result
= validateKextMapping(/* start? */ true);
7406 if (result
!= kOSReturnSuccess
) {
7410 startfunc
= kmod_info
->start
;
7412 count
= getNumDependencies();
7413 for (i
= 0; i
< count
; i
++) {
7414 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
7415 if (dependency
== NULL
) {
7417 kOSKextLogErrorLevel
|
7419 "Kext %s start - internal error, dependency disappeared.",
7420 getIdentifierCString());
7423 if (!dependency
->isStarted()) {
7424 if (startDependenciesFlag
) {
7425 OSReturn dependencyResult
=
7426 dependency
->start(startDependenciesFlag
);
7427 if (dependencyResult
!= KERN_SUCCESS
) {
7429 kOSKextLogErrorLevel
|
7431 "Kext %s start - dependency %s failed to start (error 0x%x).",
7432 getIdentifierCString(),
7433 dependency
->getIdentifierCString(),
7439 kOSKextLogErrorLevel
|
7441 "Not starting %s - dependency %s not started yet.",
7442 getIdentifierCString(),
7443 dependency
->getIdentifierCString());
7444 result
= kOSKextReturnStartStopError
; // xxx - make new return?
7451 kOSKextLogDetailLevel
|
7453 "Kext %s calling module start function.",
7454 getIdentifierCString());
7458 // Drop a log message so logd can grab the needed information to decode this kext
7459 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_load
);
7460 result
= OSRuntimeInitializeCPP(this);
7461 if (result
== KERN_SUCCESS
) {
7462 result
= startfunc(kmod_info
, kmodStartData
);
7467 /* On success overlap the setting of started/starting. On failure just
7470 if (result
== KERN_SUCCESS
) {
7473 // xxx - log start error from kernel?
7475 kOSKextLogProgressLevel
|
7477 "Kext %s is now started.",
7478 getIdentifierCString());
7480 invokeOrCancelRequestCallbacks(
7481 /* result not actually used */ kOSKextReturnStartStopError
,
7482 /* invokeFlag */ false);
7484 kOSKextLogWarningLevel
|
7486 "Kext %s did not start (return code 0x%x).",
7487 getIdentifierCString(), result
);
7494 /*********************************************************************
7495 *********************************************************************/
7498 OSKext::canUnloadKextWithIdentifier(
7499 OSString
* kextIdentifier
,
7500 bool checkClassesFlag
)
7502 bool result
= false;
7503 OSKext
* aKext
= NULL
; // do not release
7505 IORecursiveLockLock(sKextLock
);
7507 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
7510 goto finish
; // can't unload what's not loaded
7513 if (aKext
->isLoaded()) {
7514 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
7517 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
7525 IORecursiveLockUnlock(sKextLock
);
7529 /*********************************************************************
7530 *********************************************************************/
7534 OSReturn result
= kOSReturnError
;
7535 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
7537 if (!isStarted() || isInterface()) {
7538 result
= kOSReturnSuccess
;
7544 kOSKextLogErrorLevel
|
7546 "Attempt to stop nonloaded kext %s.",
7547 getIdentifierCString());
7548 result
= kOSKextReturnInvalidArgument
;
7552 /* Refuse to stop if we have clients or instances. It is up to
7553 * the caller to make sure those aren't true.
7555 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7557 kOSKextLogErrorLevel
|
7559 "Kext %s - C++ instances; can't stop.",
7560 getIdentifierCString());
7561 result
= kOSKextReturnInUse
;
7565 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7567 kOSKextLogErrorLevel
|
7569 "Kext %s - has references (linkage or tracking object); "
7571 getIdentifierCString());
7572 result
= kOSKextReturnInUse
;
7576 /* Note: If validateKextMapping fails on the stop & unload path,
7577 * we are in serious trouble and a kernel panic is likely whether
7578 * we stop & unload the kext or not.
7580 result
= validateKextMapping(/* start? */ false);
7581 if (result
!= kOSReturnSuccess
) {
7585 stopfunc
= kmod_info
->stop
;
7588 kOSKextLogDetailLevel
|
7590 "Kext %s calling module stop function.",
7591 getIdentifierCString());
7595 result
= stopfunc(kmod_info
, /* userData */ NULL
);
7596 if (result
== KERN_SUCCESS
) {
7597 result
= OSRuntimeFinalizeCPP(this);
7602 if (result
== KERN_SUCCESS
) {
7606 kOSKextLogDetailLevel
|
7608 "Kext %s is now stopped and ready to unload.",
7609 getIdentifierCString());
7612 kOSKextLogErrorLevel
|
7614 "Kext %s did not stop (return code 0x%x).",
7615 getIdentifierCString(), result
);
7616 result
= kOSKextReturnStartStopError
;
7621 // Drop a log message so logd can update this kext's metadata
7622 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_unload
);
7626 /*********************************************************************
7627 *********************************************************************/
7629 OSKext::unload(void)
7631 OSReturn result
= kOSReturnError
;
7633 uint32_t num_kmod_refs
= 0;
7634 OSKextAccount
* freeAccount
;
7635 bool in_fileset
= false;
7637 if (!sUnloadEnabled
) {
7639 kOSKextLogErrorLevel
|
7641 "Kext unloading is disabled (%s).",
7642 this->getIdentifierCString());
7644 result
= kOSKextReturnDisabled
;
7648 // cache this result so we don't need to access the kmod_info after
7649 // it's been potentially free'd
7650 in_fileset
= isInFileset();
7652 /* Refuse to unload if we have clients or instances. It is up to
7653 * the caller to make sure those aren't true.
7655 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7656 // xxx - Don't log under errors? this is more of an info thing
7658 kOSKextLogErrorLevel
|
7659 kOSKextLogKextBookkeepingFlag
,
7660 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7661 getIdentifierCString());
7662 result
= kOSKextReturnInUse
;
7666 if (isDriverKit()) {
7667 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7668 if (index
!= (unsigned int)-1) {
7669 sLoadedDriverKitKexts
->removeObject(index
);
7670 OSKextLogKextInfo(this, loadTag
, 1, firehose_tracepoint_code_unload
);
7676 result
= kOSReturnSuccess
;
7680 if (isKernelComponent()) {
7681 result
= kOSKextReturnInvalidArgument
;
7685 if (metaClasses
&& !OSMetaClass::removeClasses(metaClasses
.get())) {
7687 kOSKextLogErrorLevel
|
7688 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
7689 "Can't unload kext %s; classes have instances:",
7690 getIdentifierCString());
7691 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
7692 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
7693 result
= kOSKextReturnInUse
;
7697 /* Note that the kext is unloading before running any code that
7698 * might be in the kext (request callbacks, module stop function).
7699 * We will deny certain requests made against a kext in the process
7702 flags
.unloading
= 1;
7704 /* Update the string describing the last kext to unload in case we panic.
7706 savePanicString(/* isLoading */ false);
7710 if (result
!= KERN_SUCCESS
) {
7712 kOSKextLogErrorLevel
|
7714 "Kext %s can't unload - module stop returned 0x%x.",
7715 getIdentifierCString(), (unsigned)result
);
7716 result
= kOSKextReturnStartStopError
;
7722 kOSKextLogProgressLevel
|
7724 "Kext %s unloading.",
7725 getIdentifierCString());
7728 struct list_head
*p
;
7729 struct list_head
*prev
;
7730 struct list_head
*next
;
7731 for (p
= pendingPgoHead
.next
; p
!= &pendingPgoHead
; p
= next
) {
7732 OSKextGrabPgoStruct
*s
= container_of(p
, OSKextGrabPgoStruct
, list_head
);
7733 s
->err
= OSKextGrabPgoDataLocked(this, s
->metadata
, instance_uuid
, s
->pSize
, s
->pBuffer
, s
->bufferSize
);
7740 IORecursiveLockWakeup(sKextLock
, s
, false);
7745 /* Even if we don't call the stop function, we want to be sure we
7746 * have no OSMetaClass references before unloading the kext executable
7747 * from memory. OSMetaClasses may have pointers into the kext executable
7748 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7751 metaClasses
->flushCollection();
7753 (void) OSRuntimeFinalizeCPP(this);
7755 /* Remove the kext from the list of loaded kexts, patch the gap
7756 * in the kmod_info_t linked list, and reset "kmod" to point to the
7757 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7759 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7760 if (index
!= (unsigned int)-1) {
7761 sLoadedKexts
->removeObject(index
);
7763 OSKext
* nextKext
= OSDynamicCast(OSKext
,
7764 sLoadedKexts
->getObject(index
));
7768 OSKext
* gapKext
= OSDynamicCast(OSKext
,
7769 sLoadedKexts
->getObject(index
- 1));
7771 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
7772 } else { /* index == 0 */
7773 nextKext
->kmod_info
->next
= NULL
;
7777 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
7778 if (lastKext
&& !lastKext
->isKernel()) {
7779 kmod
= lastKext
->kmod_info
;
7781 kmod
= NULL
; // clear the global kmod variable
7785 /* Clear out the kmod references that we're keeping for compatibility
7786 * with current panic backtrace code & kgmacros.
7787 * xxx - will want to update those bits sometime and remove this.
7789 num_kmod_refs
= getNumDependencies();
7790 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
7791 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
7792 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
7793 ref
->info
->reference_count
--;
7795 kfree(kmod_info
->reference_list
,
7796 num_kmod_refs
* sizeof(kmod_reference_t
));
7800 unregisterWithDTrace();
7801 #endif /* CONFIG_DTRACE */
7803 notifyKextUnloadObservers(this);
7806 IOSimpleLockLock(sKextAccountsLock
);
7807 account
->kext
= NULL
;
7808 if (account
->site
.tag
) {
7809 account
->site
.flags
|= VM_TAG_UNLOAD
;
7811 freeAccount
= account
;
7813 IOSimpleLockUnlock(sKextAccountsLock
);
7815 IODelete(freeAccount
, OSKextAccount
, 1);
7818 /* Unwire and free the linked executable.
7820 if (linkedExecutable
) {
7822 kasan_unload_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(), linkedExecutable
->getLength());
7826 if (!isInterface() && (!in_fileset
|| flags
.resetSegmentsFromVnode
)) {
7827 kernel_segment_command_t
*seg
= NULL
;
7828 vm_map_t kext_map
= kext_get_vm_map(kmod_info
);
7832 kOSKextLogErrorLevel
|
7834 "Failed to free kext %s; couldn't find the kext map.",
7835 getIdentifierCString());
7836 result
= kOSKextReturnInternalError
;
7841 kOSKextLogProgressLevel
|
7843 "Kext %s unwiring and unmapping linked executable.",
7844 getIdentifierCString());
7846 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7848 if (segmentShouldBeWired(seg
)) {
7849 vm_map_offset_t start_wire
= trunc_page(seg
->vmaddr
);
7850 vm_map_offset_t end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7852 result
= vm_map_unwire(kext_map
, start_wire
,
7854 if (result
!= KERN_SUCCESS
) {
7856 kOSKextLogErrorLevel
|
7858 "Failed to unwire kext %s.",
7859 getIdentifierCString());
7860 result
= kOSKextReturnInternalError
;
7865 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7867 #if defined(__x86_64__) || defined(__i386__)
7868 if (in_fileset
&& flags
.resetSegmentsFromVnode
) {
7869 IORecursiveLockLock(sKextLock
);
7870 resetKCFileSetSegments();
7871 IORecursiveLockUnlock(sKextLock
);
7873 #endif // (__x86_64__) || defined(__i386__)
7875 #endif /* VM_MAPPED_KEXTS */
7876 if (flags
.resetSegmentsFromImmutableCopy
) {
7877 result
= resetMutableSegments();
7878 if (result
!= kOSReturnSuccess
) {
7880 kOSKextLogErrorLevel
|
7882 "Failed to reset kext %s.",
7883 getIdentifierCString());
7884 result
= kOSKextReturnInternalError
;
7888 if (kc_type
== KCKindUnknown
) {
7889 linkedExecutable
.reset();
7893 /* An interface kext has a fake kmod_info that was allocated,
7894 * so we have to free it.
7896 if (isInterface()) {
7897 kfree(kmod_info
, sizeof(kmod_info_t
));
7905 flags
.loaded
= false;
7906 flushDependencies();
7908 /* save a copy of the bundle ID for us to check when deciding to
7909 * rebuild the kernel cache file. If a kext was already in the kernel
7910 * cache and unloaded then later loaded we do not need to rebuild the
7911 * kernel cache. 9055303
7913 if (isPrelinked()) {
7914 if (!_OSKextInUnloadedPrelinkedKexts(bundleID
.get())) {
7915 IORecursiveLockLock(sKextLock
);
7916 if (sUnloadedPrelinkedKexts
) {
7917 sUnloadedPrelinkedKexts
->setObject(bundleID
.get());
7919 IORecursiveLockUnlock(sKextLock
);
7924 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
7925 "Kext %s unloaded.", getIdentifierCString());
7927 queueKextNotification(kKextRequestPredicateUnloadNotification
,
7928 OSDynamicCast(OSString
, bundleID
.get()));
7931 OSKext::saveLoadedKextPanicList();
7932 OSKext::updateLoadedKextSummaries();
7934 flags
.unloading
= 0;
7938 /*********************************************************************
7939 * Assumes sKextLock is held.
7940 *********************************************************************/
7943 OSKext::queueKextNotification(
7944 const char * notificationName
,
7945 OSString
* kextIdentifier
)
7947 OSReturn result
= kOSReturnError
;
7948 OSSharedPtr
<OSDictionary
> loadRequest
;
7950 if (!kextIdentifier
) {
7951 result
= kOSKextReturnInvalidArgument
;
7955 /* Create a new request unless one is already sitting
7956 * in sKernelRequests for this bundle identifier
7958 result
= _OSKextCreateRequest(notificationName
, loadRequest
);
7959 if (result
!= kOSReturnSuccess
) {
7962 if (!_OSKextSetRequestArgument(loadRequest
.get(),
7963 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
7964 result
= kOSKextReturnNoMemory
;
7967 if (!sKernelRequests
->setObject(loadRequest
.get())) {
7968 result
= kOSKextReturnNoMemory
;
7972 /* We might want to only queue the notification if the IOKit daemon is active,
7973 * but that wouldn't work for embedded. Note that we don't care if
7974 * the ping immediately succeeds here so don't do anything with the
7975 * result of this call.
7977 OSKext::pingIOKitDaemon();
7979 result
= kOSReturnSuccess
;
7987 /*********************************************************************
7988 *********************************************************************/
7990 _OSKextConsiderDestroyingLinkContext(
7991 __unused thread_call_param_t p0
,
7992 __unused thread_call_param_t p1
)
7994 /* Take multiple locks in the correct order.
7996 IORecursiveLockLock(sKextLock
);
7997 IORecursiveLockLock(sKextInnerLock
);
7999 /* The first time we destroy the kxldContext is in the first
8000 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8001 * before calling this function. Thereafter any call to this function
8002 * will actually destroy the context.
8004 if (sConsiderUnloadsCalled
&& sKxldContext
) {
8005 kxld_destroy_context(sKxldContext
);
8006 sKxldContext
= NULL
;
8009 /* Free the thread_call that was allocated to execute this function.
8011 if (sDestroyLinkContextThread
) {
8012 if (!thread_call_free(sDestroyLinkContextThread
)) {
8013 OSKextLog(/* kext */ NULL
,
8014 kOSKextLogErrorLevel
|
8015 kOSKextLogGeneralFlag
,
8016 "thread_call_free() failed for kext link context.");
8018 sDestroyLinkContextThread
= NULL
;
8021 IORecursiveLockUnlock(sKextInnerLock
);
8022 IORecursiveLockUnlock(sKextLock
);
8027 /*********************************************************************
8028 * Destroying the kxldContext requires checking variables under both
8029 * sKextInnerLock and sKextLock, so we do it on a separate thread
8030 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8031 * call relationship.
8033 * This function must be invoked with sKextInnerLock held.
8034 * Do not call any function that takes sKextLock here!
8035 *********************************************************************/
8038 OSKext::considerDestroyingLinkContext(void)
8040 IORecursiveLockLock(sKextInnerLock
);
8042 /* If we have already queued a thread to destroy the link context,
8043 * don't bother resetting; that thread will take care of it.
8045 if (sDestroyLinkContextThread
) {
8049 /* The function to be invoked in the thread will deallocate
8050 * this thread_call, so don't share it around.
8052 sDestroyLinkContextThread
= thread_call_allocate(
8053 &_OSKextConsiderDestroyingLinkContext
, NULL
);
8054 if (!sDestroyLinkContextThread
) {
8055 OSKextLog(/* kext */ NULL
,
8056 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
8057 "Can't create thread to destroy kext link context.");
8061 thread_call_enter(sDestroyLinkContextThread
);
8064 IORecursiveLockUnlock(sKextInnerLock
);
8068 #else // !CONFIG_KXLD
8072 OSKext::considerDestroyingLinkContext(void)
8077 #endif // CONFIG_KXLD
8080 #pragma mark Autounload
8082 /*********************************************************************
8083 * This is a static method because the kext will be deallocated if it
8085 *********************************************************************/
8088 OSKext::autounloadKext(OSKext
* aKext
)
8090 OSReturn result
= kOSKextReturnInUse
;
8094 * Do not unload prelinked kexts on platforms that do not have an
8095 * IOKit daemon as there is no way to reload the kext or restart
8098 if (aKext
->isPrelinked()) {
8101 #endif /* defined(__x86_64__) */
8103 /* Check for external references to this kext (usu. dependents),
8104 * instances of defined classes (or classes derived from them),
8105 * outstanding requests.
8107 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
8108 !aKext
->flags
.autounloadEnabled
||
8109 aKext
->isKernelComponent()) {
8113 /* Skip a delay-autounload kext, once.
8115 if (aKext
->flags
.delayAutounload
) {
8117 kOSKextLogProgressLevel
|
8118 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
8119 "Kext %s has delayed autounload set; skipping and clearing flag.",
8120 aKext
->getIdentifierCString());
8121 aKext
->flags
.delayAutounload
= 0;
8125 if (aKext
->hasOSMetaClassInstances() ||
8126 aKext
->countRequestCallbacks()) {
8130 result
= OSKext::removeKext(aKext
);
8136 /*********************************************************************
8137 *********************************************************************/
8139 _OSKextConsiderUnloads(
8140 __unused thread_call_param_t p0
,
8141 __unused thread_call_param_t p1
)
8143 bool didUnload
= false;
8144 unsigned int count
, i
;
8146 /* Take multiple locks in the correct order
8147 * (note also sKextSummaries lock further down).
8149 IORecursiveLockLock(sKextLock
);
8150 IORecursiveLockLock(sKextInnerLock
);
8152 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8154 /* If the system is powering down, don't try to unload anything.
8160 OSKextLog(/* kext */ NULL
,
8161 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
8162 "Checking for unused kexts to autounload.");
8165 * Remove any request callbacks marked as stale,
8166 * and mark as stale any currently in flight.
8168 count
= sRequestCallbackRecords
->getCount();
8172 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
8173 sRequestCallbackRecords
->getObject(i
));
8174 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
8175 callbackRecord
->getObject(kKextRequestStaleKey
));
8177 if (stale
== kOSBooleanTrue
) {
8178 OSKext::invokeRequestCallback(callbackRecord
,
8179 kOSKextReturnTimeout
);
8181 callbackRecord
->setObject(kKextRequestStaleKey
,
8188 * Make multiple passes through the array of loaded kexts until
8189 * we don't unload any. This handles unwinding of dependency
8190 * chains. We have to go *backwards* through the array because
8191 * kexts are removed from it when unloaded, and we cannot make
8192 * a copy or we'll mess up the retain counts we rely on to
8193 * check whether a kext will unload. If only we could have
8194 * nonretaining collections like CF has....
8199 count
= sLoadedKexts
->getCount();
8203 OSKext
* thisKext
= OSDynamicCast(OSKext
,
8204 sLoadedKexts
->getObject(i
));
8205 didUnload
|= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
8208 } while (didUnload
);
8211 sConsiderUnloadsPending
= false;
8212 sConsiderUnloadsExecuted
= true;
8214 (void) OSKext::considerRebuildOfPrelinkedKernel();
8216 IORecursiveLockUnlock(sKextInnerLock
);
8217 IORecursiveLockUnlock(sKextLock
);
8222 /*********************************************************************
8223 * Do not call any function that takes sKextLock here!
8224 *********************************************************************/
8226 OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
8230 IORecursiveLockLock(sKextInnerLock
);
8232 if (!sUnloadCallout
) {
8233 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, NULL
);
8236 /* we only reset delay value for unloading if we already have something
8237 * pending. rescheduleOnlyFlag should not start the count down.
8239 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
8243 thread_call_cancel(sUnloadCallout
);
8244 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8246 && sIOKitDaemonActive
8249 clock_interval_to_deadline(sConsiderUnloadDelay
,
8250 1000 * 1000 * 1000, &when
);
8252 OSKextLog(/* kext */ NULL
,
8253 kOSKextLogProgressLevel
|
8255 "%scheduling %sscan for unused kexts in %lu seconds.",
8256 sConsiderUnloadsPending
? "Res" : "S",
8257 sConsiderUnloadsCalled
? "" : "initial ",
8258 (unsigned long)sConsiderUnloadDelay
);
8260 sConsiderUnloadsPending
= true;
8261 thread_call_enter_delayed(sUnloadCallout
, when
);
8265 /* The kxld context should be reused throughout boot. We mark the end of
8266 * period as the first time considerUnloads() is called, and we destroy
8267 * the first kxld context in that function. Afterwards, it will be
8268 * destroyed in flushNonloadedKexts.
8270 if (!sConsiderUnloadsCalled
) {
8271 sConsiderUnloadsCalled
= true;
8272 OSKext::considerDestroyingLinkContext();
8275 IORecursiveLockUnlock(sKextInnerLock
);
8279 /*********************************************************************
8280 * Do not call any function that takes sKextLock here!
8281 *********************************************************************/
8283 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
);
8285 OSKextSystemSleepOrWake(UInt32 messageType
)
8287 IORecursiveLockLock(sKextInnerLock
);
8289 /* If the system is going to sleep, cancel the reaper thread timer,
8290 * and note that we're in a sleep state in case it just fired but hasn't
8291 * taken the lock yet. If we are coming back from sleep, just
8292 * clear the sleep flag; IOService's normal operation will cause
8293 * unloads to be considered soon enough.
8295 if (messageType
== kIOMessageSystemWillSleep
) {
8296 if (sUnloadCallout
) {
8297 thread_call_cancel(sUnloadCallout
);
8299 sSystemSleep
= true;
8300 AbsoluteTime_to_scalar(&sLastWakeTime
) = 0;
8301 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
8302 sSystemSleep
= false;
8303 clock_get_uptime(&sLastWakeTime
);
8305 IORecursiveLockUnlock(sKextInnerLock
);
8307 return kIOReturnSuccess
;
8313 #pragma mark Prelinked Kernel
8317 /*********************************************************************
8318 * Do not access sConsiderUnloads... variables other than
8319 * sConsiderUnloadsExecuted in this function. They are guarded by a
8321 *********************************************************************/
8324 OSKext::considerRebuildOfPrelinkedKernel(void)
8326 static bool requestedPrelink
= false;
8327 OSReturn checkResult
= kOSReturnError
;
8328 OSSharedPtr
<OSDictionary
> prelinkRequest
;
8329 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
8330 const OSSymbol
* thisID
= NULL
; // do not release
8331 bool doRebuild
= false;
8332 AbsoluteTime my_abstime
;
8336 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8337 if (requestedPrelink
|| !sPrelinkBoot
) {
8341 /* no direct return from this point */
8342 IORecursiveLockLock(sKextLock
);
8344 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8345 * and any new startup kexts loaded.
8347 if (!sConsiderUnloadsExecuted
||
8348 !sDeferredLoadSucceeded
) {
8352 /* we really only care about boot / system start up related kexts so bail
8353 * if we're here after REBUILD_MAX_TIME.
8355 if (!_OSKextInPrelinkRebuildWindow()) {
8356 OSKextLog(/* kext */ NULL
,
8357 kOSKextLogArchiveFlag
,
8358 "%s prebuild rebuild has expired",
8360 requestedPrelink
= true;
8364 /* we do not want to trigger a rebuild if we get here too close to waking
8365 * up. (see radar 10233768)
8367 IORecursiveLockLock(sKextInnerLock
);
8369 clock_get_uptime(&my_abstime
);
8370 delta_secs
= MINIMUM_WAKEUP_SECONDS
+ 1;
8371 if (AbsoluteTime_to_scalar(&sLastWakeTime
) != 0) {
8372 SUB_ABSOLUTETIME(&my_abstime
, &sLastWakeTime
);
8373 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
8374 delta_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
8376 IORecursiveLockUnlock(sKextInnerLock
);
8378 if (delta_secs
< MINIMUM_WAKEUP_SECONDS
) {
8379 /* too close to time of last wake from sleep */
8382 requestedPrelink
= true;
8384 /* Now it's time to see if we have a reason to rebuild. We may have done
8385 * some loads and unloads but the kernel cache didn't actually change.
8386 * We will rebuild if any kext is not marked prelinked AND is not in our
8387 * list of prelinked kexts that got unloaded. (see radar 9055303)
8389 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
8390 if (!kextIterator
) {
8394 while ((thisID
= OSDynamicCast(OSSymbol
, kextIterator
->getNextObject()))) {
8395 OSKext
* thisKext
; // do not release
8397 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
8398 if (!thisKext
|| thisKext
->isPrelinked() || thisKext
->isKernel()) {
8402 if (_OSKextInUnloadedPrelinkedKexts(thisKext
->bundleID
.get())) {
8405 /* kext is loaded and was not in current kernel cache so let's rebuild
8408 OSKextLog(/* kext */ NULL
,
8409 kOSKextLogArchiveFlag
,
8410 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8411 thisKext
->bundleID
->getCStringNoCopy());
8414 sUnloadedPrelinkedKexts
->flushCollection();
8420 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
8422 if (checkResult
!= kOSReturnSuccess
) {
8426 if (!sKernelRequests
->setObject(prelinkRequest
.get())) {
8430 OSKext::pingIOKitDaemon();
8433 IORecursiveLockUnlock(sKextLock
);
8438 #else /* !CONFIG_KXLD */
8441 OSKext::considerRebuildOfPrelinkedKernel(void)
8443 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8447 #endif /* CONFIG_KXLD */
8450 #pragma mark Dependencies
8452 /*********************************************************************
8453 *********************************************************************/
8455 OSKext::resolveDependencies(
8456 OSArray
* loopStack
)
8458 bool result
= false;
8459 OSSharedPtr
<OSArray
> localLoopStack
;
8460 bool addedToLoopStack
= false;
8461 OSDictionary
* libraries
= NULL
; // do not release
8462 OSSharedPtr
<OSCollectionIterator
> libraryIterator
;
8463 OSString
* libraryID
= NULL
; // do not release
8464 OSKext
* libraryKext
= NULL
; // do not release
8465 bool hasRawKernelDependency
= false;
8466 bool hasKernelDependency
= false;
8467 bool hasKPIDependency
= false;
8468 bool hasPrivateKPIDependency
= false;
8472 OSString
* infoString
= NULL
; // do not release
8473 OSString
* readableString
= NULL
; // do not release
8474 #endif // CONFIG_KXLD
8476 /* A kernel component will automatically have this flag set,
8477 * and a loaded kext should also have it set (as should all its
8478 * loaded dependencies).
8480 if (flags
.hasAllDependencies
) {
8485 /* Check for loops in the dependency graph.
8488 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8490 kOSKextLogErrorLevel
|
8491 kOSKextLogDependenciesFlag
,
8492 "Kext %s has a dependency loop; can't resolve dependencies.",
8493 getIdentifierCString());
8498 kOSKextLogStepLevel
|
8499 kOSKextLogDependenciesFlag
,
8500 "Kext %s resolving dependencies.",
8501 getIdentifierCString());
8503 localLoopStack
= OSArray::withCapacity(6); // any small capacity will do
8504 if (!localLoopStack
) {
8506 kOSKextLogErrorLevel
|
8507 kOSKextLogDependenciesFlag
,
8508 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8509 getIdentifierCString());
8512 loopStack
= localLoopStack
.get();
8514 if (!loopStack
->setObject(this)) {
8516 kOSKextLogErrorLevel
|
8517 kOSKextLogDependenciesFlag
,
8518 "Kext %s - internal error resolving dependencies.",
8519 getIdentifierCString());
8522 addedToLoopStack
= true;
8524 /* Purge any existing kexts in the dependency list and start over.
8526 flushDependencies();
8529 kOSKextLogErrorLevel
|
8530 kOSKextLogDependenciesFlag
,
8531 "Kext %s - internal error resolving dependencies.",
8532 getIdentifierCString());
8535 libraries
= OSDynamicCast(OSDictionary
,
8536 getPropertyForHostArch(kOSBundleLibrariesKey
));
8537 if (libraries
== NULL
|| libraries
->getCount() == 0) {
8539 kOSKextLogErrorLevel
|
8540 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8541 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8542 getIdentifierCString(), kOSBundleLibrariesKey
);
8546 /* Make a new array to hold the dependencies (flush freed the old one).
8548 dependencies
= OSArray::withCapacity(libraries
->getCount());
8549 if (!dependencies
) {
8551 kOSKextLogErrorLevel
|
8552 kOSKextLogDependenciesFlag
,
8553 "Kext %s - can't allocate dependencies array.",
8554 getIdentifierCString());
8558 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8559 // xxx - compat: if none were declared.
8561 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
8562 if (!libraryIterator
) {
8564 kOSKextLogErrorLevel
|
8565 kOSKextLogDependenciesFlag
,
8566 "Kext %s - can't allocate dependencies iterator.",
8567 getIdentifierCString());
8571 while ((libraryID
= OSDynamicCast(OSString
,
8572 libraryIterator
->getNextObject()))) {
8573 const char * library_id
= libraryID
->getCStringNoCopy();
8575 OSString
* libraryVersion
= OSDynamicCast(OSString
,
8576 libraries
->getObject(libraryID
));
8577 if (libraryVersion
== NULL
) {
8579 kOSKextLogErrorLevel
|
8580 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8581 "Kext %s - illegal type in OSBundleLibraries.",
8582 getIdentifierCString());
8586 OSKextVersion libraryVers
=
8587 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
8588 if (libraryVers
== -1) {
8590 kOSKextLogErrorLevel
|
8591 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8592 "Kext %s - invalid library version %s.",
8593 getIdentifierCString(),
8594 libraryVersion
->getCStringNoCopy());
8598 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
8599 if (libraryKext
== NULL
) {
8601 kOSKextLogErrorLevel
|
8602 kOSKextLogDependenciesFlag
,
8603 "Kext %s - library kext %s not found.",
8604 getIdentifierCString(), library_id
);
8608 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
8610 kOSKextLogErrorLevel
|
8611 kOSKextLogDependenciesFlag
,
8612 "Kext %s - library kext %s not compatible "
8613 "with requested version %s.",
8614 getIdentifierCString(), library_id
,
8615 libraryVersion
->getCStringNoCopy());
8619 /* If a nonprelinked library somehow got into the mix for a
8620 * prelinked kext, at any point in the chain, we must fail
8621 * because the prelinked relocs for the library will be all wrong.
8623 if (this->isPrelinked() &&
8624 libraryKext
->declaresExecutable() &&
8625 !libraryKext
->isPrelinked()) {
8627 kOSKextLogErrorLevel
|
8628 kOSKextLogDependenciesFlag
,
8629 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8630 getIdentifierCString(), library_id
,
8631 libraryVersion
->getCStringNoCopy());
8635 if (!libraryKext
->resolveDependencies(loopStack
)) {
8639 /* Add the library directly only if it has an executable to link.
8640 * Otherwise it's just used to collect other dependencies, so put
8641 * *its* dependencies on the list for this kext.
8643 // xxx - We are losing info here; would like to make fake entries or
8644 // xxx - keep these in the dependency graph for loaded kexts.
8645 // xxx - I really want to make kernel components not a special case!
8646 if (libraryKext
->declaresExecutable() ||
8647 libraryKext
->isInterface()) {
8648 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
8649 dependencies
->setObject(libraryKext
);
8652 kOSKextLogDetailLevel
|
8653 kOSKextLogDependenciesFlag
,
8654 "Kext %s added dependency %s.",
8655 getIdentifierCString(),
8656 libraryKext
->getIdentifierCString());
8659 int numLibDependencies
= libraryKext
->getNumDependencies();
8660 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
8663 if (numLibDependencies
) {
8664 // xxx - this msg level should be 1 lower than the per-kext one
8666 kOSKextLogDetailLevel
|
8667 kOSKextLogDependenciesFlag
,
8668 "Kext %s pulling %d dependencies from codeless library %s.",
8669 getIdentifierCString(),
8671 libraryKext
->getIdentifierCString());
8673 for (index
= 0; index
< numLibDependencies
; index
++) {
8674 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
8675 libraryDependencies
->getObject(index
));
8676 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
8677 dependencies
->setObject(thisLibDependency
);
8679 kOSKextLogDetailLevel
|
8680 kOSKextLogDependenciesFlag
,
8681 "Kext %s added dependency %s from codeless library %s.",
8682 getIdentifierCString(),
8683 thisLibDependency
->getIdentifierCString(),
8684 libraryKext
->getIdentifierCString());
8689 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
8690 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
) - 1)) {
8691 hasRawKernelDependency
= true;
8692 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
8693 hasKernelDependency
= true;
8694 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
8695 hasKPIDependency
= true;
8696 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
) - 1)) {
8697 hasPrivateKPIDependency
= true;
8702 if (hasRawKernelDependency
) {
8704 kOSKextLogErrorLevel
|
8705 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8706 "Error - kext %s declares a dependency on %s, which is not permitted.",
8707 getIdentifierCString(), KERNEL_LIB
);
8711 if (hasKernelDependency
) {
8713 kOSKextLogErrorLevel
|
8714 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8715 "Error - kext %s declares %s dependencies. "
8716 "Only %s* dependencies are supported for 64-bit kexts.",
8717 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8720 if (!hasKPIDependency
) {
8722 kOSKextLogWarningLevel
|
8723 kOSKextLogDependenciesFlag
,
8724 "Warning - kext %s declares no %s* dependencies. "
8725 "If it uses any KPIs, the link may fail with undefined symbols.",
8726 getIdentifierCString(), KPI_LIB_PREFIX
);
8728 #else /* __LP64__ */
8729 // xxx - will change to flatly disallow "kernel" dependencies at some point
8730 // xxx - is it invalid to do both "com.apple.kernel" and any
8731 // xxx - "com.apple.kernel.*"?
8733 if (hasKernelDependency
&& hasKPIDependency
) {
8735 kOSKextLogWarningLevel
|
8736 kOSKextLogDependenciesFlag
,
8737 "Warning - kext %s has immediate dependencies on both "
8738 "%s* and %s* components; use only one style.",
8739 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8742 if (!hasKernelDependency
&& !hasKPIDependency
) {
8743 // xxx - do we want to use validation flag for these too?
8745 kOSKextLogWarningLevel
|
8746 kOSKextLogDependenciesFlag
,
8747 "Warning - %s declares no kernel dependencies; using %s.",
8748 getIdentifierCString(), KERNEL6_LIB
);
8749 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
8750 sKextsByID
->getObject(KERNEL6_LIB
));
8752 dependencies
->setObject(kernelKext
);
8755 kOSKextLogErrorLevel
|
8756 kOSKextLogDependenciesFlag
,
8757 "Error - Library %s not found for %s.",
8758 KERNEL6_LIB
, getIdentifierCString());
8762 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8763 * its indirect dependencies to simulate old-style linking. XXX - Should
8764 * check for duplicates.
8766 if (!hasKPIDependency
) {
8769 flags
.hasBleedthrough
= true;
8771 count
= getNumDependencies();
8773 /* We add to the dependencies array in this loop, but do not iterate
8774 * past its original count.
8776 for (i
= 0; i
< count
; i
++) {
8777 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
8778 dependencies
->getObject(i
));
8779 dependencyKext
->addBleedthroughDependencies(dependencies
.get());
8782 #endif /* __LP64__ */
8786 * If we're not dynamically linking kexts, then we don't need to check
8787 * copyright strings. The linker in user space has already done this.
8789 if (hasPrivateKPIDependency
) {
8790 bool hasApplePrefix
= false;
8791 bool infoCopyrightIsValid
= false;
8792 bool readableCopyrightIsValid
= false;
8794 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
8797 infoString
= OSDynamicCast(OSString
,
8798 getPropertyForHostArch("CFBundleGetInfoString"));
8800 infoCopyrightIsValid
=
8801 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
8804 readableString
= OSDynamicCast(OSString
,
8805 getPropertyForHostArch("NSHumanReadableCopyright"));
8806 if (readableString
) {
8807 readableCopyrightIsValid
=
8808 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
8811 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
8813 kOSKextLogErrorLevel
|
8814 kOSKextLogDependenciesFlag
,
8815 "Error - kext %s declares a dependency on %s. "
8816 "Only Apple kexts may declare a dependency on %s.",
8817 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
8821 #endif // CONFIG_KXLD
8824 flags
.hasAllDependencies
= 1;
8828 if (addedToLoopStack
) {
8829 count
= loopStack
->getCount();
8830 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
8831 loopStack
->removeObject(count
- 1);
8834 kOSKextLogErrorLevel
|
8835 kOSKextLogDependenciesFlag
,
8836 "Kext %s - internal error resolving dependencies.",
8837 getIdentifierCString());
8841 if (result
&& localLoopStack
) {
8843 kOSKextLogStepLevel
|
8844 kOSKextLogDependenciesFlag
,
8845 "Kext %s successfully resolved dependencies.",
8846 getIdentifierCString());
8852 /*********************************************************************
8853 *********************************************************************/
8855 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
8857 bool result
= false;
8858 unsigned int dependencyIndex
, dependencyCount
;
8860 dependencyCount
= getNumDependencies();
8862 for (dependencyIndex
= 0;
8863 dependencyIndex
< dependencyCount
;
8864 dependencyIndex
++) {
8865 OSKext
* dependency
= OSDynamicCast(OSKext
,
8866 dependencies
->getObject(dependencyIndex
));
8869 kOSKextLogErrorLevel
|
8870 kOSKextLogDependenciesFlag
,
8871 "Kext %s - internal error propagating compatibility dependencies.",
8872 getIdentifierCString());
8875 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
8876 anArray
->setObject(dependency
);
8878 dependency
->addBleedthroughDependencies(anArray
);
8887 /*********************************************************************
8888 *********************************************************************/
8890 OSKext::flushDependencies(bool forceFlag
)
8892 bool result
= false;
8894 /* Only clear the dependencies if the kext isn't loaded;
8895 * we need the info for loaded kexts to track references.
8897 if (!isLoaded() || forceFlag
) {
8899 // xxx - check level
8901 kOSKextLogProgressLevel
|
8902 kOSKextLogDependenciesFlag
,
8903 "Kext %s flushing dependencies.",
8904 getIdentifierCString());
8905 dependencies
.reset();
8907 if (!isKernelComponent()) {
8908 flags
.hasAllDependencies
= 0;
8916 /*********************************************************************
8917 *********************************************************************/
8919 OSKext::getNumDependencies(void)
8921 if (!dependencies
) {
8924 return dependencies
->getCount();
8927 /*********************************************************************
8928 *********************************************************************/
8930 OSKext::getDependencies(void)
8932 return dependencies
.get();
8936 OSKext::hasDependency(const OSSymbol
* depID
)
8938 bool result __block
;
8940 if (depID
== getIdentifier()) {
8943 if (!dependencies
) {
8947 dependencies
->iterateObjects(^bool (OSObject
* obj
) {
8949 kext
= OSDynamicCast(OSKext
, obj
);
8953 result
= (depID
== kext
->getIdentifier());
8960 #pragma mark OSMetaClass Support
8962 /*********************************************************************
8963 *********************************************************************/
8966 OSMetaClass
* aClass
,
8967 uint32_t numClasses
)
8969 OSReturn result
= kOSMetaClassNoInsKModSet
;
8972 metaClasses
= OSSet::withCapacity(numClasses
);
8978 if (metaClasses
->containsObject(aClass
)) {
8980 kOSKextLogWarningLevel
|
8982 "Notice - kext %s has already registered class %s.",
8983 getIdentifierCString(),
8984 aClass
->getClassName());
8985 result
= kOSReturnSuccess
;
8989 if (!metaClasses
->setObject(aClass
)) {
8993 kOSKextLogDetailLevel
|
8995 "Kext %s registered class %s.",
8996 getIdentifierCString(),
8997 aClass
->getClassName());
9000 if (!flags
.autounloadEnabled
) {
9001 const OSMetaClass
* metaScan
= NULL
; // do not release
9003 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
9004 if (metaScan
== OSTypeID(IOService
)) {
9006 kOSKextLogProgressLevel
|
9008 "Kext %s has IOService subclass %s; enabling autounload.",
9009 getIdentifierCString(),
9010 aClass
->getClassName());
9012 flags
.autounloadEnabled
= (0 == flags
.unloadUnsupported
);
9018 notifyAddClassObservers(this, aClass
, flags
);
9020 result
= kOSReturnSuccess
;
9023 if (result
!= kOSReturnSuccess
) {
9025 kOSKextLogErrorLevel
|
9027 "Kext %s failed to register class %s.",
9028 getIdentifierCString(),
9029 aClass
->getClassName());
9035 /*********************************************************************
9036 *********************************************************************/
9038 OSKext::removeClass(
9039 OSMetaClass
* aClass
)
9041 OSReturn result
= kOSMetaClassNoKModSet
;
9047 if (!metaClasses
->containsObject(aClass
)) {
9049 kOSKextLogWarningLevel
|
9051 "Notice - kext %s asked to unregister unknown class %s.",
9052 getIdentifierCString(),
9053 aClass
->getClassName());
9054 result
= kOSReturnSuccess
;
9059 kOSKextLogDetailLevel
|
9061 "Kext %s unregistering class %s.",
9062 getIdentifierCString(),
9063 aClass
->getClassName());
9065 metaClasses
->removeObject(aClass
);
9067 notifyRemoveClassObservers(this, aClass
, flags
);
9069 result
= kOSReturnSuccess
;
9072 if (result
!= kOSReturnSuccess
) {
9074 kOSKextLogErrorLevel
|
9076 "Failed to unregister kext %s class %s.",
9077 getIdentifierCString(),
9078 aClass
->getClassName());
9083 /*********************************************************************
9084 *********************************************************************/
9086 OSKext::getMetaClasses(void)
9088 return metaClasses
.get();
9091 /*********************************************************************
9092 *********************************************************************/
9094 OSKext::hasOSMetaClassInstances(void)
9096 bool result
= false;
9097 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9098 OSMetaClass
* checkClass
= NULL
; // do not release
9104 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9105 if (!classIterator
) {
9106 // xxx - log alloc failure?
9109 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9110 if (checkClass
->getInstanceCount()) {
9120 /*********************************************************************
9121 *********************************************************************/
9124 OSKext::reportOSMetaClassInstances(
9125 const char * kextIdentifier
,
9126 OSKextLogSpec msgLogSpec
)
9128 OSSharedPtr
<OSKext
> theKext
;
9130 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
9135 theKext
->reportOSMetaClassInstances(msgLogSpec
);
9140 /*********************************************************************
9141 *********************************************************************/
9143 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
9145 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9146 OSMetaClass
* checkClass
= NULL
; // do not release
9152 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9153 if (!classIterator
) {
9156 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9157 if (checkClass
->getInstanceCount()) {
9160 " Kext %s class %s has %d instance%s.",
9161 getIdentifierCString(),
9162 checkClass
->getClassName(),
9163 checkClass
->getInstanceCount(),
9164 checkClass
->getInstanceCount() == 1 ? "" : "s");
9173 #pragma mark User-Space Requests
9176 static kern_return_t
9177 patchDextLaunchRequests(task_t calling_task
, OSArray
*requests
)
9179 OSReturn result
= kOSReturnSuccess
;
9180 for (uint32_t requestIndex
= 0; requestIndex
< requests
->getCount(); requestIndex
++) {
9181 OSDictionary
* request
= NULL
; //do not release
9182 IOUserServerCheckInToken
* token
= NULL
; //do not release
9183 OSString
* requestPredicate
= NULL
; //do not release
9184 OSSharedPtr
<OSNumber
> portNameNumber
;
9185 mach_port_name_t portName
= 0;
9186 request
= OSDynamicCast(OSDictionary
, requests
->getObject(requestIndex
));
9188 OSKextLog(/* kext */ NULL
,
9189 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9190 "Elements of request should be of type OSDictionary");
9191 result
= kOSKextReturnInternalError
;
9194 requestPredicate
= _OSKextGetRequestPredicate(request
);
9195 if (!requestPredicate
) {
9196 OSKextLog(/* kext */ NULL
,
9197 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9198 "Failed to get request predicate");
9199 result
= kOSKextReturnInternalError
;
9202 // is this a dext launch?
9203 if (requestPredicate
->isEqualTo(kKextRequestPredicateRequestDaemonLaunch
)) {
9204 token
= OSDynamicCast(IOUserServerCheckInToken
, _OSKextGetRequestArgument(request
, kKextRequestArgumentCheckInToken
));
9206 OSKextLog(/* kext */ NULL
,
9207 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9208 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9209 result
= kOSKextReturnInternalError
;
9212 portName
= iokit_make_send_right(calling_task
, token
, IKOT_IOKIT_IDENT
);
9213 if (portName
== 0 || portName
== MACH_PORT_DEAD
) {
9214 OSKextLog(/* kext */ NULL
,
9215 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9216 "Could not create send right for object.");
9217 result
= kOSKextReturnInternalError
;
9220 // Store the mach port name as a OSNumber
9221 portNameNumber
= OSNumber::withNumber(portName
, CHAR_BIT
* sizeof(portName
));
9222 if (!portNameNumber
) {
9223 OSKextLog(/* kext */ NULL
,
9224 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9225 "Could not create OSNumber object.");
9226 result
= kOSKextReturnNoMemory
;
9229 if (!_OSKextSetRequestArgument(request
, kKextRequestArgumentCheckInToken
, portNameNumber
.get())) {
9230 OSKextLog(/* kext */ NULL
,
9231 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9232 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken
);
9233 result
= kOSKextReturnNoMemory
;
9238 if (result
!= kOSReturnSuccess
) {
9245 /*********************************************************************
9246 * XXX - this function is a big ugly mess
9247 *********************************************************************/
9250 OSKext::handleRequest(
9251 host_priv_t hostPriv
,
9252 OSKextLogSpec clientLogFilter
,
9253 char * requestBuffer
,
9254 uint32_t requestLength
,
9255 char ** responseOut
,
9256 uint32_t * responseLengthOut
,
9258 uint32_t * logInfoLengthOut
)
9260 OSReturn result
= kOSReturnError
;
9261 kern_return_t kmem_result
= KERN_FAILURE
;
9263 char * response
= NULL
; // returned by reference
9264 uint32_t responseLength
= 0;
9266 bool taskCanManageAllKCs
= false;
9267 bool taskOnlyManagesBootKC
= false;
9269 OSSharedPtr
<OSObject
> parsedXML
;
9270 OSDictionary
* requestDict
= NULL
; // do not release
9271 OSSharedPtr
<OSString
> errorString
;
9273 OSSharedPtr
<OSObject
> responseObject
;
9275 OSSharedPtr
<OSSerialize
> serializer
;
9277 OSSharedPtr
<OSArray
> logInfoArray
;
9279 OSString
* predicate
= NULL
; // do not release
9280 OSString
* kextIdentifier
= NULL
; // do not release
9281 OSArray
* kextIdentifiers
= NULL
; // do not release
9282 OSKext
* theKext
= NULL
; // do not release
9283 OSBoolean
* boolArg
= NULL
; // do not release
9285 IORecursiveLockLock(sKextLock
);
9288 *responseOut
= NULL
;
9289 *responseLengthOut
= 0;
9293 *logInfoLengthOut
= 0;
9296 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
9298 /* XML must be nul-terminated.
9300 if (requestBuffer
[requestLength
- 1] != '\0') {
9301 OSKextLog(/* kext */ NULL
,
9302 kOSKextLogErrorLevel
|
9304 "Invalid request from user space (not nul-terminated).");
9305 result
= kOSKextReturnBadData
;
9308 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, errorString
);
9310 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9313 const char * errorCString
= "(unknown error)";
9315 if (errorString
&& errorString
->getCStringNoCopy()) {
9316 errorCString
= errorString
->getCStringNoCopy();
9317 } else if (parsedXML
) {
9318 errorCString
= "not a dictionary";
9320 OSKextLog(/* kext */ NULL
,
9321 kOSKextLogErrorLevel
|
9323 "Error unserializing request from user space: %s.",
9325 result
= kOSKextReturnSerialization
;
9329 predicate
= _OSKextGetRequestPredicate(requestDict
);
9331 OSKextLog(/* kext */ NULL
,
9332 kOSKextLogErrorLevel
|
9334 "Recieved kext request from user space with no predicate.");
9335 result
= kOSKextReturnInvalidArgument
;
9339 OSKextLog(/* kext */ NULL
,
9340 kOSKextLogDebugLevel
|
9342 "Received '%s' request from user space.",
9343 predicate
->getCStringNoCopy());
9346 * All management of file sets requires an entitlement
9348 result
= kOSKextReturnNotPrivileged
;
9349 if (predicate
->isEqualTo(kKextRequestPredicateUnload
) ||
9350 predicate
->isEqualTo(kKextRequestPredicateStart
) ||
9351 predicate
->isEqualTo(kKextRequestPredicateStop
) ||
9352 predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9353 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9354 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9355 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9356 predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
) ||
9357 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9358 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9359 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9360 if (hostPriv
== HOST_PRIV_NULL
) {
9361 OSKextLog(/* kext */ NULL
,
9362 kOSKextLogErrorLevel
|
9364 "Access Failure - must be root user.");
9367 taskCanManageAllKCs
= IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
) == TRUE
;
9368 taskOnlyManagesBootKC
= IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement
) == TRUE
;
9370 if (!taskCanManageAllKCs
&& !taskOnlyManagesBootKC
) {
9371 OSKextLog(/* kext */ NULL
,
9372 kOSKextLogErrorLevel
|
9374 "Access Failure - client not entitled to manage file sets.");
9379 * The OnlyBootKC entitlement restricts the
9380 * collection-management entitlement to only managing kexts in
9381 * the BootKC. All other predicates that alter global state or
9382 * add new KCs are disallowed.
9384 if (taskOnlyManagesBootKC
&&
9385 (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9386 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9387 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9388 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9389 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9390 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9391 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
))) {
9392 OSKextLog(/* kext */ NULL
,
9393 kOSKextLogErrorLevel
|
9395 "Access Failure - client not entitled to manage non-primary KCs");
9400 * If we get here, then the process either has the full KC
9401 * management entitlement, or it has the BootKC-only
9402 * entitlement and the request is about the BootKC.
9406 /* Get common args in anticipation of use.
9408 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
9409 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9410 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
9411 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9412 if (kextIdentifier
) {
9413 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
9415 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
9416 requestDict
, kKextRequestArgumentValueKey
));
9418 if (taskOnlyManagesBootKC
&&
9420 theKext
->isInFileset() &&
9421 theKext
->kc_type
!= KCKindPrimary
) {
9422 OSKextLog(/* kext */ NULL
,
9423 kOSKextLogErrorLevel
|
9425 "Access Failure - client not entitled to manage kext in non-primary KC");
9426 result
= kOSKextReturnNotPrivileged
;
9430 result
= kOSKextReturnInvalidArgument
;
9432 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
9433 if (!kextIdentifier
) {
9434 OSKextLog(/* kext */ NULL
,
9435 kOSKextLogErrorLevel
|
9437 "Invalid arguments to kext start request.");
9438 } else if (!theKext
) {
9439 OSKextLog(/* kext */ NULL
,
9440 kOSKextLogErrorLevel
|
9442 "Kext %s not found for start request.",
9443 kextIdentifier
->getCStringNoCopy());
9444 result
= kOSKextReturnNotFound
;
9446 result
= theKext
->start();
9448 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
9449 if (!kextIdentifier
) {
9450 OSKextLog(/* kext */ NULL
,
9451 kOSKextLogErrorLevel
|
9453 "Invalid arguments to kext stop request.");
9454 } else if (!theKext
) {
9455 OSKextLog(/* kext */ NULL
,
9456 kOSKextLogErrorLevel
|
9458 "Kext %s not found for stop request.",
9459 kextIdentifier
->getCStringNoCopy());
9460 result
= kOSKextReturnNotFound
;
9462 result
= theKext
->stop();
9464 } else if (predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
)) {
9465 result
= OSKext::setMissingAuxKCBundles(requestDict
);
9466 } else if (predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
)) {
9467 if (!kextIdentifier
) {
9468 OSKextLog(/* kext */ NULL
,
9469 kOSKextLogErrorLevel
|
9471 "Invalid arguments to AuxKC Bundle Available request.");
9473 result
= OSKext::setAuxKCBundleAvailable(kextIdentifier
, requestDict
);
9475 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
)) {
9476 if (!kextIdentifier
) {
9477 OSKextLog(/* kext */ NULL
,
9478 kOSKextLogErrorLevel
|
9480 "Invalid arguments to kext load from KC request.");
9481 } else if (!theKext
) {
9482 OSKextLog(/* kext */ NULL
,
9483 kOSKextLogErrorLevel
|
9485 "Kext %s not found for load from KC request.",
9486 kextIdentifier
->getCStringNoCopy());
9487 result
= kOSKextReturnNotFound
;
9488 } else if (!theKext
->isInFileset()) {
9489 OSKextLog(/* kext */ NULL
,
9490 kOSKextLogErrorLevel
|
9492 "Kext %s does not exist in a KC: refusing to load.",
9493 kextIdentifier
->getCStringNoCopy());
9494 result
= kOSKextReturnNotLoadable
;
9496 result
= OSKext::loadKextFromKC(theKext
, requestDict
);
9498 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
)) {
9499 if (!kextIdentifier
) {
9500 OSKextLog(/* kext */ NULL
,
9501 kOSKextLogErrorLevel
|
9503 "Invalid arguments to codeless kext load interface (missing identifier).");
9505 result
= OSKext::loadCodelessKext(kextIdentifier
, requestDict
);
9507 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
9508 if (!kextIdentifier
) {
9509 OSKextLog(/* kext */ NULL
,
9510 kOSKextLogErrorLevel
|
9512 "Invalid arguments to kext unload request.");
9513 } else if (!theKext
) {
9514 OSKextLog(/* kext */ NULL
,
9515 kOSKextLogErrorLevel
|
9517 "Kext %s not found for unload request.",
9518 kextIdentifier
->getCStringNoCopy());
9519 result
= kOSKextReturnNotFound
;
9521 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
9522 _OSKextGetRequestArgument(requestDict
,
9523 kKextRequestArgumentTerminateIOServicesKey
));
9524 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
9526 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
9527 result
= OSKext::dispatchResource(requestDict
);
9528 } else if (predicate
->isEqualTo(kKextRequestPredicateGetUUIDByAddress
)) {
9529 OSNumber
*lookupNum
= NULL
;
9530 lookupNum
= OSDynamicCast(OSNumber
,
9531 _OSKextGetRequestArgument(requestDict
,
9532 kKextRequestArgumentLookupAddressKey
));
9534 responseObject
= OSKext::copyKextUUIDForAddress(lookupNum
);
9535 if (responseObject
) {
9536 result
= kOSReturnSuccess
;
9540 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) ||
9541 predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
) ||
9542 predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9543 OSBoolean
* delayAutounloadBool
= NULL
;
9544 OSObject
* infoKeysRaw
= NULL
;
9545 OSArray
* infoKeys
= NULL
;
9546 uint32_t infoKeysCount
= 0;
9548 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
9549 _OSKextGetRequestArgument(requestDict
,
9550 kKextRequestArgumentDelayAutounloadKey
));
9552 /* If asked to delay autounload, reset the timer if it's currently set.
9553 * (That is, don't schedule an unload if one isn't already pending.
9555 if (delayAutounloadBool
== kOSBooleanTrue
) {
9556 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9559 infoKeysRaw
= _OSKextGetRequestArgument(requestDict
,
9560 kKextRequestArgumentInfoKeysKey
);
9561 infoKeys
= OSDynamicCast(OSArray
, infoKeysRaw
);
9562 if (infoKeysRaw
&& !infoKeys
) {
9563 OSKextLog(/* kext */ NULL
,
9564 kOSKextLogErrorLevel
|
9566 "Invalid arguments to kext info request.");
9571 infoKeysCount
= infoKeys
->getCount();
9572 for (uint32_t i
= 0; i
< infoKeysCount
; i
++) {
9573 if (!OSDynamicCast(OSString
, infoKeys
->getObject(i
))) {
9574 OSKextLog(/* kext */ NULL
,
9575 kOSKextLogErrorLevel
|
9577 "Invalid arguments to kext info request.");
9583 if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
9584 responseObject
= OSKext::copyLoadedKextInfo(kextIdentifiers
, infoKeys
);
9585 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
)) {
9586 responseObject
= OSKext::copyLoadedKextInfoByUUID(kextIdentifiers
, infoKeys
);
9587 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9588 responseObject
= OSKext::copyKextCollectionInfo(requestDict
, infoKeys
);
9591 if (!responseObject
) {
9592 result
= kOSKextReturnInternalError
;
9594 OSKextLog(/* kext */ NULL
,
9595 kOSKextLogDebugLevel
|
9597 "Returning loaded kext info.");
9598 result
= kOSReturnSuccess
;
9600 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9601 /* Hand the current sKernelRequests array to the caller
9602 * (who must release it), and make a new one.
9604 responseObject
= os::move(sKernelRequests
);
9605 sKernelRequests
= OSArray::withCapacity(0);
9606 sPostedKextLoadIdentifiers
->flushCollection();
9607 OSKextLog(/* kext */ NULL
,
9608 kOSKextLogDebugLevel
|
9610 "Returning kernel requests.");
9611 result
= kOSReturnSuccess
;
9612 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
9613 /* Return the set of all requested bundle identifiers */
9614 responseObject
= sAllKextLoadIdentifiers
;
9615 OSKextLog(/* kext */ NULL
,
9616 kOSKextLogDebugLevel
|
9618 "Returning load requests.");
9619 result
= kOSReturnSuccess
;
9620 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
)) {
9621 printf("KextLog: Loading FileSet KC(s)\n");
9622 result
= OSKext::loadFileSetKexts(requestDict
);
9623 } else if (predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9624 printf("KextLog: " kIOKitDaemonName
" is %s\n", sIOKitDaemonActive
? "active" : "not active");
9625 result
= (sIOKitDaemonActive
&& !sOSKextWasResetAfterUserspaceReboot
) ? kOSReturnSuccess
: kIOReturnNotReady
;
9627 OSKextLog(/* kext */ NULL
,
9628 kOSKextLogDebugLevel
|
9630 "Received '%s' invalid request from user space.",
9631 predicate
->getCStringNoCopy());
9636 * Now we have handle the request, or not. Gather up the response & logging
9637 * info to ship to user space.
9640 /* Note: Nothing in OSKext is supposed to retain requestDict,
9641 * but you never know....
9643 if (requestDict
->getRetainCount() > 1) {
9644 OSKextLog(/* kext */ NULL
,
9645 kOSKextLogWarningLevel
|
9647 "Request from user space still retained by a kext; "
9648 "probable memory leak.");
9651 if (responseOut
&& responseObject
) {
9652 serializer
= OSSerialize::withCapacity(0);
9654 result
= kOSKextReturnNoMemory
;
9658 * Before serializing the kernel requests, patch the dext launch requests so
9659 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9660 * IOUserServerCheckInToken kernel object.
9662 if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9663 OSArray
* requests
= OSDynamicCast(OSArray
, responseObject
.get());
9664 task_t calling_task
= current_task();
9666 OSKextLog(/* kext */ NULL
,
9667 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9668 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests
);
9669 result
= kOSKextReturnInternalError
;
9672 result
= patchDextLaunchRequests(calling_task
, requests
);
9673 if (result
!= kOSReturnSuccess
) {
9674 OSKextLog(/* kext */ NULL
,
9675 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9676 "Failed to patch dext launch requests.");
9681 if (!responseObject
->serialize(serializer
.get())) {
9682 OSKextLog(/* kext */ NULL
,
9683 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9684 "Failed to serialize response to request from user space.");
9685 result
= kOSKextReturnSerialization
;
9689 response
= (char *)serializer
->text();
9690 responseLength
= serializer
->getLength();
9693 if (responseOut
&& response
) {
9696 /* This kmem_alloc sets the return value of the function.
9698 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
9699 round_page(responseLength
), VM_KERN_MEMORY_OSKEXT
);
9700 if (kmem_result
!= KERN_SUCCESS
) {
9701 OSKextLog(/* kext */ NULL
,
9702 kOSKextLogErrorLevel
|
9704 "Failed to copy response to request from user space.");
9705 result
= kmem_result
;
9708 /* 11981737 - clear uninitialized data in last page */
9709 bzero((void *)(buffer
+ responseLength
),
9710 (round_page(responseLength
) - responseLength
));
9711 memcpy(buffer
, response
, responseLength
);
9712 *responseOut
= buffer
;
9713 *responseLengthOut
= responseLength
;
9719 /* Gather up the collected log messages for user space. Any messages
9720 * messages past this call will not make it up as log messages but
9721 * will be in the system log. Note that we ignore the return of the
9722 * serialize; it has no bearing on the operation at hand even if we
9723 * fail to get the log messages.
9725 logInfoArray
= OSKext::clearUserSpaceLogFilter();
9727 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
9728 (void)OSKext::serializeLogInfo(logInfoArray
.get(),
9729 logInfoOut
, logInfoLengthOut
);
9732 IORecursiveLockUnlock(sKextLock
);
9738 #pragma mark Linked Kext Collection Support
9742 __whereIsAddr(vm_offset_t theAddr
, unsigned long *segSizes
, vm_offset_t
*segAddrs
, int segCount
)
9744 for (int i
= 0; i
< segCount
; i
++) {
9745 vm_offset_t segStart
= segAddrs
[i
];
9746 vm_offset_t segEnd
= segStart
+ (vm_offset_t
)segSizes
[i
];
9748 if (theAddr
>= segStart
&& theAddr
< segEnd
) {
9756 __slideOldKaslrOffsets(kernel_mach_header_t
*mh
,
9757 kernel_segment_command_t
*kextTextSeg
,
9758 OSData
*kaslrOffsets
)
9760 static const char *plk_segNames
[] = {
9774 static const size_t num_plk_seg
= (size_t)(sizeof(plk_segNames
) / sizeof(plk_segNames
[0]));
9776 unsigned long plk_segSizes
[num_plk_seg
];
9777 vm_offset_t plk_segAddrs
[num_plk_seg
];
9779 for (size_t i
= 0; i
< num_plk_seg
; i
++) {
9780 plk_segSizes
[i
] = 0;
9781 plk_segAddrs
[i
] = (vm_offset_t
)getsegdatafromheader(mh
, plk_segNames
[i
], &plk_segSizes
[i
]);
9784 uint64_t kextTextStart
= (uint64_t)kextTextSeg
->vmaddr
;
9786 int slidKextAddrCount
= 0;
9787 int badSlideAddr
= 0;
9788 int badSlideTarget
= 0;
9790 struct kaslrPackedOffsets
{
9791 uint32_t count
; /* number of offsets */
9792 uint32_t offsetsArray
[]; /* offsets to slide */
9794 const struct kaslrPackedOffsets
*myOffsets
= NULL
;
9795 myOffsets
= (const struct kaslrPackedOffsets
*)kaslrOffsets
->getBytesNoCopy();
9797 for (uint32_t j
= 0; j
< myOffsets
->count
; j
++) {
9798 uint64_t slideOffset
= (uint64_t)myOffsets
->offsetsArray
[j
];
9799 vm_offset_t
*slideAddr
= (vm_offset_t
*)((uint64_t)kextTextStart
+ slideOffset
);
9800 int slideAddrSegIndex
= -1;
9801 int addrToSlideSegIndex
= -1;
9803 slideAddrSegIndex
= __whereIsAddr((vm_offset_t
)slideAddr
, &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9804 if (slideAddrSegIndex
>= 0) {
9805 addrToSlideSegIndex
= __whereIsAddr(ml_static_slide(*slideAddr
), &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9806 if (addrToSlideSegIndex
< 0) {
9815 slidKextAddrCount
++;
9816 *slideAddr
= ml_static_slide(*slideAddr
);
9822 /********************************************************************
9823 * addKextsFromKextCollection
9825 * Input: MachO header of kext collection. The MachO is assumed to
9826 * have a section named 'info_seg_name,info_sect_name' that
9827 * contains a serialized XML info dictionary. This dictionary
9828 * contains a UUID, possibly a set of relocations (for older
9829 * kxld-built binaries), and an array of kext personalities.
9831 ********************************************************************/
9833 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9834 OSDictionary
*infoDict
, const char *text_seg_name
,
9835 OSData
**kcUUID
, kc_kind_t type
)
9837 bool result
= false;
9839 OSArray
*kextArray
= NULL
; // do not release
9840 OSData
*infoDictKCUUID
= NULL
; // do not release
9841 OSData
*kaslrOffsets
= NULL
; // do not release
9843 IORegistryEntry
*registryRoot
= NULL
; // do not release
9844 OSSharedPtr
<OSNumber
> kcKextCount
;
9846 /* extract the KC UUID from the dictionary */
9847 infoDictKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
9848 if (infoDictKCUUID
) {
9849 if (infoDictKCUUID
->getLength() != sizeof(uuid_t
)) {
9850 panic("kcUUID length is %d, expected %lu",
9851 infoDictKCUUID
->getLength(), sizeof(uuid_t
));
9855 /* locate the array of kext dictionaries */
9856 kextArray
= OSDynamicCast(OSArray
, infoDict
->getObject(kPrelinkInfoDictionaryKey
));
9858 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9859 "The given KC has no kext info dictionaries");
9864 * old-style KASLR offsets may be present in the info dictionary. If
9865 * we find them, use them and eventually slide them.
9867 kaslrOffsets
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkLinkKASLROffsetsKey
));
9870 * Before processing any kexts, locate the special kext bundle which
9871 * contains a list of kexts that we are to prevent from loading.
9873 createExcludeListFromPrelinkInfo(kextArray
);
9876 * Create OSKext objects for each kext we find in the array of kext
9877 * info plist dictionaries.
9879 for (int i
= 0; i
< (int)kextArray
->getCount(); ++i
) {
9880 OSDictionary
*kextDict
= NULL
;
9881 kextDict
= OSDynamicCast(OSDictionary
, kextArray
->getObject(i
));
9883 OSKextLog(/* kext */ NULL
,
9884 kOSKextLogErrorLevel
|
9885 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9886 "Kext info dictionary for kext #%d isn't a dictionary?", i
);
9891 * Create the kext for the entry, then release it, because the
9892 * kext system keeps a reference around until the kext is
9893 * explicitly removed. Any creation/registration failures are
9894 * already logged for us.
9896 withPrelinkedInfoDict(kextDict
, (kaslrOffsets
? TRUE
: FALSE
), type
);
9900 * slide old-style kxld relocations
9901 * NOTE: this is still used on embedded KCs built with kcgen
9902 * TODO: Remove this once we use the new kext linker everywhere!
9904 if (kaslrOffsets
&& vm_kernel_slide
> 0) {
9905 kernel_segment_command_t
*text_segment
= NULL
;
9906 text_segment
= getsegbynamefromheader(mh
, text_seg_name
);
9907 if (!text_segment
) {
9908 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9909 "Can't find a TEXT segment named '%s' in macho header", text_seg_name
);
9913 __slideOldKaslrOffsets(mh
, text_segment
, kaslrOffsets
);
9914 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9915 setAllVMAttributes();
9918 /* Store the number of prelinked kexts in the registry so we can tell
9919 * when the system has been started from a prelinked kernel.
9921 registryRoot
= IORegistryEntry::getRegistryRoot();
9922 assert(registryRoot
);
9924 kcKextCount
= OSNumber::withNumber((unsigned long long)infoDict
->getCount(), 8 * sizeof(uint32_t));
9925 assert(kcKextCount
);
9927 OSSharedPtr
<OSObject
> prop
= registryRoot
->copyProperty(kOSPrelinkKextCountKey
);
9929 num
= OSDynamicCast(OSNumber
, prop
.get());
9931 kcKextCount
->addValue(num
->unsigned64BitValue());
9933 registryRoot
->setProperty(kOSPrelinkKextCountKey
, kcKextCount
.get());
9936 OSKextLog(/* kext */ NULL
,
9937 kOSKextLogProgressLevel
|
9938 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
9939 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9940 "%u prelinked kexts", infoDict
->getCount());
9943 if (kcUUID
&& infoDictKCUUID
) {
9944 *kcUUID
= OSData::withData(infoDictKCUUID
).detach();
9954 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9955 OSDictionary
*infoDict
, const char *text_seg_name
,
9956 OSSharedPtr
<OSData
> &kcUUID
, kc_kind_t type
)
9958 OSData
*result
= NULL
;
9959 bool success
= addKextsFromKextCollection(mh
,
9965 kcUUID
.reset(result
, OSNoRetain
);
9970 static OSSharedPtr
<OSObject
> deferredAuxKCXML
;
9972 OSKext::registerDeferredKextCollection(kernel_mach_header_t
*mh
,
9973 OSSharedPtr
<OSObject
> &parsedXML
, kc_kind_t type
)
9975 if (type
!= KCKindAuxiliary
) {
9979 kernel_mach_header_t
*_mh
;
9980 _mh
= (kernel_mach_header_t
*)PE_get_kc_header(type
);
9981 if (!_mh
|| _mh
!= mh
) {
9985 if (deferredAuxKCXML
) {
9986 /* only allow this to be called once */
9987 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9988 "An Aux KC has already been registered for deferred processing.");
9992 OSDictionary
*infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9994 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9995 "The Aux KC has info dictionary");
9999 OSData
*kcUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
10000 if (!kcUUID
|| kcUUID
->getLength() != sizeof(uuid_t
)) {
10001 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
10002 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey
);
10007 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10008 * sysctl can return the UUID to user space which will check this
10009 * value for errors.
10011 memcpy((void *)&auxkc_uuid
, (const void *)kcUUID
->getBytesNoCopy(),
10012 kcUUID
->getLength());
10013 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
10014 auxkc_uuid_valid
= TRUE
;
10016 deferredAuxKCXML
= parsedXML
;
10021 OSSharedPtr
<OSObject
>
10022 OSKext::consumeDeferredKextCollection(kc_kind_t type
)
10024 if (type
!= KCKindAuxiliary
|| !deferredAuxKCXML
) {
10028 return os::move(deferredAuxKCXML
);
10032 #pragma mark Profile-Guided-Optimization Support
10035 // #include <InstrProfiling.h>
10037 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin
,
10038 const char *DataEnd
,
10039 const char *CountersBegin
,
10040 const char *CountersEnd
,
10041 const char *NamesBegin
,
10042 const char *NamesEnd
);
10043 int __llvm_profile_write_buffer_internal(char *Buffer
,
10044 const char *DataBegin
,
10045 const char *DataEnd
,
10046 const char *CountersBegin
,
10047 const char *CountersEnd
,
10048 const char *NamesBegin
,
10049 const char *NamesEnd
);
10055 OSKextPgoMetadataPut(char *pBuffer
,
10058 uint32_t *num_pairs
,
10062 size_t strlen_key
= strlen(key
);
10063 size_t strlen_value
= strlen(value
);
10064 size_t len
= strlen(key
) + 1 + strlen(value
) + 1;
10065 char *pos
= pBuffer
+ *position
;
10067 if (pBuffer
&& bufferSize
&& *position
<= bufferSize
) {
10068 memcpy(pos
, key
, strlen_key
); pos
+= strlen_key
;
10070 memcpy(pos
, value
, strlen_value
); pos
+= strlen_value
;
10081 OSKextPgoMetadataPutMax(size_t *position
, const char *key
, size_t value_max
)
10083 *position
+= strlen(key
) + 1 + value_max
+ 1;
10089 OSKextPgoMetadataPutAll(OSKext
*kext
,
10090 uuid_t instance_uuid
,
10094 uint32_t *num_pairs
)
10096 _static_assert_1_arg(sizeof(clock_sec_t
) % 2 == 0);
10097 //log_10 2^16 ≈ 4.82
10098 const size_t max_secs_string_size
= 5 * sizeof(clock_sec_t
) / 2;
10099 const size_t max_timestamp_string_size
= max_secs_string_size
+ 1 + 6;
10102 OSKextPgoMetadataPutMax(position
, "INSTANCE", 36);
10103 OSKextPgoMetadataPutMax(position
, "UUID", 36);
10104 OSKextPgoMetadataPutMax(position
, "TIMESTAMP", max_timestamp_string_size
);
10106 uuid_string_t instance_uuid_string
;
10107 uuid_unparse(instance_uuid
, instance_uuid_string
);
10108 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10109 "INSTANCE", instance_uuid_string
);
10111 OSSharedPtr
<OSData
> uuid_data
;
10113 uuid_string_t uuid_string
;
10114 uuid_data
= kext
->copyUUID();
10116 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
10117 uuid_unparse(uuid
, uuid_string
);
10118 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10119 "UUID", uuid_string
);
10123 clock_usec_t usecs
;
10124 clock_get_calendar_microtime(&secs
, &usecs
);
10125 assert(usecs
< 1000000);
10126 char timestamp
[max_timestamp_string_size
+ 1];
10127 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t
));
10128 snprintf(timestamp
, sizeof(timestamp
), "%lu.%06d", (unsigned long)secs
, (int)usecs
);
10129 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10130 "TIMESTAMP", timestamp
);
10133 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10134 "NAME", kext
->getIdentifierCString());
10136 char versionCString
[kOSKextVersionMaxLength
];
10137 OSKextVersionGetString(kext
->getVersion(), versionCString
, kOSKextVersionMaxLength
);
10138 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10139 "VERSION", versionCString
);
10144 OSKextPgoMetadataSize(OSKext
*kext
)
10146 size_t position
= 0;
10147 uuid_t fakeuuid
= {};
10148 OSKextPgoMetadataPutAll(kext
, fakeuuid
, NULL
, &position
, 0, NULL
);
10153 OSKextGrabPgoDataLocked(OSKext
*kext
,
10155 uuid_t instance_uuid
,
10158 uint64_t bufferSize
)
10162 kernel_section_t
*sect_prf_data
= NULL
;
10163 kernel_section_t
*sect_prf_name
= NULL
;
10164 kernel_section_t
*sect_prf_cnts
= NULL
;
10166 size_t metadata_size
= 0;
10167 size_t offset_to_pairs
= 0;
10169 sect_prf_data
= kext
->lookupSection("__DATA", "__llvm_prf_data");
10170 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_names");
10171 if (!sect_prf_name
) {
10172 // kextcache sometimes truncates the section name to 15 chars
10173 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10174 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_name");
10176 sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10178 if (!sect_prf_data
|| !sect_prf_name
|| !sect_prf_cnts
) {
10183 size
= __llvm_profile_get_size_for_buffer_internal(
10184 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10185 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10186 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10189 metadata_size
= OSKextPgoMetadataSize(kext
);
10190 size
+= metadata_size
;
10191 size
+= sizeof(pgo_metadata_footer
);
10199 if (pBuffer
&& bufferSize
) {
10200 if (bufferSize
< size
) {
10205 err
= __llvm_profile_write_buffer_internal(
10207 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10208 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10209 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10217 offset_to_pairs
= sizeof(struct pgo_metadata_footer
) + metadata_size
;
10218 if (offset_to_pairs
> UINT32_MAX
) {
10223 char *end_of_buffer
= pBuffer
+ size
;
10224 struct pgo_metadata_footer
*footerp
= (struct pgo_metadata_footer
*) (end_of_buffer
- sizeof(struct pgo_metadata_footer
));
10225 char *metadata_buffer
= end_of_buffer
- (sizeof(struct pgo_metadata_footer
) + metadata_size
);
10227 size_t metadata_position
= 0;
10228 uint32_t num_pairs
= 0;
10229 OSKextPgoMetadataPutAll(kext
, instance_uuid
, metadata_buffer
, &metadata_position
, metadata_size
, &num_pairs
);
10230 while (metadata_position
< metadata_size
) {
10231 metadata_buffer
[metadata_position
++] = 0;
10234 struct pgo_metadata_footer footer
;
10235 footer
.magic
= htonl(0x6d657461);
10236 footer
.number_of_pairs
= htonl( num_pairs
);
10237 footer
.offset_to_pairs
= htonl((uint32_t)offset_to_pairs
);
10238 memcpy(footerp
, &footer
, sizeof(footer
));
10248 OSKextGrabPgoData(uuid_t uuid
,
10251 uint64_t bufferSize
,
10252 int wait_for_unload
,
10256 OSSharedPtr
<OSKext
> kext
;
10259 IORecursiveLockLock(sKextLock
);
10261 kext
= OSKext::lookupKextWithUUID(uuid
);
10267 if (wait_for_unload
) {
10268 OSKextGrabPgoStruct s
;
10270 s
.metadata
= metadata
;
10272 s
.pBuffer
= pBuffer
;
10273 s
.bufferSize
= bufferSize
;
10276 struct list_head
*prev
= &kext
->pendingPgoHead
;
10277 struct list_head
*next
= kext
->pendingPgoHead
.next
;
10279 s
.list_head
.prev
= prev
;
10280 s
.list_head
.next
= next
;
10282 prev
->next
= &s
.list_head
;
10283 next
->prev
= &s
.list_head
;
10287 IORecursiveLockSleep(sKextLock
, &s
, THREAD_ABORTSAFE
);
10289 prev
= s
.list_head
.prev
;
10290 next
= s
.list_head
.next
;
10297 err
= OSKextGrabPgoDataLocked(kext
.get(), metadata
, kext
->instance_uuid
, pSize
, pBuffer
, bufferSize
);
10302 IORecursiveLockUnlock(sKextLock
);
10308 OSKextResetPgoCountersLock()
10310 IORecursiveLockLock(sKextLock
);
10314 OSKextResetPgoCountersUnlock()
10316 IORecursiveLockUnlock(sKextLock
);
10320 extern unsigned int not_in_kdp
;
10323 OSKextResetPgoCounters()
10325 assert(!not_in_kdp
);
10326 uint32_t count
= sLoadedKexts
->getCount();
10327 for (uint32_t i
= 0; i
< count
; i
++) {
10328 OSKext
*kext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
10329 kernel_section_t
*sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10330 if (!sect_prf_cnts
) {
10333 memset((void*)sect_prf_cnts
->addr
, 0, sect_prf_cnts
->size
);
10337 OSSharedPtr
<OSDictionary
>
10338 OSKext::copyLoadedKextInfoByUUID(
10339 OSArray
* kextIdentifiers
,
10340 OSArray
* infoKeys
)
10342 OSSharedPtr
<OSDictionary
> result
;
10343 OSSharedPtr
<OSDictionary
> kextInfo
;
10344 uint32_t max_count
, i
, j
;
10345 uint32_t idCount
= 0;
10346 uint32_t idIndex
= 0;
10347 IORecursiveLockLock(sKextLock
);
10348 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
10349 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
10352 /* Is the calling process allowed to query kext info? */
10353 if (current_task() != kernel_task
) {
10354 int macCheckResult
= 0;
10355 kauth_cred_t cred
= NULL
;
10357 cred
= kauth_cred_get_with_ref();
10358 macCheckResult
= mac_kext_check_query(cred
);
10359 kauth_cred_unref(&cred
);
10361 if (macCheckResult
!= 0) {
10362 OSKextLog(/* kext */ NULL
,
10363 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10364 "Failed to query kext info (MAC policy error 0x%x).",
10371 /* Empty list of UUIDs is equivalent to no list (get all).
10373 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10374 kextIdentifiers
= NULL
;
10375 } else if (kextIdentifiers
) {
10376 idCount
= kextIdentifiers
->getCount();
10381 if (infoKeys
&& !infoKeys
->getCount()) {
10385 max_count
= count
[0] + count
[1];
10386 result
= OSDictionary::withCapacity(max_count
);
10391 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
10392 for (i
= 0; i
< count
[j
]; i
++) {
10393 OSKext
*thisKext
= NULL
; // do not release
10394 Boolean includeThis
= true;
10395 uuid_t thisKextUUID
;
10396 uuid_t thisKextTextUUID
;
10397 OSSharedPtr
<OSData
> uuid_data
;
10398 uuid_string_t uuid_key
;
10400 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
10405 uuid_data
= thisKext
->copyUUID();
10410 memcpy(&thisKextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextUUID
));
10412 uuid_unparse(thisKextUUID
, uuid_key
);
10414 uuid_data
= thisKext
->copyTextUUID();
10418 memcpy(&thisKextTextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextTextUUID
));
10420 /* Skip current kext if we have a list of UUIDs and
10421 * it isn't in the list.
10423 if (kextIdentifiers
) {
10424 includeThis
= false;
10426 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10427 const OSString
* wantedUUID
= OSDynamicCast(OSString
,
10428 kextIdentifiers
->getObject(idIndex
));
10431 uuid_parse(wantedUUID
->getCStringNoCopy(), uuid
);
10433 if ((0 == uuid_compare(uuid
, thisKextUUID
))
10434 || (0 == uuid_compare(uuid
, thisKextTextUUID
))) {
10435 includeThis
= true;
10436 /* Only need to find the first kext if multiple match,
10437 * ie. asking for the kernel uuid does not need to find
10438 * interface kexts or builtin static kexts.
10440 kextIdentifiers
->removeObject(idIndex
);
10441 uuid_unparse(uuid
, uuid_key
);
10447 if (!includeThis
) {
10451 kextInfo
= thisKext
->copyInfo(infoKeys
);
10453 result
->setObject(uuid_key
, kextInfo
.get());
10456 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10463 IORecursiveLockUnlock(sKextLock
);
10468 /*********************************************************************
10469 *********************************************************************/
10471 OSSharedPtr
<OSDictionary
>
10472 OSKext::copyKextCollectionInfo(
10473 OSDictionary
*requestDict
,
10476 OSSharedPtr
<OSDictionary
> result
;
10477 OSString
*collectionType
= NULL
;
10478 OSObject
*rawLoadedState
= NULL
;
10479 OSString
*loadedState
= NULL
;
10481 kc_kind_t kc_request_kind
= KCKindUnknown
;
10482 bool onlyLoaded
= false;
10483 bool onlyUnloaded
= false;
10486 /* Is the calling process allowed to query kext info? */
10487 if (current_task() != kernel_task
) {
10488 int macCheckResult
= 0;
10489 kauth_cred_t cred
= NULL
;
10491 cred
= kauth_cred_get_with_ref();
10492 macCheckResult
= mac_kext_check_query(cred
);
10493 kauth_cred_unref(&cred
);
10495 if (macCheckResult
!= 0) {
10496 OSKextLog(/* kext */ NULL
,
10497 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10498 "Failed to query kext info (MAC policy error 0x%x).",
10505 if (infoKeys
&& !infoKeys
->getCount()) {
10509 collectionType
= OSDynamicCast(OSString
,
10510 _OSKextGetRequestArgument(requestDict
,
10511 kKextRequestArgumentCollectionTypeKey
));
10512 if (!collectionType
) {
10513 OSKextLog(/* kext */ NULL
,
10514 kOSKextLogErrorLevel
|
10516 "Invalid '%s' argument to kext collection info request.",
10517 kKextRequestArgumentCollectionTypeKey
);
10520 if (collectionType
->isEqualTo(kKCTypePrimary
)) {
10521 kc_request_kind
= KCKindPrimary
;
10522 } else if (collectionType
->isEqualTo(kKCTypeSystem
)) {
10523 kc_request_kind
= KCKindPageable
;
10524 } else if (collectionType
->isEqualTo(kKCTypeAuxiliary
)) {
10525 kc_request_kind
= KCKindAuxiliary
;
10526 } else if (collectionType
->isEqualTo(kKCTypeCodeless
)) {
10527 kc_request_kind
= KCKindNone
;
10528 } else if (!collectionType
->isEqualTo(kKCTypeAny
)) {
10529 OSKextLog(/* kext */ NULL
,
10530 kOSKextLogErrorLevel
|
10532 "Invalid '%s' argument value '%s' to kext collection info request.",
10533 kKextRequestArgumentCollectionTypeKey
,
10534 collectionType
->getCStringNoCopy());
10538 rawLoadedState
= _OSKextGetRequestArgument(requestDict
,
10539 kKextRequestArgumentLoadedStateKey
);
10540 if (rawLoadedState
) {
10541 loadedState
= OSDynamicCast(OSString
, rawLoadedState
);
10542 if (!loadedState
) {
10543 OSKextLog(/* kext */ NULL
,
10544 kOSKextLogErrorLevel
|
10546 "Invalid '%s' argument to kext collection info request.",
10547 kKextRequestArgumentLoadedStateKey
);
10552 if (loadedState
->isEqualTo("Loaded")) {
10554 } else if (loadedState
->isEqualTo("Unloaded")) {
10555 onlyUnloaded
= true;
10556 } else if (!loadedState
->isEqualTo("Any")) {
10557 OSKextLog(/* kext */ NULL
,
10558 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10559 "Invalid '%s' argument value '%s' for '%s' collection info",
10560 kKextRequestArgumentLoadedStateKey
,
10561 loadedState
->getCStringNoCopy(),
10562 collectionType
->getCStringNoCopy());
10567 result
= OSDictionary::withCapacity(sKextsByID
->getCount());
10572 IORecursiveLockLock(sKextLock
);
10573 { // start block scope
10574 sKextsByID
->iterateObjects(^bool (const OSSymbol
*thisKextID
, OSObject
*obj
)
10576 OSKext
*thisKext
= NULL
; // do not release
10577 OSSharedPtr
<OSDictionary
> kextInfo
;
10581 thisKext
= OSDynamicCast(OSKext
, obj
);
10587 * skip the kext if it came from the wrong collection type
10588 * (and the caller requested a specific type)
10590 if ((kc_request_kind
!= KCKindUnknown
) && (thisKext
->kc_type
!= kc_request_kind
)) {
10595 * respect the caller's desire to find only loaded or
10598 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10601 if (onlyUnloaded
&& (-1U != sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10605 kextInfo
= thisKext
->copyInfo(infoKeys
);
10607 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10611 } // end block scope
10612 IORecursiveLockUnlock(sKextLock
);
10618 /*********************************************************************
10619 *********************************************************************/
10621 OSSharedPtr
<OSDictionary
>
10622 OSKext::copyLoadedKextInfo(
10623 OSArray
* kextIdentifiers
,
10624 OSArray
* infoKeys
)
10626 OSSharedPtr
<OSDictionary
> result
;
10627 uint32_t idCount
= 0;
10630 IORecursiveLockLock(sKextLock
);
10633 /* Is the calling process allowed to query kext info? */
10634 if (current_task() != kernel_task
) {
10635 int macCheckResult
= 0;
10636 kauth_cred_t cred
= NULL
;
10638 cred
= kauth_cred_get_with_ref();
10639 macCheckResult
= mac_kext_check_query(cred
);
10640 kauth_cred_unref(&cred
);
10642 if (macCheckResult
!= 0) {
10643 OSKextLog(/* kext */ NULL
,
10644 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10645 "Failed to query kext info (MAC policy error 0x%x).",
10652 /* Empty list of bundle ids is equivalent to no list (get all).
10654 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10655 kextIdentifiers
= NULL
;
10656 } else if (kextIdentifiers
) {
10657 idCount
= kextIdentifiers
->getCount();
10662 if (infoKeys
&& !infoKeys
->getCount()) {
10666 onlyLoaded
= (!infoKeys
|| !_OSArrayContainsCString(infoKeys
, kOSBundleAllPrelinkedKey
));
10668 result
= OSDictionary::withCapacity(128);
10674 OSKextLog(/* kext */ NULL
,
10675 kOSKextLogErrorLevel
|
10676 kOSKextLogGeneralFlag
,
10677 "kaslr: vm_kernel_slide 0x%lx \n",
10679 OSKextLog(/* kext */ NULL
,
10680 kOSKextLogErrorLevel
|
10681 kOSKextLogGeneralFlag
,
10682 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10683 vm_kernel_stext
, vm_kernel_etext
);
10684 OSKextLog(/* kext */ NULL
,
10685 kOSKextLogErrorLevel
|
10686 kOSKextLogGeneralFlag
,
10687 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10688 vm_kernel_base
, vm_kernel_top
);
10689 OSKextLog(/* kext */ NULL
,
10690 kOSKextLogErrorLevel
|
10691 kOSKextLogGeneralFlag
,
10692 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10693 vm_kext_base
, vm_kext_top
);
10694 OSKextLog(/* kext */ NULL
,
10695 kOSKextLogErrorLevel
|
10696 kOSKextLogGeneralFlag
,
10697 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10698 vm_prelink_stext
, vm_prelink_etext
);
10699 OSKextLog(/* kext */ NULL
,
10700 kOSKextLogErrorLevel
|
10701 kOSKextLogGeneralFlag
,
10702 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10703 vm_prelink_sinfo
, vm_prelink_einfo
);
10704 OSKextLog(/* kext */ NULL
,
10705 kOSKextLogErrorLevel
|
10706 kOSKextLogGeneralFlag
,
10707 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10708 vm_slinkedit
, vm_elinkedit
);
10710 { // start block scope
10711 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisKextID
, OSObject
* obj
)
10713 OSKext
* thisKext
= NULL
; // do not release
10714 Boolean includeThis
= true;
10715 OSSharedPtr
<OSDictionary
> kextInfo
;
10717 thisKext
= OSDynamicCast(OSKext
, obj
);
10722 /* Skip current kext if not yet started and caller didn't request all.
10724 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10728 /* Skip current kext if we have a list of bundle IDs and
10729 * it isn't in the list.
10731 if (kextIdentifiers
) {
10732 includeThis
= false;
10734 for (uint32_t idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10735 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
10736 kextIdentifiers
->getObject(idIndex
));
10737 if (thisKextID
->isEqualTo(thisRequestID
)) {
10738 includeThis
= true;
10744 if (!includeThis
) {
10748 kextInfo
= thisKext
->copyInfo(infoKeys
);
10750 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10754 } // end block scope
10757 IORecursiveLockUnlock(sKextLock
);
10762 /*********************************************************************
10763 * Any info that needs to do allocations must goto finish on alloc
10764 * failure. Info that is just a lookup should just not set the object
10765 * if the info does not exist.
10766 *********************************************************************/
10767 #define _OSKextLoadInfoDictCapacity (12)
10769 OSSharedPtr
<OSDictionary
>
10770 OSKext::copyInfo(OSArray
* infoKeys
)
10772 OSSharedPtr
<OSDictionary
> result
;
10773 bool success
= false;
10774 OSSharedPtr
<OSData
> headerData
;
10775 OSSharedPtr
<OSData
> logData
;
10776 OSSharedPtr
<OSNumber
> cpuTypeNumber
;
10777 OSSharedPtr
<OSNumber
> cpuSubtypeNumber
;
10778 OSString
* versionString
= NULL
; // do not release
10779 OSString
* bundleType
= NULL
; // do not release
10780 uint32_t executablePathCStringSize
= 0;
10781 char * executablePathCString
= NULL
; // must kfree
10782 OSSharedPtr
<OSString
> executablePathString
;
10783 OSSharedPtr
<OSData
> uuid
;
10784 OSSharedPtr
<OSArray
> dependencyLoadTags
;
10785 OSSharedPtr
<OSCollectionIterator
> metaClassIterator
;
10786 OSSharedPtr
<OSArray
> metaClassInfo
;
10787 OSSharedPtr
<OSDictionary
> metaClassDict
;
10788 OSMetaClass
* thisMetaClass
= NULL
; // do not release
10789 OSSharedPtr
<OSString
> metaClassName
;
10790 OSSharedPtr
<OSString
> superclassName
;
10791 kc_format_t kcformat
;
10794 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
10800 /* Empty keys means no keys, but NULL is quicker to check.
10802 if (infoKeys
&& !infoKeys
->getCount()) {
10806 if (!PE_get_primary_kc_format(&kcformat
)) {
10810 /* Headers, CPU type, and CPU subtype.
10813 _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
) ||
10814 _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
) ||
10815 _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
) ||
10816 _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10817 if (linkedExecutable
&& !isInterface()) {
10818 kernel_mach_header_t
*kext_mach_hdr
= (kernel_mach_header_t
*)
10819 linkedExecutable
->getBytesNoCopy();
10821 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10822 // do not return macho header info on shipping embedded - 19095897
10823 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
)) {
10824 kernel_mach_header_t
* temp_kext_mach_hdr
;
10825 struct load_command
* lcp
;
10827 headerData
= OSData::withBytes(kext_mach_hdr
,
10828 (u_int
) (sizeof(*kext_mach_hdr
) + kext_mach_hdr
->sizeofcmds
));
10833 // unslide any vmaddrs we return to userspace - 10726716
10834 temp_kext_mach_hdr
= (kernel_mach_header_t
*)
10835 headerData
->getBytesNoCopy();
10836 if (temp_kext_mach_hdr
== NULL
) {
10840 lcp
= (struct load_command
*) (temp_kext_mach_hdr
+ 1);
10841 for (i
= 0; i
< temp_kext_mach_hdr
->ncmds
; i
++) {
10842 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
10843 kernel_segment_command_t
* segp
;
10844 kernel_section_t
* secp
;
10846 segp
= (kernel_segment_command_t
*) lcp
;
10847 // 10543468 - if we jettisoned __LINKEDIT clear size info
10848 if (flags
.jettisonLinkeditSeg
) {
10849 if (strncmp(segp
->segname
, SEG_LINKEDIT
, sizeof(segp
->segname
)) == 0) {
10852 segp
->filesize
= 0;
10856 #if __arm__ || __arm64__
10857 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10858 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10859 if (segp
->vmsize
== 0 && segp
->vmaddr
< gVirtBase
) {
10860 segp
->vmaddr
= gVirtBase
;
10861 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10862 secp
->size
= 0; // paranoia :)
10863 secp
->addr
= gVirtBase
;
10869 OSKextLog(/* kext */ NULL
,
10870 kOSKextLogErrorLevel
|
10871 kOSKextLogGeneralFlag
,
10872 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10873 __FUNCTION__
, segp
->segname
, segp
->vmaddr
,
10874 VM_KERNEL_UNSLIDE(segp
->vmaddr
),
10875 segp
->vmsize
, segp
->nsects
);
10876 if ((VM_KERNEL_IS_SLID(segp
->vmaddr
) == false) &&
10877 (VM_KERNEL_IS_KEXT(segp
->vmaddr
) == false) &&
10878 (VM_KERNEL_IS_PRELINKTEXT(segp
->vmaddr
) == false) &&
10879 (VM_KERNEL_IS_PRELINKINFO(segp
->vmaddr
) == false) &&
10880 (VM_KERNEL_IS_KEXT_LINKEDIT(segp
->vmaddr
) == false)) {
10881 OSKextLog(/* kext */ NULL
,
10882 kOSKextLogErrorLevel
|
10883 kOSKextLogGeneralFlag
,
10884 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10885 __FUNCTION__
, segp
->vmaddr
, vm_kext_base
, vm_kext_top
);
10888 segp
->vmaddr
= ml_static_unslide(segp
->vmaddr
);
10890 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10891 secp
->addr
= ml_static_unslide(secp
->addr
);
10894 lcp
= (struct load_command
*)((caddr_t
)lcp
+ lcp
->cmdsize
);
10896 result
->setObject(kOSBundleMachOHeadersKey
, headerData
.get());
10898 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10900 if (_OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10901 osLogDataHeaderRef
*header
;
10902 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10904 void *os_log_data
= NULL
;
10905 void *cstring_data
= NULL
;
10906 unsigned long os_log_size
= 0;
10907 unsigned long cstring_size
= 0;
10908 uint32_t os_log_offset
= 0;
10909 uint32_t cstring_offset
= 0;
10912 os_log_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__os_log", &os_log_size
);
10913 os_log_offset
= (uintptr_t)os_log_data
- (uintptr_t)kext_mach_hdr
;
10914 cstring_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__cstring", &cstring_size
);
10915 cstring_offset
= (uintptr_t)cstring_data
- (uintptr_t)kext_mach_hdr
;
10917 header
= (osLogDataHeaderRef
*) headerBytes
;
10918 header
->version
= OS_LOG_HDR_VERSION
;
10919 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10920 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= os_log_offset
;
10921 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) os_log_size
;
10922 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= cstring_offset
;
10923 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) cstring_size
;
10926 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10930 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10935 res
= logData
->appendBytes(os_log_data
, (u_int
)header
->sections
[OS_LOG_SECT_IDX
].sect_size
);
10940 if (cstring_data
) {
10941 res
= logData
->appendBytes(cstring_data
, (u_int
)header
->sections
[CSTRING_SECT_IDX
].sect_size
);
10946 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10949 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
)) {
10950 cpuTypeNumber
= OSNumber::withNumber(
10951 (uint64_t) kext_mach_hdr
->cputype
,
10952 8 * sizeof(kext_mach_hdr
->cputype
));
10953 if (!cpuTypeNumber
) {
10956 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
.get());
10959 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10960 cpuSubtypeNumber
= OSNumber::withNumber(
10961 (uint64_t) kext_mach_hdr
->cpusubtype
,
10962 8 * sizeof(kext_mach_hdr
->cpusubtype
));
10963 if (!cpuSubtypeNumber
) {
10966 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
.get());
10969 if (isDriverKit() && _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10970 osLogDataHeaderRef
*header
;
10971 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10974 header
= (osLogDataHeaderRef
*) headerBytes
;
10975 header
->version
= OS_LOG_HDR_VERSION
;
10976 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10977 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= 0;
10978 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) 0;
10979 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= 0;
10980 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) 0;
10982 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10986 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10990 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10995 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10997 result
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
10999 /* CFBundlePackageType
11001 bundleType
= infoDict
? OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
)): NULL
;
11003 result
->setObject(kCFBundlePackageTypeKey
, bundleType
);
11006 /* CFBundleVersion.
11008 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kCFBundleVersionKey
)) {
11009 versionString
= OSDynamicCast(OSString
,
11010 getPropertyForHostArch(kCFBundleVersionKey
));
11011 if (versionString
) {
11012 result
->setObject(kCFBundleVersionKey
, versionString
);
11016 /* OSBundleCompatibleVersion.
11018 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCompatibleVersionKey
)) {
11019 versionString
= OSDynamicCast(OSString
,
11020 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
11021 if (versionString
) {
11022 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
11028 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePathKey
)) {
11030 result
->setObject(kOSBundlePathKey
, path
.get());
11035 /* OSBundleExecutablePath.
11037 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecutablePathKey
)) {
11038 if (path
&& executableRelPath
) {
11039 uint32_t pathLength
= path
->getLength(); // gets incremented below
11041 // +1 for slash, +1 for \0
11042 executablePathCStringSize
= pathLength
+ executableRelPath
->getLength() + 2;
11044 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11045 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
); // +1 for \0
11046 if (!executablePathCString
) {
11049 strlcpy(executablePathCString
, path
->getCStringNoCopy(),
11050 executablePathCStringSize
);
11051 executablePathCString
[pathLength
++] = '/';
11052 executablePathCString
[pathLength
++] = '\0';
11053 strlcat(executablePathCString
, executableRelPath
->getCStringNoCopy(),
11054 executablePathCStringSize
);
11056 executablePathString
= OSString::withCString(executablePathCString
);
11058 if (!executablePathString
) {
11062 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11063 } else if (flags
.builtin
) {
11064 result
->setObject(kOSBundleExecutablePathKey
, bundleID
.get());
11065 } else if (isDriverKit()) {
11067 // +1 for slash, +1 for \0
11068 uint32_t pathLength
= path
->getLength();
11069 executablePathCStringSize
= pathLength
+ 2;
11071 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11072 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
11073 if (!executablePathCString
) {
11076 strlcpy(executablePathCString
, path
->getCStringNoCopy(), executablePathCStringSize
);
11077 executablePathCString
[pathLength
++] = '/';
11078 executablePathCString
[pathLength
++] = '\0';
11080 executablePathString
= OSString::withCString(executablePathCString
);
11082 if (!executablePathString
) {
11086 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11091 /* UUID, if the kext has one.
11093 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
11096 result
->setObject(kOSBundleUUIDKey
, uuid
.get());
11099 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleTextUUIDKey
)) {
11100 uuid
= copyTextUUID();
11102 result
->setObject(kOSBundleTextUUIDKey
, uuid
.get());
11107 * Info.plist digest
11109 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextInfoPlistDigestKey
)) {
11111 digest
= infoDict
? OSDynamicCast(OSData
, infoDict
->getObject(kOSKextInfoPlistDigestKey
)) : NULL
;
11113 result
->setObject(kOSKextInfoPlistDigestKey
, digest
);
11120 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextBundleCollectionTypeKey
)) {
11121 result
->setObject(kOSKextBundleCollectionTypeKey
, OSString::withCString(getKCTypeString()));
11125 * Collection availability
11127 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextAuxKCAvailabilityKey
)) {
11128 result
->setObject(kOSKextAuxKCAvailabilityKey
,
11129 isLoadable() ? kOSBooleanTrue
: kOSBooleanFalse
);
11135 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleAllowUserLoadKey
)) {
11136 OSBoolean
*allowUserLoad
= OSDynamicCast(OSBoolean
, getPropertyForHostArch(kOSBundleAllowUserLoadKey
));
11137 if (allowUserLoad
) {
11138 result
->setObject(kOSBundleAllowUserLoadKey
, allowUserLoad
);
11143 * Bundle Dependencies (OSBundleLibraries)
11145 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLibrariesKey
)) {
11146 OSDictionary
*libraries
= OSDynamicCast(OSDictionary
, getPropertyForHostArch(kOSBundleLibrariesKey
));
11148 result
->setObject(kOSBundleLibrariesKey
, libraries
);
11153 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11155 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKernelResourceKey
)) {
11156 result
->setObject(kOSKernelResourceKey
,
11157 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
11160 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleIsInterfaceKey
)) {
11161 result
->setObject(kOSBundleIsInterfaceKey
,
11162 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
11165 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePrelinkedKey
)) {
11166 result
->setObject(kOSBundlePrelinkedKey
,
11167 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
11170 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleStartedKey
)) {
11171 result
->setObject(kOSBundleStartedKey
,
11172 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
11175 /* LoadTag (Index).
11177 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadTagKey
)) {
11178 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
11179 /* numBits */ 8 * sizeof(loadTag
));
11180 if (!scratchNumber
) {
11183 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
.get());
11186 /* LoadAddress, LoadSize.
11189 _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
) ||
11190 _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
) ||
11191 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
) ||
11192 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
) ||
11193 _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11194 bool is_dext
= isDriverKit();
11195 if (isInterface() || flags
.builtin
|| linkedExecutable
|| is_dext
) {
11196 /* These go to userspace via serialization, so we don't want any doubts
11197 * about their size.
11199 uint64_t loadAddress
= 0;
11200 uint32_t loadSize
= 0;
11201 uint32_t wiredSize
= 0;
11202 uint64_t execLoadAddress
= 0;
11203 uint32_t execLoadSize
= 0;
11205 /* Interfaces always report 0 load address & size.
11206 * Just the way they roll.
11208 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11209 * xxx - shouldn't have one!
11212 if (flags
.builtin
|| linkedExecutable
) {
11213 kernel_mach_header_t
*mh
= NULL
;
11214 kernel_segment_command_t
*seg
= NULL
;
11216 if (flags
.builtin
) {
11217 loadAddress
= kmod_info
->address
;
11218 loadSize
= (uint32_t)kmod_info
->size
;
11220 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
11221 loadSize
= linkedExecutable
->getLength();
11223 mh
= (kernel_mach_header_t
*)loadAddress
;
11224 loadAddress
= ml_static_unslide(loadAddress
);
11226 /* Walk through the kext, looking for the first executable
11227 * segment in case we were asked for its size/address.
11229 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
11230 if (seg
->initprot
& VM_PROT_EXECUTE
) {
11231 execLoadAddress
= ml_static_unslide(seg
->vmaddr
);
11232 execLoadSize
= (uint32_t)seg
->vmsize
;
11237 /* If we have a kmod_info struct, calculated the wired size
11238 * from that. Otherwise it's the full load size.
11241 wiredSize
= loadSize
- (uint32_t)kmod_info
->hdr_size
;
11243 wiredSize
= loadSize
;
11245 } else if (is_dext
) {
11247 * DriverKit userspace executables do not have a kernel linkedExecutable,
11248 * so we "fake" their address range with the LoadTag.
11251 loadAddress
= execLoadAddress
= loadTag
;
11252 loadSize
= execLoadSize
= 1;
11256 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
)) {
11257 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11258 (unsigned long long)(loadAddress
),
11259 /* numBits */ 8 * sizeof(loadAddress
));
11260 if (!scratchNumber
) {
11263 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
.get());
11265 if (kcformat
== KCFormatStatic
|| kcformat
== KCFormatKCGEN
) {
11266 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCacheLoadAddressKey
))
11267 && loadAddress
&& loadSize
) {
11268 void *baseAddress
= PE_get_kc_baseaddress(KCKindPrimary
);
11269 if (!baseAddress
) {
11273 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11274 (unsigned long long)ml_static_unslide((vm_offset_t
)baseAddress
),
11275 /* numBits */ 8 * sizeof(loadAddress
));
11276 if (!scratchNumber
) {
11279 result
->setObject(kOSBundleCacheLoadAddressKey
, scratchNumber
.get());
11281 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleKextsInKernelTextKey
))
11282 && (this == sKernelKext
) && gBuiltinKmodsCount
) {
11283 result
->setObject(kOSBundleKextsInKernelTextKey
, kOSBooleanTrue
);
11287 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
)) {
11288 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11289 (unsigned long long)(execLoadAddress
),
11290 /* numBits */ 8 * sizeof(execLoadAddress
));
11291 if (!scratchNumber
) {
11294 result
->setObject(kOSBundleExecLoadAddressKey
, scratchNumber
.get());
11296 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
)) {
11297 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11298 (unsigned long long)(loadSize
),
11299 /* numBits */ 8 * sizeof(loadSize
));
11300 if (!scratchNumber
) {
11303 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
.get());
11305 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
)) {
11306 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11307 (unsigned long long)(execLoadSize
),
11308 /* numBits */ 8 * sizeof(execLoadSize
));
11309 if (!scratchNumber
) {
11312 result
->setObject(kOSBundleExecLoadSizeKey
, scratchNumber
.get());
11314 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11315 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11316 (unsigned long long)(wiredSize
),
11317 /* numBits */ 8 * sizeof(wiredSize
));
11318 if (!scratchNumber
) {
11321 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
.get());
11326 /* OSBundleDependencies. In descending order for
11327 * easy compatibility with kextstat(8).
11329 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleDependenciesKey
)) {
11330 if ((count
= getNumDependencies())) {
11331 dependencyLoadTags
= OSArray::withCapacity(count
);
11332 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
.get());
11336 OSKext
* dependency
= OSDynamicCast(OSKext
,
11337 dependencies
->getObject(i
));
11342 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11343 (unsigned long long)dependency
->getLoadTag(),
11344 /* numBits*/ 8 * sizeof(loadTag
));
11345 if (!scratchNumber
) {
11348 dependencyLoadTags
->setObject(scratchNumber
.get());
11353 /* OSBundleMetaClasses.
11355 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleClassesKey
)) {
11356 if (metaClasses
&& metaClasses
->getCount()) {
11357 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
11358 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
11359 if (!metaClassIterator
|| !metaClassInfo
) {
11362 result
->setObject(kOSBundleClassesKey
, metaClassInfo
.get());
11364 while ((thisMetaClass
= OSDynamicCast(OSMetaClass
,
11365 metaClassIterator
->getNextObject()))) {
11366 metaClassDict
= OSDictionary::withCapacity(3);
11367 if (!metaClassDict
) {
11371 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
11372 if (thisMetaClass
->getSuperClass()) {
11373 superclassName
= OSString::withCString(
11374 thisMetaClass
->getSuperClass()->getClassName());
11376 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
11377 8 * sizeof(unsigned int));
11379 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11382 if (!metaClassDict
|| !metaClassName
|| !scratchNumber
) {
11386 metaClassInfo
->setObject(metaClassDict
.get());
11387 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
.get());
11388 if (superclassName
) {
11389 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
.get());
11391 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
.get());
11396 /* OSBundleRetainCount.
11398 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleRetainCountKey
)) {
11400 int kextRetainCount
= getRetainCount() - 1;
11404 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11405 (int)kextRetainCount
,
11406 /* numBits*/ 8 * sizeof(int));
11407 if (scratchNumber
) {
11408 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
.get());
11416 if (executablePathCString
) {
11417 kheap_free(KHEAP_TEMP
, executablePathCString
, executablePathCStringSize
);
11425 /*********************************************************************
11426 *********************************************************************/
11429 OSKext::copyUserExecutablePath(const OSSymbol
* bundleID
, char * pathResult
, size_t pathSize
)
11432 OSSharedPtr
<OSKext
> kext
;
11434 IORecursiveLockLock(sKextLock
);
11435 kext
.reset(OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
)), OSRetain
);
11436 IORecursiveLockUnlock(sKextLock
);
11438 if (!kext
|| !kext
->path
|| !kext
->userExecutableRelPath
) {
11441 snprintf(pathResult
, pathSize
, "%s/Contents/MacOS/%s",
11442 kext
->path
->getCStringNoCopy(),
11443 kext
->userExecutableRelPath
->getCStringNoCopy());
11449 /*********************************************************************
11450 *********************************************************************/
11453 OSKext::requestResource(
11454 const char * kextIdentifierCString
,
11455 const char * resourceNameCString
,
11456 OSKextRequestResourceCallback callback
,
11458 OSKextRequestTag
* requestTagOut
)
11460 OSReturn result
= kOSReturnError
;
11461 OSSharedPtr
<OSKext
> callbackKext
; // looked up
11463 OSKextRequestTag requestTag
= -1;
11464 OSSharedPtr
<OSNumber
> requestTagNum
;
11465 OSSharedPtr
<OSDictionary
> requestDict
;
11466 OSSharedPtr
<OSString
> kextIdentifier
;
11467 OSSharedPtr
<OSString
> resourceName
;
11469 OSSharedPtr
<OSDictionary
> callbackRecord
;
11470 OSSharedPtr
<OSData
> callbackWrapper
;
11472 OSSharedPtr
<OSData
> contextWrapper
;
11474 IORecursiveLockLock(sKextLock
);
11476 if (requestTagOut
) {
11477 *requestTagOut
= kOSKextRequestTagInvalid
;
11480 /* If requests to user space are disabled, don't go any further */
11481 if (!sKernelRequestsEnabled
) {
11482 OSKextLog(/* kext */ NULL
,
11483 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11484 "Can't request resource %s for %s - requests to user space are disabled.",
11485 resourceNameCString
,
11486 kextIdentifierCString
);
11487 result
= kOSKextReturnDisabled
;
11491 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
11492 result
= kOSKextReturnInvalidArgument
;
11496 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
11497 if (!callbackKext
) {
11498 OSKextLog(/* kext */ NULL
,
11499 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11500 "Resource request has bad callback address.");
11501 result
= kOSKextReturnInvalidArgument
;
11504 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
11505 OSKextLog(/* kext */ NULL
,
11506 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11507 "Resource request callback is in a kext that is not started.");
11508 result
= kOSKextReturnInvalidArgument
;
11512 /* Do not allow any new requests to be made on a kext that is unloading.
11514 if (callbackKext
->flags
.stopping
) {
11515 result
= kOSKextReturnStopping
;
11519 /* If we're wrapped the next available request tag around to the negative
11520 * numbers, we can't service any more requests.
11522 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
11523 OSKextLog(/* kext */ NULL
,
11524 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11525 "No more request tags available; restart required.");
11526 result
= kOSKextReturnNoResources
;
11529 requestTag
= sNextRequestTag
++;
11531 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
11533 if (result
!= kOSReturnSuccess
) {
11537 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
11538 resourceName
= OSString::withCString(resourceNameCString
);
11539 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11540 8 * sizeof(requestTag
));
11541 if (!kextIdentifier
||
11544 !_OSKextSetRequestArgument(requestDict
.get(),
11545 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
.get()) ||
11546 !_OSKextSetRequestArgument(requestDict
.get(),
11547 kKextRequestArgumentNameKey
, resourceName
.get()) ||
11548 !_OSKextSetRequestArgument(requestDict
.get(),
11549 kKextRequestArgumentRequestTagKey
, requestTagNum
.get())) {
11550 result
= kOSKextReturnNoMemory
;
11554 callbackRecord
= OSDynamicPtrCast
<OSDictionary
>(requestDict
->copyCollection());
11555 if (!callbackRecord
) {
11556 result
= kOSKextReturnNoMemory
;
11559 // we validate callback address at call time
11560 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
11562 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
11564 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11565 kKextRequestArgumentCallbackKey
, callbackWrapper
.get())) {
11566 result
= kOSKextReturnNoMemory
;
11571 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11572 kKextRequestArgumentContextKey
, contextWrapper
.get())) {
11573 result
= kOSKextReturnNoMemory
;
11578 /* Only post the requests after all the other potential failure points
11579 * have been passed.
11581 if (!sKernelRequests
->setObject(requestDict
.get()) ||
11582 !sRequestCallbackRecords
->setObject(callbackRecord
.get())) {
11583 result
= kOSKextReturnNoMemory
;
11587 OSKext::pingIOKitDaemon();
11589 result
= kOSReturnSuccess
;
11590 if (requestTagOut
) {
11591 *requestTagOut
= requestTag
;
11596 /* If we didn't succeed, yank the request & callback
11597 * from their holding arrays.
11599 if (result
!= kOSReturnSuccess
) {
11600 unsigned int index
;
11602 index
= sKernelRequests
->getNextIndexOfObject(requestDict
.get(), 0);
11603 if (index
!= (unsigned int)-1) {
11604 sKernelRequests
->removeObject(index
);
11606 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
.get(), 0);
11607 if (index
!= (unsigned int)-1) {
11608 sRequestCallbackRecords
->removeObject(index
);
11612 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11614 IORecursiveLockUnlock(sKextLock
);
11620 OSKext::requestDaemonLaunch(
11621 OSString
*kextIdentifier
,
11622 OSString
*serverName
,
11623 OSNumber
*serverTag
,
11624 OSSharedPtr
<IOUserServerCheckInToken
> &checkInToken
)
11627 IOUserServerCheckInToken
* checkInTokenRaw
= NULL
;
11629 result
= requestDaemonLaunch(kextIdentifier
, serverName
,
11630 serverTag
, &checkInTokenRaw
);
11632 if (kOSReturnSuccess
== result
) {
11633 checkInToken
.reset(checkInTokenRaw
, OSNoRetain
);
11640 OSKext::requestDaemonLaunch(
11641 OSString
*kextIdentifier
,
11642 OSString
*serverName
,
11643 OSNumber
*serverTag
,
11644 IOUserServerCheckInToken
** checkInToken
)
11646 OSReturn result
= kOSReturnError
;
11647 OSSharedPtr
<OSDictionary
> requestDict
;
11648 OSSharedPtr
<IOUserServerCheckInToken
> token
;
11650 if (!kextIdentifier
|| !serverName
|| !serverTag
) {
11651 result
= kOSKextReturnInvalidArgument
;
11655 IORecursiveLockLock(sKextLock
);
11657 OSKextLog(/* kext */ NULL
,
11658 kOSKextLogDebugLevel
|
11659 kOSKextLogGeneralFlag
,
11660 "Requesting daemon launch for %s with serverName %s and tag %llu",
11661 kextIdentifier
->getCStringNoCopy(),
11662 serverName
->getCStringNoCopy(),
11663 serverTag
->unsigned64BitValue()
11666 result
= _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch
, requestDict
);
11667 if (result
!= kOSReturnSuccess
) {
11671 token
.reset(IOUserServerCheckInToken::create(), OSNoRetain
);
11673 result
= kOSKextReturnNoMemory
;
11677 if (!_OSKextSetRequestArgument(requestDict
.get(),
11678 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
11679 !_OSKextSetRequestArgument(requestDict
.get(),
11680 kKextRequestArgumentDriverExtensionServerName
, serverName
) ||
11681 !_OSKextSetRequestArgument(requestDict
.get(),
11682 kKextRequestArgumentDriverExtensionServerTag
, serverTag
) ||
11683 !_OSKextSetRequestArgument(requestDict
.get(),
11684 kKextRequestArgumentCheckInToken
, token
.get())) {
11685 result
= kOSKextReturnNoMemory
;
11689 /* Only post the requests after all the other potential failure points
11690 * have been passed.
11692 if (!sKernelRequests
->setObject(requestDict
.get())) {
11693 result
= kOSKextReturnNoMemory
;
11696 *checkInToken
= token
.detach();
11697 OSKext::pingIOKitDaemon();
11699 result
= kOSReturnSuccess
;
11701 IORecursiveLockUnlock(sKextLock
);
11705 /*********************************************************************
11706 * Assumes sKextLock is held.
11707 *********************************************************************/
11710 OSKext::dequeueCallbackForRequestTag(
11711 OSKextRequestTag requestTag
,
11712 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11714 OSDictionary
* callbackRecordOutRaw
= NULL
;
11717 result
= dequeueCallbackForRequestTag(requestTag
,
11718 &callbackRecordOutRaw
);
11720 if (kOSReturnSuccess
== result
) {
11721 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11727 OSKext::dequeueCallbackForRequestTag(
11728 OSKextRequestTag requestTag
,
11729 OSDictionary
** callbackRecordOut
)
11731 OSReturn result
= kOSReturnError
;
11732 OSSharedPtr
<OSNumber
> requestTagNum
;
11734 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11735 8 * sizeof(requestTag
));
11736 if (!requestTagNum
) {
11740 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
.get(),
11741 callbackRecordOut
);
11747 /*********************************************************************
11748 * Assumes sKextLock is held.
11749 *********************************************************************/
11752 OSKext::dequeueCallbackForRequestTag(
11753 OSNumber
* requestTagNum
,
11754 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11756 OSDictionary
* callbackRecordOutRaw
= NULL
;
11759 result
= dequeueCallbackForRequestTag(requestTagNum
,
11760 &callbackRecordOutRaw
);
11762 if (kOSReturnSuccess
== result
) {
11763 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11769 OSKext::dequeueCallbackForRequestTag(
11770 OSNumber
* requestTagNum
,
11771 OSDictionary
** callbackRecordOut
)
11773 OSReturn result
= kOSKextReturnInvalidArgument
;
11774 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
11775 OSNumber
* callbackTagNum
= NULL
; // do not release
11776 unsigned int count
, i
;
11778 result
= kOSReturnError
;
11779 count
= sRequestCallbackRecords
->getCount();
11780 for (i
= 0; i
< count
; i
++) {
11781 callbackRecord
= OSDynamicCast(OSDictionary
,
11782 sRequestCallbackRecords
->getObject(i
));
11783 if (!callbackRecord
) {
11787 /* If we don't find a tag, we basically have a leak here. Maybe
11788 * we should just remove it.
11790 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
11791 callbackRecord
, kKextRequestArgumentRequestTagKey
));
11792 if (!callbackTagNum
) {
11796 /* We could be even more paranoid and check that all the incoming
11797 * args match what's in the callback record.
11799 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
11800 if (callbackRecordOut
) {
11801 *callbackRecordOut
= callbackRecord
;
11802 callbackRecord
->retain();
11804 sRequestCallbackRecords
->removeObject(i
);
11805 result
= kOSReturnSuccess
;
11809 result
= kOSKextReturnNotFound
;
11816 /*********************************************************************
11817 * Busy timeout triage
11818 *********************************************************************/
11821 OSKext::pendingIOKitDaemonRequests(void)
11823 return sRequestCallbackRecords
&& sRequestCallbackRecords
->getCount();
11826 /*********************************************************************
11827 * Acquires and releases sKextLock
11829 * This function is designed to be called exactly once on boot by
11830 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11831 * kext and dext personalities, and then attempts to map a System
11832 * (pageable) KC and an Auxiliary (aux) KC.
11834 * Even if the pageable or aux KC fail to load - this function will
11835 * not allow a second call. This avoids security issues where
11836 * kernelmanagerd has been compromised or the pageable kc has been
11837 * tampered with and the attacker attempts to re-load a malicious
11840 * Return: if a KC fails to load the return value will contain:
11841 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11842 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11843 * Similarly, if the aux kc load fails, the return value will
11844 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11845 * compose with each other and with kOSKextReturnKCLoadFailure.
11846 *********************************************************************/
11849 OSKext::loadFileSetKexts(OSDictionary
* requestDict __unused
)
11851 static bool daemon_ready
= false;
11853 OSReturn ret
= kOSKextReturnInvalidArgument
;
11854 OSReturn kcerr
= 0;
11855 bool start_matching
= false;
11857 bool allow_fileset_load
= !daemon_ready
;
11858 #if !(defined(__x86_64__) || defined(__i386__))
11859 /* never allow KCs full of kexts on non-x86 machines */
11860 allow_fileset_load
= false;
11864 * Change with 70582300
11866 #if 0 || !defined(VM_MAPPED_KEXTS)
11868 * On platforms that don't support the SystemKC or a file-backed
11869 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11870 * needs to be queried before we load any codeless kexts or release
11871 * any 3rd party kexts to run. On platforms that support a file-backed
11872 * AuxKC, this process is done via the kext audit mechanism.
11875 printf("KextLog: waiting for kext receipt to be queried.\n");
11876 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried
, UINT64_MAX
)) {
11879 #endif /* !VM_MAPPED_KEXTS */
11882 * Get the args from the request. Right now we need the file
11883 * name for the pageable and the aux kext collection file sets.
11885 OSDictionary
* requestArgs
= NULL
; // do not release
11886 OSString
* pageable_filepath
= NULL
; // do not release
11887 OSString
* aux_filepath
= NULL
; // do not release
11888 OSArray
* codeless_kexts
= NULL
; // do not release
11890 kernel_mach_header_t
*akc_mh
= NULL
;
11892 requestArgs
= OSDynamicCast(OSDictionary
,
11893 requestDict
->getObject(kKextRequestArgumentsKey
));
11895 if (requestArgs
== NULL
) {
11896 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11897 "KextLog: No arguments in plist for loading fileset kext\n");
11898 printf("KextLog: No arguments in plist for loading fileset kext\n");
11902 ret
= kOSKextReturnDisabled
;
11904 IORecursiveLockLock(sKextLock
);
11906 if (!sLoadEnabled
) {
11907 OSKextLog(NULL
, kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11908 "KextLog: Kext loading is disabled (attempt to load KCs).");
11909 IORecursiveLockUnlock(sKextLock
);
11913 pageable_filepath
= OSDynamicCast(OSString
,
11914 requestArgs
->getObject(kKextRequestArgumentPageableKCFilename
));
11916 if (allow_fileset_load
&& pageable_filepath
!= NULL
) {
11917 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath
->getCStringNoCopy());
11919 ret
= OSKext::loadKCFileSet(pageable_filepath
->getCStringNoCopy(), KCKindPageable
);
11921 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11922 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11924 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11925 ret
= kOSKextReturnKCLoadFailure
;
11926 kcerr
|= kOSKextReturnKCLoadFailureSystemKC
;
11930 * Even if the AuxKC fails to load, we still want to send
11931 * the System KC personalities to the catalog for matching
11933 start_matching
= true;
11934 } else if (pageable_filepath
!= NULL
) {
11935 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11936 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath
->getCStringNoCopy());
11937 ret
= kOSKextReturnUnsupported
;
11941 akc_mh
= (kernel_mach_header_t
*)PE_get_kc_header(KCKindAuxiliary
);
11944 * If we try to load a deferred AuxKC, then don't ever attempt
11945 * a filesystem map of a file
11947 allow_fileset_load
= false;
11950 * This function is only called once per boot, so we haven't
11951 * yet loaded an AuxKC. If we have registered the AuxKC mach
11952 * header, that means that the kext collection has been placed
11953 * in memory for us by the booter, and is waiting for us to
11954 * process it. Grab the deferred XML plist of info
11955 * dictionaries and add all the kexts.
11957 OSSharedPtr
<OSObject
> parsedXML
;
11958 OSSharedPtr
<OSData
> loaded_kcUUID
;
11959 OSDictionary
*infoDict
;
11960 parsedXML
= consumeDeferredKextCollection(KCKindAuxiliary
);
11961 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
11962 #if !defined(VM_MAPPED_KEXTS)
11964 * On platforms where we don't dynamically wire-down / page-in
11965 * kext memory, we need to maintain the invariant that if the
11966 * AuxKC in memory does not contain a kext receipt, then we
11967 * should not load any of the kexts.
11969 size_t receipt_sz
= 0;
11970 if (getsectdatafromheader(akc_mh
, kReceiptInfoSegment
, kAuxKCReceiptSection
, &receipt_sz
) == NULL
|| receipt_sz
== 0) {
11971 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11972 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
11973 ret
= kOSKextReturnKCLoadFailure
;
11979 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11980 added
= OSKext::addKextsFromKextCollection(akc_mh
, infoDict
,
11981 kPrelinkTextSegment
, loaded_kcUUID
, KCKindAuxiliary
);
11982 if (!loaded_kcUUID
) {
11983 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11984 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11985 } else if (!added
) {
11986 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11987 "KextLog: WARNING: Failed to load AuxKC from memory.");
11989 /* only return success if the pageable load (above) was successful */
11990 if (ret
!= kOSKextReturnKCLoadFailure
) {
11991 ret
= kOSReturnSuccess
;
11993 /* the registration of the AuxKC parsed out the KC's UUID already */
11995 if (daemon_ready
) {
11997 * Complain, but don't return an error if this isn't the first time the
11998 * IOKit daemon is checking in. If the daemon ever restarts, we will
11999 * hit this case because we've already consumed the deferred personalities.
12000 * We return success here so that a call to this function from a restarted
12001 * daemon with no codeless kexts will succeed.
12003 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
12004 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12005 if (ret
!= kOSKextReturnKCLoadFailure
) {
12006 ret
= kOSReturnSuccess
;
12009 /* this is a real error case */
12010 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
12011 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12012 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12013 ret
= kOSKextReturnKCLoadFailure
;
12014 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
12019 aux_filepath
= OSDynamicCast(OSString
,
12020 requestArgs
->getObject(kKextRequestArgumentAuxKCFilename
));
12021 if (allow_fileset_load
&& aux_filepath
!= NULL
) {
12022 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath
->getCStringNoCopy());
12024 ret
= OSKext::loadKCFileSet(aux_filepath
->getCStringNoCopy(), KCKindAuxiliary
);
12026 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12027 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
12029 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
12030 ret
= kOSKextReturnKCLoadFailure
;
12031 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
12034 start_matching
= true;
12035 } else if (aux_filepath
!= NULL
) {
12036 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
12037 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath
->getCStringNoCopy());
12038 if (ret
!= kOSKextReturnKCLoadFailure
) {
12039 ret
= kOSKextReturnUnsupported
;
12045 * Load codeless kexts last so that there is no possibilty of a
12046 * codeless kext bundle ID preventing a kext in the system KC from
12049 codeless_kexts
= OSDynamicCast(OSArray
,
12050 requestArgs
->getObject(kKextRequestArgumentCodelessPersonalities
));
12051 if (codeless_kexts
!= NULL
) {
12052 uint32_t count
= codeless_kexts
->getCount();
12053 OSKextLog(NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12054 "KextLog: loading %d codeless kexts/dexts", count
);
12055 for (uint32_t i
= 0; i
< count
; i
++) {
12056 OSDictionary
*infoDict
;
12057 infoDict
= OSDynamicCast(OSDictionary
,
12058 codeless_kexts
->getObject(i
));
12062 // instantiate a new kext, and don't hold a reference
12063 // (the kext subsystem will hold one implicitly)
12064 OSKext::withCodelessInfo(infoDict
);
12066 /* ignore errors that are not KC load failures */
12067 if (ret
!= kOSKextReturnKCLoadFailure
) {
12068 ret
= kOSReturnSuccess
;
12070 start_matching
= true;
12073 /* send personalities to the IOCatalog once */
12074 if (ret
== kOSReturnSuccess
|| start_matching
|| sOSKextWasResetAfterUserspaceReboot
) {
12075 OSKext::sendAllKextPersonalitiesToCatalog(true);
12077 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12078 * things as active and start all the delayed matching: the
12079 * dext and codeless kext personalities should have all been
12080 * delivered via this one call.
12082 if (!daemon_ready
) {
12083 OSKext::setIOKitDaemonActive();
12084 OSKext::setDeferredLoadSucceeded(TRUE
);
12085 IOService::iokitDaemonLaunched();
12087 if (sOSKextWasResetAfterUserspaceReboot
) {
12088 sOSKextWasResetAfterUserspaceReboot
= false;
12089 OSKext::setIOKitDaemonActive();
12090 IOService::startDeferredMatches();
12094 if (ret
== kOSKextReturnKCLoadFailure
) {
12099 * Only allow this function to attempt to load the pageable and
12100 * aux KCs once per boot.
12102 daemon_ready
= true;
12104 IORecursiveLockUnlock(sKextLock
);
12110 OSKext::resetMutableSegments(void)
12112 kernel_segment_command_t
*seg
= NULL
;
12113 kernel_mach_header_t
*k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12115 OSKextSavedMutableSegment
*savedSegment
= NULL
;
12116 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
12119 if (!savedMutableSegments
) {
12120 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
12121 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12122 err
= kOSKextReturnInternalError
;
12126 for (seg
= firstsegfromheader(k_mh
), index
= 0; seg
; seg
= nextsegfromheader(k_mh
, seg
)) {
12127 if (!segmentIsMutable(seg
)) {
12130 uint64_t unslid_vmaddr
= seg
->vmaddr
- kext_slide
;
12131 uint64_t vmsize
= seg
->vmsize
;
12132 err
= kOSKextReturnInternalError
;
12133 for (index
= 0; index
< savedMutableSegments
->getCount(); index
++) {
12134 savedSegment
= OSDynamicCast(OSKextSavedMutableSegment
, savedMutableSegments
->getObject(index
));
12135 assert(savedSegment
);
12136 if (savedSegment
->getVMAddr() == seg
->vmaddr
&& savedSegment
->getVMSize() == seg
->vmsize
) {
12137 OSKextLog(this, kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
12138 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg
->segname
, sizeof(seg
->segname
)), seg
->segname
, unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12139 err
= savedSegment
->restoreContents(seg
);
12140 if (err
!= kOSReturnSuccess
) {
12141 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12145 if (err
!= kOSReturnSuccess
) {
12146 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12149 err
= kOSReturnSuccess
;
12155 /*********************************************************************
12156 * Assumes sKextLock is held.
12157 *********************************************************************/
12160 OSKext::loadKCFileSet(
12161 const char *filepath
,
12164 #if VM_MAPPED_KEXTS
12165 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12167 struct vnode
*vp
= NULL
;
12168 void *fileset_control
;
12170 bool pageable
= (type
== KCKindPageable
);
12172 if ((pageable
&& pageableKCloaded
) ||
12173 (!pageable
&& auxKCloaded
)) {
12174 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12175 "KC FileSet of type %s is already loaded", (pageable
? "Pageable" : "Aux"));
12177 return kOSKextReturnInvalidArgument
;
12180 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12181 if (!pageable
&& !pageableKCloaded
) {
12182 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12183 "Trying to load the Aux KC without loading the Pageable KC");
12184 return kOSKextReturnInvalidArgument
;
12187 fileset_control
= ubc_getobject_from_filename(filepath
, &vp
, &fsize
);
12189 if (fileset_control
== NULL
) {
12190 printf("Could not get memory control object for file %s", filepath
);
12192 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12193 "Could not get memory control object for file %s", filepath
);
12194 return kOSKextReturnInvalidArgument
;
12197 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12198 "Could not find vnode for file %s", filepath
);
12199 return kOSKextReturnInvalidArgument
;
12202 kernel_mach_header_t
*mh
= NULL
;
12203 uintptr_t slide
= 0;
12207 * When SIP is enabled, the KC we map must be SIP-protected
12209 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS
) != 0) {
12210 struct vnode_attr va
;
12213 VATTR_WANTED(&va
, va_flags
);
12214 error
= vnode_getattr(vp
, &va
, vfs_context_current());
12216 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12217 "vnode_getattr(%s) failed (error=%d)", filepath
, error
);
12218 err
= kOSKextReturnInternalError
;
12221 if (!(va
.va_flags
& SF_RESTRICTED
)) {
12222 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12223 "Path to KC '%s' is not SIP-protected", filepath
);
12224 err
= kOSKextReturnInvalidArgument
;
12230 err
= OSKext::mapKCFileSet(fileset_control
, (vm_size_t
)fsize
, &mh
, 0, &slide
, pageable
, NULL
);
12232 printf("KextLog: mapKCFileSet returned %d\n", err
);
12234 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12235 "mapKCFileSet returned %d\n", err
);
12237 err
= kOSKextReturnInvalidArgument
;
12243 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12244 assert(vp
!= NULL
);
12245 if (err
== kOSReturnSuccess
) {
12246 PE_set_kc_vp(type
, vp
);
12248 pageableKCloaded
= true;
12250 auxKCloaded
= true;
12260 return kOSKextReturnUnsupported
;
12261 #endif // VM_MAPPED_KEXTS
12264 #if defined(__x86_64__) || defined(__i386__)
12265 /*********************************************************************
12266 * Assumes sKextLock is held.
12267 *********************************************************************/
12270 OSKext::mapKCFileSet(
12273 kernel_mach_header_t
**mhp
,
12277 void *map_entry_list
)
12279 bool fileset_load
= false;
12282 kernel_section_t
*infoPlistSection
= NULL
;
12283 OSDictionary
*infoDict
= NULL
;
12285 OSSharedPtr
<OSObject
> parsedXML
;
12286 OSSharedPtr
<OSString
> errorString
;
12287 OSSharedPtr
<OSData
> loaded_kcUUID
;
12289 /* Check if initial load for file set */
12290 if (*mhp
== NULL
) {
12291 fileset_load
= true;
12293 /* Get a page aligned address from kext map to map the file */
12294 vm_map_offset_t pagealigned_addr
= get_address_from_kext_map(fsize
);
12295 if (pagealigned_addr
== 0) {
12296 return kOSKextReturnNoMemory
;
12299 *mhp
= (kernel_mach_header_t
*)pagealigned_addr
;
12301 /* Allocate memory for bailout mechanism */
12302 map_entry_list
= allocate_kcfileset_map_entry_list();
12303 if (map_entry_list
== NULL
) {
12304 return kOSKextReturnNoMemory
;
12308 uintptr_t *slideptr
= fileset_load
? slidep
: NULL
;
12309 err
= mapKCTextSegment(control
, mhp
, file_offset
, slideptr
, map_entry_list
);
12310 /* mhp and slideptr are updated by mapKCTextSegment */
12312 if (fileset_load
) {
12313 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12318 /* Initialize the kc header globals */
12319 if (fileset_load
) {
12321 PE_set_kc_header(KCKindPageable
, *mhp
, *slidep
);
12323 PE_set_kc_header(KCKindAuxiliary
, *mhp
, *slidep
);
12327 /* Iterate through all the segments and map necessary segments */
12328 struct load_command
*lcp
= (struct load_command
*) (*mhp
+ 1);
12329 for (unsigned int i
= 0; i
< (*mhp
)->ncmds
; i
++, lcp
= (struct load_command
*)((uintptr_t)lcp
+ lcp
->cmdsize
)) {
12330 vm_map_offset_t start
;
12331 kernel_mach_header_t
*k_mh
= NULL
;
12332 kernel_segment_command_t
* seg
= NULL
;
12333 struct fileset_entry_command
*fse
= NULL
;
12335 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
12336 seg
= (kernel_segment_command_t
*)lcp
;
12337 start
= ((uintptr_t)(seg
->vmaddr
)) + *slidep
;
12338 } else if (lcp
->cmd
== LC_FILESET_ENTRY
) {
12339 fse
= (struct fileset_entry_command
*)lcp
;
12340 k_mh
= (kernel_mach_header_t
*)(((uintptr_t)(fse
->vmaddr
)) + *slidep
);
12342 /* Map the segments of the mach-o binary */
12343 err
= OSKext::mapKCFileSet(control
, 0, &k_mh
, fse
->fileoff
, slidep
, pageable
, map_entry_list
);
12345 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12346 return kOSKextReturnInvalidArgument
;
12349 } else if (lcp
->cmd
== LC_DYLD_CHAINED_FIXUPS
) {
12350 /* Check if the Aux KC is built pageable style */
12351 if (!pageable
&& !fileset_load
&& !auxKCloaded
) {
12352 resetAuxKCSegmentOnUnload
= true;
12359 if (fileset_load
) {
12360 if (seg
->vmsize
== 0) {
12364 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12365 if (strncmp(seg
->segname
, kPrelinkInfoSegment
, sizeof(seg
->segname
)) != 0 &&
12366 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) != 0 &&
12367 strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) != 0 &&
12368 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0) {
12372 if (seg
->vmsize
== 0) {
12376 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12377 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12378 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12379 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12384 ret
= vm_map_kcfileset_segment(
12385 &start
, seg
->vmsize
,
12386 (memory_object_control_t
)control
, seg
->fileoff
, seg
->maxprot
);
12388 if (ret
!= KERN_SUCCESS
) {
12389 if (fileset_load
) {
12390 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12392 return kOSKextReturnInvalidArgument
;
12394 add_kcfileset_map_entry(map_entry_list
, start
, seg
->vmsize
);
12397 /* Return if regular mach-o */
12398 if (!fileset_load
) {
12403 * Fixup for the Pageable KC and the Aux KC is done by
12404 * i386_slide_kext_collection_mh_addrs, but it differs in
12407 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12408 * The fixup of kext segments and kext load commands are done at kext
12409 * load time by calling i386_slide_individual_kext.
12411 * AuxKC old style: Fixup all the segments and all the load commands.
12413 * AuxKC pageable style: Same as the Pageable KC.
12415 bool adjust_mach_header
= (pageable
? true : ((resetAuxKCSegmentOnUnload
) ? true : false));
12416 ret
= i386_slide_kext_collection_mh_addrs(*mhp
, *slidep
, adjust_mach_header
);
12417 if (ret
!= KERN_SUCCESS
) {
12418 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12419 return kOSKextReturnInvalidArgument
;
12422 /* Get the prelink info dictionary */
12423 infoPlistSection
= getsectbynamefromheader(*mhp
, kPrelinkInfoSegment
, kPrelinkInfoSection
);
12424 parsedXML
= OSUnserializeXML((const char *)infoPlistSection
->addr
, errorString
);
12426 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
12430 const char *errorCString
= "(unknown error)";
12432 if (errorString
&& errorString
->getCStringNoCopy()) {
12433 errorCString
= errorString
->getCStringNoCopy();
12434 } else if (parsedXML
) {
12435 errorCString
= "not a dictionary";
12437 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12438 "Error unserializing kext info plist section: %s.", errorCString
);
12439 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12440 return kOSKextReturnInvalidArgument
;
12443 /* Validate that the Kext Collection is prelinked to the loaded KC */
12444 err
= OSKext::validateKCFileSetUUID(infoDict
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12446 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12447 return kOSKextReturnInvalidArgument
;
12450 /* Set Protection of Segments */
12451 OSKext::protectKCFileSet(*mhp
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12453 OSKext::addKextsFromKextCollection(*mhp
,
12454 infoDict
, kPrelinkTextSegment
,
12455 loaded_kcUUID
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12457 /* Copy in the KC UUID */
12458 if (!loaded_kcUUID
) {
12459 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12460 "WARNING: did not find UUID in prelinked %s KC!", pageable
? "Pageable" : "Aux");
12461 } else if (pageable
) {
12462 pageablekc_uuid_valid
= TRUE
;
12463 memcpy((void *)&pageablekc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12464 uuid_unparse_upper(pageablekc_uuid
, pageablekc_uuid_string
);
12466 auxkc_uuid_valid
= TRUE
;
12467 memcpy((void *)&auxkc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12468 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
12471 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, FALSE
, pageable
);
12476 /*********************************************************************
12477 * Assumes sKextLock is held.
12478 *********************************************************************/
12481 OSKext::mapKCTextSegment(
12483 kernel_mach_header_t
**mhp
,
12486 void *map_entry_list
)
12489 vm_map_offset_t mach_header_map_size
= vm_map_round_page(sizeof(kernel_mach_header_t
),
12491 vm_map_offset_t load_command_map_size
= 0;
12492 kernel_mach_header_t
*base_mh
= *mhp
;
12494 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12495 ret
= vm_map_kcfileset_segment(
12496 (vm_map_offset_t
*)&base_mh
, mach_header_map_size
,
12497 (memory_object_control_t
)control
, file_offset
, (VM_PROT_READ
| VM_PROT_WRITE
));
12499 if (ret
!= KERN_SUCCESS
) {
12500 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret
);
12502 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12503 "Failed to map mach header of kc fileset with error %d", ret
);
12504 return kOSKextReturnInvalidArgument
;
12508 /* Verify that it's an MH_FILESET */
12509 if (base_mh
->filetype
!= MH_FILESET
) {
12510 printf("Kext Log: mapKCTextSegment mach header filetype"
12511 " is not an MH_FILESET, it is %x", base_mh
->filetype
);
12513 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12514 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh
->filetype
);
12516 /* Unmap the mach header */
12517 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12518 return kOSKextReturnInvalidArgument
;
12522 /* Map the remaining pages of load commands */
12523 if (base_mh
->sizeofcmds
> mach_header_map_size
) {
12524 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12525 load_command_map_size
= base_mh
->sizeofcmds
- mach_header_map_size
;
12527 /* Map the load commands */
12528 ret
= vm_map_kcfileset_segment(
12529 &load_command_addr
, load_command_map_size
,
12530 (memory_object_control_t
)control
, file_offset
+ mach_header_map_size
,
12531 (VM_PROT_READ
| VM_PROT_WRITE
));
12533 if (ret
!= KERN_SUCCESS
) {
12534 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret
);
12535 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12536 "Failed to map load commands of kc fileset with error %d", ret
);
12538 /* Unmap the mach header */
12539 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12540 return kOSKextReturnInvalidArgument
;
12544 kernel_segment_command_t
*text_seg
;
12545 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)base_mh
, SEG_TEXT
);
12547 /* Calculate the slide and vm addr of mach header */
12549 *mhp
= (kernel_mach_header_t
*)((uintptr_t)base_mh
+ text_seg
->vmaddr
);
12550 *slidep
= ((uintptr_t)*mhp
) - text_seg
->vmaddr
;
12553 /* Cache the text segment size and file offset before unmapping */
12554 vm_map_offset_t text_segment_size
= text_seg
->vmsize
;
12555 vm_object_offset_t text_segment_fileoff
= text_seg
->fileoff
;
12556 vm_prot_t text_maxprot
= text_seg
->maxprot
;
12558 /* Unmap the first page and loadcommands and map the text segment */
12559 ret
= vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12560 assert(ret
== KERN_SUCCESS
);
12562 if (load_command_map_size
) {
12563 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12564 ret
= vm_unmap_kcfileset_segment(&load_command_addr
, load_command_map_size
);
12565 assert(ret
== KERN_SUCCESS
);
12568 /* Map the text segment at actual vm addr specified in fileset */
12569 ret
= vm_map_kcfileset_segment((vm_map_offset_t
*)mhp
, text_segment_size
,
12570 (memory_object_control_t
)control
, text_segment_fileoff
, text_maxprot
);
12571 if (ret
!= KERN_SUCCESS
) {
12572 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12573 "Failed to map Text segment of kc fileset with error %d", ret
);
12574 return kOSKextReturnInvalidArgument
;
12577 add_kcfileset_map_entry(map_entry_list
, (vm_map_offset_t
)*mhp
, text_segment_size
);
12581 /*********************************************************************
12582 * Assumes sKextLock is held.
12583 *********************************************************************/
12586 OSKext::protectKCFileSet(
12587 kernel_mach_header_t
*mh
,
12590 vm_map_t kext_map
= g_kext_map
;
12591 kernel_segment_command_t
* seg
= NULL
;
12592 vm_map_offset_t start
= 0;
12593 vm_map_offset_t end
= 0;
12596 /* Set VM permissions */
12597 seg
= firstsegfromheader((kernel_mach_header_t
*)mh
);
12599 start
= round_page(seg
->vmaddr
);
12600 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
12603 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12604 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12605 * for the Aux KC as well.
12607 if (strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) == 0 ||
12608 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) == 0 ||
12609 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0 ||
12610 (type
== KCKindAuxiliary
&& !resetAuxKCSegmentOnUnload
&&
12611 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0)) {
12612 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12613 kext_map
, start
, end
, seg
->maxprot
, TRUE
, type
);
12614 if (ret
!= KERN_SUCCESS
) {
12615 printf("OSKext protect failed with error %d", ret
);
12616 return kOSKextReturnInvalidArgument
;
12619 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12620 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12621 if (ret
!= KERN_SUCCESS
) {
12622 printf("OSKext protect failed with error %d", ret
);
12623 return kOSKextReturnInvalidArgument
;
12626 ret
= OSKext_wire((kernel_mach_header_t
*)mh
,
12627 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12628 if (ret
!= KERN_SUCCESS
) {
12629 printf("OSKext wire failed with error %d", ret
);
12630 return kOSKextReturnInvalidArgument
;
12634 seg
= nextsegfromheader((kernel_mach_header_t
*) mh
, seg
);
12640 /*********************************************************************
12641 * Assumes sKextLock is held.
12642 *********************************************************************/
12645 OSKext::freeKCFileSetcontrol(void)
12647 PE_reset_all_kc_vp();
12650 /*********************************************************************
12651 * Assumes sKextLock is held.
12653 * resetKCFileSetSegments: Kext start function expects data segment to
12654 * be pristine on every load, unmap the dirty segments on unload and
12655 * remap them from FileSet on disk. Remap all segments of kext since
12656 * fixups are done per kext and not per segment.
12657 *********************************************************************/
12659 OSKext::resetKCFileSetSegments(void)
12661 kernel_segment_command_t
*seg
= NULL
;
12662 kernel_segment_command_t
*text_seg
;
12663 uint32_t text_fileoff
;
12664 kernel_mach_header_t
*k_mh
= NULL
;
12666 struct vnode
*vp
= NULL
;
12667 void *fileset_control
= NULL
;
12668 bool pageable
= (kc_type
== KCKindPageable
);
12672 /* Check the vnode reference is still available */
12673 vp
= (struct vnode
*)PE_get_kc_vp(kc_type
);
12675 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12676 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12677 return kOSKextReturnInternalError
;
12680 fileset_control
= ubc_getobject(vp
, 0);
12681 assert(fileset_control
!= NULL
);
12683 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12684 "Kext %s resetting all segments", getIdentifierCString());
12686 k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12687 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)kmod_info
->address
, SEG_TEXT
);
12688 text_fileoff
= text_seg
->fileoff
;
12689 slide
= PE_get_kc_slide(kc_type
);
12691 seg
= firstsegfromheader((kernel_mach_header_t
*)k_mh
);
12693 if (seg
->vmsize
== 0) {
12694 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12698 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12699 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12700 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12701 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12702 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12706 kr
= vm_unmap_kcfileset_segment(&seg
->vmaddr
, seg
->vmsize
);
12707 assert(kr
== KERN_SUCCESS
);
12708 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12711 /* Unmap the text segment */
12712 kr
= vm_unmap_kcfileset_segment(&text_seg
->vmaddr
, text_seg
->vmsize
);
12713 assert(kr
== KERN_SUCCESS
);
12715 /* Map all the segments of the kext */
12716 err
= OSKext::mapKCFileSet(fileset_control
, 0, &k_mh
, text_fileoff
, &slide
, pageable
, NULL
);
12718 panic("Could not reset segments of a mapped kext, error %x", err
);
12721 /* Update address in kmod_info, since it has been reset */
12722 if (kmod_info
->address
) {
12723 kmod_info
->address
= (((uintptr_t)(kmod_info
->address
)) + slide
);
12729 /*********************************************************************
12730 * Mechanism to track all segment mapping while mapping KC fileset.
12731 *********************************************************************/
12733 struct kcfileset_map_entry
{
12734 vm_map_offset_t me_start
;
12735 vm_map_offset_t me_size
;
12738 struct kcfileset_map_entry_list
{
12739 int kme_list_count
;
12740 int kme_list_index
;
12741 struct kcfileset_map_entry kme_list
[];
12744 #define KCFILESET_MAP_ENTRY_MAX (16380)
12747 allocate_kcfileset_map_entry_list(void)
12749 struct kcfileset_map_entry_list
*entry_list
;
12751 entry_list
= (struct kcfileset_map_entry_list
*)kalloc(sizeof(struct kcfileset_map_entry_list
) +
12752 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12754 entry_list
->kme_list_count
= KCFILESET_MAP_ENTRY_MAX
;
12755 entry_list
->kme_list_index
= 0;
12760 add_kcfileset_map_entry(
12761 void *map_entry_list
,
12762 vm_map_offset_t start
,
12763 vm_map_offset_t size
)
12765 if (map_entry_list
== NULL
) {
12769 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12771 if (entry_list
->kme_list_index
>= entry_list
->kme_list_count
) {
12772 panic("Ran out of map kc fileset list\n");
12775 entry_list
->kme_list
[entry_list
->kme_list_index
].me_start
= start
;
12776 entry_list
->kme_list
[entry_list
->kme_list_index
].me_size
= size
;
12778 entry_list
->kme_list_index
++;
12782 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12783 void *map_entry_list
,
12784 boolean_t unmap_entries
,
12787 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12789 if (unmap_entries
) {
12790 for (int i
= 0; i
< entry_list
->kme_list_index
; i
++) {
12792 ret
= vm_unmap_kcfileset_segment(
12793 &(entry_list
->kme_list
[i
].me_start
),
12794 entry_list
->kme_list
[i
].me_size
);
12795 assert(ret
== KERN_SUCCESS
);
12798 PE_reset_kc_header(pageable
? KCKindPageable
: KCKindAuxiliary
);
12801 kfree(entry_list
, sizeof(struct kcfileset_map_entry_list
) +
12802 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12805 /*********************************************************************
12806 * Mechanism to map kext segment.
12807 *********************************************************************/
12810 vm_map_kcfileset_segment(
12811 vm_map_offset_t
*start
,
12812 vm_map_offset_t size
,
12814 vm_object_offset_t fileoffset
,
12815 vm_prot_t max_prot
)
12817 vm_map_kernel_flags_t vmk_flags
;
12818 vmk_flags
.vmkf_no_copy_on_read
= 1;
12819 vmk_flags
.vmkf_cs_enforcement
= 0;
12820 vmk_flags
.vmkf_cs_enforcement_override
= 1;
12823 /* Add Write to max prot to allow fixups */
12824 max_prot
= max_prot
| VM_PROT_WRITE
;
12827 * Map the segments from file as COPY mappings to
12828 * make sure changes on disk to the file does not affect
12831 ret
= vm_map_enter_mem_object_control(
12835 (mach_vm_offset_t
)0,
12838 VM_KERN_MEMORY_OSKEXT
,
12839 (memory_object_control_t
)control
,
12842 (VM_PROT_READ
| VM_PROT_WRITE
), max_prot
,
12849 vm_unmap_kcfileset_segment(
12850 vm_map_offset_t
*start
,
12851 vm_map_offset_t size
)
12853 return mach_vm_deallocate(g_kext_map
, *start
, size
);
12856 #endif //(__x86_64__) || defined(__i386__)
12858 /*********************************************************************
12859 * Assumes sKextLock is held.
12860 *********************************************************************/
12863 OSKext::validateKCFileSetUUID(
12864 OSDictionary
*infoDict
,
12867 OSReturn ret
= kOSReturnSuccess
;
12869 if (!kernelcache_uuid_valid
) {
12870 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12871 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12872 ret
= kOSKextReturnInvalidArgument
;
12875 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid
, type
, infoDict
, kPrelinkInfoBootKCIDKey
);
12880 #if defined(__x86_64__) || defined(__i386__)
12881 /* Check if the Aux KC is prelinked to correct Pageable KC */
12882 if (type
== KCKindAuxiliary
) {
12883 if (!pageablekc_uuid_valid
) {
12884 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12885 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12886 ret
= kOSKextReturnInvalidArgument
;
12889 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid
, type
, infoDict
, kPrelinkInfoPageableKCIDKey
);
12894 #endif //(__x86_64__) || defined(__i386__)
12896 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12901 /*********************************************************************
12902 * Assumes sKextLock is held.
12903 *********************************************************************/
12906 OSKext::validateKCUUIDfromPrelinkInfo(
12907 uuid_t
*loaded_kcuuid
,
12909 OSDictionary
*infoDict
,
12910 const char *uuid_key
)
12912 /* extract the UUID from the dictionary */
12913 OSData
*prelinkinfoKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(uuid_key
));
12914 if (!prelinkinfoKCUUID
) {
12915 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12916 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key
);
12917 return kOSKextReturnInvalidArgument
;
12920 if (prelinkinfoKCUUID
->getLength() != sizeof(uuid_t
)) {
12921 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12922 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key
, prelinkinfoKCUUID
->getLength());
12923 return kOSKextReturnInvalidArgument
;
12926 if (memcmp((void *)loaded_kcuuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(),
12927 prelinkinfoKCUUID
->getLength())) {
12928 OSData
*info_dict_uuid
;
12929 uuid_string_t info_dict_uuid_str
= {};
12930 uuid_string_t expected_uuid_str
= {};
12931 uuid_string_t given_uuid_str
= {};
12934 /* extract the KC UUID from the dictionary */
12935 info_dict_uuid
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
12936 if (info_dict_uuid
&& info_dict_uuid
->getLength() == sizeof(uuid_t
)) {
12938 memcpy(tmp_uuid
, (const void *)info_dict_uuid
->getBytesNoCopy(), sizeof(tmp_uuid
));
12939 uuid_unparse(tmp_uuid
, info_dict_uuid_str
);
12942 uuid_unparse(*loaded_kcuuid
, expected_uuid_str
);
12943 memcpy(given_uuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(), sizeof(given_uuid
));
12944 uuid_unparse(given_uuid
, given_uuid_str
);
12946 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12947 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12948 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12949 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12950 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12951 if (type
== KCKindPageable
&& sPanicOnKCMismatch
) {
12952 panic("System KC UUID %s linked against %s, but %s is loaded",
12953 info_dict_uuid_str
, given_uuid_str
, expected_uuid_str
);
12955 return kOSKextReturnInvalidArgument
;
12961 /*********************************************************************
12962 * Assumes sKextLock is held.
12963 *********************************************************************/
12966 OSKext::dispatchResource(OSDictionary
* requestDict
)
12968 OSReturn result
= kOSReturnError
;
12969 OSSharedPtr
<OSDictionary
> callbackRecord
;
12970 OSNumber
* requestTag
= NULL
; // do not release
12971 OSNumber
* requestResult
= NULL
; // do not release
12972 OSData
* dataObj
= NULL
; // do not release
12973 uint32_t dataLength
= 0;
12974 const void * dataPtr
= NULL
; // do not free
12975 OSData
* callbackWrapper
= NULL
; // do not release
12976 OSKextRequestResourceCallback callback
= NULL
;
12977 OSData
* contextWrapper
= NULL
; // do not release
12978 void * context
= NULL
; // do not free
12979 OSSharedPtr
<OSKext
> callbackKext
;
12981 /* Get the args from the request. Right now we need the tag
12982 * to look up the callback record, and the result for invoking the callback.
12984 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12985 kKextRequestArgumentRequestTagKey
));
12986 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12987 kKextRequestArgumentResultKey
));
12988 if (!requestTag
|| !requestResult
) {
12989 result
= kOSKextReturnInvalidArgument
;
12993 /* Look for a callback record matching this request's tag.
12995 result
= dequeueCallbackForRequestTag(requestTag
, callbackRecord
);
12996 if (result
!= kOSReturnSuccess
) {
13001 * Get the context pointer of the callback record (if there is one).
13003 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
.get(),
13004 kKextRequestArgumentContextKey
));
13005 context
= _OSKextExtractPointer(contextWrapper
);
13006 if (contextWrapper
&& !context
) {
13010 callbackWrapper
= OSDynamicCast(OSData
,
13011 _OSKextGetRequestArgument(callbackRecord
.get(),
13012 kKextRequestArgumentCallbackKey
));
13013 callback
= _OSKextExtractCallbackPointer(callbackWrapper
);
13018 /* Check for a data obj. We might not have one and that's ok, that means
13019 * we didn't find the requested resource, and we still have to tell the
13020 * caller that via the callback.
13022 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
13023 kKextRequestArgumentValueKey
));
13025 dataPtr
= dataObj
->getBytesNoCopy();
13026 dataLength
= dataObj
->getLength();
13029 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
13030 if (!callbackKext
) {
13031 OSKextLog(/* kext */ NULL
,
13032 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
13033 "Can't invoke callback for resource request; ");
13036 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
13037 OSKextLog(/* kext */ NULL
,
13038 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
13039 "Can't invoke kext resource callback; ");
13043 (void)callback(requestTag
->unsigned32BitValue(),
13044 (OSReturn
)requestResult
->unsigned32BitValue(),
13045 dataPtr
, dataLength
, context
);
13047 result
= kOSReturnSuccess
;
13053 /*********************************************************************
13054 * Assumes sKextLock is held.
13055 *********************************************************************/
13058 OSKext::setMissingAuxKCBundles(OSDictionary
* requestDict
)
13060 OSSharedPtr
<OSDictionary
> missingIDs
;
13061 OSArray
*bundleIDList
= NULL
; // do not release
13063 bundleIDList
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
13064 requestDict
, kKextRequestArgumentMissingBundleIDs
));
13065 if (!bundleIDList
) {
13066 return kOSKextReturnInvalidArgument
;
13069 missingIDs
= OSDictionary::withCapacity(bundleIDList
->getCount());
13071 return kOSKextReturnNoMemory
;
13075 count
= bundleIDList
->getCount();
13076 for (i
= 0; i
< count
; i
++) {
13077 OSString
*thisID
= OSDynamicCast(OSString
, bundleIDList
->getObject(i
));
13079 missingIDs
->setObject(thisID
, kOSBooleanFalse
);
13083 sNonLoadableKextsByID
.reset(missingIDs
.get(), OSRetain
);
13085 return kOSReturnSuccess
;
13088 /*********************************************************************
13089 * Assumes sKextLock is held.
13090 *********************************************************************/
13093 OSKext::setAuxKCBundleAvailable(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
13095 bool loadable
= true;
13096 if (!kextIdentifier
) {
13097 return kOSKextReturnInvalidArgument
;
13101 OSBoolean
*loadableArg
;
13102 loadableArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
13103 requestDict
, kKextRequestArgumentBundleAvailability
));
13104 /* If we find the "Bundle Available" arg, and it's false, then
13105 * mark the bundle ID as _not_ loadable
13107 if (loadableArg
&& !loadableArg
->getValue()) {
13112 if (!sNonLoadableKextsByID
) {
13113 sNonLoadableKextsByID
= OSDictionary::withCapacity(1);
13116 sNonLoadableKextsByID
->setObject(kextIdentifier
, OSBoolean::withBoolean(loadable
));
13118 OSKextLog(/* kext */ NULL
,
13119 kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
13120 "KextLog: AuxKC bundle %s marked as %s",
13121 kextIdentifier
->getCStringNoCopy(),
13122 (loadable
? "loadable" : "NOT loadable"));
13124 return kOSReturnSuccess
;
13127 /*********************************************************************
13128 *********************************************************************/
13131 OSKext::invokeRequestCallback(
13132 OSDictionary
* callbackRecord
,
13133 OSReturn callbackResult
)
13135 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
13136 OSSharedPtr
<OSNumber
> resultNum
;
13142 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
13143 8 * sizeof(callbackResult
));
13148 /* Insert the result into the callback record and dispatch it as if it
13149 * were the reply coming down from user space.
13151 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
13154 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
13155 /* This removes the pending callback record.
13157 OSKext::dispatchResource(callbackRecord
);
13164 /*********************************************************************
13165 * Assumes sKextLock is held.
13166 *********************************************************************/
13169 OSKext::cancelRequest(
13170 OSKextRequestTag requestTag
,
13171 void ** contextOut
)
13173 OSReturn result
= kOSKextReturnNoMemory
;
13174 OSSharedPtr
<OSDictionary
> callbackRecord
;
13175 OSData
* contextWrapper
= NULL
; // do not release
13177 IORecursiveLockLock(sKextLock
);
13178 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
13180 IORecursiveLockUnlock(sKextLock
);
13182 if (result
== kOSReturnSuccess
&& contextOut
) {
13183 contextWrapper
= OSDynamicCast(OSData
,
13184 _OSKextGetRequestArgument(callbackRecord
.get(),
13185 kKextRequestArgumentContextKey
));
13186 *contextOut
= _OSKextExtractPointer(contextWrapper
);
13192 /*********************************************************************
13193 * Assumes sKextLock is held.
13194 *********************************************************************/
13196 OSKext::invokeOrCancelRequestCallbacks(
13197 OSReturn callbackResult
,
13200 unsigned int count
, i
;
13202 count
= sRequestCallbackRecords
->getCount();
13209 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13210 sRequestCallbackRecords
->getObject(i
));
13215 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13216 _OSKextGetRequestArgument(request
,
13217 kKextRequestArgumentCallbackKey
));
13219 if (!callbackWrapper
) {
13220 sRequestCallbackRecords
->removeObject(i
);
13224 vm_address_t callbackAddress
= (vm_address_t
)
13225 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13227 if ((kmod_info
->address
<= callbackAddress
) &&
13228 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13230 /* This removes the callback record.
13232 invokeRequestCallback(request
, callbackResult
);
13234 sRequestCallbackRecords
->removeObject(i
);
13243 /*********************************************************************
13244 * Assumes sKextLock is held.
13245 *********************************************************************/
13247 OSKext::countRequestCallbacks(void)
13249 uint32_t result
= 0;
13250 unsigned int count
, i
;
13252 count
= sRequestCallbackRecords
->getCount();
13259 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13260 sRequestCallbackRecords
->getObject(i
));
13265 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13266 _OSKextGetRequestArgument(request
,
13267 kKextRequestArgumentCallbackKey
));
13269 if (!callbackWrapper
) {
13273 vm_address_t callbackAddress
= (vm_address_t
)
13274 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13276 if ((kmod_info
->address
<= callbackAddress
) &&
13277 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13286 /*********************************************************************
13287 *********************************************************************/
13289 _OSKextCreateRequest(
13290 const char * predicate
,
13291 OSSharedPtr
<OSDictionary
> & requestR
)
13293 OSReturn result
= kOSKextReturnNoMemory
;
13294 OSSharedPtr
<OSDictionary
> request
;
13296 request
= OSDictionary::withCapacity(2);
13300 result
= _OSDictionarySetCStringValue(request
.get(),
13301 kKextRequestPredicateKey
, predicate
);
13302 if (result
!= kOSReturnSuccess
) {
13305 result
= kOSReturnSuccess
;
13308 if (result
== kOSReturnSuccess
) {
13309 requestR
= os::move(request
);
13315 /*********************************************************************
13316 *********************************************************************/
13318 _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
13320 return OSDynamicCast(OSString
,
13321 requestDict
->getObject(kKextRequestPredicateKey
));
13324 /*********************************************************************
13325 *********************************************************************/
13327 _OSKextGetRequestArgument(
13328 OSDictionary
* requestDict
,
13329 const char * argName
)
13331 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13332 requestDict
->getObject(kKextRequestArgumentsKey
));
13334 return args
->getObject(argName
);
13339 /*********************************************************************
13340 *********************************************************************/
13342 _OSKextSetRequestArgument(
13343 OSDictionary
* requestDict
,
13344 const char * argName
,
13347 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13348 requestDict
->getObject(kKextRequestArgumentsKey
));
13349 OSSharedPtr
<OSDictionary
> newArgs
;
13351 newArgs
= OSDictionary::withCapacity(2);
13352 args
= newArgs
.get();
13356 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
13359 return args
->setObject(argName
, value
);
13365 /*********************************************************************
13366 *********************************************************************/
13368 _OSKextExtractPointer(OSData
* wrapper
)
13370 void * result
= NULL
;
13371 const void * resultPtr
= NULL
;
13376 resultPtr
= wrapper
->getBytesNoCopy();
13377 result
= *(void **)resultPtr
;
13382 /*********************************************************************
13383 *********************************************************************/
13384 static OSKextRequestResourceCallback
13385 _OSKextExtractCallbackPointer(OSData
* wrapper
)
13387 OSKextRequestResourceCallback result
= NULL
;
13388 const void * resultPtr
= NULL
;
13393 resultPtr
= wrapper
->getBytesNoCopy();
13394 result
= *(OSKextRequestResourceCallback
*)resultPtr
;
13400 /*********************************************************************
13401 *********************************************************************/
13403 _OSDictionarySetCStringValue(
13404 OSDictionary
* dict
,
13406 const char * cValue
)
13408 OSReturn result
= kOSKextReturnNoMemory
;
13409 OSSharedPtr
<const OSSymbol
> key
;
13410 OSSharedPtr
<OSString
> value
;
13412 key
= OSSymbol::withCString(cKey
);
13413 value
= OSString::withCString(cValue
);
13414 if (!key
|| !value
) {
13417 if (dict
->setObject(key
.get(), value
.get())) {
13418 result
= kOSReturnSuccess
;
13425 /*********************************************************************
13426 *********************************************************************/
13428 _OSArrayContainsCString(
13430 const char * cString
)
13432 bool result
= false;
13433 OSSharedPtr
<const OSSymbol
> symbol
;
13436 if (!array
|| !cString
) {
13440 symbol
= OSSymbol::withCStringNoCopy(cString
);
13445 count
= array
->getCount();
13446 for (i
= 0; i
< count
; i
++) {
13447 OSObject
* thisObject
= array
->getObject(i
);
13448 if (symbol
->isEqualTo(thisObject
)) {
13459 /*********************************************************************
13460 * We really only care about boot / system start up related kexts.
13461 * We return true if we're less than REBUILD_MAX_TIME since start up,
13462 * otherwise return false.
13463 *********************************************************************/
13465 _OSKextInPrelinkRebuildWindow(void)
13467 static bool outside_the_window
= false;
13468 AbsoluteTime my_abstime
;
13472 if (outside_the_window
) {
13475 clock_get_uptime(&my_abstime
);
13476 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
13477 my_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
13478 if (my_secs
> REBUILD_MAX_TIME
) {
13479 outside_the_window
= true;
13484 #endif /* CONFIG_KXLD */
13486 /*********************************************************************
13487 *********************************************************************/
13489 _OSKextInUnloadedPrelinkedKexts( const OSSymbol
* theBundleID
)
13491 int unLoadedCount
, i
;
13492 bool result
= false;
13494 IORecursiveLockLock(sKextLock
);
13496 if (sUnloadedPrelinkedKexts
== NULL
) {
13499 unLoadedCount
= sUnloadedPrelinkedKexts
->getCount();
13500 if (unLoadedCount
== 0) {
13504 for (i
= 0; i
< unLoadedCount
; i
++) {
13505 const OSSymbol
* myBundleID
; // do not release
13507 myBundleID
= OSDynamicCast(OSSymbol
, sUnloadedPrelinkedKexts
->getObject(i
));
13511 if (theBundleID
->isEqualTo(myBundleID
->getCStringNoCopy())) {
13517 IORecursiveLockUnlock(sKextLock
);
13522 #pragma mark Personalities (IOKit Drivers)
13524 /*********************************************************************
13525 *********************************************************************/
13527 OSSharedPtr
<OSArray
>
13528 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
13530 OSSharedPtr
<OSArray
> result
;
13531 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
13532 OSSharedPtr
<OSArray
> personalities
;
13534 OSString
* kextID
= NULL
; // do not release
13535 OSKext
* theKext
= NULL
; // do not release
13537 IORecursiveLockLock(sKextLock
);
13539 /* Let's conservatively guess that any given kext has around 3
13540 * personalities for now.
13542 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
13547 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
13548 if (!kextIterator
) {
13552 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
13553 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
13554 if (theKext
->flags
.requireExplicitLoad
) {
13556 kOSKextLogDebugLevel
|
13557 kOSKextLogLoadFlag
,
13558 "Kext %s requires an explicit kextload; "
13559 "omitting its personalities.",
13560 theKext
->getIdentifierCString());
13561 } else if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
13562 personalities
= theKext
->copyPersonalitiesArray();
13563 if (!personalities
) {
13566 result
->merge(personalities
.get());
13568 // xxx - check for better place to put this log msg
13570 kOSKextLogWarningLevel
|
13571 kOSKextLogLoadFlag
,
13572 "Kext %s is not loadable during safe boot; "
13573 "omitting its personalities.",
13574 theKext
->getIdentifierCString());
13579 IORecursiveLockUnlock(sKextLock
);
13584 /*********************************************************************
13585 *********************************************************************/
13588 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
13590 int numPersonalities
= 0;
13592 OSKextLog(/* kext */ NULL
,
13593 kOSKextLogStepLevel
|
13594 kOSKextLogLoadFlag
,
13595 "Sending all eligible registered kexts' personalities "
13596 "to the IOCatalogue %s.",
13597 startMatching
? "and starting matching" : "but not starting matching");
13599 OSSharedPtr
<OSArray
> personalities
= OSKext::copyAllKextPersonalities(
13600 /* filterSafeBootFlag */ true);
13602 if (personalities
) {
13603 gIOCatalogue
->addDrivers(personalities
.get(), startMatching
);
13604 numPersonalities
= personalities
->getCount();
13607 OSKextLog(/* kext */ NULL
,
13608 kOSKextLogStepLevel
|
13609 kOSKextLogLoadFlag
,
13610 "%d kext personalit%s sent to the IOCatalogue; %s.",
13611 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
13612 startMatching
? "matching started" : "matching not started");
13616 /*********************************************************************
13617 * Do not make a deep copy, just convert the IOKitPersonalities dict
13618 * to an array for sending to the IOCatalogue.
13619 *********************************************************************/
13620 OSSharedPtr
<OSArray
>
13621 OSKext::copyPersonalitiesArray(void)
13623 OSSharedPtr
<OSArray
> result
;
13624 OSDictionary
* personalities
= NULL
; // do not release
13625 OSSharedPtr
<OSCollectionIterator
> personalitiesIterator
;
13627 OSString
* personalityName
= NULL
; // do not release
13628 OSString
* personalityBundleIdentifier
= NULL
; // do not release
13630 personalities
= OSDynamicCast(OSDictionary
,
13631 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13632 if (!personalities
) {
13636 result
= OSArray::withCapacity(personalities
->getCount());
13641 personalitiesIterator
=
13642 OSCollectionIterator::withCollection(personalities
);
13643 if (!personalitiesIterator
) {
13646 while ((personalityName
= OSDynamicCast(OSString
,
13647 personalitiesIterator
->getNextObject()))) {
13648 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13649 personalities
->getObject(personalityName
));
13652 * If the personality doesn't have a CFBundleIdentifier, or if it
13653 * differs from the kext's, insert the kext's ID so we can find it.
13654 * The publisher ID is used to remove personalities from bundles
13657 personalityBundleIdentifier
= OSDynamicCast(OSString
,
13658 personality
->getObject(kCFBundleIdentifierKey
));
13660 if (!personalityBundleIdentifier
) {
13661 personality
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
13662 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
.get())) {
13663 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
.get());
13666 result
->setObject(personality
);
13673 /*********************************************************************
13674 * Might want to change this to a bool return?
13675 *********************************************************************/
13677 OSKext::sendPersonalitiesToCatalog(
13678 bool startMatching
,
13679 OSArray
* personalityNames
)
13681 OSReturn result
= kOSReturnSuccess
;
13682 OSSharedPtr
<OSArray
> personalitiesToSend
;
13683 OSDictionary
* kextPersonalities
= NULL
; // do not release
13686 if (!sLoadEnabled
) {
13688 kOSKextLogErrorLevel
|
13689 kOSKextLogLoadFlag
,
13690 "Kext loading is disabled (attempt to start matching for kext %s).",
13691 getIdentifierCString());
13692 result
= kOSKextReturnDisabled
;
13696 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
13698 kOSKextLogErrorLevel
|
13699 kOSKextLogLoadFlag
,
13700 "Kext %s is not loadable during safe boot; "
13701 "not sending personalities to the IOCatalogue.",
13702 getIdentifierCString());
13703 result
= kOSKextReturnNotLoadable
;
13707 if (!personalityNames
|| !personalityNames
->getCount()) {
13708 personalitiesToSend
= copyPersonalitiesArray();
13710 kextPersonalities
= OSDynamicCast(OSDictionary
,
13711 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13712 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
13716 personalitiesToSend
= OSArray::withCapacity(0);
13717 if (!personalitiesToSend
) {
13718 result
= kOSKextReturnNoMemory
;
13721 count
= personalityNames
->getCount();
13722 for (i
= 0; i
< count
; i
++) {
13723 OSString
* name
= OSDynamicCast(OSString
,
13724 personalityNames
->getObject(i
));
13728 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13729 kextPersonalities
->getObject(name
));
13731 personalitiesToSend
->setObject(personality
);
13735 if (personalitiesToSend
) {
13736 unsigned numPersonalities
= personalitiesToSend
->getCount();
13738 kOSKextLogStepLevel
|
13739 kOSKextLogLoadFlag
,
13740 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13741 getIdentifierCString(),
13743 numPersonalities
> 1 ? "ies" : "y",
13744 startMatching
? " and starting matching" : " but not starting matching");
13745 gIOCatalogue
->addDrivers(personalitiesToSend
.get(), startMatching
);
13751 /*********************************************************************
13752 * xxx - We should allow removing the kext's declared personalities,
13753 * xxx - even with other bundle identifiers.
13754 *********************************************************************/
13756 OSKext::removePersonalitiesFromCatalog(void)
13758 OSSharedPtr
<OSDictionary
> personality
;
13760 personality
= OSDictionary::withCapacity(1);
13761 if (!personality
) {
13764 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
13767 kOSKextLogStepLevel
|
13768 kOSKextLogLoadFlag
,
13769 "Kext %s removing all personalities naming it from the IOCatalogue.",
13770 getIdentifierCString());
13772 /* Have the IOCatalog remove all personalities matching this kext's
13773 * bundle ID and trigger matching anew.
13775 gIOCatalogue
->removeDrivers(personality
.get(), /* startMatching */ true);
13783 #pragma mark Logging
13785 /*********************************************************************
13786 * Do not call any function that takes sKextLock here!
13787 *********************************************************************/
13790 OSKext::setUserSpaceLogFilter(
13791 OSKextLogSpec newUserLogFilter
,
13794 OSKextLogSpec result
;
13795 bool allocError
= false;
13797 /* Do not call any function that takes sKextLoggingLock during
13798 * this critical block. That means do logging after.
13800 IOLockLock(sKextLoggingLock
);
13802 result
= sUserSpaceKextLogFilter
;
13803 sUserSpaceKextLogFilter
= newUserLogFilter
;
13805 if (newUserLogFilter
&& captureFlag
&&
13806 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
13807 // xxx - do some measurements for a good initial capacity?
13808 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
13809 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
13811 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
13816 IOLockUnlock(sKextLoggingLock
);
13818 /* If the config flag itself is changing, log the state change
13819 * going both ways, before setting up the user-space log arrays,
13820 * so that this is only logged in the kernel.
13822 if (result
!= newUserLogFilter
) {
13823 OSKextLog(/* kext */ NULL
,
13824 kOSKextLogDebugLevel
|
13825 kOSKextLogGeneralFlag
,
13826 "User-space log flags changed from 0x%x to 0x%x.",
13827 result
, newUserLogFilter
);
13830 OSKextLog(/* kext */ NULL
,
13831 kOSKextLogErrorLevel
|
13832 kOSKextLogGeneralFlag
,
13833 "Failed to allocate user-space log message arrays.");
13839 /*********************************************************************
13840 * Do not call any function that takes sKextLock here!
13841 *********************************************************************/
13843 OSSharedPtr
<OSArray
>
13844 OSKext::clearUserSpaceLogFilter(void)
13846 OSSharedPtr
<OSArray
> result
;
13847 OSKextLogSpec oldLogFilter
;
13848 OSKextLogSpec newLogFilter
= kOSKextLogSilentFilter
;
13850 /* Do not call any function that takes sKextLoggingLock during
13851 * this critical block. That means do logging after.
13853 IOLockLock(sKextLoggingLock
);
13855 result
= OSArray::withCapacity(2);
13857 result
->setObject(sUserSpaceLogSpecArray
.get());
13858 result
->setObject(sUserSpaceLogMessageArray
.get());
13860 sUserSpaceLogSpecArray
.reset();
13861 sUserSpaceLogMessageArray
.reset();
13863 oldLogFilter
= sUserSpaceKextLogFilter
;
13864 sUserSpaceKextLogFilter
= newLogFilter
;
13866 IOLockUnlock(sKextLoggingLock
);
13868 /* If the config flag itself is changing, log the state change
13869 * going both ways, after tearing down the user-space log
13870 * arrays, so this is only logged within the kernel.
13872 if (oldLogFilter
!= newLogFilter
) {
13873 OSKextLog(/* kext */ NULL
,
13874 kOSKextLogDebugLevel
|
13875 kOSKextLogGeneralFlag
,
13876 "User-space log flags changed from 0x%x to 0x%x.",
13877 oldLogFilter
, newLogFilter
);
13884 /*********************************************************************
13885 * Do not call any function that takes sKextLock here!
13886 *********************************************************************/
13889 OSKext::getUserSpaceLogFilter(void)
13891 OSKextLogSpec result
;
13893 IOLockLock(sKextLoggingLock
);
13894 result
= sUserSpaceKextLogFilter
;
13895 IOLockUnlock(sKextLoggingLock
);
13900 /*********************************************************************
13901 * This function is called by OSMetaClass during kernel C++ setup.
13902 * Be careful what you access here; assume only OSKext::initialize()
13905 * Do not call any function that takes sKextLock here!
13906 *********************************************************************/
13907 #define VTRESET "\033[0m"
13909 #define VTBOLD "\033[1m"
13910 #define VTUNDER "\033[4m"
13912 #define VTRED "\033[31m"
13913 #define VTGREEN "\033[32m"
13914 #define VTYELLOW "\033[33m"
13915 #define VTBLUE "\033[34m"
13916 #define VTMAGENTA "\033[35m"
13917 #define VTCYAN "\033[36m"
13919 inline const char *
13920 colorForFlags(OSKextLogSpec flags
)
13922 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
13924 switch (logLevel
) {
13925 case kOSKextLogErrorLevel
:
13926 return VTRED VTBOLD
;
13927 case kOSKextLogWarningLevel
:
13929 case kOSKextLogBasicLevel
:
13930 return VTYELLOW VTUNDER
;
13931 case kOSKextLogProgressLevel
:
13933 case kOSKextLogStepLevel
:
13935 case kOSKextLogDetailLevel
:
13937 case kOSKextLogDebugLevel
:
13940 return ""; // white
13946 OSKextLogSpec msgLogSpec
,
13947 OSKextLogSpec logFilter
)
13949 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
13950 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
13951 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
13953 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
13954 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
13955 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
13957 /* Explicit messages always get logged.
13959 if (msgLevel
== kOSKextLogExplicitLevel
) {
13963 /* Warnings and errors are logged regardless of the flags.
13965 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
13969 /* A verbose message that isn't for a logging-enabled kext and isn't global
13970 * does *not* get logged.
13972 if (!msgKextGlobal
&& !filterKextGlobal
) {
13976 /* Warnings and errors are logged regardless of the flags.
13977 * All other messages must fit the flags and
13978 * have a level at or below the filter.
13981 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
13991 OSKextLogSpec msgLogSpec
,
13992 const char * format
, ...)
13996 va_start(argList
, format
);
13997 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
14004 OSKextLogSpec msgLogSpec
,
14005 const char * format
,
14006 va_list srcArgList
)
14008 extern int disableConsoleOutput
;
14010 bool logForKernel
= false;
14011 bool logForUser
= false;
14013 char stackBuffer
[120];
14014 uint32_t length
= 0;
14015 char * allocBuffer
= NULL
; // must kfree
14016 OSSharedPtr
<OSNumber
> logSpecNum
;
14017 OSSharedPtr
<OSString
> logString
;
14018 char * buffer
= stackBuffer
; // do not free
14020 IOLockLock(sKextLoggingLock
);
14022 /* Set the kext/global bit in the message spec if we have no
14023 * kext or if the kext requests logging.
14025 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
14026 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
14029 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
14030 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
14031 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
14034 if (!(logForKernel
|| logForUser
)) {
14038 /* No goto from here until past va_end()!
14040 va_copy(argList
, srcArgList
);
14041 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
14044 if (length
+ 1 >= sizeof(stackBuffer
)) {
14045 allocBuffer
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
14046 length
+ 1, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
14047 if (!allocBuffer
) {
14051 /* No goto from here until past va_end()!
14053 va_copy(argList
, srcArgList
);
14054 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
14057 buffer
= allocBuffer
;
14060 /* If user space wants the log message, queue it up.
14062 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
14063 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
14064 logString
= OSString::withCString(buffer
);
14065 if (logSpecNum
&& logString
) {
14066 sUserSpaceLogSpecArray
->setObject(logSpecNum
.get());
14067 sUserSpaceLogMessageArray
->setObject(logString
.get());
14071 /* Always log messages from the kernel according to the kernel's
14074 if (logForKernel
) {
14075 /* If we are in console mode and have a custom log filter,
14076 * colorize the log message.
14078 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
14079 const char * color
= ""; // do not free
14080 color
= colorForFlags(msgLogSpec
);
14081 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
14082 buffer
, color
[0] ? VTRESET
: "");
14084 printf("%s\n", buffer
);
14089 IOLockUnlock(sKextLoggingLock
);
14092 kheap_free(KHEAP_TEMP
, allocBuffer
, (length
+ 1) * sizeof(char));
14097 #if KASLR_IOREG_DEBUG
14099 #define IOLOG_INDENT( the_indention ) \
14102 for ( i = 0; i < (the_indention); i++ ) { \
14107 extern vm_offset_t vm_kernel_stext
;
14108 extern vm_offset_t vm_kernel_etext
;
14109 extern mach_vm_offset_t kext_alloc_base
;
14110 extern mach_vm_offset_t kext_alloc_max
;
14112 bool ScanForAddrInObject(OSObject
* theObject
,
14116 ScanForAddrInObject(OSObject
* theObject
,
14119 const OSMetaClass
* myTypeID
;
14120 OSSharedPtr
<OSCollectionIterator
> myIter
;
14122 OSObject
* myValue
;
14123 bool myResult
= false;
14125 if (theObject
== NULL
) {
14126 IOLog("%s: theObject is NULL \n",
14131 myTypeID
= OSTypeIDInst(theObject
);
14133 if (myTypeID
== OSTypeID(OSDictionary
)) {
14134 OSDictionary
* myDictionary
;
14136 myDictionary
= OSDynamicCast(OSDictionary
, theObject
);
14137 myIter
= OSCollectionIterator::withCollection( myDictionary
);
14138 if (myIter
== NULL
) {
14142 // !! reset the iterator
14145 while ((myKey
= OSDynamicCast(OSSymbol
, myIter
->getNextObject()))) {
14148 myValue
= myDictionary
->getObject(myKey
);
14149 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14150 if (myTempResult
) {
14151 // if we ever get a true result return true
14153 IOLOG_INDENT(indent
);
14154 IOLog("OSDictionary key \"%s\" \n", myKey
->getCStringNoCopy());
14158 // !! release the iterator
14160 } else if (myTypeID
== OSTypeID(OSArray
)) {
14163 myArray
= OSDynamicCast(OSArray
, theObject
);
14164 myIter
= OSCollectionIterator::withCollection(myArray
);
14165 if (myIter
== NULL
) {
14168 // !! reset the iterator
14171 while ((myValue
= myIter
->getNextObject())) {
14173 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14174 if (myTempResult
) {
14175 // if we ever get a true result return true
14177 IOLOG_INDENT(indent
);
14178 IOLog("OSArray: \n");
14181 // !! release the iterator
14183 } else if (myTypeID
== OSTypeID(OSString
) || myTypeID
== OSTypeID(OSSymbol
)) {
14184 // should we look for addresses in strings?
14185 } else if (myTypeID
== OSTypeID(OSData
)) {
14187 unsigned int myLen
;
14188 OSData
* myDataObj
;
14190 myDataObj
= OSDynamicCast(OSData
, theObject
);
14191 myPtrPtr
= (void * *) myDataObj
->getBytesNoCopy();
14192 myLen
= myDataObj
->getLength();
14194 if (myPtrPtr
&& myLen
&& myLen
> 7) {
14196 int myPtrCount
= (myLen
/ sizeof(void *));
14198 for (i
= 0; i
< myPtrCount
; i
++) {
14199 UInt64 numberValue
= (UInt64
) * (myPtrPtr
);
14201 if (kext_alloc_max
!= 0 &&
14202 numberValue
>= kext_alloc_base
&&
14203 numberValue
< kext_alloc_max
) {
14204 OSSharedPtr
<OSKext
> myKext
;
14205 // IOLog("found OSData %p in kext map %p to %p \n",
14207 // (void *) kext_alloc_base,
14208 // (void *) kext_alloc_max);
14210 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) *(myPtrPtr
));
14212 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14214 myKext
->getIdentifierCString());
14218 if (vm_kernel_etext
!= 0 &&
14219 numberValue
>= vm_kernel_stext
&&
14220 numberValue
< vm_kernel_etext
) {
14221 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14223 (void *) vm_kernel_stext
,
14224 (void *) vm_kernel_etext
);
14230 } else if (myTypeID
== OSTypeID(OSBoolean
)) {
14231 // do nothing here...
14232 } else if (myTypeID
== OSTypeID(OSNumber
)) {
14233 OSNumber
* number
= OSDynamicCast(OSNumber
, theObject
);
14235 UInt64 numberValue
= number
->unsigned64BitValue();
14237 if (kext_alloc_max
!= 0 &&
14238 numberValue
>= kext_alloc_base
&&
14239 numberValue
< kext_alloc_max
) {
14240 OSSharedPtr
<OSKext
> myKext
;
14241 IOLog("found OSNumber in kext map %p to %p \n",
14242 (void *) kext_alloc_base
,
14243 (void *) kext_alloc_max
);
14244 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14246 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) numberValue
);
14248 IOLog("found in kext \"%s\" \n",
14249 myKext
->getIdentifierCString());
14254 if (vm_kernel_etext
!= 0 &&
14255 numberValue
>= vm_kernel_stext
&&
14256 numberValue
< vm_kernel_etext
) {
14257 IOLog("found OSNumber in kernel text segment %p to %p \n",
14258 (void *) vm_kernel_stext
,
14259 (void *) vm_kernel_etext
);
14260 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14266 const OSMetaClass
* myMetaClass
= NULL
;
14268 myMetaClass
= theObject
->getMetaClass();
14270 IOLog("class %s \n", myMetaClass
->getClassName());
14272 IOLog("Unknown object \n" );
14279 #endif // KASLR_KEXT_DEBUG
14280 }; /* extern "C" */
14283 #pragma mark Backtrace Dump & kmod_get_info() support
14285 /*********************************************************************
14286 * This function must be safe to call in panic context.
14287 *********************************************************************/
14290 OSKext::printKextsInBacktrace(
14291 vm_offset_t
* addr __unused
,
14292 unsigned int cnt __unused
,
14293 int (* printf_func
)(const char *fmt
, ...) __unused
,
14294 uint32_t flags __unused
)
14296 addr64_t summary_page
= 0;
14297 addr64_t last_summary_page
= 0;
14298 bool found_kmod
= false;
14301 if (kPrintKextsLock
& flags
) {
14302 if (!sKextSummariesLock
) {
14305 IOLockLock(sKextSummariesLock
);
14308 if (!gLoadedKextSummaries
) {
14309 (*printf_func
)(" can't perform kext scan: no kext summary");
14313 summary_page
= trunc_page((addr64_t
)(uintptr_t)gLoadedKextSummaries
);
14314 last_summary_page
= round_page(summary_page
+ sLoadedKextSummariesAllocSize
);
14315 for (; summary_page
< last_summary_page
; summary_page
+= PAGE_SIZE
) {
14316 if (pmap_find_phys(kernel_pmap
, summary_page
) == 0) {
14317 (*printf_func
)(" can't perform kext scan: "
14318 "missing kext summary page %p", summary_page
);
14323 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14324 OSKextLoadedKextSummary
* summary
;
14326 summary
= gLoadedKextSummaries
->summaries
+ i
;
14327 if (!summary
->address
) {
14331 if (!summaryIsInBacktrace(summary
, addr
, cnt
)) {
14336 if (!(kPrintKextsTerse
& flags
)) {
14337 (*printf_func
)(" Kernel Extensions in backtrace:\n");
14342 printSummary(summary
, printf_func
, flags
);
14346 if (kPrintKextsLock
& flags
) {
14347 IOLockUnlock(sKextSummariesLock
);
14353 /*********************************************************************
14354 * This function must be safe to call in panic context.
14355 *********************************************************************/
14358 OSKext::summaryIsInBacktrace(
14359 OSKextLoadedKextSummary
* summary
,
14360 vm_offset_t
* addr
,
14365 for (i
= 0; i
< cnt
; i
++) {
14366 vm_offset_t kscan_addr
= addr
[i
];
14367 #if __has_feature(ptrauth_calls)
14368 kscan_addr
= (vm_offset_t
)VM_KERNEL_STRIP_PTR(kscan_addr
);
14369 #endif /* __has_feature(ptrauth_calls) */
14370 if ((kscan_addr
>= summary
->text_exec_address
) &&
14371 (kscan_addr
< (summary
->text_exec_address
+ summary
->text_exec_size
))) {
14380 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14381 * sKextSummariesLock held.
14383 OSKextLoadedKextSummary
*
14384 OSKext::summaryForAddress(uintptr_t addr
)
14386 #if __has_feature(ptrauth_calls)
14387 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14388 #endif /* __has_feature(ptrauth_calls) */
14389 for (unsigned i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14390 OSKextLoadedKextSummary
*summary
= &gLoadedKextSummaries
->summaries
[i
];
14391 if (!summary
->address
) {
14395 #if VM_MAPPED_KEXTS
14396 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14397 * support split kexts, but we also may unmap the kexts, which can
14398 * race with the above codepath (see OSKext::unload). As such,
14399 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14401 if ((addr
>= summary
->address
) && (addr
< (summary
->address
+ summary
->size
))) {
14405 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)summary
->address
;
14406 kernel_segment_command_t
*seg
;
14408 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
14409 if ((addr
>= seg
->vmaddr
) && (addr
< (seg
->vmaddr
+ seg
->vmsize
))) {
14416 /* addr did not map to any kext */
14422 OSKext::kextForAddress(const void *address
)
14424 void * image
= NULL
;
14425 OSKextActiveAccount
* active
;
14426 OSKext
* kext
= NULL
;
14429 uintptr_t addr
= (uintptr_t) address
;
14435 #if __has_feature(ptrauth_calls)
14436 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14437 #endif /* __has_feature(ptrauth_calls) */
14439 if (sKextAccountsCount
) {
14440 IOSimpleLockLock(sKextAccountsLock
);
14441 // bsearch sKextAccounts list
14442 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
14443 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
14444 if ((addr
>= active
->address
) && (addr
< active
->address_end
)) {
14445 kext
= active
->account
->kext
;
14446 if (kext
&& kext
->kmod_info
) {
14447 image
= (void *) kext
->kmod_info
->address
;
14450 } else if (addr
> active
->address
) {
14452 baseIdx
+= (lim
>> 1) + 1;
14457 IOSimpleLockUnlock(sKextAccountsLock
);
14459 if (!image
&& (addr
>= vm_kernel_stext
) && (addr
< vm_kernel_etext
)) {
14460 image
= (void *) &_mh_execute_header
;
14462 if (!image
&& gLoadedKextSummaries
) {
14463 IOLockLock(sKextSummariesLock
);
14464 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; i
++) {
14465 OSKextLoadedKextSummary
*summary
= gLoadedKextSummaries
->summaries
+ i
;
14466 if (addr
>= summary
->address
&& addr
< summary
->address
+ summary
->size
) {
14467 image
= (void *)summary
->address
;
14470 IOLockUnlock(sKextSummariesLock
);
14477 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14478 * Safe to call in panic context.
14480 static OSKextLoadedKextSummary
*
14481 findSummary(uint32_t tagID
)
14483 OSKextLoadedKextSummary
* summary
;
14484 for (size_t i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14485 summary
= gLoadedKextSummaries
->summaries
+ i
;
14486 if (summary
->loadTag
== tagID
) {
14493 /*********************************************************************
14494 * This function must be safe to call in panic context.
14495 *********************************************************************/
14497 OSKext::printSummary(
14498 OSKextLoadedKextSummary
* summary
,
14499 int (* printf_func
)(const char *fmt
, ...),
14502 kmod_reference_t
* kmod_ref
= NULL
;
14503 uuid_string_t uuid
;
14504 char version
[kOSKextVersionMaxLength
];
14507 OSKextLoadedKextSummary
*dependencySummary
;
14509 if (!OSKextVersionGetString(summary
->version
, version
, sizeof(version
))) {
14510 strlcpy(version
, "unknown version", sizeof(version
));
14512 (void) uuid_unparse(summary
->uuid
, uuid
);
14514 #if defined(__arm__) || defined(__arm64__)
14515 tmpAddr
= summary
->text_exec_address
;
14516 tmpSize
= summary
->text_exec_size
;
14518 tmpAddr
= summary
->address
;
14519 tmpSize
= summary
->size
;
14521 if (kPrintKextsUnslide
& flags
) {
14522 tmpAddr
= ml_static_unslide(tmpAddr
);
14524 (*printf_func
)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14525 (kPrintKextsTerse
& flags
) ? "" : " ",
14526 summary
->name
, version
, uuid
,
14527 tmpAddr
, tmpAddr
+ tmpSize
- 1);
14529 if (kPrintKextsTerse
& flags
) {
14533 /* print dependency info */
14534 for (kmod_ref
= (kmod_reference_t
*) summary
->reference_list
;
14536 kmod_ref
= kmod_ref
->next
) {
14537 kmod_info_t
* rinfo
;
14539 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_ref
)) == 0) {
14540 (*printf_func
)(" kmod dependency scan stopped "
14541 "due to missing dependency page: %p\n",
14542 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)kmod_ref
) : kmod_ref
);
14545 rinfo
= kmod_ref
->info
;
14547 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
14548 (*printf_func
)(" kmod dependency scan stopped "
14549 "due to missing kmod page: %p\n",
14550 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)rinfo
) : rinfo
);
14554 if (!rinfo
->address
) {
14555 continue; // skip fake entries for built-ins
14558 dependencySummary
= findSummary(rinfo
->id
);
14560 tmpAddr
= rinfo
->address
;
14561 tmpSize
= rinfo
->size
;
14562 if (dependencySummary
) {
14563 (void) uuid_unparse(dependencySummary
->uuid
, uuid
);
14564 #if defined(__arm__) || defined(__arm64__)
14565 tmpAddr
= dependencySummary
->text_exec_address
;
14566 tmpSize
= dependencySummary
->text_exec_size
;
14570 if (kPrintKextsUnslide
& flags
) {
14571 tmpAddr
= ml_static_unslide(tmpAddr
);
14573 (*printf_func
)(" dependency: %s(%s)[%s]@%p->%p\n",
14574 rinfo
->name
, rinfo
->version
, uuid
, tmpAddr
, tmpAddr
+ tmpSize
- 1);
14580 #if !defined(__arm__) && !defined(__arm64__)
14581 /*******************************************************************************
14582 * substitute() looks at an input string (a pointer within a larger buffer)
14583 * for a match to a substring, and on match it writes the marker & substitution
14584 * character to an output string, updating the scan (from) and
14585 * output (to) indexes as appropriate.
14586 *******************************************************************************/
14587 static int substitute(
14588 const char * scan_string
,
14590 uint32_t * to_index
,
14591 uint32_t * from_index
,
14592 const char * substring
,
14594 char substitution
);
14596 /* string_out must be at least KMOD_MAX_NAME bytes.
14600 const char * scan_string
,
14602 uint32_t * to_index
,
14603 uint32_t * from_index
,
14604 const char * substring
,
14608 size_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
14610 /* On a substring match, append the marker (if there is one) and then
14611 * the substitution character, updating the output (to) index accordingly.
14612 * Then update the input (from) length by the length of the substring
14613 * that got replaced.
14615 if (!strncmp(scan_string
, substring
, substring_length
)) {
14617 string_out
[(*to_index
)++] = marker
;
14619 string_out
[(*to_index
)++] = substitution
;
14620 (*from_index
) += substring_length
;
14626 /*******************************************************************************
14627 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14628 * KMOD_MAX_NAME characters and performs various substitutions of common
14629 * prefixes & substrings as defined by tables in kext_panic_report.h.
14630 *******************************************************************************/
14631 static void compactIdentifier(
14632 const char * identifier
,
14633 char * identifier_out
,
14634 char ** identifier_out_end
);
14638 const char * identifier
,
14639 char * identifier_out
,
14640 char ** identifier_out_end
)
14642 uint32_t from_index
, to_index
;
14643 uint32_t scan_from_index
= 0;
14644 uint32_t scan_to_index
= 0;
14645 subs_entry_t
* subs_entry
= NULL
;
14648 from_index
= to_index
= 0;
14649 identifier_out
[0] = '\0';
14651 /* Replace certain identifier prefixes with shorter @+character sequences.
14652 * Check the return value of substitute() so we only replace the prefix.
14654 for (subs_entry
= &kext_identifier_prefix_subs
[0];
14655 subs_entry
->substring
&& !did_sub
;
14657 did_sub
= substitute(identifier
, identifier_out
,
14658 &scan_to_index
, &scan_from_index
,
14659 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
14663 /* Now scan through the identifier looking for the common substrings
14664 * and replacing them with shorter !+character sequences via substitute().
14666 for (/* see above */;
14667 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
14669 const char * scan_string
= &identifier
[scan_from_index
];
14673 if (scan_from_index
) {
14674 for (subs_entry
= &kext_identifier_substring_subs
[0];
14675 subs_entry
->substring
&& !did_sub
;
14677 did_sub
= substitute(scan_string
, identifier_out
,
14678 &scan_to_index
, &scan_from_index
,
14679 subs_entry
->substring
, '!', subs_entry
->substitute
);
14683 /* If we didn't substitute, copy the input character to the output.
14686 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
14690 identifier_out
[scan_to_index
] = '\0';
14691 if (identifier_out_end
) {
14692 *identifier_out_end
= &identifier_out
[scan_to_index
];
14697 #endif /* !defined(__arm__) && !defined(__arm64__) */
14699 /*******************************************************************************
14700 * assemble_identifier_and_version() adds to a string buffer a compacted
14701 * bundle identifier followed by a version string.
14702 *******************************************************************************/
14704 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14706 static size_t assemble_identifier_and_version(
14707 kmod_info_t
* kmod_info
,
14708 char * identPlusVers
,
14712 assemble_identifier_and_version(
14713 kmod_info_t
* kmod_info
,
14714 char * identPlusVers
,
14719 #if defined(__arm__) || defined(__arm64__)
14720 result
= strlcpy(identPlusVers
, kmod_info
->name
, KMOD_MAX_NAME
);
14722 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
14723 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
14725 identPlusVers
[result
++] = '\t'; // increment for real char
14726 identPlusVers
[result
] = '\0'; // don't increment for nul char
14727 result
= strlcat(identPlusVers
, kmod_info
->version
, bufSize
);
14728 if (result
>= bufSize
) {
14729 identPlusVers
[bufSize
- 1] = '\0';
14730 result
= bufSize
- 1;
14736 /*******************************************************************************
14737 * Assumes sKextLock is held.
14738 *******************************************************************************/
14741 OSKext::saveLoadedKextPanicListTyped(
14742 const char * prefix
,
14746 uint32_t list_size
)
14749 unsigned int count
, i
;
14751 count
= sLoadedKexts
->getCount();
14758 OSObject
* rawKext
= sLoadedKexts
->getObject(i
);
14759 OSKext
* theKext
= OSDynamicCast(OSKext
, rawKext
);
14761 size_t identPlusVersLength
;
14763 char identPlusVers
[2 * KMOD_MAX_NAME
];
14766 printf("OSKext::saveLoadedKextPanicListTyped - "
14767 "NULL kext in loaded kext list; continuing\n");
14772 printf("OSKext::saveLoadedKextPanicListTyped - "
14773 "Kext type cast failed in loaded kext list; continuing\n");
14777 /* Skip all built-in kexts.
14779 if (theKext
->isKernelComponent()) {
14783 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
14785 /* Filter for kmod name (bundle identifier).
14787 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
14788 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
14792 /* Filter for libraries (kexts that have a compatible version).
14794 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
14795 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
14800 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
14801 printf("kext scan stopped due to missing kmod_info page: %p\n",
14806 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
14808 sizeof(identPlusVers
));
14809 if (!identPlusVersLength
) {
14810 printf("error saving loaded kext info\n");
14814 /* make sure everything fits and we null terminate.
14816 tempLen
= strlcat(paniclist
, identPlusVers
, list_size
);
14817 if (tempLen
>= list_size
) {
14818 // panic list is full, keep it and null terminate
14819 paniclist
[list_size
- 1] = 0x00;
14823 tempLen
= strlcat(paniclist
, "\n", list_size
);
14824 if (tempLen
>= list_size
) {
14825 // panic list is full, keep it and null terminate
14826 paniclist
[list_size
- 1] = 0x00;
14838 /*********************************************************************
14839 *********************************************************************/
14842 OSKext::saveLoadedKextPanicList(void)
14844 char * newlist
= NULL
;
14845 uint32_t newlist_size
= 0;
14847 newlist_size
= KEXT_PANICLIST_SIZE
;
14848 newlist
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, newlist_size
,
14849 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
14852 OSKextLog(/* kext */ NULL
,
14853 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
14854 "Couldn't allocate kext panic log buffer.");
14860 // non-"com.apple." kexts
14861 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14862 /* libs? */ -1, newlist
, newlist_size
) != 0) {
14865 // "com.apple." nonlibrary kexts
14866 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14867 /* libs? */ 0, newlist
, newlist_size
) != 0) {
14870 // "com.apple." library kexts
14871 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14872 /* libs? */ 1, newlist
, newlist_size
) != 0) {
14876 if (loaded_kext_paniclist
) {
14877 kheap_free(KHEAP_DATA_BUFFERS
, loaded_kext_paniclist
,
14878 loaded_kext_paniclist_size
);
14880 loaded_kext_paniclist
= newlist
;
14882 loaded_kext_paniclist_size
= newlist_size
;
14886 kheap_free(KHEAP_TEMP
, newlist
, newlist_size
);
14891 /*********************************************************************
14892 * Assumes sKextLock is held.
14893 *********************************************************************/
14895 OSKext::savePanicString(bool isLoading
)
14900 return; // do not goto finish here b/c of lock
14903 len
= assemble_identifier_and_version( kmod_info
,
14904 (isLoading
) ? last_loaded_str_buf
: last_unloaded_str_buf
,
14905 (isLoading
) ? sizeof(last_loaded_str_buf
) : sizeof(last_unloaded_str_buf
));
14907 printf("error saving unloaded kext info\n");
14912 last_loaded_strlen
= len
;
14913 last_loaded_address
= (void *)kmod_info
->address
;
14914 last_loaded_size
= kmod_info
->size
;
14915 clock_get_uptime(&last_loaded_timestamp
);
14917 last_unloaded_strlen
= len
;
14918 last_unloaded_address
= (void *)kmod_info
->address
;
14919 last_unloaded_size
= kmod_info
->size
;
14920 clock_get_uptime(&last_unloaded_timestamp
);
14927 /*********************************************************************
14928 *********************************************************************/
14931 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
14933 if (last_loaded_strlen
) {
14934 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14935 AbsoluteTime_to_scalar(&last_loaded_timestamp
),
14936 last_loaded_strlen
, last_loaded_str_buf
,
14937 last_loaded_address
, last_loaded_size
);
14940 if (last_unloaded_strlen
) {
14941 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14942 AbsoluteTime_to_scalar(&last_unloaded_timestamp
),
14943 last_unloaded_strlen
, last_unloaded_str_buf
,
14944 last_unloaded_address
, last_unloaded_size
);
14947 printf_func("loaded kexts:\n");
14948 if (loaded_kext_paniclist
&&
14949 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
14950 loaded_kext_paniclist
[0]) {
14951 printf_func("%.*s",
14952 strnlen(loaded_kext_paniclist
, loaded_kext_paniclist_size
),
14953 loaded_kext_paniclist
);
14955 printf_func("(none)\n");
14960 /*********************************************************************
14961 * Assumes sKextLock is held.
14962 *********************************************************************/
14965 OSKext::updateLoadedKextSummaries(void)
14967 kern_return_t result
= KERN_FAILURE
;
14968 OSKextLoadedKextSummaryHeader
*summaryHeader
= NULL
;
14969 OSKextLoadedKextSummaryHeader
*summaryHeaderAlloc
= NULL
;
14971 vm_map_offset_t start
, end
;
14972 size_t summarySize
= 0;
14977 OSKextActiveAccount
* accountingList
;
14978 OSKextActiveAccount
* prevAccountingList
;
14979 uint32_t idx
, accountingListAlloc
, accountingListCount
, prevAccountingListCount
;
14981 prevAccountingList
= NULL
;
14982 prevAccountingListCount
= 0;
14984 #if DEVELOPMENT || DEBUG
14985 if (IORecursiveLockHaveLock(sKextLock
) == false) {
14986 panic("sKextLock must be held");
14990 IOLockLock(sKextSummariesLock
);
14992 count
= sLoadedKexts
->getCount();
14993 for (i
= 0, maxKexts
= 0; i
< count
; ++i
) {
14994 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14995 maxKexts
+= (aKext
&& aKext
->isExecutable());
15001 if (maxKexts
< kOSKextTypicalLoadCount
) {
15002 maxKexts
= kOSKextTypicalLoadCount
;
15005 /* Calculate the size needed for the new summary headers.
15008 size
= sizeof(*gLoadedKextSummaries
);
15009 size
+= maxKexts
* sizeof(*gLoadedKextSummaries
->summaries
);
15010 size
= round_page(size
);
15012 if (gLoadedKextSummaries
== NULL
|| sLoadedKextSummariesAllocSize
< size
) {
15013 if (gLoadedKextSummaries
) {
15014 kmem_free(kernel_map
, (vm_offset_t
)gLoadedKextSummaries
, sLoadedKextSummariesAllocSize
);
15015 gLoadedKextSummaries
= NULL
;
15016 gLoadedKextSummariesTimestamp
= mach_absolute_time();
15017 sLoadedKextSummariesAllocSize
= 0;
15019 result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&summaryHeaderAlloc
, size
, VM_KERN_MEMORY_OSKEXT
);
15020 if (result
!= KERN_SUCCESS
) {
15023 summaryHeader
= summaryHeaderAlloc
;
15024 summarySize
= size
;
15026 summaryHeader
= gLoadedKextSummaries
;
15027 summarySize
= sLoadedKextSummariesAllocSize
;
15029 start
= (vm_map_offset_t
) summaryHeader
;
15030 end
= start
+ summarySize
;
15031 result
= vm_map_protect(kernel_map
,
15036 if (result
!= KERN_SUCCESS
) {
15041 /* Populate the summary header.
15044 bzero(summaryHeader
, summarySize
);
15045 summaryHeader
->version
= kOSKextLoadedKextSummaryVersion
;
15046 summaryHeader
->entry_size
= sizeof(OSKextLoadedKextSummary
);
15048 /* Populate each kext summary.
15051 count
= sLoadedKexts
->getCount();
15052 accountingListAlloc
= 0;
15053 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
15054 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
15055 if (!aKext
|| !aKext
->isExecutable()) {
15059 aKext
->updateLoadedKextSummary(&summaryHeader
->summaries
[j
++]);
15060 summaryHeader
->numSummaries
++;
15061 accountingListAlloc
++;
15064 accountingList
= IONew(typeof(accountingList
[0]), accountingListAlloc
);
15065 accountingListCount
= 0;
15066 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
15067 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
15068 if (!aKext
|| !aKext
->isExecutable()) {
15072 OSKextActiveAccount activeAccount
;
15073 aKext
->updateActiveAccount(&activeAccount
);
15074 // order by address
15075 for (idx
= 0; idx
< accountingListCount
; idx
++) {
15076 if (activeAccount
.address
< accountingList
[idx
].address
) {
15080 bcopy(&accountingList
[idx
], &accountingList
[idx
+ 1], (accountingListCount
- idx
) * sizeof(accountingList
[0]));
15081 accountingList
[idx
] = activeAccount
;
15082 accountingListCount
++;
15084 assert(accountingListCount
== accountingListAlloc
);
15085 /* Write protect the buffer and move it into place.
15088 start
= (vm_map_offset_t
) summaryHeader
;
15089 end
= start
+ summarySize
;
15091 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_READ
, FALSE
);
15092 if (result
!= KERN_SUCCESS
) {
15096 gLoadedKextSummaries
= summaryHeader
;
15097 gLoadedKextSummariesTimestamp
= mach_absolute_time();
15098 sLoadedKextSummariesAllocSize
= summarySize
;
15099 summaryHeaderAlloc
= NULL
;
15101 /* Call the magic breakpoint function through a static function pointer so
15102 * the compiler can't optimize the function away.
15104 if (sLoadedKextSummariesUpdated
) {
15105 (*sLoadedKextSummariesUpdated
)();
15108 IOSimpleLockLock(sKextAccountsLock
);
15109 prevAccountingList
= sKextAccounts
;
15110 prevAccountingListCount
= sKextAccountsCount
;
15111 sKextAccounts
= accountingList
;
15112 sKextAccountsCount
= accountingListCount
;
15113 IOSimpleLockUnlock(sKextAccountsLock
);
15116 IOLockUnlock(sKextSummariesLock
);
15118 /* If we had to allocate a new buffer but failed to generate the summaries,
15121 if (summaryHeaderAlloc
) {
15122 kmem_free(kernel_map
, (vm_offset_t
)summaryHeaderAlloc
, summarySize
);
15124 if (prevAccountingList
) {
15125 IODelete(prevAccountingList
, typeof(accountingList
[0]), prevAccountingListCount
);
15131 /*********************************************************************
15132 *********************************************************************/
15134 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary
*summary
)
15136 OSSharedPtr
<OSData
> uuid
;
15138 strlcpy(summary
->name
, getIdentifierCString(),
15139 sizeof(summary
->name
));
15143 memcpy(summary
->uuid
, uuid
->getBytesNoCopy(), sizeof(summary
->uuid
));
15146 if (flags
.builtin
) {
15147 // this value will stop lldb from parsing the mach-o header
15148 // summary->address = UINT64_MAX;
15149 // summary->size = 0;
15150 summary
->address
= kmod_info
->address
;
15151 summary
->size
= kmod_info
->size
;
15153 summary
->address
= kmod_info
->address
;
15154 summary
->size
= kmod_info
->size
;
15156 summary
->version
= getVersion();
15157 summary
->loadTag
= kmod_info
->id
;
15158 summary
->flags
= 0;
15159 summary
->reference_list
= (uint64_t) kmod_info
->reference_list
;
15161 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT_EXEC", &summary
->text_exec_size
);
15162 if (summary
->text_exec_address
== 0) {
15163 // Fallback to __TEXT
15164 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT", &summary
->text_exec_size
);
15169 /*********************************************************************
15170 *********************************************************************/
15173 OSKext::updateActiveAccount(OSKextActiveAccount
*accountp
)
15175 kernel_mach_header_t
*hdr
= NULL
;
15176 kernel_segment_command_t
*seg
= NULL
;
15178 bzero(accountp
, sizeof(*accountp
));
15180 hdr
= (kernel_mach_header_t
*)kmod_info
->address
;
15181 if (getcommandfromheader(hdr
, LC_SEGMENT_SPLIT_INFO
) || isInFileset()) {
15183 * If this kext supports split segments (or is in a new
15184 * MH_FILESET kext collection), use the first
15185 * executable segment as the range for instructions
15186 * (and thus for backtracing.
15188 for (seg
= firstsegfromheader(hdr
); seg
!= NULL
; seg
= nextsegfromheader(hdr
, seg
)) {
15189 if (seg
->initprot
& VM_PROT_EXECUTE
) {
15195 accountp
->address
= seg
->vmaddr
;
15196 if (accountp
->address
) {
15197 accountp
->address_end
= seg
->vmaddr
+ seg
->vmsize
;
15200 /* For non-split kexts and for kexts without executable
15201 * segments, just use the kmod_info range (as the kext
15202 * is either all in one range or should not show up in
15203 * instruction backtraces).
15205 accountp
->address
= kmod_info
->address
;
15206 if (accountp
->address
) {
15207 accountp
->address_end
= kmod_info
->address
+ kmod_info
->size
;
15211 accountp
->account
= this->account
;
15215 OSKext::isDriverKit(void)
15217 OSString
*bundleType
;
15220 bundleType
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
));
15221 if (bundleType
&& bundleType
->isEqualTo(kOSKextBundlePackageTypeDriverKit
)) {
15229 OSKext::isInFileset(void)
15232 goto check_prelinked
;
15235 if (kmod_info
->address
&& kernel_mach_header_is_in_fileset((kernel_mach_header_t
*)kmod_info
->address
)) {
15240 if (isPrelinked()) {
15242 * If we haven't setup kmod_info yet, but we know
15243 * we're loading a prelinked kext in an MH_FILESET KC,
15246 kc_format_t kc_format
;
15247 if (PE_get_primary_kc_format(&kc_format
) && kc_format
== KCFormatFileset
) {
15255 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t
*seg
)
15257 kern_return_t result
;
15258 if (!super::init()) {
15261 if (seg
== nullptr) {
15264 result
= kmem_alloc_pageable(kernel_map
, (vm_offset_t
*)&data
, seg
->vmsize
, VM_KERN_MEMORY_KEXT
);
15265 if (result
!= KERN_SUCCESS
) {
15268 memcpy((void *)data
, (const void *)seg
->vmaddr
, seg
->vmsize
);
15269 savedSegment
= seg
;
15270 vmsize
= seg
->vmsize
;
15271 vmaddr
= seg
->vmaddr
;
15275 OSSharedPtr
<OSKextSavedMutableSegment
>
15276 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t
*seg
)
15278 OSSharedPtr
<OSKextSavedMutableSegment
> me
= OSMakeShared
<OSKextSavedMutableSegment
>();
15279 if (me
&& !me
->initWithSegment(seg
)) {
15286 OSKextSavedMutableSegment::free(void)
15289 kmem_free(kernel_map
, (vm_offset_t
)data
, vmsize
);
15294 OSKextSavedMutableSegment::getVMAddr() const
15300 OSKextSavedMutableSegment::getVMSize() const
15306 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t
*seg
)
15308 if (seg
!= savedSegment
) {
15309 return kOSKextReturnInvalidArgument
;
15311 if (seg
->vmaddr
!= vmaddr
|| seg
->vmsize
!= vmsize
) {
15312 return kOSKextReturnInvalidArgument
;
15314 memcpy((void *)seg
->vmaddr
, data
, vmsize
);
15315 return kOSReturnSuccess
;
15318 extern "C" kern_return_t
15319 OSKextSetReceiptQueried(void)
15321 OSKextLog(/* kext */ NULL
,
15322 kOSKextLogStepLevel
| kOSKextLogGeneralFlag
,
15323 "Setting kext receipt as queried");
15325 IOService::publishResource(kOSKextReceiptQueried
, kOSBooleanTrue
);
15326 return KERN_SUCCESS
;
15329 extern "C" const vm_allocation_site_t
*
15330 OSKextGetAllocationSiteForCaller(uintptr_t address
)
15332 OSKextActiveAccount
* active
;
15333 vm_allocation_site_t
* site
;
15334 vm_allocation_site_t
* releasesite
;
15338 #if __has_feature(ptrauth_calls)
15339 address
= (uintptr_t)VM_KERNEL_STRIP_PTR(address
);
15340 #endif /* __has_feature(ptrauth_calls) */
15342 IOSimpleLockLock(sKextAccountsLock
);
15343 site
= releasesite
= NULL
;
15345 // bsearch sKextAccounts list
15346 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
15347 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
15348 if ((address
>= active
->address
) && (address
< active
->address_end
)) {
15349 site
= &active
->account
->site
;
15351 vm_tag_alloc_locked(site
, &releasesite
);
15354 } else if (address
> active
->address
) {
15356 baseIdx
+= (lim
>> 1) + 1;
15361 IOSimpleLockUnlock(sKextAccountsLock
);
15363 kern_allocation_name_release(releasesite
);
15369 extern "C" uint32_t
15370 OSKextGetKmodIDForSite(const vm_allocation_site_t
* site
, char * name
, vm_size_t namelen
)
15372 OSKextAccount
* account
= (typeof(account
))site
;
15373 const char * kname
;
15376 if (account
->kext
) {
15377 kname
= account
->kext
->getIdentifierCString();
15381 strlcpy(name
, kname
, namelen
);
15384 return account
->loadTag
;
15388 OSKextFreeSite(vm_allocation_site_t
* site
)
15390 OSKextAccount
* freeAccount
= (typeof(freeAccount
))site
;
15391 IODelete(freeAccount
, OSKextAccount
, 1);
15394 /*********************************************************************
15395 *********************************************************************/
15397 #if CONFIG_IMAGEBOOT
15399 OSKextGetUUIDForName(const char *name
, uuid_t uuid
)
15401 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithIdentifier(name
);
15406 OSSharedPtr
<OSData
> uuid_data
= kext
->copyUUID();
15408 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_t
));
15417 sysctl_willuserspacereboot
15418 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
15420 int new_value
= 0, old_value
= 0, changed
= 0;
15421 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
15426 OSKext::willUserspaceReboot();
15431 static SYSCTL_PROC(_kern
, OID_AUTO
, willuserspacereboot
,
15432 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
15433 NULL
, 0, sysctl_willuserspacereboot
, "I", "");