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_to_remove
= NULL
;
980 const char __unused
* dt_segment_name
= NULL
;
981 void __unused
* segment_paddress
= NULL
;
982 int __unused segment_size
= 0;
984 OSKextLog(/* kext */ NULL
,
985 kOSKextLogProgressLevel
|
986 kOSKextLogGeneralFlag
,
987 "Jettisoning kext bootstrap segments.");
990 * keep the linkedit segment around when booted from a new MH_FILESET
991 * KC because all the kexts shared a linkedit segment.
993 kc_format_t kc_format
;
994 if (!PE_get_primary_kc_format(&kc_format
)) {
995 OSKextLog(/* kext */ NULL
,
996 kOSKextLogErrorLevel
|
997 kOSKextLogGeneralFlag
,
998 "Unable to determine primary KC format");
1002 * Dispose of unnecessary stuff that the booter didn't need to load.
1004 dt_result
= IODTGetLoaderInfo(dt_kernel_header_name
,
1005 (void **)&dt_mach_header
, &dt_mach_header_size
);
1006 if (dt_result
== 0 && dt_mach_header
) {
1007 IODTFreeLoaderInfo(dt_kernel_header_name
, (void *)dt_mach_header
,
1008 round_page_32(dt_mach_header_size
));
1010 dt_result
= IODTGetLoaderInfo(dt_kernel_symtab_name
,
1011 (void **)&dt_symtab
, &dt_symtab_size
);
1012 if (dt_result
== 0 && dt_symtab
) {
1013 IODTFreeLoaderInfo(dt_kernel_symtab_name
, (void *)dt_symtab
,
1014 round_page_32(dt_symtab_size
));
1018 * KLD bootstrap segment.
1020 // xxx - should rename KLD segment
1021 seg_to_remove
= getsegbyname("__KLD");
1022 if (seg_to_remove
) {
1023 OSRuntimeUnloadCPPForSegment(seg_to_remove
);
1026 #if __arm__ || __arm64__
1027 /* Free the memory that was set up by bootx.
1029 dt_segment_name
= "Kernel-__KLD";
1030 if (0 == IODTGetLoaderInfo(dt_segment_name
, &segment_paddress
, &segment_size
)) {
1031 /* We cannot free this with KTRR enabled, as we cannot
1032 * update the permissions on the KLD range this late
1033 * in the boot process.
1035 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
1038 #elif __i386__ || __x86_64__
1039 /* On x86, use the mapping data from the segment load command to
1040 * unload KLD directly.
1041 * This may invalidate any assumptions about "avail_start"
1042 * defining the lower bound for valid physical addresses.
1044 if (seg_to_remove
&& seg_to_remove
->vmaddr
&& seg_to_remove
->vmsize
) {
1045 bzero((void *)seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
1046 ml_static_mfree(seg_to_remove
->vmaddr
, seg_to_remove
->vmsize
);
1052 seg_to_remove
= NULL
;
1055 * Prelinked kernel's symtab (if there is one).
1057 if (kc_format
!= KCFormatFileset
) {
1058 kernel_section_t
* sect
;
1059 sect
= getsectbyname("__PRELINK", "__symtab");
1060 if (sect
&& sect
->addr
&& sect
->size
) {
1061 ml_static_mfree(sect
->addr
, sect
->size
);
1065 seg_to_remove
= (kernel_segment_command_t
*)getsegbyname("__LINKEDIT");
1067 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1068 * pageable, unless keepsyms is set. To do that, we have to copy it from
1069 * its booter-allocated memory, free the booter memory, reallocate proper
1070 * managed memory, then copy the segment back in.
1072 * NOTE: This optimization is not valid for fileset KCs because each
1073 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1074 * that points to one fileset-global LINKEDIT segment. This
1075 * optimization is also only valid for platforms that support vm
1076 * mapped kexts or mapped kext collections (pageable KCs)
1079 if (!sKeepSymbols
&& kc_format
!= KCFormatFileset
) {
1080 kern_return_t mem_result
;
1081 void *seg_copy
= NULL
;
1082 void *seg_data
= NULL
;
1083 vm_map_offset_t seg_offset
= 0;
1084 vm_map_offset_t seg_copy_offset
= 0;
1085 vm_map_size_t seg_length
= 0;
1087 seg_data
= (void *) seg_to_remove
->vmaddr
;
1088 seg_offset
= (vm_map_offset_t
) seg_to_remove
->vmaddr
;
1089 seg_length
= (vm_map_size_t
) seg_to_remove
->vmsize
;
1091 /* Allocate space for the LINKEDIT copy.
1093 mem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*) &seg_copy
,
1094 seg_length
, VM_KERN_MEMORY_KEXT
);
1095 if (mem_result
!= KERN_SUCCESS
) {
1096 OSKextLog(/* kext */ NULL
,
1097 kOSKextLogErrorLevel
|
1098 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1099 "Can't copy __LINKEDIT segment for VM reassign.");
1102 seg_copy_offset
= (vm_map_offset_t
) seg_copy
;
1106 memcpy(seg_copy
, seg_data
, seg_length
);
1108 /* Dump the booter memory.
1110 ml_static_mfree(seg_offset
, seg_length
);
1112 /* Set up the VM region.
1114 mem_result
= vm_map_enter_mem_object(
1117 seg_length
, /* mask */ 0,
1118 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
1119 VM_MAP_KERNEL_FLAGS_NONE
,
1120 VM_KERN_MEMORY_NONE
,
1122 (vm_object_offset_t
) 0,
1124 /* cur_protection */ VM_PROT_READ
| VM_PROT_WRITE
,
1125 /* max_protection */ VM_PROT_ALL
,
1126 /* inheritance */ VM_INHERIT_DEFAULT
);
1127 if ((mem_result
!= KERN_SUCCESS
) ||
1128 (seg_offset
!= (vm_map_offset_t
) seg_data
)) {
1129 OSKextLog(/* kext */ NULL
,
1130 kOSKextLogErrorLevel
|
1131 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1132 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1133 seg_data
, seg_length
, mem_result
);
1137 /* And copy it back.
1139 memcpy(seg_data
, seg_copy
, seg_length
);
1143 kmem_free(kernel_map
, seg_copy_offset
, seg_length
);
1144 } else if (!sKeepSymbols
&& kc_format
== KCFormatFileset
) {
1145 /* Remove the linkedit segment of the Boot KC */
1146 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)PE_get_kc_header(KCKindPrimary
);
1147 OSKext::jettisonFileSetLinkeditSegment(mh
);
1149 #else // !VM_MAPPED_KEXTS
1151 * Dump the LINKEDIT segment, unless keepsyms is set.
1153 if (!sKeepSymbols
&& kc_format
!= KCFormatFileset
) {
1154 dt_segment_name
= "Kernel-__LINKEDIT";
1155 if (0 == IODTGetLoaderInfo(dt_segment_name
,
1156 &segment_paddress
, &segment_size
)) {
1157 #ifdef SECURE_KERNEL
1158 vm_offset_t vmaddr
= ml_static_ptovirt((vm_offset_t
)segment_paddress
);
1159 bzero((void*)vmaddr
, segment_size
);
1161 IODTFreeLoaderInfo(dt_segment_name
, (void *)segment_paddress
,
1165 OSKextLog(/* kext */ NULL
,
1166 kOSKextLogBasicLevel
|
1167 kOSKextLogGeneralFlag
,
1168 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1170 #endif // VM_MAPPED_KEXTS
1172 seg_to_remove
= NULL
;
1174 result
= kOSReturnSuccess
;
1180 /*********************************************************************
1181 *********************************************************************/
1183 OSKext::flushNonloadedKexts(
1184 Boolean flushPrelinkedKexts
)
1186 OSSharedPtr
<OSSet
> keepKexts
;
1188 /* TODO: make this more efficient with MH_FILESET kexts */
1190 // Do not unload prelinked kexts on arm because the kernelcache is not
1191 // structured in a way that allows them to be unmapped
1192 #if !defined(__x86_64__)
1193 flushPrelinkedKexts
= false;
1194 #endif /* defined(__x86_64__) */
1196 IORecursiveLockLock(sKextLock
);
1198 OSKextLog(/* kext */ NULL
,
1199 kOSKextLogProgressLevel
|
1200 kOSKextLogKextBookkeepingFlag
,
1201 "Flushing nonloaded kexts and other unused data.");
1203 OSKext::considerDestroyingLinkContext();
1205 /* If we aren't flushing unused prelinked kexts, we have to put them
1206 * aside while we flush everything else so make a container for them.
1208 keepKexts
= OSSet::withCapacity(16);
1213 /* Set aside prelinked kexts (in-use or not) and break
1214 * any lingering inter-kext references for nonloaded kexts
1215 * so they have min. retain counts.
1218 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisID __unused
, OSObject
* obj
) {
1219 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1223 if (!flushPrelinkedKexts
&& thisKext
->isPrelinked()) {
1224 keepKexts
->setObject(thisKext
);
1225 } else if (!thisKext
->declaresExecutable()) {
1227 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1228 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1229 * flushNonloadedKexts().
1230 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1232 keepKexts
->setObject(thisKext
);
1233 } else if (thisKext
->isInFileset()) {
1234 /* keep all kexts in the new MH_FILESET KC */
1235 keepKexts
->setObject(thisKext
);
1238 thisKext
->flushDependencies(/* forceIfLoaded */ false);
1242 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1244 sKextsByID
->flushCollection();
1246 /* Now put the loaded kexts back into the ID dictionary.
1248 sLoadedKexts
->iterateObjects(^bool (OSObject
* obj
) {
1249 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1253 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
1257 /* Finally, put back the kept kexts if we saved any.
1259 keepKexts
->iterateObjects(^bool (OSObject
* obj
) {
1260 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1264 sKextsByID
->setObject(thisKext
->getIdentifierCString(), thisKext
);
1269 IORecursiveLockUnlock(sKextLock
);
1272 #else /* !CONFIG_KXLD */
1275 OSKext::flushNonloadedKexts(
1276 Boolean flushPrelinkedKexts __unused
)
1278 IORecursiveLockLock(sKextLock
);
1280 OSKextLog(/* kext */ NULL
,
1281 kOSKextLogProgressLevel
|
1282 kOSKextLogKextBookkeepingFlag
,
1283 "Flushing dependency info for non-loaded kexts.");
1286 * In a world where we don't dynamically link kexts, they all come
1287 * from a kext collection that's either in wired memory, or
1288 * wire-on-demand. We don't need to mess around with moving kexts in
1289 * and out of the sKextsByID array - they can all just stay there.
1290 * Here we just flush the dependency list for kexts that are not
1293 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisID __unused
, OSObject
* obj
) {
1294 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
1298 thisKext
->flushDependencies(/* forceIfLoaded */ false);
1302 IORecursiveLockUnlock(sKextLock
);
1306 #endif /* CONFIG_KXLD */
1308 /*********************************************************************
1309 *********************************************************************/
1312 OSKext::setIOKitDaemonActive(bool active
)
1314 IOServiceTrace(IOSERVICE_KEXTD_ALIVE
, 0, 0, 0, 0);
1315 IORecursiveLockLock(sKextLock
);
1316 sIOKitDaemonActive
= active
;
1317 if (sKernelRequests
->getCount()) {
1318 OSKext::pingIOKitDaemon();
1320 IORecursiveLockUnlock(sKextLock
);
1325 /*********************************************************************
1326 * OSKextLib.cpp might need access to this someday but for now it's
1328 *********************************************************************/
1330 extern void ipc_port_release_send(ipc_port_t
);
1335 OSKext::pingIOKitDaemon(void)
1337 OSReturn result
= kOSReturnError
;
1339 mach_port_t kextd_port
= IPC_PORT_NULL
;
1341 if (!sIOKitDaemonActive
) {
1342 result
= kOSKextReturnDisabled
; // basically unavailable
1346 result
= host_get_kextd_port(host_priv_self(), &kextd_port
);
1347 if (result
!= KERN_SUCCESS
|| !IPC_PORT_VALID(kextd_port
)) {
1348 OSKextLog(/* kext */ NULL
,
1349 kOSKextLogErrorLevel
|
1351 "Can't get " kIOKitDaemonName
" port.");
1355 result
= kextd_ping(kextd_port
);
1356 if (result
!= KERN_SUCCESS
) {
1357 OSKextLog(/* kext */ NULL
,
1358 kOSKextLogErrorLevel
|
1360 kIOKitDaemonName
" ping failed (0x%x).", (int)result
);
1365 if (IPC_PORT_VALID(kextd_port
)) {
1366 ipc_port_release_send(kextd_port
);
1373 /*********************************************************************
1374 *********************************************************************/
1377 OSKext::setDeferredLoadSucceeded(Boolean succeeded
)
1379 IORecursiveLockLock(sKextLock
);
1380 sDeferredLoadSucceeded
= succeeded
;
1381 IORecursiveLockUnlock(sKextLock
);
1386 /*********************************************************************
1387 * Called from IOSystemShutdownNotification.
1388 *********************************************************************/
1391 OSKext::willShutdown(void)
1394 OSReturn checkResult
= kOSReturnError
;
1396 OSSharedPtr
<OSDictionary
> exitRequest
;
1398 IORecursiveLockLock(sKextLock
);
1400 OSKext::setLoadEnabled(false);
1401 OSKext::setUnloadEnabled(false);
1402 OSKext::setAutounloadsEnabled(false);
1403 OSKext::setKernelRequestsEnabled(false);
1405 #if defined(__x86_64__) || defined(__i386__)
1406 if (IOPMRootDomainGetWillShutdown()) {
1407 OSKext::freeKCFileSetcontrol();
1409 #endif // (__x86_64__) || defined(__i386__)
1412 OSKextLog(/* kext */ NULL
,
1413 kOSKextLogProgressLevel
|
1414 kOSKextLogGeneralFlag
,
1415 "System shutdown; requesting immediate " kIOKitDaemonName
" exit.");
1417 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit
,
1419 if (checkResult
!= kOSReturnSuccess
) {
1422 if (!sKernelRequests
->setObject(exitRequest
.get())) {
1426 OSKext::pingIOKitDaemon();
1431 IORecursiveLockUnlock(sKextLock
);
1436 OSKext::willUserspaceReboot(void)
1438 OSKext::willShutdown();
1439 IOService::userSpaceWillReboot();
1440 gIOCatalogue
->terminateDriversForUserspaceReboot();
1444 OSKext::resetAfterUserspaceReboot(void)
1446 OSSharedPtr
<OSArray
> arr
= OSArray::withCapacity(1);
1447 IOService::updateConsoleUsers(arr
.get(), 0, true /* after_userspace_reboot */);
1449 IORecursiveLockLock(sKextLock
);
1450 gIOCatalogue
->resetAfterUserspaceReboot();
1451 IOService::userSpaceDidReboot();
1452 OSKext::setLoadEnabled(true);
1453 OSKext::setUnloadEnabled(true);
1454 OSKext::setAutounloadsEnabled(true);
1455 OSKext::setKernelRequestsEnabled(true);
1456 sOSKextWasResetAfterUserspaceReboot
= true;
1457 IORecursiveLockUnlock(sKextLock
);
1461 OSKextResetAfterUserspaceReboot(void)
1463 OSKext::resetAfterUserspaceReboot();
1466 /*********************************************************************
1467 *********************************************************************/
1470 OSKext::getLoadEnabled(void)
1474 IORecursiveLockLock(sKextLock
);
1475 result
= sLoadEnabled
;
1476 IORecursiveLockUnlock(sKextLock
);
1480 /*********************************************************************
1481 *********************************************************************/
1484 OSKext::setLoadEnabled(bool flag
)
1488 IORecursiveLockLock(sKextLock
);
1489 result
= sLoadEnabled
;
1490 sLoadEnabled
= (flag
? true : false);
1492 if (sLoadEnabled
!= result
) {
1493 OSKextLog(/* kext */ NULL
,
1494 kOSKextLogBasicLevel
|
1496 "Kext loading now %sabled.", sLoadEnabled
? "en" : "dis");
1499 IORecursiveLockUnlock(sKextLock
);
1504 /*********************************************************************
1505 *********************************************************************/
1508 OSKext::getUnloadEnabled(void)
1512 IORecursiveLockLock(sKextLock
);
1513 result
= sUnloadEnabled
;
1514 IORecursiveLockUnlock(sKextLock
);
1518 /*********************************************************************
1519 *********************************************************************/
1522 OSKext::setUnloadEnabled(bool flag
)
1526 IORecursiveLockLock(sKextLock
);
1527 result
= sUnloadEnabled
;
1528 sUnloadEnabled
= (flag
? true : false);
1529 IORecursiveLockUnlock(sKextLock
);
1531 if (sUnloadEnabled
!= result
) {
1532 OSKextLog(/* kext */ NULL
,
1533 kOSKextLogBasicLevel
|
1534 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1535 "Kext unloading now %sabled.", sUnloadEnabled
? "en" : "dis");
1541 /*********************************************************************
1542 * Do not call any function that takes sKextLock here!
1543 *********************************************************************/
1546 OSKext::getAutounloadEnabled(void)
1550 IORecursiveLockLock(sKextInnerLock
);
1551 result
= sAutounloadEnabled
? true : false;
1552 IORecursiveLockUnlock(sKextInnerLock
);
1556 /*********************************************************************
1557 * Do not call any function that takes sKextLock here!
1558 *********************************************************************/
1561 OSKext::setAutounloadsEnabled(bool flag
)
1565 IORecursiveLockLock(sKextInnerLock
);
1567 result
= sAutounloadEnabled
;
1568 sAutounloadEnabled
= (flag
? true : false);
1569 if (!sAutounloadEnabled
&& sUnloadCallout
) {
1570 thread_call_cancel(sUnloadCallout
);
1573 if (sAutounloadEnabled
!= result
) {
1574 OSKextLog(/* kext */ NULL
,
1575 kOSKextLogBasicLevel
|
1576 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
1577 "Kext autounloading now %sabled.",
1578 sAutounloadEnabled
? "en" : "dis");
1581 IORecursiveLockUnlock(sKextInnerLock
);
1586 /*********************************************************************
1587 *********************************************************************/
1588 /* instance method operating on OSKext field */
1590 OSKext::setAutounloadEnabled(bool flag
)
1592 bool result
= flags
.autounloadEnabled
? true : false;
1593 flags
.autounloadEnabled
= flag
? 1 : 0;
1595 if (result
!= (flag
? true : false)) {
1597 kOSKextLogProgressLevel
|
1598 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
1599 "Autounloading for kext %s now %sabled.",
1600 getIdentifierCString(),
1601 flags
.autounloadEnabled
? "en" : "dis");
1606 /*********************************************************************
1607 *********************************************************************/
1610 OSKext::setKernelRequestsEnabled(bool flag
)
1614 IORecursiveLockLock(sKextLock
);
1615 result
= sKernelRequestsEnabled
;
1616 sKernelRequestsEnabled
= flag
? true : false;
1618 if (sKernelRequestsEnabled
!= result
) {
1619 OSKextLog(/* kext */ NULL
,
1620 kOSKextLogBasicLevel
|
1621 kOSKextLogGeneralFlag
,
1622 "Kernel requests now %sabled.",
1623 sKernelRequestsEnabled
? "en" : "dis");
1625 IORecursiveLockUnlock(sKextLock
);
1629 /*********************************************************************
1630 *********************************************************************/
1633 OSKext::getKernelRequestsEnabled(void)
1637 IORecursiveLockLock(sKextLock
);
1638 result
= sKernelRequestsEnabled
;
1639 IORecursiveLockUnlock(sKextLock
);
1644 segmentIsMutable(kernel_segment_command_t
*seg
)
1646 /* Mutable segments have to have VM_PROT_WRITE */
1647 if ((seg
->maxprot
& VM_PROT_WRITE
) == 0) {
1650 /* Exclude the __DATA_CONST segment */
1651 if (strncmp(seg
->segname
, "__DATA_CONST", sizeof(seg
->segname
)) == 0) {
1654 /* Exclude __LINKEDIT */
1655 if (strncmp(seg
->segname
, "__LINKEDIT", sizeof(seg
->segname
)) == 0) {
1662 #pragma mark Kext Life Cycle
1664 /*********************************************************************
1665 *********************************************************************/
1667 OSKext::withPrelinkedInfoDict(
1668 OSDictionary
* anInfoDict
,
1669 bool doCoalescedSlides
,
1672 OSSharedPtr
<OSKext
> newKext(OSMakeShared
<OSKext
>());
1674 if (newKext
&& !newKext
->initWithPrelinkedInfoDict(anInfoDict
, doCoalescedSlides
, type
)) {
1681 /*********************************************************************
1682 *********************************************************************/
1684 OSKext::initWithPrelinkedInfoDict(
1685 OSDictionary
* anInfoDict
,
1686 bool doCoalescedSlides
,
1689 bool result
= false;
1690 OSString
* kextPath
= NULL
; // do not release
1691 OSNumber
* addressNum
= NULL
; // reused; do not release
1692 OSNumber
* lengthNum
= NULL
; // reused; do not release
1693 OSBoolean
* scratchBool
= NULL
; // do not release
1694 void * data
= NULL
; // do not free
1695 void * srcData
= NULL
; // do not free
1696 OSSharedPtr
<OSData
> prelinkedExecutable
;
1697 uint32_t length
= 0; // reused
1698 uintptr_t kext_slide
= PE_get_kc_slide(type
);
1699 bool shouldSaveSegments
= false;
1701 if (!super::init()) {
1705 /* Get the path. Don't look for an arch-specific path property.
1707 kextPath
= OSDynamicCast(OSString
,
1708 anInfoDict
->getObject(kPrelinkBundlePathKey
));
1710 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
1714 #if KASLR_KEXT_DEBUG
1715 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides
, getIdentifierCString());
1718 /* Also get the executable's bundle-relative path if present.
1719 * Don't look for an arch-specific path property.
1721 executableRelPath
.reset(OSDynamicCast(OSString
,
1722 anInfoDict
->getObject(kPrelinkExecutableRelativePathKey
)), OSRetain
);
1723 userExecutableRelPath
.reset(OSDynamicCast(OSString
,
1724 anInfoDict
->getObject(kCFBundleDriverKitExecutableKey
)), OSRetain
);
1726 /* Don't need the paths to be in the info dictionary any more.
1728 anInfoDict
->removeObject(kPrelinkBundlePathKey
);
1729 anInfoDict
->removeObject(kPrelinkExecutableRelativePathKey
);
1731 scratchBool
= OSDynamicCast(OSBoolean
,
1732 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey
));
1733 if (scratchBool
== kOSBooleanTrue
) {
1734 flags
.requireExplicitLoad
= 1;
1737 /* Create an OSData wrapper around the linked executable.
1739 addressNum
= OSDynamicCast(OSNumber
,
1740 anInfoDict
->getObject(kPrelinkExecutableLoadKey
));
1741 if (addressNum
&& addressNum
->unsigned64BitValue() != kOSKextCodelessKextLoadAddr
) {
1742 lengthNum
= OSDynamicCast(OSNumber
,
1743 anInfoDict
->getObject(kPrelinkExecutableSizeKey
));
1746 kOSKextLogErrorLevel
|
1747 kOSKextLogArchiveFlag
,
1748 "Kext %s can't find prelinked kext executable size.",
1749 getIdentifierCString());
1753 data
= (void *) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1754 length
= (uint32_t) (lengthNum
->unsigned32BitValue());
1756 #if KASLR_KEXT_DEBUG
1757 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1758 (unsigned long)ml_static_unslide((vm_offset_t
)data
),
1759 (unsigned long)data
,
1763 anInfoDict
->removeObject(kPrelinkExecutableLoadKey
);
1764 anInfoDict
->removeObject(kPrelinkExecutableSizeKey
);
1766 /* If the kext's load address differs from its source address, allocate
1767 * space in the kext map at the load address and copy the kext over.
1769 addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject(kPrelinkExecutableSourceKey
));
1771 srcData
= (void *) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1773 #if KASLR_KEXT_DEBUG
1774 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1775 (unsigned long)ml_static_unslide((vm_offset_t
)srcData
),
1776 (unsigned long)srcData
);
1779 if (data
!= srcData
) {
1781 kern_return_t alloc_result
;
1783 alloc_result
= kext_alloc((vm_offset_t
*)&data
, length
, /* fixed */ TRUE
);
1784 if (alloc_result
!= KERN_SUCCESS
) {
1786 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1787 "Failed to allocate space for prelinked kext %s.",
1788 getIdentifierCString());
1791 memcpy(data
, srcData
, length
);
1794 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
1795 "Error: prelinked kext %s - source and load addresses "
1796 "differ on ILP32 architecture.",
1797 getIdentifierCString());
1799 #endif /* __LP64__ */
1802 anInfoDict
->removeObject(kPrelinkExecutableSourceKey
);
1805 prelinkedExecutable
= OSData::withBytesNoCopy(data
, length
);
1806 if (!prelinkedExecutable
) {
1808 kOSKextLogErrorLevel
|
1809 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
1810 "Kext %s failed to create executable wrapper.",
1811 getIdentifierCString());
1816 prelinkedExecutable
->setDeallocFunction(osdata_kext_free
);
1818 prelinkedExecutable
->setDeallocFunction(osdata_phys_free
);
1820 setLinkedExecutable(prelinkedExecutable
.get());
1821 addressNum
= OSDynamicCast(OSNumber
,
1822 anInfoDict
->getObject(kPrelinkKmodInfoKey
));
1825 kOSKextLogErrorLevel
|
1826 kOSKextLogArchiveFlag
,
1827 "Kext %s can't find prelinked kext kmod_info address.",
1828 getIdentifierCString());
1832 if (addressNum
->unsigned64BitValue() != 0) {
1833 kmod_info
= (kmod_info_t
*) (((uintptr_t) (addressNum
->unsigned64BitValue())) + kext_slide
);
1834 if (kmod_info
->address
) {
1835 kmod_info
->address
= (((uintptr_t)(kmod_info
->address
)) + kext_slide
);
1837 kmod_info
->address
= (uintptr_t)data
;
1838 kmod_info
->size
= length
;
1840 #if KASLR_KEXT_DEBUG
1841 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1842 (unsigned long)((vm_offset_t
)kmod_info
) - kext_slide
,
1843 (unsigned long)kmod_info
);
1844 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1845 (unsigned long)((vm_offset_t
)kmod_info
->address
) - kext_slide
,
1846 (unsigned long)kmod_info
->address
);
1850 anInfoDict
->removeObject(kPrelinkKmodInfoKey
);
1853 if ((addressNum
= OSDynamicCast(OSNumber
, anInfoDict
->getObject("ModuleIndex")))) {
1854 uintptr_t builtinTextStart
;
1855 uintptr_t builtinTextEnd
;
1857 flags
.builtin
= true;
1858 builtinKmodIdx
= addressNum
->unsigned32BitValue();
1859 assert(builtinKmodIdx
< gBuiltinKmodsCount
);
1861 builtinTextStart
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[builtinKmodIdx
];
1862 builtinTextEnd
= ((uintptr_t *)gBuiltinKmodsSectionStart
->addr
)[builtinKmodIdx
+ 1];
1864 kmod_info
= ((kmod_info_t
**)gBuiltinKmodsSectionInfo
->addr
)[builtinKmodIdx
];
1865 kmod_info
->address
= builtinTextStart
;
1866 kmod_info
->size
= builtinTextEnd
- builtinTextStart
;
1869 /* If the plist has a UUID for an interface, save that off.
1871 if (isInterface()) {
1872 interfaceUUID
.reset(OSDynamicCast(OSData
,
1873 anInfoDict
->getObject(kPrelinkInterfaceUUIDKey
)), OSRetain
);
1874 if (interfaceUUID
) {
1875 anInfoDict
->removeObject(kPrelinkInterfaceUUIDKey
);
1879 result
= (kOSReturnSuccess
== slidePrelinkedExecutable(doCoalescedSlides
));
1885 /* Exclude builtin and codeless kexts */
1886 if (prelinkedExecutable
&& kmod_info
) {
1889 shouldSaveSegments
= (
1890 getPropertyForHostArch(kOSMutableSegmentCopy
) == kOSBooleanTrue
||
1891 getPropertyForHostArch(kOSBundleAllowUserLoadKey
) == kOSBooleanTrue
);
1892 if (shouldSaveSegments
) {
1893 flags
.resetSegmentsFromImmutableCopy
= 1;
1896 case KCKindPageable
:
1897 flags
.resetSegmentsFromVnode
= 1;
1899 case KCKindAuxiliary
:
1900 if (!pageableKCloaded
) {
1901 flags
.resetSegmentsFromImmutableCopy
= 1;
1902 } else if (resetAuxKCSegmentOnUnload
) {
1903 flags
.resetSegmentsFromVnode
= 1;
1911 if (flags
.resetSegmentsFromImmutableCopy
) {
1912 /* Save a pristine copy of the mutable segments */
1913 kernel_segment_command_t
*seg
= NULL
;
1914 kernel_mach_header_t
*k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
1916 savedMutableSegments
= OSArray::withCapacity(0);
1918 for (seg
= firstsegfromheader(k_mh
); seg
; seg
= nextsegfromheader(k_mh
, seg
)) {
1919 if (!segmentIsMutable(seg
)) {
1922 uint64_t unslid_vmaddr
= seg
->vmaddr
- kext_slide
;
1923 uint64_t vmsize
= seg
->vmsize
;
1924 OSKextLog(this, kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
1925 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg
->segname
, sizeof(seg
->segname
)), seg
->segname
, unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
1926 OSSharedPtr
<OSKextSavedMutableSegment
> savedSegment
= OSKextSavedMutableSegment::withSegment(seg
);
1927 if (!savedSegment
) {
1929 kOSKextLogErrorLevel
|
1930 kOSKextLogGeneralFlag
,
1931 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
1932 result
= kOSKextReturnInternalError
;
1935 savedMutableSegments
->setObject(savedSegment
);
1939 if (doCoalescedSlides
== false && !flags
.resetSegmentsFromVnode
) {
1941 * set VM protections now, wire pages for the old style Aux KC now,
1942 * wire pages for the rest of the KC types at load time.
1944 result
= (kOSReturnSuccess
== setVMAttributes(true, (type
== KCKindAuxiliary
) ? true : false));
1950 flags
.prelinked
= true;
1952 /* If we created a kext from prelink info,
1953 * we must be booting from a prelinked kernel.
1955 sPrelinkBoot
= true;
1957 result
= registerIdentifier();
1963 /*********************************************************************
1964 *********************************************************************/
1967 OSKext::withCodelessInfo(OSDictionary
* anInfoDict
)
1969 OSSharedPtr
<OSKext
> newKext
= OSMakeShared
<OSKext
>();
1971 if (newKext
&& !newKext
->initWithCodelessInfo(anInfoDict
)) {
1978 /*********************************************************************
1979 *********************************************************************/
1981 OSKext::initWithCodelessInfo(OSDictionary
* anInfoDict
)
1983 bool result
= false;
1984 OSString
* kextPath
= NULL
; // do not release
1985 OSBoolean
* scratchBool
= NULL
; // do not release
1987 if (anInfoDict
== NULL
|| !super::init()) {
1992 * Get the path. Don't look for an arch-specific path property.
1994 kextPath
= OSDynamicCast(OSString
,
1995 anInfoDict
->getObject(kKextRequestArgumentCodelessInfoBundlePathKey
));
1998 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
1999 "Requested codeless kext dictionary does not contain the '%s' key",
2000 kKextRequestArgumentCodelessInfoBundlePathKey
);
2004 uniquePersonalityProperties(anInfoDict
);
2006 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
2011 * This path is meant to initialize codeless kexts only. Refuse
2012 * anything that looks like it has an executable and/or declares
2013 * itself as a kernel component.
2015 if (declaresExecutable() || isKernelComponent()) {
2017 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
2018 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2019 getIdentifierCString());
2023 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID
) == 0) {
2024 boolean_t updated
= updateExcludeList(infoDict
.get());
2027 kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
2028 "KextExcludeList was updated to version: %lld", sExcludeListVersion
);
2032 kc_type
= KCKindNone
;
2034 scratchBool
= OSDynamicCast(OSBoolean
,
2035 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey
));
2036 if (scratchBool
== kOSBooleanTrue
) {
2037 flags
.requireExplicitLoad
= 1;
2040 /* Also get the executable's bundle-relative path if present.
2041 * Don't look for an arch-specific path property.
2043 userExecutableRelPath
.reset(OSDynamicCast(OSString
,
2044 anInfoDict
->getObject(kCFBundleDriverKitExecutableKey
)), OSRetain
);
2046 /* remove unnecessary paths from the info dict */
2047 anInfoDict
->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey
);
2049 result
= registerIdentifier();
2055 /*********************************************************************
2056 *********************************************************************/
2059 OSKext::setAllVMAttributes(void)
2061 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
2062 const OSSymbol
* thisID
= NULL
; // do not release
2064 IORecursiveLockLock(sKextLock
);
2066 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
2067 if (!kextIterator
) {
2071 while ((thisID
= OSDynamicCast(OSSymbol
, kextIterator
->getNextObject()))) {
2072 OSKext
* thisKext
; // do not release
2074 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
2075 if (!thisKext
|| thisKext
->isInterface() || !thisKext
->declaresExecutable()) {
2079 if (!thisKext
->flags
.resetSegmentsFromVnode
) {
2081 * set VM protections now, wire pages for the old style Aux KC now,
2082 * wire pages for the rest of the KC types at load time.
2084 thisKext
->setVMAttributes(true, (thisKext
->kc_type
== KCKindAuxiliary
) ? true : false);
2089 IORecursiveLockUnlock(sKextLock
);
2094 /*********************************************************************
2095 *********************************************************************/
2097 OSKext::withBooterData(
2098 OSString
* deviceTreeName
,
2099 OSData
* booterData
)
2101 OSSharedPtr
<OSKext
> newKext(OSMakeShared
<OSKext
>());
2103 if (newKext
&& !newKext
->initWithBooterData(deviceTreeName
, booterData
)) {
2110 /*********************************************************************
2111 *********************************************************************/
2112 typedef struct _BooterKextFileInfo
{
2113 uint32_t infoDictPhysAddr
;
2114 uint32_t infoDictLength
;
2115 uint32_t executablePhysAddr
;
2116 uint32_t executableLength
;
2117 uint32_t bundlePathPhysAddr
;
2118 uint32_t bundlePathLength
;
2119 } _BooterKextFileInfo
;
2122 OSKext::initWithBooterData(
2123 OSString
* deviceTreeName
,
2124 OSData
* booterData
)
2126 bool result
= false;
2127 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not free
2128 char * infoDictAddr
= NULL
; // do not free
2129 void * executableAddr
= NULL
; // do not free
2130 char * bundlePathAddr
= NULL
; // do not free
2132 OSDictionary
* theInfoDict
= NULL
; // do not release
2133 OSSharedPtr
<OSObject
> parsedXML
;
2134 OSSharedPtr
<OSString
> kextPath
;
2136 OSSharedPtr
<OSString
> errorString
;
2137 OSSharedPtr
<OSData
> executable
;
2139 if (!super::init()) {
2143 kextFileInfo
= (_BooterKextFileInfo
*)booterData
->getBytesNoCopy();
2144 if (!kextFileInfo
) {
2146 kOSKextLogErrorLevel
|
2147 kOSKextLogGeneralFlag
,
2148 "No booter-provided data for kext device tree entry %s.",
2149 deviceTreeName
->getCStringNoCopy());
2153 /* The info plist must exist or we can't read the kext.
2155 if (!kextFileInfo
->infoDictPhysAddr
|| !kextFileInfo
->infoDictLength
) {
2157 kOSKextLogErrorLevel
|
2158 kOSKextLogGeneralFlag
,
2159 "No kext info dictionary for booter device tree entry %s.",
2160 deviceTreeName
->getCStringNoCopy());
2164 infoDictAddr
= (char *)ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
2165 if (!infoDictAddr
) {
2167 kOSKextLogErrorLevel
|
2168 kOSKextLogGeneralFlag
,
2169 "Can't translate physical address 0x%x of kext info dictionary "
2170 "for device tree entry %s.",
2171 (int)kextFileInfo
->infoDictPhysAddr
,
2172 deviceTreeName
->getCStringNoCopy());
2176 parsedXML
= OSUnserializeXML(infoDictAddr
, errorString
);
2178 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
2181 const char * errorCString
= "(unknown error)";
2183 if (errorString
&& errorString
->getCStringNoCopy()) {
2184 errorCString
= errorString
->getCStringNoCopy();
2185 } else if (parsedXML
) {
2186 errorCString
= "not a dictionary";
2189 kOSKextLogErrorLevel
|
2190 kOSKextLogGeneralFlag
,
2191 "Error unserializing info dictionary for device tree entry %s: %s.",
2192 deviceTreeName
->getCStringNoCopy(), errorCString
);
2196 /* A bundle path is not mandatory.
2198 if (kextFileInfo
->bundlePathPhysAddr
&& kextFileInfo
->bundlePathLength
) {
2199 bundlePathAddr
= (char *)ml_static_ptovirt(kextFileInfo
->bundlePathPhysAddr
);
2200 if (!bundlePathAddr
) {
2202 kOSKextLogErrorLevel
|
2203 kOSKextLogGeneralFlag
,
2204 "Can't translate physical address 0x%x of kext bundle path "
2205 "for device tree entry %s.",
2206 (int)kextFileInfo
->bundlePathPhysAddr
,
2207 deviceTreeName
->getCStringNoCopy());
2210 bundlePathAddr
[kextFileInfo
->bundlePathLength
- 1] = '\0'; // just in case!
2212 kextPath
= OSString::withCString(bundlePathAddr
);
2215 kOSKextLogErrorLevel
|
2216 kOSKextLogGeneralFlag
,
2217 "Failed to create wrapper for device tree entry %s kext path %s.",
2218 deviceTreeName
->getCStringNoCopy(), bundlePathAddr
);
2223 if (!setInfoDictionaryAndPath(theInfoDict
, kextPath
.get())) {
2227 /* An executable is not mandatory.
2229 if (kextFileInfo
->executablePhysAddr
&& kextFileInfo
->executableLength
) {
2230 executableAddr
= (void *)ml_static_ptovirt(kextFileInfo
->executablePhysAddr
);
2231 if (!executableAddr
) {
2233 kOSKextLogErrorLevel
|
2234 kOSKextLogGeneralFlag
,
2235 "Can't translate physical address 0x%x of kext executable "
2236 "for device tree entry %s.",
2237 (int)kextFileInfo
->executablePhysAddr
,
2238 deviceTreeName
->getCStringNoCopy());
2242 executable
= OSData::withBytesNoCopy(executableAddr
,
2243 kextFileInfo
->executableLength
);
2246 kOSKextLogErrorLevel
|
2247 kOSKextLogGeneralFlag
,
2248 "Failed to create executable wrapper for device tree entry %s.",
2249 deviceTreeName
->getCStringNoCopy());
2253 /* A kext with an executable needs to retain the whole booterData
2254 * object to keep the executable in memory.
2256 if (!setExecutable(executable
.get(), booterData
)) {
2258 kOSKextLogErrorLevel
|
2259 kOSKextLogGeneralFlag
,
2260 "Failed to set kext executable for device tree entry %s.",
2261 deviceTreeName
->getCStringNoCopy());
2266 result
= registerIdentifier();
2272 /*********************************************************************
2273 *********************************************************************/
2275 OSKext::registerIdentifier(void)
2277 bool result
= false;
2278 OSKext
* existingKext
= NULL
; // do not release
2279 bool existingIsLoaded
= false;
2280 bool existingIsPrelinked
= false;
2281 bool existingIsCodeless
= false;
2282 bool existingIsDext
= false;
2283 OSKextVersion newVersion
= -1;
2284 OSKextVersion existingVersion
= -1;
2285 char newVersionCString
[kOSKextVersionMaxLength
];
2286 char existingVersionCString
[kOSKextVersionMaxLength
];
2287 OSSharedPtr
<OSData
> newUUID
;
2288 OSSharedPtr
<OSData
> existingUUID
;
2290 IORecursiveLockLock(sKextLock
);
2292 /* Get the new kext's version for checks & log messages.
2294 newVersion
= getVersion();
2295 OSKextVersionGetString(newVersion
, newVersionCString
,
2296 kOSKextVersionMaxLength
);
2298 /* If we don't have an existing kext with this identifier,
2299 * just record the new kext and we're done!
2301 existingKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
.get()));
2302 if (!existingKext
) {
2303 sKextsByID
->setObject(bundleID
.get(), this);
2308 /* Get the existing kext's version for checks & log messages.
2310 existingVersion
= existingKext
->getVersion();
2311 OSKextVersionGetString(existingVersion
,
2312 existingVersionCString
, kOSKextVersionMaxLength
);
2314 existingIsLoaded
= existingKext
->isLoaded();
2315 existingIsPrelinked
= existingKext
->isPrelinked();
2316 existingIsDext
= existingKext
->isDriverKit();
2317 existingIsCodeless
= !existingKext
->declaresExecutable() && !existingIsDext
;
2319 /* If we have a non-codeless kext with this identifier that's already
2320 * loaded/prelinked, we can't use the new one, but let's be really
2321 * thorough and check how the two are related for a precise diagnostic
2324 * This check is valid for kexts that declare an executable and for
2325 * dexts, but not for codeless kexts - we can just replace those.
2327 if ((!existingIsCodeless
|| existingIsDext
) &&
2328 (existingIsLoaded
|| existingIsPrelinked
)) {
2329 bool sameVersion
= (newVersion
== existingVersion
);
2330 bool sameExecutable
= true; // assume true unless we have UUIDs
2332 /* Only get the UUID if the existing kext is loaded. Doing so
2333 * might have to uncompress an mkext executable and we shouldn't
2334 * take that hit when neither kext is loaded.
2336 * Note: there is no decompression that happens when all kexts
2337 * are loaded from kext collecitons.
2339 newUUID
= copyUUID();
2340 existingUUID
= existingKext
->copyUUID();
2342 if (existingIsDext
&& !isDriverKit()) {
2344 kOSKextLogWarningLevel
|
2345 kOSKextLogKextBookkeepingFlag
,
2346 "Notice - new kext %s, v%s matches a %s dext"
2347 "with the same bundle ID, v%s.",
2348 getIdentifierCString(), newVersionCString
,
2349 (existingIsLoaded
? "loaded" : "prelinked"),
2350 existingVersionCString
);
2354 /* I'm entirely too paranoid about checking equivalence of executables,
2355 * but I remember nasty problems with it in the past.
2357 * - If we have UUIDs for both kexts, compare them.
2358 * - If only one kext has a UUID, they're definitely different.
2360 if (newUUID
&& existingUUID
) {
2361 sameExecutable
= newUUID
->isEqualTo(existingUUID
.get());
2362 } else if (newUUID
|| existingUUID
) {
2363 sameExecutable
= false;
2366 if (!newUUID
&& !existingUUID
) {
2367 /* If there are no UUIDs, we can't really tell that the executables
2368 * are *different* without a lot of work; the loaded kext's
2369 * unrelocated executable is no longer around (and we never had it
2370 * in-kernel for a prelinked kext). We certainly don't want to do
2371 * a whole fake link for the new kext just to compare, either.
2374 kOSKextLogWarningLevel
|
2375 kOSKextLogKextBookkeepingFlag
,
2376 "Notice - new kext %s, v%s matches %s kext "
2377 "but can't determine if executables are the same (no UUIDs).",
2378 getIdentifierCString(),
2380 (existingIsLoaded
? "loaded" : "prelinked"));
2383 if (sameVersion
&& sameExecutable
) {
2385 (existingIsLoaded
? kOSKextLogWarningLevel
: kOSKextLogStepLevel
) |
2386 kOSKextLogKextBookkeepingFlag
,
2387 "Refusing new kext %s, v%s: a %s copy is already present "
2388 "(same version and executable).",
2389 getIdentifierCString(), newVersionCString
,
2390 (existingIsLoaded
? "loaded" : "prelinked"));
2393 /* This condition is significant so log it under warnings.
2396 kOSKextLogWarningLevel
|
2397 kOSKextLogKextBookkeepingFlag
,
2398 "Refusing new kext %s, v%s: already have %s v%s.",
2399 getIdentifierCString(),
2401 (existingIsLoaded
? "loaded" : "prelinked"),
2402 existingVersionCString
);
2404 /* This condition is significant so log it under warnings.
2407 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
2408 "Refusing new kext %s, v%s: a %s copy with a different "
2409 "executable UUID is already present.",
2410 getIdentifierCString(), newVersionCString
,
2411 (existingIsLoaded
? "loaded" : "prelinked"));
2415 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2417 /* Refuse to allow an existing loaded codeless kext be replaced by a
2418 * normal kext with the same bundle ID.
2420 if (existingIsCodeless
&& declaresExecutable()) {
2422 kOSKextLogWarningLevel
| kOSKextLogKextBookkeepingFlag
,
2423 "Refusing new kext %s, v%s: a codeless copy is already %s",
2424 getIdentifierCString(), newVersionCString
,
2425 (existingIsLoaded
? "loaded" : "prelinked"));
2429 /* Dexts packaged in the BootKC will be protected against replacement
2430 * by non-dexts by the logic above which checks if they are prelinked.
2431 * Dexts which are prelinked into the System KC will be registered
2432 * before any other kexts in the AuxKC are registered, and we never
2433 * put dexts in the AuxKC. Therefore, there is no need to check if an
2434 * existing object is a dext and is being replaced by a non-dext.
2435 * The scenario cannot happen by construction.
2437 * See: OSKext::loadFileSetKexts()
2440 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2441 * user loads are happening or if we're still in early boot. User agents are
2442 * supposed to resolve dependencies topside and include only the exact
2443 * kexts needed; so we always accept the new kext (in fact we should never
2444 * see an older unloaded copy hanging around).
2446 if (sUserLoadsActive
) {
2447 sKextsByID
->setObject(bundleID
.get(), this);
2451 kOSKextLogStepLevel
|
2452 kOSKextLogKextBookkeepingFlag
,
2453 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2454 getIdentifierCString(),
2455 existingVersionCString
,
2461 /* During early boot, the kext with the highest version always wins out.
2462 * Prelinked kernels will never hit this, but mkexts and booter-read
2463 * kexts might have duplicates.
2465 if (newVersion
> existingVersion
) {
2466 sKextsByID
->setObject(bundleID
.get(), this);
2470 kOSKextLogStepLevel
|
2471 kOSKextLogKextBookkeepingFlag
,
2472 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2473 existingVersionCString
,
2474 getIdentifierCString(),
2478 kOSKextLogStepLevel
|
2479 kOSKextLogKextBookkeepingFlag
,
2480 "Kext %s is already registered with a higher/same version (v%s); "
2481 "dropping newly-added (v%s).",
2482 getIdentifierCString(),
2483 existingVersionCString
,
2487 /* result has been set appropriately by now. */
2491 IORecursiveLockUnlock(sKextLock
);
2495 kOSKextLogStepLevel
|
2496 kOSKextLogKextBookkeepingFlag
,
2497 "Kext %s, v%s registered and available for loading.",
2498 getIdentifierCString(), newVersionCString
);
2504 /*********************************************************************
2505 * Does the bare minimum validation to look up a kext.
2506 * All other validation is done on the spot as needed.
2507 **********************************************************************/
2509 OSKext::setInfoDictionaryAndPath(
2510 OSDictionary
* aDictionary
,
2513 bool result
= false;
2514 OSString
* bundleIDString
= NULL
; // do not release
2515 OSString
* versionString
= NULL
; // do not release
2516 OSString
* compatibleVersionString
= NULL
; // do not release
2517 const char * versionCString
= NULL
; // do not free
2518 const char * compatibleVersionCString
= NULL
; // do not free
2519 OSBoolean
* scratchBool
= NULL
; // do not release
2520 OSDictionary
* scratchDict
= NULL
; // do not release
2523 panic("Attempt to set info dictionary on a kext "
2524 "that already has one (%s).",
2525 getIdentifierCString());
2528 if (!aDictionary
|| !OSDynamicCast(OSDictionary
, aDictionary
)) {
2532 infoDict
.reset(aDictionary
, OSRetain
);
2534 /* Check right away if the info dictionary has any log flags.
2536 scratchBool
= OSDynamicCast(OSBoolean
,
2537 getPropertyForHostArch(kOSBundleEnableKextLoggingKey
));
2538 if (scratchBool
== kOSBooleanTrue
) {
2539 flags
.loggingEnabled
= 1;
2542 /* The very next thing to get is the bundle identifier. Unlike
2543 * in user space, a kext with no bundle identifier gets axed
2546 bundleIDString
= OSDynamicCast(OSString
,
2547 getPropertyForHostArch(kCFBundleIdentifierKey
));
2548 if (!bundleIDString
) {
2550 kOSKextLogErrorLevel
|
2551 kOSKextLogValidationFlag
,
2552 "CFBundleIdentifier missing/invalid type in kext %s.",
2553 aPath
? aPath
->getCStringNoCopy() : "(unknown)");
2556 bundleID
= OSSymbol::withString(bundleIDString
);
2559 kOSKextLogErrorLevel
|
2560 kOSKextLogValidationFlag
,
2561 "Can't copy bundle identifier as symbol for kext %s.",
2562 bundleIDString
->getCStringNoCopy());
2566 /* Save the path if we got one (it should always be available but it's
2567 * just something nice to have for bookkeeping).
2570 path
.reset(aPath
, OSRetain
);
2574 * Minimal validation to initialize. We'll do other validation on the spot.
2576 if (bundleID
->getLength() >= KMOD_MAX_NAME
) {
2578 kOSKextLogErrorLevel
|
2579 kOSKextLogValidationFlag
,
2580 "Kext %s error - CFBundleIdentifier over max length %d.",
2581 getIdentifierCString(), KMOD_MAX_NAME
- 1);
2585 version
= compatibleVersion
= -1;
2587 versionString
= OSDynamicCast(OSString
,
2588 getPropertyForHostArch(kCFBundleVersionKey
));
2589 if (!versionString
) {
2591 kOSKextLogErrorLevel
|
2592 kOSKextLogValidationFlag
,
2593 "Kext %s error - CFBundleVersion missing/invalid type.",
2594 getIdentifierCString());
2597 versionCString
= versionString
->getCStringNoCopy();
2598 version
= OSKextParseVersionString(versionCString
);
2601 kOSKextLogErrorLevel
|
2602 kOSKextLogValidationFlag
,
2603 "Kext %s error - CFBundleVersion bad value '%s'.",
2604 getIdentifierCString(), versionCString
);
2608 compatibleVersion
= -1; // set to illegal value for kexts that don't have
2610 compatibleVersionString
= OSDynamicCast(OSString
,
2611 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
2612 if (compatibleVersionString
) {
2613 compatibleVersionCString
= compatibleVersionString
->getCStringNoCopy();
2614 compatibleVersion
= OSKextParseVersionString(compatibleVersionCString
);
2615 if (compatibleVersion
< 0) {
2617 kOSKextLogErrorLevel
|
2618 kOSKextLogValidationFlag
,
2619 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2620 getIdentifierCString(), compatibleVersionCString
);
2624 if (compatibleVersion
> version
) {
2626 kOSKextLogErrorLevel
|
2627 kOSKextLogValidationFlag
,
2628 "Kext %s error - %s %s > %s %s (must be <=).",
2629 getIdentifierCString(),
2630 kOSBundleCompatibleVersionKey
, compatibleVersionCString
,
2631 kCFBundleVersionKey
, versionCString
);
2636 /* Check to see if this kext is in exclude list */
2637 if (isInExcludeList()) {
2639 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
2640 "Kext %s is in exclude list, not loadable",
2641 getIdentifierCString());
2645 /* Set flags for later use if the infoDict gets flushed. We only
2646 * check for true values, not false ones(!)
2648 scratchBool
= OSDynamicCast(OSBoolean
,
2649 getPropertyForHostArch(kOSBundleIsInterfaceKey
));
2650 if (scratchBool
== kOSBooleanTrue
) {
2651 flags
.interface
= 1;
2654 scratchBool
= OSDynamicCast(OSBoolean
,
2655 getPropertyForHostArch(kOSKernelResourceKey
));
2656 if (scratchBool
== kOSBooleanTrue
) {
2657 flags
.kernelComponent
= 1;
2658 flags
.interface
= 1; // xxx - hm. the kernel itself isn't an interface...
2661 /* A kernel component has one implicit dependency on the kernel.
2663 flags
.hasAllDependencies
= 1;
2666 /* Make sure common string values in personalities are uniqued to OSSymbols.
2668 scratchDict
= OSDynamicCast(OSDictionary
,
2669 getPropertyForHostArch(kIOKitPersonalitiesKey
));
2671 uniquePersonalityProperties(scratchDict
);
2681 /*********************************************************************
2682 * Not used for prelinked kernel boot as there is no unrelocated
2684 *********************************************************************/
2686 OSKext::setExecutable(
2687 OSData
* anExecutable
,
2688 OSData
* externalData
,
2689 bool externalDataIsMkext
)
2691 bool result
= false;
2692 const char * executableKey
= NULL
; // do not free
2694 if (!anExecutable
) {
2695 infoDict
->removeObject(_kOSKextExecutableKey
);
2696 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
2697 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
2702 if (infoDict
->getObject(_kOSKextExecutableKey
) ||
2703 infoDict
->getObject(_kOSKextMkextExecutableReferenceKey
)) {
2704 panic("Attempt to set an executable on a kext "
2705 "that already has one (%s).",
2706 getIdentifierCString());
2710 if (externalDataIsMkext
) {
2711 executableKey
= _kOSKextMkextExecutableReferenceKey
;
2713 executableKey
= _kOSKextExecutableKey
;
2717 infoDict
->setObject(executableKey
, anExecutable
);
2719 infoDict
->setObject(_kOSKextExecutableExternalDataKey
, externalData
);
2729 /*********************************************************************
2730 *********************************************************************/
2732 uniqueStringPlistProperty(OSDictionary
* dict
, const char * key
)
2734 OSObject
* value
= NULL
; // do not release
2735 OSString
* stringValue
= NULL
; // do not release
2736 OSSharedPtr
<const OSSymbol
> symbolValue
;
2738 value
= dict
->getObject(key
);
2742 if (OSDynamicCast(OSSymbol
, value
)) {
2743 /* this is already an OSSymbol: we're good */
2747 stringValue
= OSDynamicCast(OSString
, value
);
2752 symbolValue
= OSSymbol::withString(stringValue
);
2757 dict
->setObject(key
, symbolValue
.get());
2763 /*********************************************************************
2764 *********************************************************************/
2766 uniqueStringPlistProperty(OSDictionary
* dict
, const OSString
* key
)
2768 OSObject
* value
= NULL
; // do not release
2769 OSString
* stringValue
= NULL
; // do not release
2770 OSSharedPtr
<const OSSymbol
> symbolValue
;
2772 value
= dict
->getObject(key
);
2776 if (OSDynamicCast(OSSymbol
, value
)) {
2777 /* this is already an OSSymbol: we're good */
2781 stringValue
= OSDynamicCast(OSString
, value
);
2786 symbolValue
= OSSymbol::withString(stringValue
);
2791 dict
->setObject(key
, symbolValue
.get());
2798 OSKext::uniquePersonalityProperties(OSDictionary
* personalityDict
)
2800 OSKext::uniquePersonalityProperties(personalityDict
, true);
2803 /*********************************************************************
2804 * Replace common personality property values with uniqued instances
2805 * to save on wired memory.
2806 *********************************************************************/
2809 OSKext::uniquePersonalityProperties(OSDictionary
* personalityDict
, bool defaultAddKernelBundleIdentifier
)
2811 /* Properties every personality has.
2813 uniqueStringPlistProperty(personalityDict
, kCFBundleIdentifierKey
);
2814 uniqueStringPlistProperty(personalityDict
, kIOProviderClassKey
);
2815 uniqueStringPlistProperty(personalityDict
, gIOClassKey
.get());
2816 if (personalityDict
->getObject(kCFBundleIdentifierKernelKey
)) {
2817 uniqueStringPlistProperty(personalityDict
, kCFBundleIdentifierKernelKey
);
2818 } else if (defaultAddKernelBundleIdentifier
) {
2819 personalityDict
->setObject(kCFBundleIdentifierKernelKey
, personalityDict
->getObject(kCFBundleIdentifierKey
));
2822 /* Other commonly used properties.
2824 uniqueStringPlistProperty(personalityDict
, gIOMatchCategoryKey
);
2825 uniqueStringPlistProperty(personalityDict
, gIOResourceMatchKey
);
2826 uniqueStringPlistProperty(personalityDict
, gIOUserClientClassKey
);
2828 uniqueStringPlistProperty(personalityDict
, "HIDDefaultBehavior");
2829 uniqueStringPlistProperty(personalityDict
, "HIDPointerAccelerationType");
2830 uniqueStringPlistProperty(personalityDict
, "HIDRemoteControlType");
2831 uniqueStringPlistProperty(personalityDict
, "HIDScrollAccelerationType");
2832 uniqueStringPlistProperty(personalityDict
, "IOPersonalityPublisher");
2833 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect");
2834 uniqueStringPlistProperty(personalityDict
, "Physical Interconnect Location");
2835 uniqueStringPlistProperty(personalityDict
, "Vendor");
2836 uniqueStringPlistProperty(personalityDict
, "Vendor Identification");
2837 uniqueStringPlistProperty(personalityDict
, "Vendor Name");
2838 uniqueStringPlistProperty(personalityDict
, "bConfigurationValue");
2839 uniqueStringPlistProperty(personalityDict
, "bInterfaceNumber");
2840 uniqueStringPlistProperty(personalityDict
, "idProduct");
2845 /*********************************************************************
2846 *********************************************************************/
2851 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2857 executableRelPath
.reset();
2858 userExecutableRelPath
.reset();
2859 dependencies
.reset();
2860 linkedExecutable
.reset();
2861 metaClasses
.reset();
2862 interfaceUUID
.reset();
2863 driverKitUUID
.reset();
2865 if (isInterface() && kmod_info
) {
2866 kfree(kmod_info
, sizeof(kmod_info_t
));
2874 #pragma mark Mkext files
2879 * mkext archives are really only relevant on kxld-enabled kernels.
2880 * Without a dynamic kernel linker, we don't need to support any mkexts.
2883 /*********************************************************************
2884 *********************************************************************/
2886 OSKext::readMkextArchive(OSData
* mkextData
,
2887 uint32_t * checksumPtr
)
2889 OSReturn result
= kOSKextReturnBadData
;
2890 uint32_t mkextLength
= 0;
2891 mkext_header
* mkextHeader
= NULL
; // do not free
2892 uint32_t mkextVersion
= 0;
2894 /* Note default return of kOSKextReturnBadData above.
2896 mkextLength
= mkextData
->getLength();
2897 if (mkextLength
< sizeof(mkext_basic_header
)) {
2898 OSKextLog(/* kext */ NULL
,
2899 kOSKextLogErrorLevel
|
2900 kOSKextLogArchiveFlag
,
2901 "Mkext archive too small to be valid.");
2905 mkextHeader
= (mkext_header
*)mkextData
->getBytesNoCopy();
2907 if (MKEXT_GET_MAGIC(mkextHeader
) != MKEXT_MAGIC
||
2908 MKEXT_GET_SIGNATURE(mkextHeader
) != MKEXT_SIGN
) {
2909 OSKextLog(/* kext */ NULL
,
2910 kOSKextLogErrorLevel
|
2911 kOSKextLogArchiveFlag
,
2912 "Mkext archive has invalid magic or signature.");
2916 if (MKEXT_GET_LENGTH(mkextHeader
) != mkextLength
) {
2917 OSKextLog(/* kext */ NULL
,
2918 kOSKextLogErrorLevel
|
2919 kOSKextLogArchiveFlag
,
2920 "Mkext archive recorded length doesn't match actual file length.");
2924 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2926 if (mkextVersion
== MKEXT_VERS_2
) {
2927 result
= OSKext::readMkext2Archive(mkextData
, NULL
, checksumPtr
);
2929 OSKextLog(/* kext */ NULL
,
2930 kOSKextLogErrorLevel
|
2931 kOSKextLogArchiveFlag
,
2932 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion
);
2933 result
= kOSKextReturnUnsupported
;
2940 /*********************************************************************
2941 * Assumes magic, signature, version, length have been checked.
2942 * xxx - need to add further bounds checking for each file entry
2944 * Should keep track of all kexts created so far, and if we hit a
2945 * fatal error halfway through, remove those kexts. If we've dropped
2946 * an older version that had already been read, whoops! Might want to
2947 * add a level of buffering?
2948 *********************************************************************/
2951 OSKext::readMkext2Archive(
2953 OSDictionary
** mkextPlistOut
,
2954 uint32_t * checksumPtr
)
2956 OSReturn result
= kOSReturnError
;
2957 uint32_t mkextLength
;
2958 mkext2_header
* mkextHeader
= NULL
; // do not free
2959 void * mkextEnd
= NULL
; // do not free
2960 uint32_t mkextVersion
;
2961 uint8_t * crc_address
= NULL
;
2962 size_t crc_buffer_size
= 0;
2964 uint32_t mkextPlistOffset
;
2965 uint32_t mkextPlistCompressedSize
;
2966 char * mkextPlistEnd
= NULL
; // do not free
2967 uint32_t mkextPlistFullSize
;
2968 OSSharedPtr
<OSString
> errorString
;
2969 OSSharedPtr
<OSData
> mkextPlistUncompressedData
;
2970 const char * mkextPlistDataBuffer
= NULL
; // do not free
2971 OSSharedPtr
<OSObject
> parsedXML
;
2972 OSDictionary
* mkextPlist
= NULL
; // do not release
2973 OSArray
* mkextInfoDictArray
= NULL
; // do not release
2975 kc_format_t kc_format
;
2977 if (!PE_get_primary_kc_format(&kc_format
)) {
2978 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
2979 "Unable to determine primary KC format");
2983 mkextLength
= mkextData
->getLength();
2984 mkextHeader
= (mkext2_header
*)mkextData
->getBytesNoCopy();
2985 mkextEnd
= (char *)mkextHeader
+ mkextLength
;
2986 mkextVersion
= MKEXT_GET_VERSION(mkextHeader
);
2988 crc_address
= (u_int8_t
*)&mkextHeader
->version
;
2989 crc_buffer_size
= (uintptr_t)mkextHeader
+
2990 MKEXT_GET_LENGTH(mkextHeader
) - (uintptr_t)crc_address
;
2991 if (crc_buffer_size
> INT32_MAX
) {
2992 OSKextLog(/* kext */ NULL
,
2993 kOSKextLogErrorLevel
|
2994 kOSKextLogArchiveFlag
,
2995 "Mkext archive size is too large (%lu > INT32_MAX).",
2997 result
= kOSKextReturnBadData
;
3000 checksum
= mkext_adler32(crc_address
, (int32_t)crc_buffer_size
);
3002 if (MKEXT_GET_CHECKSUM(mkextHeader
) != checksum
) {
3003 OSKextLog(/* kext */ NULL
,
3004 kOSKextLogErrorLevel
|
3005 kOSKextLogArchiveFlag
,
3006 "Mkext archive has bad checksum.");
3007 result
= kOSKextReturnBadData
;
3012 *checksumPtr
= checksum
;
3015 /* Check that the CPU type & subtype match that of the running kernel. */
3016 if (MKEXT_GET_CPUTYPE(mkextHeader
) == (UInt32
)CPU_TYPE_ANY
) {
3017 OSKextLog(/* kext */ NULL
,
3018 kOSKextLogErrorLevel
|
3019 kOSKextLogArchiveFlag
,
3020 "Mkext archive must have a specific CPU type.");
3021 result
= kOSKextReturnBadData
;
3024 if ((UInt32
)_mh_execute_header
.cputype
!=
3025 MKEXT_GET_CPUTYPE(mkextHeader
)) {
3026 OSKextLog(/* kext */ NULL
,
3027 kOSKextLogErrorLevel
|
3028 kOSKextLogArchiveFlag
,
3029 "Mkext archive does not match the running kernel's CPU type.");
3030 result
= kOSKextReturnArchNotFound
;
3035 mkextPlistOffset
= MKEXT2_GET_PLIST(mkextHeader
);
3036 mkextPlistCompressedSize
= MKEXT2_GET_PLIST_COMPSIZE(mkextHeader
);
3037 mkextPlistEnd
= (char *)mkextHeader
+ mkextPlistOffset
+
3038 mkextPlistCompressedSize
;
3039 if (mkextPlistEnd
> mkextEnd
) {
3040 OSKextLog(/* kext */ NULL
,
3041 kOSKextLogErrorLevel
|
3042 kOSKextLogArchiveFlag
,
3043 "Mkext archive file overrun.");
3044 result
= kOSKextReturnBadData
;
3047 mkextPlistFullSize
= MKEXT2_GET_PLIST_FULLSIZE(mkextHeader
);
3048 if (mkextPlistCompressedSize
) {
3049 mkextPlistUncompressedData
= sKernelKext
->extractMkext2FileData(
3050 (UInt8
*)mkextHeader
+ mkextPlistOffset
,
3052 mkextPlistCompressedSize
, mkextPlistFullSize
);
3053 if (!mkextPlistUncompressedData
) {
3056 mkextPlistDataBuffer
= (const char *)
3057 mkextPlistUncompressedData
->getBytesNoCopy();
3059 mkextPlistDataBuffer
= (const char *)mkextHeader
+ mkextPlistOffset
;
3062 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3064 parsedXML
= OSUnserializeXML(mkextPlistDataBuffer
, errorString
);
3066 mkextPlist
= OSDynamicCast(OSDictionary
, parsedXML
.get());
3069 const char * errorCString
= "(unknown error)";
3071 if (errorString
&& errorString
->getCStringNoCopy()) {
3072 errorCString
= errorString
->getCStringNoCopy();
3073 } else if (parsedXML
) {
3074 errorCString
= "not a dictionary";
3076 OSKextLog(/* kext */ NULL
,
3077 kOSKextLogErrorLevel
|
3078 kOSKextLogArchiveFlag
,
3079 "Error unserializing mkext plist: %s.", errorCString
);
3083 mkextInfoDictArray
= OSDynamicCast(OSArray
,
3084 mkextPlist
->getObject(kMKEXTInfoDictionariesKey
));
3085 if (!mkextInfoDictArray
) {
3086 OSKextLog(/* kext */ NULL
,
3087 kOSKextLogErrorLevel
|
3088 kOSKextLogArchiveFlag
,
3089 "Mkext archive contains no kext info dictionaries.");
3093 count
= mkextInfoDictArray
->getCount();
3094 for (i
= 0; i
< count
; i
++) {
3095 OSDictionary
* infoDict
;
3098 infoDict
= OSDynamicCast(OSDictionary
,
3099 mkextInfoDictArray
->getObject(i
));
3101 /* Create the kext for the entry, then release it, because the
3102 * kext system keeps them around until explicitly removed.
3103 * Any creation/registration failures are already logged for us.
3106 OSSharedPtr
<OSKext
> newKext
= OSKext::withMkext2Info(infoDict
, mkextData
);
3108 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3109 if (kc_format
== KCFormatFileset
&&
3111 !(newKext
->isPrelinked()) &&
3112 newKext
->declaresExecutable()) {
3113 result
= kOSReturnError
;
3114 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3115 newKext
->getIdentifier() ? newKext
->getIdentifierCString() : "unknown kext");
3117 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
3118 "Dynamic loading of kext denied for kext %s\n",
3119 newKext
->getIdentifier() ? newKext
->getIdentifierCString() : "unknown kext");
3125 /* If the caller needs the plist, hand them back our copy
3127 if (mkextPlistOut
) {
3128 *mkextPlistOut
= mkextPlist
;
3132 /* Even if we didn't keep any kexts from the mkext, we may have a load
3133 * request to process, so we are successful (no errors occurred).
3135 result
= kOSReturnSuccess
;
3143 OSKext::readMkext2Archive(
3145 OSSharedPtr
<OSDictionary
> &mkextPlistOut
,
3146 uint32_t * checksumPtr
)
3148 OSDictionary
* mkextPlist
= NULL
;
3151 if (kOSReturnSuccess
== (ret
= readMkext2Archive(mkextData
,
3154 mkextPlistOut
.reset(mkextPlist
, OSNoRetain
);
3159 /*********************************************************************
3160 *********************************************************************/
3163 OSKext::withMkext2Info(
3164 OSDictionary
* anInfoDict
,
3167 OSSharedPtr
<OSKext
> newKext
= OSMakeShared
<OSKext
>();
3169 if (newKext
&& !newKext
->initWithMkext2Info(anInfoDict
, mkextData
)) {
3176 /*********************************************************************
3177 *********************************************************************/
3179 OSKext::initWithMkext2Info(
3180 OSDictionary
* anInfoDict
,
3183 bool result
= false;
3184 OSString
* kextPath
= NULL
; // do not release
3185 OSNumber
* executableOffsetNum
= NULL
; // do not release
3186 OSSharedPtr
<OSData
> executable
;
3188 if (anInfoDict
== NULL
|| !super::init()) {
3192 /* Get the path. Don't look for an arch-specific path property.
3194 kextPath
= OSDynamicCast(OSString
,
3195 anInfoDict
->getObject(kMKEXTBundlePathKey
));
3197 if (!setInfoDictionaryAndPath(anInfoDict
, kextPath
)) {
3201 /* If we have a path to the executable, save it.
3203 executableRelPath
.reset(OSDynamicCast(OSString
,
3204 anInfoDict
->getObject(kMKEXTExecutableRelativePathKey
)), OSRetain
);
3206 /* Don't need the paths to be in the info dictionary any more.
3208 anInfoDict
->removeObject(kMKEXTBundlePathKey
);
3209 anInfoDict
->removeObject(kMKEXTExecutableRelativePathKey
);
3211 executableOffsetNum
= OSDynamicCast(OSNumber
,
3212 infoDict
->getObject(kMKEXTExecutableKey
));
3213 if (executableOffsetNum
) {
3214 executable
= createMkext2FileEntry(mkextData
,
3215 executableOffsetNum
, "executable");
3216 infoDict
->removeObject(kMKEXTExecutableKey
);
3220 if (!setExecutable(executable
.get(), mkextData
, true)) {
3225 result
= registerIdentifier();
3231 /*********************************************************************
3232 *********************************************************************/
3234 OSKext::createMkext2FileEntry(
3236 OSNumber
* offsetNum
,
3239 OSSharedPtr
<OSData
> result
;
3240 MkextEntryRef entryRef
;
3241 uint8_t * mkextBuffer
= (uint8_t *)mkextData
->getBytesNoCopy();
3242 uint32_t entryOffset
= offsetNum
->unsigned32BitValue();
3244 result
= OSData::withCapacity(sizeof(entryRef
));
3249 entryRef
.mkext
= (mkext_basic_header
*)mkextBuffer
;
3250 entryRef
.fileinfo
= mkextBuffer
+ entryOffset
;
3251 if (!result
->appendBytes(&entryRef
, sizeof(entryRef
))) {
3259 kOSKextLogErrorLevel
|
3260 kOSKextLogArchiveFlag
,
3261 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3262 name
, getIdentifierCString());
3267 /*********************************************************************
3268 *********************************************************************/
3270 static void * z_alloc(void *, u_int items
, u_int size
);
3271 static void z_free(void *, void *ptr
);
3273 typedef struct z_mem
{
3274 uint32_t alloc_size
;
3279 * Space allocation and freeing routines for use by zlib routines.
3282 z_alloc(void * notused __unused
, u_int num_items
, u_int size
)
3284 void * result
= NULL
;
3285 z_mem
* zmem
= NULL
;
3287 uint64_t total
= ((uint64_t)num_items
) * ((uint64_t)size
);
3288 //Check for overflow due to multiplication
3289 if (total
> UINT32_MAX
) {
3290 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3291 notused
, num_items
, size
, num_items
, size
);
3294 uint64_t allocSize64
= total
+ ((uint64_t)sizeof(zmem
));
3295 //Check for overflow due to addition
3296 if (allocSize64
> UINT32_MAX
) {
3297 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3298 notused
, num_items
, size
, (uint32_t)total
, sizeof(zmem
));
3300 uint32_t allocSize
= (uint32_t)allocSize64
;
3302 zmem
= (z_mem
*)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, allocSize
,
3303 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
3307 zmem
->alloc_size
= allocSize
;
3308 result
= (void *)&(zmem
->data
);
3314 z_free(void * notused __unused
, void * ptr
)
3316 uint32_t * skipper
= (uint32_t *)ptr
- 1;
3317 z_mem
* zmem
= (z_mem
*)skipper
;
3318 kheap_free(KHEAP_DATA_BUFFERS
, zmem
, zmem
->alloc_size
);
3324 OSKext::extractMkext2FileData(
3327 uint32_t compressedSize
,
3330 OSSharedPtr
<OSData
> result
;
3331 OSSharedPtr
<OSData
> uncompressedData
; // release on error
3333 uint8_t * uncompressedDataBuffer
= NULL
; // do not free
3334 unsigned long uncompressedSize
;
3336 bool zstream_inited
= false;
3339 /* If the file isn't compressed, we want to make a copy
3340 * so that we don't have the tie to the larger mkext file buffer any more.
3342 if (!compressedSize
) {
3343 uncompressedData
= OSData::withBytes(data
, fullSize
);
3344 // xxx - no check for failure?
3345 result
= uncompressedData
;
3349 if (KERN_SUCCESS
!= kmem_alloc(kernel_map
,
3350 (vm_offset_t
*)&uncompressedDataBuffer
, fullSize
, VM_KERN_MEMORY_OSKEXT
)) {
3351 /* How's this for cheesy? The kernel is only asked to extract
3352 * kext plists so we tailor the log messages.
3356 kOSKextLogErrorLevel
|
3357 kOSKextLogArchiveFlag
,
3358 "Allocation failure extracting %s from mkext.", name
);
3361 kOSKextLogErrorLevel
|
3362 kOSKextLogArchiveFlag
,
3363 "Allocation failure extracting %s from mkext for kext %s.",
3364 name
, getIdentifierCString());
3369 uncompressedData
= OSData::withBytesNoCopy(uncompressedDataBuffer
, fullSize
);
3370 if (!uncompressedData
) {
3373 kOSKextLogErrorLevel
|
3374 kOSKextLogArchiveFlag
,
3375 "Allocation failure extracting %s from mkext.", name
);
3378 kOSKextLogErrorLevel
|
3379 kOSKextLogArchiveFlag
,
3380 "Allocation failure extracting %s from mkext for kext %s.",
3381 name
, getIdentifierCString());
3385 uncompressedData
->setDeallocFunction(&osdata_kmem_free
);
3389 kOSKextLogDetailLevel
|
3390 kOSKextLogArchiveFlag
,
3391 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3392 name
, compressedSize
, fullSize
);
3395 kOSKextLogDetailLevel
|
3396 kOSKextLogArchiveFlag
,
3397 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3398 getIdentifierCString(), name
, compressedSize
, fullSize
);
3401 bzero(&zstream
, sizeof(zstream
));
3402 zstream
.next_in
= (UInt8
*)data
;
3403 zstream
.avail_in
= compressedSize
;
3405 zstream
.next_out
= uncompressedDataBuffer
;
3406 zstream
.avail_out
= fullSize
;
3408 zstream
.zalloc
= z_alloc
;
3409 zstream
.zfree
= z_free
;
3411 zlib_result
= inflateInit(&zstream
);
3412 if (Z_OK
!= zlib_result
) {
3415 kOSKextLogErrorLevel
|
3416 kOSKextLogArchiveFlag
,
3417 "Mkext error; zlib inflateInit failed (%d) for %s.",
3421 kOSKextLogErrorLevel
|
3422 kOSKextLogArchiveFlag
,
3423 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3424 getIdentifierCString(), zlib_result
, name
);
3428 zstream_inited
= true;
3431 zlib_result
= inflate(&zstream
, Z_FINISH
);
3433 if (zlib_result
== Z_STREAM_END
|| zlib_result
== Z_OK
) {
3434 uncompressedSize
= zstream
.total_out
;
3438 kOSKextLogErrorLevel
|
3439 kOSKextLogArchiveFlag
,
3440 "Mkext error; zlib inflate failed (%d) for %s.",
3444 kOSKextLogErrorLevel
|
3445 kOSKextLogArchiveFlag
,
3446 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3447 getIdentifierCString(), zlib_result
, name
);
3451 kOSKextLogErrorLevel
|
3452 kOSKextLogArchiveFlag
,
3453 "zlib error: %s.", zstream
.msg
);
3458 if (uncompressedSize
!= fullSize
) {
3461 kOSKextLogErrorLevel
|
3462 kOSKextLogArchiveFlag
,
3463 "Mkext error; zlib inflate discrepancy for %s, "
3464 "uncompressed size != original size.", name
);
3467 kOSKextLogErrorLevel
|
3468 kOSKextLogArchiveFlag
,
3469 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3470 "uncompressed size != original size.",
3471 getIdentifierCString(), name
);
3476 result
= os::move(uncompressedData
);
3479 /* Don't bother checking return, nothing we can do on fail.
3481 if (zstream_inited
) {
3482 inflateEnd(&zstream
);
3488 /*********************************************************************
3489 *********************************************************************/
3492 OSKext::loadFromMkext(
3493 OSKextLogSpec clientLogFilter
,
3495 uint32_t mkextBufferLength
,
3497 uint32_t * logInfoLengthOut
)
3499 OSReturn result
= kOSReturnError
;
3500 OSReturn tempResult
= kOSReturnError
;
3502 OSSharedPtr
<OSData
> mkextData
;
3503 OSSharedPtr
<OSDictionary
> mkextPlist
;
3505 OSSharedPtr
<OSArray
> logInfoArray
;
3506 OSSharedPtr
<OSSerialize
> serializer
;
3508 OSString
* predicate
= NULL
; // do not release
3509 OSDictionary
* requestArgs
= NULL
; // do not release
3511 OSString
* kextIdentifier
= NULL
; // do not release
3512 OSNumber
* startKextExcludeNum
= NULL
; // do not release
3513 OSNumber
* startMatchingExcludeNum
= NULL
; // do not release
3514 OSBoolean
* delayAutounloadBool
= NULL
; // do not release
3515 OSArray
* personalityNames
= NULL
; // do not release
3517 /* Default values for these two options: regular autounload behavior,
3518 * load all kexts, send no personalities.
3520 Boolean delayAutounload
= false;
3521 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
3522 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeAll
;
3524 IORecursiveLockLock(sKextLock
);
3528 *logInfoLengthOut
= 0;
3531 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
3533 OSKextLog(/* kext */ NULL
,
3534 kOSKextLogDebugLevel
|
3536 "Received kext load request from user space.");
3538 /* Regardless of processing, the fact that we have gotten here means some
3539 * user-space program is up and talking to us, so we'll switch our kext
3540 * registration to reflect that.
3542 if (!sUserLoadsActive
) {
3543 OSKextLog(/* kext */ NULL
,
3544 kOSKextLogProgressLevel
|
3545 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
3546 "Switching to late startup (user-space) kext loading policy.");
3548 sUserLoadsActive
= true;
3551 if (!sLoadEnabled
) {
3552 OSKextLog(/* kext */ NULL
,
3553 kOSKextLogErrorLevel
|
3555 "Kext loading is disabled.");
3556 result
= kOSKextReturnDisabled
;
3560 /* Note that we do not set a dealloc function on this OSData
3561 * object! No references to it can remain after the loadFromMkext()
3562 * call since we are in a MIG function, and will vm_deallocate()
3565 mkextData
= OSData::withBytesNoCopy(mkextBuffer
,
3568 OSKextLog(/* kext */ NULL
,
3569 kOSKextLogErrorLevel
|
3570 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3571 "Failed to create wrapper for kext load request.");
3572 result
= kOSKextReturnNoMemory
;
3576 result
= readMkext2Archive(mkextData
.get(), mkextPlist
, NULL
);
3577 if (result
!= kOSReturnSuccess
) {
3578 OSKextLog(/* kext */ NULL
,
3579 kOSKextLogErrorLevel
|
3581 "Failed to read kext load request.");
3585 predicate
= _OSKextGetRequestPredicate(mkextPlist
.get());
3586 if (!predicate
|| !predicate
->isEqualTo(kKextRequestPredicateLoad
)) {
3587 OSKextLog(/* kext */ NULL
,
3588 kOSKextLogErrorLevel
|
3590 "Received kext load request with no predicate; skipping.");
3591 result
= kOSKextReturnInvalidArgument
;
3595 requestArgs
= OSDynamicCast(OSDictionary
,
3596 mkextPlist
->getObject(kKextRequestArgumentsKey
));
3597 if (!requestArgs
|| !requestArgs
->getCount()) {
3598 OSKextLog(/* kext */ NULL
,
3599 kOSKextLogErrorLevel
|
3601 "Received kext load request with no arguments.");
3602 result
= kOSKextReturnInvalidArgument
;
3606 kextIdentifier
= OSDynamicCast(OSString
,
3607 requestArgs
->getObject(kKextRequestArgumentBundleIdentifierKey
));
3609 if (!kextIdentifier
) {
3610 OSKextLog(/* kext */ NULL
,
3611 kOSKextLogErrorLevel
|
3613 "Received kext load request with no kext identifier.");
3614 result
= kOSKextReturnInvalidArgument
;
3618 startKextExcludeNum
= OSDynamicCast(OSNumber
,
3619 requestArgs
->getObject(kKextRequestArgumentStartExcludeKey
));
3620 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
3621 requestArgs
->getObject(kKextRequestArgumentStartMatchingExcludeKey
));
3622 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
3623 requestArgs
->getObject(kKextRequestArgumentDelayAutounloadKey
));
3624 personalityNames
= OSDynamicCast(OSArray
,
3625 requestArgs
->getObject(kKextRequestArgumentPersonalityNamesKey
));
3627 if (delayAutounloadBool
) {
3628 delayAutounload
= delayAutounloadBool
->getValue();
3630 if (startKextExcludeNum
) {
3631 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
3633 if (startMatchingExcludeNum
) {
3634 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
3637 OSKextLog(/* kext */ NULL
,
3638 kOSKextLogProgressLevel
|
3640 "Received request from user space to load kext %s.",
3641 kextIdentifier
->getCStringNoCopy());
3643 /* Load the kext, with no deferral, since this is a load from outside
3645 * xxx - Would like a better way to handle the default values for the
3646 * xxx - start/match opt args.
3648 result
= OSKext::loadKextWithIdentifier(
3651 /* allowDefer */ false,
3653 startKextExcludeLevel
,
3654 startMatchingExcludeLevel
,
3656 if (result
!= kOSReturnSuccess
) {
3659 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3660 * for matching via a separate IOKit calldown.
3665 /* Gather up the collected log messages for user space. Any
3666 * error messages past this call will not make it up as log messages
3667 * but will be in the system log.
3669 logInfoArray
= OSKext::clearUserSpaceLogFilter();
3671 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
3672 tempResult
= OSKext::serializeLogInfo(logInfoArray
.get(),
3673 logInfoOut
, logInfoLengthOut
);
3674 if (tempResult
!= kOSReturnSuccess
) {
3675 result
= tempResult
;
3679 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3681 IORecursiveLockUnlock(sKextLock
);
3683 /* Note: mkextDataObject will have been retained by every kext w/an
3684 * executable in it. That should all have been flushed out at the
3685 * and of the load operation, but you never know....
3687 if (mkextData
&& mkextData
->getRetainCount() > 1) {
3688 OSKextLog(/* kext */ NULL
,
3689 kOSKextLogErrorLevel
|
3690 kOSKextLogLoadFlag
| kOSKextLogIPCFlag
,
3691 "Kext load request buffer from user space still retained by a kext; "
3692 "probable memory leak.");
3698 #endif // CONFIG_KXLD
3700 /*********************************************************************
3701 *********************************************************************/
3704 OSKext::serializeLogInfo(
3705 OSArray
* logInfoArray
,
3707 uint32_t * logInfoLengthOut
)
3709 OSReturn result
= kOSReturnError
;
3710 char * buffer
= NULL
;
3711 kern_return_t kmem_result
= KERN_FAILURE
;
3712 OSSharedPtr
<OSSerialize
> serializer
;
3713 char * logInfo
= NULL
; // returned by reference
3714 uint32_t logInfoLength
= 0;
3716 if (!logInfoArray
|| !logInfoOut
|| !logInfoLengthOut
) {
3717 OSKextLog(/* kext */ NULL
,
3718 kOSKextLogErrorLevel
|
3720 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3721 /* Bad programmer. */
3722 result
= kOSKextReturnInvalidArgument
;
3726 serializer
= OSSerialize::withCapacity(0);
3728 OSKextLog(/* kext */ NULL
,
3729 kOSKextLogErrorLevel
|
3731 "Failed to create serializer on log info for request from user space.");
3732 /* Incidental error; we're going to (try to) allow the request
3733 * itself to succeed. */
3736 if (!logInfoArray
->serialize(serializer
.get())) {
3737 OSKextLog(/* kext */ NULL
,
3738 kOSKextLogErrorLevel
|
3740 "Failed to serialize log info for request from user space.");
3741 /* Incidental error; we're going to (try to) allow the request
3742 * itself to succeed. */
3744 logInfo
= serializer
->text();
3745 logInfoLength
= serializer
->getLength();
3747 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
, round_page(logInfoLength
), VM_KERN_MEMORY_OSKEXT
);
3748 if (kmem_result
!= KERN_SUCCESS
) {
3749 OSKextLog(/* kext */ NULL
,
3750 kOSKextLogErrorLevel
|
3752 "Failed to copy log info for request from user space.");
3753 /* Incidental error; we're going to (try to) allow the request
3756 /* 11981737 - clear uninitialized data in last page */
3757 bzero((void *)(buffer
+ logInfoLength
),
3758 (round_page(logInfoLength
) - logInfoLength
));
3759 memcpy(buffer
, logInfo
, logInfoLength
);
3760 *logInfoOut
= buffer
;
3761 *logInfoLengthOut
= logInfoLength
;
3765 result
= kOSReturnSuccess
;
3771 #pragma mark Instance Management Methods
3773 /*********************************************************************
3774 *********************************************************************/
3776 OSKext::lookupKextWithIdentifier(const char * kextIdentifier
)
3778 OSSharedPtr
<OSKext
> foundKext
;
3780 IORecursiveLockLock(sKextLock
);
3781 foundKext
.reset(OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
)), OSRetain
);
3782 IORecursiveLockUnlock(sKextLock
);
3787 /*********************************************************************
3788 *********************************************************************/
3790 OSKext::lookupKextWithIdentifier(OSString
* kextIdentifier
)
3792 return OSKext::lookupKextWithIdentifier(kextIdentifier
->getCStringNoCopy());
3795 /*********************************************************************
3796 *********************************************************************/
3798 OSKext::lookupKextWithLoadTag(uint32_t aTag
)
3800 OSSharedPtr
<OSKext
> foundKext
; // returned
3802 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
3803 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
3805 IORecursiveLockLock(sKextLock
);
3807 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
3808 for (i
= 0; i
< count
[j
]; i
++) {
3809 OSKext
* thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
3810 if (thisKext
->getLoadTag() == aTag
) {
3811 foundKext
.reset(thisKext
, OSRetain
);
3818 IORecursiveLockUnlock(sKextLock
);
3823 /*********************************************************************
3824 *********************************************************************/
3826 OSKext::lookupKextWithAddress(vm_address_t address
)
3828 OSSharedPtr
<OSKext
> foundKext
; // returned
3830 kmod_info_t
*kmod_info
;
3831 #if defined(__arm64__)
3832 uint64_t textExecBase
;
3833 size_t textExecSize
;
3834 #endif /* defined(__arm64__) */
3836 #if __has_feature(ptrauth_calls)
3837 address
= (vm_address_t
)VM_KERNEL_STRIP_PTR(address
);
3838 #endif /* __has_feature(ptrauth_calls) */
3840 IORecursiveLockLock(sKextLock
);
3842 count
= sLoadedKexts
->getCount();
3843 for (i
= 0; i
< count
; i
++) {
3844 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3845 if (thisKext
== sKernelKext
) {
3848 if (thisKext
->kmod_info
&& thisKext
->kmod_info
->address
) {
3849 kmod_info
= thisKext
->kmod_info
;
3850 vm_address_t kext_start
= kmod_info
->address
;
3851 vm_address_t kext_end
= kext_start
+ kmod_info
->size
;
3852 if ((kext_start
<= address
) && (address
< kext_end
)) {
3853 foundKext
.reset(thisKext
, OSRetain
);
3856 #if defined(__arm64__)
3857 textExecBase
= (uintptr_t) getsegdatafromheader((kernel_mach_header_t
*)kmod_info
->address
, "__TEXT_EXEC", &textExecSize
);
3858 if ((textExecBase
<= address
) && (address
< textExecBase
+ textExecSize
)) {
3859 foundKext
.reset(thisKext
, OSRetain
);
3862 #endif /* defined (__arm64__) */
3865 if ((address
>= vm_kernel_stext
) && (address
< vm_kernel_etext
)) {
3866 foundKext
.reset(sKernelKext
, OSRetain
);
3870 * DriverKit userspace executables do not have a kernel linkedExecutable,
3871 * so we "fake" their address range with the LoadTag.
3873 * This is supposed to be used for logging reasons only. When logd
3874 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3875 * remove it here before checking it against the LoadTag.
3876 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3879 address
= address
& ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK
| FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT
);
3880 count
= sLoadedDriverKitKexts
->getCount();
3881 for (i
= 0; i
< count
; i
++) {
3882 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedDriverKitKexts
->getObject(i
));
3883 if (thisKext
->getLoadTag() == address
) {
3884 foundKext
.reset(thisKext
, OSRetain
);
3889 IORecursiveLockUnlock(sKextLock
);
3895 OSKext::copyKextUUIDForAddress(OSNumber
*address
)
3897 OSSharedPtr
<OSData
> uuid
;
3898 OSSharedPtr
<OSKext
> kext
;
3904 uintptr_t addr
= ml_static_slide((uintptr_t)address
->unsigned64BitValue());
3908 #if __has_feature(ptrauth_calls)
3909 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
3910 #endif /* __has_feature(ptrauth_calls) */
3913 /* Is the calling process allowed to query kext info? */
3914 if (current_task() != kernel_task
) {
3915 int macCheckResult
= 0;
3916 kauth_cred_t cred
= NULL
;
3918 cred
= kauth_cred_get_with_ref();
3919 macCheckResult
= mac_kext_check_query(cred
);
3920 kauth_cred_unref(&cred
);
3922 if (macCheckResult
!= 0) {
3923 OSKextLog(/* kext */ NULL
,
3924 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
3925 "Failed to query kext UUID (MAC policy error 0x%x).",
3931 kext
= lookupKextWithAddress(addr
);
3933 uuid
= kext
->copyTextUUID();
3938 /*********************************************************************
3939 *********************************************************************/
3941 OSKext::lookupKextWithUUID(uuid_t wanted
)
3943 OSSharedPtr
<OSKext
> foundKext
; // returned
3945 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
3946 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
3949 IORecursiveLockLock(sKextLock
);
3951 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
3952 for (i
= 0; i
< count
[j
]; i
++) {
3953 OSKext
* thisKext
= NULL
;
3955 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
3960 OSSharedPtr
<OSData
> uuid_data
= thisKext
->copyUUID();
3966 memcpy(&uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
3968 if (0 == uuid_compare(wanted
, uuid
)) {
3969 foundKext
.reset(thisKext
, OSRetain
);
3975 IORecursiveLockUnlock(sKextLock
);
3983 /*********************************************************************
3984 *********************************************************************/
3987 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
3989 bool result
= false;
3990 OSKext
* foundKext
= NULL
; // returned
3992 IORecursiveLockLock(sKextLock
);
3994 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
3995 if (foundKext
&& foundKext
->isLoaded()) {
3999 IORecursiveLockUnlock(sKextLock
);
4004 /*********************************************************************
4005 * xxx - should spawn a separate thread so a kext can safely have
4006 * xxx - itself unloaded.
4007 *********************************************************************/
4015 bool terminateServicesAndRemovePersonalitiesFlag
)
4019 kOSKextLogErrorLevel
|
4020 kOSKextLogKextBookkeepingFlag
,
4021 "removeKext() called for %s, not supported on embedded",
4022 aKext
->getIdentifier() ? aKext
->getIdentifierCString() : "unknown kext");
4024 return kOSReturnSuccess
;
4025 #else /* CONFIG_EMBEDDED */
4027 OSReturn result
= kOSKextReturnInUse
;
4028 OSKext
* checkKext
= NULL
; // do not release
4030 int macCheckResult
= 0;
4031 kauth_cred_t cred
= NULL
;
4034 IORecursiveLockLock(sKextLock
);
4036 /* If the kext has no identifier, it failed to init
4037 * so isn't in sKextsByID and it isn't loaded.
4039 if (!aKext
->getIdentifier()) {
4040 result
= kOSReturnSuccess
;
4044 checkKext
= OSDynamicCast(OSKext
,
4045 sKextsByID
->getObject(aKext
->getIdentifier()));
4046 if (checkKext
!= aKext
) {
4047 result
= kOSKextReturnNotFound
;
4051 if (aKext
->isLoaded()) {
4053 if (current_task() != kernel_task
) {
4054 cred
= kauth_cred_get_with_ref();
4055 macCheckResult
= mac_kext_check_unload(cred
, aKext
->getIdentifierCString());
4056 kauth_cred_unref(&cred
);
4059 if (macCheckResult
!= 0) {
4060 result
= kOSReturnError
;
4062 kOSKextLogErrorLevel
|
4063 kOSKextLogKextBookkeepingFlag
,
4064 "Failed to remove kext %s (MAC policy error 0x%x).",
4065 aKext
->getIdentifierCString(), macCheckResult
);
4070 /* make sure there are no resource requests in flight - 17187548 */
4071 if (aKext
->countRequestCallbacks()) {
4075 /* If we are terminating, send the request to the IOCatalogue
4076 * (which will actually call us right back but that's ok we have
4077 * a recursive lock don't you know) but do not ask the IOCatalogue
4078 * to call back with an unload, we'll do that right here.
4080 if (terminateServicesAndRemovePersonalitiesFlag
) {
4081 result
= gIOCatalogue
->terminateDriversForModule(
4082 aKext
->getIdentifierCString(), /* unload */ false);
4083 if (result
!= kOSReturnSuccess
) {
4085 kOSKextLogErrorLevel
|
4086 kOSKextLogKextBookkeepingFlag
,
4087 "Can't remove kext %s; services failed to terminate - 0x%x.",
4088 aKext
->getIdentifierCString(), result
);
4093 result
= aKext
->unload();
4094 if (result
!= kOSReturnSuccess
) {
4099 /* Remove personalities as requested. This is a bit redundant for a loaded
4100 * kext as IOCatalogue::terminateDriversForModule() removes driver
4101 * personalities, but it doesn't restart matching, which we always want
4102 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4105 if (terminateServicesAndRemovePersonalitiesFlag
) {
4106 aKext
->removePersonalitiesFromCatalog();
4109 if (aKext
->isInFileset()) {
4111 kOSKextLogProgressLevel
|
4112 kOSKextLogKextBookkeepingFlag
,
4113 "Fileset kext %s unloaded.",
4114 aKext
->getIdentifierCString());
4117 kOSKextLogProgressLevel
|
4118 kOSKextLogKextBookkeepingFlag
,
4119 "Removing kext %s.",
4120 aKext
->getIdentifierCString());
4122 sKextsByID
->removeObject(aKext
->getIdentifier());
4124 result
= kOSReturnSuccess
;
4127 IORecursiveLockUnlock(sKextLock
);
4129 #endif /* CONFIG_EMBEDDED */
4132 /*********************************************************************
4133 *********************************************************************/
4136 OSKext::removeKextWithIdentifier(
4137 const char * kextIdentifier
,
4138 bool terminateServicesAndRemovePersonalitiesFlag
)
4140 OSReturn result
= kOSReturnError
;
4142 IORecursiveLockLock(sKextLock
);
4144 OSKext
* aKext
= OSDynamicCast(OSKext
,
4145 sKextsByID
->getObject(kextIdentifier
));
4147 result
= kOSKextReturnNotFound
;
4148 OSKextLog(/* kext */ NULL
,
4149 kOSKextLogErrorLevel
|
4150 kOSKextLogKextBookkeepingFlag
,
4151 "Can't remove kext %s - not found.",
4156 result
= OSKext::removeKext(aKext
,
4157 terminateServicesAndRemovePersonalitiesFlag
);
4160 IORecursiveLockUnlock(sKextLock
);
4165 /*********************************************************************
4166 *********************************************************************/
4169 OSKext::removeKextWithLoadTag(
4170 OSKextLoadTag loadTag
,
4171 bool terminateServicesAndRemovePersonalitiesFlag
)
4173 OSReturn result
= kOSReturnError
;
4174 OSKext
* foundKext
= NULL
;
4176 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
4177 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
4180 IORecursiveLockLock(sKextLock
);
4182 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
4183 for (i
= 0; i
< count
[j
]; i
++) {
4184 OSKext
* thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
4185 if (thisKext
->loadTag
== loadTag
) {
4186 foundKext
= thisKext
;
4193 result
= kOSKextReturnNotFound
;
4194 OSKextLog(/* kext */ NULL
,
4195 kOSKextLogErrorLevel
|
4196 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
4197 "Can't remove kext with load tag %d - not found.",
4202 result
= OSKext::removeKext(foundKext
,
4203 terminateServicesAndRemovePersonalitiesFlag
);
4206 IORecursiveLockUnlock(sKextLock
);
4211 /*********************************************************************
4212 *********************************************************************/
4213 OSSharedPtr
<OSDictionary
>
4214 OSKext::copyKexts(void)
4216 OSSharedPtr
<OSDictionary
> result
;
4218 IORecursiveLockLock(sKextLock
);
4219 result
= OSDynamicPtrCast
<OSDictionary
>(sKextsByID
->copyCollection());
4220 IORecursiveLockUnlock(sKextLock
);
4225 /*********************************************************************
4226 *********************************************************************/
4227 #define BOOTER_KEXT_PREFIX "Driver-"
4229 typedef struct _DeviceTreeBuffer
{
4232 } _DeviceTreeBuffer
;
4234 /*********************************************************************
4235 * Create a dictionary of excluded kexts from the given booter data.
4236 *********************************************************************/
4239 OSKext::createExcludeListFromBooterData(
4240 OSDictionary
* theDictionary
,
4241 OSCollectionIterator
* theIterator
)
4243 OSString
* deviceTreeName
= NULL
; // do not release
4244 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not release
4245 char * booterDataPtr
= NULL
; // do not release
4246 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not release
4247 char * infoDictAddr
= NULL
; // do not release
4248 OSSharedPtr
<OSObject
> parsedXML
;
4249 OSDictionary
* theInfoDict
= NULL
; // do not release
4251 theIterator
->reset();
4253 /* look for AppleKextExcludeList.kext */
4254 while ((deviceTreeName
=
4255 OSDynamicCast(OSString
, theIterator
->getNextObject()))) {
4256 const char * devTreeNameCString
;
4257 OSData
* deviceTreeEntry
; // do not release
4258 OSString
* myBundleID
; // do not release
4261 OSDynamicCast(OSData
, theDictionary
->getObject(deviceTreeName
));
4262 if (!deviceTreeEntry
) {
4266 /* Make sure it is a kext */
4267 devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
4268 if (strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
4269 (sizeof(BOOTER_KEXT_PREFIX
) - 1)) != 0) {
4271 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4272 "\"%s\" not a kext",
4273 devTreeNameCString
);
4277 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
4278 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
4279 if (!deviceTreeBuffer
) {
4283 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
4284 if (!booterDataPtr
) {
4288 kextFileInfo
= (_BooterKextFileInfo
*) booterDataPtr
;
4289 if (!kextFileInfo
->infoDictPhysAddr
||
4290 !kextFileInfo
->infoDictLength
) {
4294 infoDictAddr
= (char *)
4295 ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
4296 if (!infoDictAddr
) {
4300 parsedXML
= OSUnserializeXML(infoDictAddr
);
4305 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
4311 OSDynamicCast(OSString
,
4312 theInfoDict
->getObject(kCFBundleIdentifierKey
));
4314 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4315 boolean_t updated
= updateExcludeList(theInfoDict
);
4318 panic("Missing OSKextExcludeList dictionary\n");
4322 } // while ( (deviceTreeName = ...) )
4327 /*********************************************************************
4328 * Create a dictionary of excluded kexts from the given prelink
4329 * info (kernelcache).
4330 *********************************************************************/
4333 OSKext::createExcludeListFromPrelinkInfo( OSArray
* theInfoArray
)
4335 OSDictionary
* myInfoDict
= NULL
; // do not release
4336 OSString
* myBundleID
; // do not release
4339 /* Find the Apple Kext Exclude List. */
4340 for (i
= 0; i
< theInfoArray
->getCount(); i
++) {
4341 myInfoDict
= OSDynamicCast(OSDictionary
, theInfoArray
->getObject(i
));
4346 OSDynamicCast(OSString
,
4347 myInfoDict
->getObject(kCFBundleIdentifierKey
));
4349 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4350 boolean_t updated
= updateExcludeList(myInfoDict
);
4353 panic("Missing OSKextExcludeList dictionary\n");
4357 } // for (i = 0; i < theInfoArray->getCount()...
4364 OSKext::updateExcludeList(OSDictionary
*infoDict
)
4366 OSDictionary
*myTempDict
= NULL
; // do not free
4367 OSString
*myTempString
= NULL
; // do not free
4368 OSKextVersion newVersion
= 0;
4369 boolean_t updated
= false;
4375 myTempDict
= OSDynamicCast(OSDictionary
, infoDict
->getObject("OSKextExcludeList"));
4380 myTempString
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundleVersionKey
));
4381 if (!myTempString
) {
4385 newVersion
= OSKextParseVersionString(myTempString
->getCStringNoCopy());
4386 if (newVersion
== 0) {
4390 IORecursiveLockLock(sKextLock
);
4392 if (newVersion
> sExcludeListVersion
) {
4393 sExcludeListByID
= OSDictionary::withDictionary(myTempDict
, 0);
4394 sExcludeListVersion
= newVersion
;
4398 IORecursiveLockUnlock(sKextLock
);
4403 #pragma mark Accessors
4405 /*********************************************************************
4406 *********************************************************************/
4408 OSKext::getIdentifier(void)
4410 return bundleID
.get();
4413 /*********************************************************************
4414 * A kext must have a bundle identifier to even survive initialization;
4415 * this is guaranteed to exist past then.
4416 *********************************************************************/
4418 OSKext::getIdentifierCString(void)
4420 return bundleID
->getCStringNoCopy();
4423 /*********************************************************************
4424 *********************************************************************/
4426 OSKext::getVersion(void)
4431 /*********************************************************************
4432 *********************************************************************/
4434 OSKext::getCompatibleVersion(void)
4436 return compatibleVersion
;
4439 /*********************************************************************
4440 *********************************************************************/
4442 OSKext::isLibrary(void)
4444 return getCompatibleVersion() > 0;
4447 /*********************************************************************
4448 *********************************************************************/
4450 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
4452 if ((compatibleVersion
> -1 && version
> -1) &&
4453 (compatibleVersion
<= version
&& aVersion
<= version
)) {
4459 /*********************************************************************
4460 *********************************************************************/
4462 OSKext::declaresExecutable(void)
4464 if (isDriverKit()) {
4467 return getPropertyForHostArch(kCFBundleExecutableKey
) != NULL
;
4470 /*********************************************************************
4471 *********************************************************************/
4473 OSKext::getExecutable(void)
4475 OSData
* result
= NULL
;
4476 OSSharedPtr
<OSData
> extractedExecutable
;
4478 if (flags
.builtin
) {
4479 return sKernelKext
->linkedExecutable
.get();
4482 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
4488 OSData
* mkextExecutableRef
= NULL
; // do not release
4489 mkextExecutableRef
= OSDynamicCast(OSData
,
4490 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
4492 if (mkextExecutableRef
) {
4493 MkextEntryRef
* mkextEntryRef
= (MkextEntryRef
*)
4494 mkextExecutableRef
->getBytesNoCopy();
4495 uint32_t mkextVersion
= MKEXT_GET_VERSION(mkextEntryRef
->mkext
);
4496 if (mkextVersion
== MKEXT_VERS_2
) {
4497 mkext2_file_entry
* fileinfo
=
4498 (mkext2_file_entry
*)mkextEntryRef
->fileinfo
;
4499 uint32_t compressedSize
= MKEXT2_GET_ENTRY_COMPSIZE(fileinfo
);
4500 uint32_t fullSize
= MKEXT2_GET_ENTRY_FULLSIZE(fileinfo
);
4501 extractedExecutable
= extractMkext2FileData(
4502 MKEXT2_GET_ENTRY_DATA(fileinfo
), "executable",
4503 compressedSize
, fullSize
);
4505 OSKextLog(this, kOSKextLogErrorLevel
|
4506 kOSKextLogArchiveFlag
,
4507 "Kext %s - unknown mkext version 0x%x for executable.",
4508 getIdentifierCString(), mkextVersion
);
4511 /* Regardless of success, remove the mkext executable,
4512 * and drop one reference on the mkext. (setExecutable() does not
4513 * replace, it removes, or panics if asked to replace.)
4515 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
4516 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
4518 if (extractedExecutable
&& extractedExecutable
->getLength()) {
4519 if (!setExecutable(extractedExecutable
.get())) {
4522 result
= extractedExecutable
.get();
4529 #endif // CONFIG_KXLD
4533 /*********************************************************************
4534 *********************************************************************/
4536 OSKext::isInterface(void)
4538 return flags
.interface
;
4541 /*********************************************************************
4542 *********************************************************************/
4544 OSKext::isKernel(void)
4546 return this == sKernelKext
;
4549 /*********************************************************************
4550 *********************************************************************/
4552 OSKext::isKernelComponent(void)
4554 return flags
.kernelComponent
? true : false;
4557 /*********************************************************************
4558 *********************************************************************/
4560 OSKext::isExecutable(void)
4562 return !isKernel() && !isInterface() && declaresExecutable();
4565 /*********************************************************************
4566 * We might want to check this recursively for all dependencies,
4567 * since a subtree of dependencies could get loaded before we hit
4568 * a dependency that isn't safe-boot-loadable.
4570 * xxx - Might want to return false if OSBundleEnableKextLogging or
4571 * OSBundleDebugLevel
4572 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4573 * the point except it's usually development drivers, which might
4574 * cause panics on startup, that have those properties). Heh; could
4575 * use a "kx" boot-arg!
4576 *********************************************************************/
4578 OSKext::isLoadableInSafeBoot(void)
4580 bool result
= false;
4581 OSString
* required
= NULL
; // do not release
4588 if (isDriverKit()) {
4593 required
= OSDynamicCast(OSString
,
4594 getPropertyForHostArch(kOSBundleRequiredKey
));
4598 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
4599 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
4600 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
4601 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
4602 required
->isEqualTo(kOSBundleRequiredConsole
)) {
4610 /*********************************************************************
4611 *********************************************************************/
4613 OSKext::isPrelinked(void)
4615 return flags
.prelinked
? true : false;
4618 /*********************************************************************
4619 *********************************************************************/
4621 OSKext::isLoaded(void)
4623 return flags
.loaded
? true : false;
4626 /*********************************************************************
4627 *********************************************************************/
4629 OSKext::isStarted(void)
4631 return flags
.started
? true : false;
4634 /*********************************************************************
4635 *********************************************************************/
4637 OSKext::isCPPInitialized(void)
4639 return flags
.CPPInitialized
;
4642 /*********************************************************************
4643 *********************************************************************/
4645 OSKext::setCPPInitialized(bool initialized
)
4647 flags
.CPPInitialized
= initialized
;
4650 /*********************************************************************
4651 *********************************************************************/
4653 OSKext::getLoadTag(void)
4658 /*********************************************************************
4659 *********************************************************************/
4661 OSKext::getSizeInfo(uint32_t *loadSize
, uint32_t *wiredSize
)
4663 if (linkedExecutable
) {
4664 *loadSize
= linkedExecutable
->getLength();
4666 /* If we have a kmod_info struct, calculated the wired size
4667 * from that. Otherwise it's the full load size.
4670 *wiredSize
= *loadSize
- (uint32_t)kmod_info
->hdr_size
;
4672 *wiredSize
= *loadSize
;
4680 /*********************************************************************
4681 *********************************************************************/
4683 OSKext::copyUUID(void)
4685 OSSharedPtr
<OSData
> result
;
4686 OSData
* theExecutable
= NULL
; // do not release
4687 const kernel_mach_header_t
* header
;
4689 /* An interface kext doesn't have a linked executable with an LC_UUID,
4690 * we create one when it's linked.
4692 if (interfaceUUID
) {
4693 result
= interfaceUUID
;
4697 if (flags
.builtin
|| isInterface()) {
4698 return sKernelKext
->copyUUID();
4701 if (isDriverKit() && infoDict
) {
4702 return driverKitUUID
;
4705 /* For real kexts, try to get the UUID from the linked executable,
4706 * or if is hasn't been linked yet, the unrelocated executable.
4708 theExecutable
= linkedExecutable
.get();
4709 if (!theExecutable
) {
4710 theExecutable
= getExecutable();
4713 if (!theExecutable
) {
4717 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
4718 result
= copyMachoUUID(header
);
4724 /*********************************************************************
4725 *********************************************************************/
4727 OSKext::copyTextUUID(void)
4729 if (flags
.builtin
) {
4730 return copyMachoUUID((const kernel_mach_header_t
*)kmod_info
->address
);
4735 /*********************************************************************
4736 *********************************************************************/
4738 OSKext::copyMachoUUID(const kernel_mach_header_t
* header
)
4740 OSSharedPtr
<OSData
> result
;
4741 const struct load_command
* load_cmd
= NULL
;
4742 const struct uuid_command
* uuid_cmd
= NULL
;
4745 load_cmd
= (const struct load_command
*)&header
[1];
4747 if (header
->magic
!= MH_MAGIC_KERNEL
) {
4749 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4750 "%s: bad header %p",
4756 for (i
= 0; i
< header
->ncmds
; i
++) {
4757 if (load_cmd
->cmd
== LC_UUID
) {
4758 uuid_cmd
= (struct uuid_command
*)load_cmd
;
4759 result
= OSData::withBytes(uuid_cmd
->uuid
, sizeof(uuid_cmd
->uuid
));
4762 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
4770 OSKext::setDriverKitUUID(OSData
*uuid
)
4772 if (!OSCompareAndSwapPtr(nullptr, uuid
, &driverKitUUID
)) {
4773 OSSafeReleaseNULL(uuid
);
4777 /*********************************************************************
4778 *********************************************************************/
4779 #if defined (__arm__)
4780 #include <arm/arch.h>
4783 #if defined (__x86_64__)
4784 #define ARCHNAME "x86_64"
4785 #elif defined (__arm64__)
4786 #define ARCHNAME "arm64"
4787 #elif defined (__arm__)
4789 #if defined (__ARM_ARCH_7S__)
4790 #define ARCHNAME "armv7s"
4791 #elif defined (__ARM_ARCH_7F__)
4792 #define ARCHNAME "armv7f"
4793 #elif defined (__ARM_ARCH_7K__)
4794 #define ARCHNAME "armv7k"
4795 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4796 #define ARCHNAME "armv7"
4797 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4798 #define ARCHNAME "armv6"
4801 #elif defined (__arm64__)
4802 #define ARCHNAME "arm64"
4804 #error architecture not supported
4807 #define ARCH_SEPARATOR_CHAR '_'
4810 makeHostArchKey(const char * key
, size_t * keySizeOut
)
4812 char * result
= NULL
;
4813 size_t keyLength
= strlen(key
);
4816 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4818 keySize
= 1 + 1 + keyLength
+ strlen(ARCHNAME
);
4819 result
= (char *)kheap_alloc_tag(KHEAP_TEMP
, keySize
,
4820 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
4825 strlcpy(result
, key
, keySize
);
4826 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
4827 result
[keyLength
] = '\0';
4828 strlcat(result
, ARCHNAME
, keySize
);
4829 *keySizeOut
= keySize
;
4835 /*********************************************************************
4836 *********************************************************************/
4838 OSKext::getPropertyForHostArch(const char * key
)
4840 OSObject
* result
= NULL
;// do not release
4841 size_t hostArchKeySize
= 0;
4842 char * hostArchKey
= NULL
;// must kfree
4844 if (!key
|| !infoDict
) {
4848 /* Some properties are not allowed to be arch-variant:
4849 * - Any CFBundle... property.
4850 * - OSBundleIsInterface.
4851 * - OSKernelResource.
4853 if (STRING_HAS_PREFIX(key
, "OS") ||
4854 STRING_HAS_PREFIX(key
, "IO")) {
4855 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
4857 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
4858 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4859 "Allocation failure.");
4862 result
= infoDict
->getObject(hostArchKey
);
4866 result
= infoDict
->getObject(key
);
4871 kheap_free(KHEAP_TEMP
, hostArchKey
, hostArchKeySize
);
4877 #pragma mark Load/Start/Stop/Unload
4880 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4882 /*********************************************************************
4883 * sExcludeListByID is a dictionary with keys / values of:
4884 * key = bundleID string of kext we will not allow to load
4885 * value = version string(s) of the kext that is to be denied loading.
4886 * The version strings can be comma delimited. For example if kext
4887 * com.foocompany.fookext has two versions that we want to deny
4888 * loading then the version strings might look like:
4890 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4891 * not load the kext.
4893 * Value may also be in the form of "LE 2.0.0" (version numbers
4894 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4895 * number less than 2.0.0 will not load)
4897 * NOTE - we cannot use the characters "<=" or "<" because we have code
4898 * that serializes plists and treats '<' as a special character.
4899 *********************************************************************/
4901 OSKext::isInExcludeList(void)
4903 OSString
* versionString
= NULL
; // do not release
4904 char * versionCString
= NULL
; // do not free
4906 boolean_t wantLessThan
= false;
4907 boolean_t wantLessThanEqualTo
= false;
4908 boolean_t isInExcludeList
= true;
4911 IORecursiveLockLock(sKextLock
);
4913 if (!sExcludeListByID
) {
4914 isInExcludeList
= false;
4916 /* look up by bundleID in our exclude list and if found get version
4917 * string (or strings) that we will not allow to load
4919 versionString
= OSDynamicCast(OSString
, sExcludeListByID
->getObject(bundleID
.get()));
4920 if (versionString
== NULL
|| versionString
->getLength() > (sizeof(myBuffer
) - 1)) {
4921 isInExcludeList
= false;
4925 IORecursiveLockUnlock(sKextLock
);
4927 if (!isInExcludeList
) {
4931 /* parse version strings */
4932 versionCString
= (char *) versionString
->getCStringNoCopy();
4934 /* look for "LT" or "LE" form of version string, must be in first two
4937 if (*versionCString
== 'L' && *(versionCString
+ 1) == 'T') {
4938 wantLessThan
= true;
4939 versionCString
+= 2;
4940 } else if (*versionCString
== 'L' && *(versionCString
+ 1) == 'E') {
4941 wantLessThanEqualTo
= true;
4942 versionCString
+= 2;
4945 for (i
= 0; *versionCString
!= 0x00; versionCString
++) {
4946 /* skip whitespace */
4947 if (isWhiteSpace(*versionCString
)) {
4951 /* peek ahead for version string separator or null terminator */
4952 if (*(versionCString
+ 1) == ',' || *(versionCString
+ 1) == 0x00) {
4953 /* OK, we have a version string */
4954 myBuffer
[i
++] = *versionCString
;
4957 OSKextVersion excludeVers
;
4958 excludeVers
= OSKextParseVersionString(myBuffer
);
4960 if (wantLessThanEqualTo
) {
4961 if (version
<= excludeVers
) {
4964 } else if (wantLessThan
) {
4965 if (version
< excludeVers
) {
4968 } else if (version
== excludeVers
) {
4972 /* reset for the next (if any) version string */
4974 wantLessThan
= false;
4975 wantLessThanEqualTo
= false;
4977 /* save valid version character */
4978 myBuffer
[i
++] = *versionCString
;
4980 /* make sure bogus version string doesn't overrun local buffer */
4981 if (i
>= sizeof(myBuffer
)) {
4990 /*********************************************************************
4991 * sNonLoadableKextsByID is a dictionary with keys / values of:
4992 * key = bundleID string of kext we will not allow to load
4993 * value = boolean (true == loadable, false == not loadable)
4995 * Only kexts which are in the AuxKC will be marked as "not loadble,"
4996 * i.e., the value for the kext's bundleID will be false. All kexts in
4997 * the primary and system KCs will always be marked as "loadable."
4999 * This list ultimately comes from kexts which have been uninstalled
5000 * in user space by deleting the kext from disk, but which have not
5001 * yet been removed from the AuxKC. Because the user could choose to
5002 * re-install the exact same version of the kext, we need to keep
5003 * a dictionary of boolean values so that user space only needs to
5004 * keep a simple list of "uninstalled" or "missing" bundles. When
5005 * a bundle is re-installed, the iokit daemon can use the
5006 * AucKCBundleAvailable predicate to set the individual kext's
5007 * availability to true.
5008 *********************************************************************/
5010 OSKext::isLoadable(void)
5012 bool isLoadable
= true;
5014 if (kc_type
!= KCKindAuxiliary
) {
5015 /* this filtering only applies to kexts in the auxkc */
5019 IORecursiveLockLock(sKextLock
);
5021 if (sNonLoadableKextsByID
) {
5022 /* look up by bundleID in our exclude list and if found get version
5023 * string (or strings) that we will not allow to load
5025 OSBoolean
*loadableVal
;
5026 loadableVal
= OSDynamicCast(OSBoolean
, sNonLoadableKextsByID
->getObject(bundleID
.get()));
5027 if (loadableVal
&& !loadableVal
->getValue()) {
5031 IORecursiveLockUnlock(sKextLock
);
5036 /*********************************************************************
5037 *********************************************************************/
5040 OSKext::loadKextWithIdentifier(
5041 const char * kextIdentifierCString
,
5042 Boolean allowDeferFlag
,
5043 Boolean delayAutounloadFlag
,
5044 OSKextExcludeLevel startOpt
,
5045 OSKextExcludeLevel startMatchingOpt
,
5046 OSArray
* personalityNames
)
5048 OSReturn result
= kOSReturnError
;
5049 OSSharedPtr
<OSString
> kextIdentifier
;
5051 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
5052 if (!kextIdentifier
) {
5053 result
= kOSKextReturnNoMemory
;
5056 result
= OSKext::loadKextWithIdentifier(kextIdentifier
.get(),
5058 allowDeferFlag
, delayAutounloadFlag
,
5059 startOpt
, startMatchingOpt
, personalityNames
);
5066 OSKext::loadKextWithIdentifier(
5067 OSString
* kextIdentifier
,
5068 OSSharedPtr
<OSObject
> &kextRef
,
5069 Boolean allowDeferFlag
,
5070 Boolean delayAutounloadFlag
,
5071 OSKextExcludeLevel startOpt
,
5072 OSKextExcludeLevel startMatchingOpt
,
5073 OSArray
* personalityNames
)
5075 OSObject
* kextRefRaw
= NULL
;
5078 result
= loadKextWithIdentifier(kextIdentifier
,
5081 delayAutounloadFlag
,
5085 if ((kOSReturnSuccess
== result
) && kextRefRaw
) {
5086 kextRef
.reset(kextRefRaw
, OSNoRetain
);
5091 /*********************************************************************
5092 *********************************************************************/
5094 OSKext::loadKextWithIdentifier(
5095 OSString
* kextIdentifier
,
5096 OSObject
** kextRef
,
5097 Boolean allowDeferFlag
,
5098 Boolean delayAutounloadFlag
,
5099 OSKextExcludeLevel startOpt
,
5100 OSKextExcludeLevel startMatchingOpt
,
5101 OSArray
* personalityNames
)
5103 OSReturn result
= kOSReturnError
;
5104 OSReturn pingResult
= kOSReturnError
;
5105 OSKext
* theKext
= NULL
; // do not release
5106 OSSharedPtr
<OSDictionary
> loadRequest
;
5107 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5113 IORecursiveLockLock(sKextLock
);
5115 if (!kextIdentifier
) {
5116 result
= kOSKextReturnInvalidArgument
;
5120 OSKext::recordIdentifierRequest(kextIdentifier
);
5122 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
5124 if (!allowDeferFlag
) {
5125 OSKextLog(/* kext */ NULL
,
5126 kOSKextLogErrorLevel
|
5128 "Can't load kext %s - not found.",
5129 kextIdentifier
->getCStringNoCopy());
5133 if (!sKernelRequestsEnabled
) {
5135 kOSKextLogErrorLevel
|
5137 "Can't load kext %s - requests to user space are disabled.",
5138 kextIdentifier
->getCStringNoCopy());
5139 result
= kOSKextReturnDisabled
;
5143 /* Create a new request unless one is already sitting
5144 * in sKernelRequests for this bundle identifier
5146 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5147 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5148 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
5150 if (result
!= kOSReturnSuccess
) {
5153 if (!_OSKextSetRequestArgument(loadRequest
.get(),
5154 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
5155 result
= kOSKextReturnNoMemory
;
5158 if (!sKernelRequests
->setObject(loadRequest
.get())) {
5159 result
= kOSKextReturnNoMemory
;
5163 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5164 result
= kOSKextReturnNoMemory
;
5169 kOSKextLogDebugLevel
|
5171 "Kext %s not found; queued load request to user space.",
5172 kextIdentifier
->getCStringNoCopy());
5175 pingResult
= OSKext::pingIOKitDaemon();
5176 if (pingResult
== kOSKextReturnDisabled
) {
5177 OSKextLog(/* kext */ NULL
,
5178 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
5180 "Kext %s might not load - " kIOKitDaemonName
" is currently unavailable.",
5181 kextIdentifier
->getCStringNoCopy());
5184 result
= kOSKextReturnDeferred
;
5188 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
5190 if (result
!= kOSReturnSuccess
) {
5192 kOSKextLogErrorLevel
|
5194 "Failed to load kext %s (error 0x%x).",
5195 kextIdentifier
->getCStringNoCopy(), (int)result
);
5197 if (theKext
->kc_type
== KCKindUnknown
) {
5198 OSKext::removeKext(theKext
,
5199 /* terminateService/removePersonalities */ true);
5204 if (delayAutounloadFlag
) {
5206 kOSKextLogProgressLevel
|
5207 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5208 "Setting delayed autounload for %s.",
5209 kextIdentifier
->getCStringNoCopy());
5210 theKext
->flags
.delayAutounload
= 1;
5214 if ((kOSReturnSuccess
== result
) && kextRef
) {
5216 theKext
->matchingRefCount
++;
5220 IORecursiveLockUnlock(sKextLock
);
5225 /*********************************************************************
5226 *********************************************************************/
5229 OSKext::loadKextFromKC(OSKext
*theKext
, OSDictionary
*requestDict
)
5231 OSReturn result
= kOSReturnError
;
5233 OSBoolean
*delayAutounloadBool
= NULL
; // do not release
5234 OSNumber
*startKextExcludeNum
= NULL
; // do not release
5235 OSNumber
*startMatchingExcludeNum
= NULL
; // do not release
5236 OSArray
*personalityNames
= NULL
; // do not release
5239 * Default values for these options:
5240 * regular autounload behavior
5242 * send all personalities to the catalog
5244 Boolean delayAutounload
= false;
5245 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
5246 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeNone
;
5248 IORecursiveLockLock(sKextLock
);
5250 OSKextLog(/* kext */ NULL
,
5251 kOSKextLogDebugLevel
|
5253 "Received kext KC load request from user space.");
5255 /* Regardless of processing, the fact that we have gotten here means some
5256 * user-space program is up and talking to us, so we'll switch our kext
5257 * registration to reflect that.
5259 if (!sUserLoadsActive
) {
5260 OSKextLog(/* kext */ NULL
,
5261 kOSKextLogProgressLevel
|
5262 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5263 "Switching to late startup (user-space) kext loading policy.");
5264 sUserLoadsActive
= true;
5267 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
5268 _OSKextGetRequestArgument(requestDict
,
5269 kKextRequestArgumentDelayAutounloadKey
));
5270 startKextExcludeNum
= OSDynamicCast(OSNumber
,
5271 _OSKextGetRequestArgument(requestDict
,
5272 kKextRequestArgumentStartExcludeKey
));
5273 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
5274 _OSKextGetRequestArgument(requestDict
,
5275 kKextRequestArgumentStartMatchingExcludeKey
));
5276 personalityNames
= OSDynamicCast(OSArray
,
5277 _OSKextGetRequestArgument(requestDict
,
5278 kKextRequestArgumentPersonalityNamesKey
));
5280 if (delayAutounloadBool
) {
5281 delayAutounload
= delayAutounloadBool
->getValue();
5283 if (startKextExcludeNum
) {
5284 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
5286 if (startMatchingExcludeNum
) {
5287 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
5290 OSKextLog(/* kext */ NULL
,
5291 kOSKextLogProgressLevel
|
5293 "Received request from user space to load KC kext %s.",
5294 theKext
->getIdentifierCString());
5296 /* this could be in the Auxiliary KC, so record the load request */
5297 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, theKext
->getIdentifier()));
5302 result
= theKext
->load(startKextExcludeLevel
,
5303 startMatchingExcludeLevel
, personalityNames
);
5305 if (result
!= kOSReturnSuccess
) {
5307 kOSKextLogErrorLevel
|
5309 "Failed to load kext %s (error 0x%x).",
5310 theKext
->getIdentifierCString(), (int)result
);
5312 OSKext::removeKext(theKext
,
5313 /* terminateService/removePersonalities */ true);
5317 kOSKextLogProgressLevel
|
5319 "Kext %s Loaded successfully from %s KC",
5320 theKext
->getIdentifierCString(), theKext
->getKCTypeString());
5323 if (delayAutounload
) {
5325 kOSKextLogProgressLevel
|
5326 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5327 "Setting delayed autounload for %s.",
5328 theKext
->getIdentifierCString());
5329 theKext
->flags
.delayAutounload
= 1;
5333 IORecursiveLockUnlock(sKextLock
);
5338 /*********************************************************************
5339 *********************************************************************/
5342 OSKext::loadCodelessKext(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
5344 OSReturn result
= kOSReturnError
;
5345 OSDictionary
*anInfoDict
= NULL
; // do not release
5347 anInfoDict
= OSDynamicCast(OSDictionary
,
5348 _OSKextGetRequestArgument(requestDict
,
5349 kKextRequestArgumentCodelessInfoKey
));
5350 if (anInfoDict
== NULL
) {
5351 OSKextLog(/* kext */ NULL
,
5352 kOSKextLogErrorLevel
|
5353 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5354 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5355 kextIdentifier
->getCStringNoCopy());
5356 return kOSKextReturnInvalidArgument
;
5359 IORecursiveLockLock(sKextLock
);
5361 OSKextLog(/* kext */ NULL
,
5362 kOSKextLogProgressLevel
|
5364 "Received request from user space to load codeless kext %s.",
5365 kextIdentifier
->getCStringNoCopy());
5368 // instantiate a new kext, and don't hold a reference
5369 // (the kext subsystem will hold one implicitly)
5370 OSSharedPtr
<OSKext
> newKext
= OSKext::withCodelessInfo(anInfoDict
);
5372 OSKextLog(/* kext */ NULL
,
5373 kOSKextLogErrorLevel
|
5374 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5375 "Could not instantiate codeless kext.");
5376 result
= kOSKextReturnNotLoadable
;
5379 if (!kextIdentifier
->isEqualTo(newKext
->getIdentifierCString())) {
5380 OSKextLog(/* kext */ NULL
,
5381 kOSKextLogErrorLevel
|
5382 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5383 "Codeless kext identifiers don't match '%s' != '%s'",
5384 kextIdentifier
->getCStringNoCopy(), newKext
->getIdentifierCString());
5386 OSKext::removeKext(newKext
.get(), false);
5387 result
= kOSKextReturnInvalidArgument
;
5391 /* Record the request for the codeless kext */
5392 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, newKext
->getIdentifier()));
5394 result
= kOSReturnSuccess
;
5395 /* send the kext's personalities to the IOCatalog */
5396 if (!newKext
->flags
.requireExplicitLoad
) {
5397 result
= newKext
->sendPersonalitiesToCatalog(true, NULL
);
5402 IORecursiveLockUnlock(sKextLock
);
5407 /*********************************************************************
5408 *********************************************************************/
5411 OSKext::dropMatchingReferences(
5414 IORecursiveLockLock(sKextLock
);
5415 kexts
->iterateObjects(^bool (OSObject
* obj
) {
5416 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
5420 thisKext
->matchingRefCount
--;
5423 IORecursiveLockUnlock(sKextLock
);
5426 /*********************************************************************
5427 *********************************************************************/
5430 OSKext::recordIdentifierRequest(
5431 OSString
* kextIdentifier
)
5433 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5436 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
5440 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5441 if (!kextIdentifierSymbol
) {
5442 // xxx - this is really a basic alloc failure
5447 IORecursiveLockLock(sKextLock
);
5448 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5449 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5452 // xxx - need to find a way to associate this whole func w/the kext
5453 OSKextLog(/* kext */ NULL
,
5454 // xxx - check level
5455 kOSKextLogStepLevel
|
5456 kOSKextLogArchiveFlag
,
5457 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5458 kextIdentifier
->getCStringNoCopy());
5461 IORecursiveLockUnlock(sKextLock
);
5466 OSKextLog(/* kext */ NULL
,
5467 kOSKextLogErrorLevel
|
5468 kOSKextLogArchiveFlag
,
5469 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5470 kextIdentifier
->getCStringNoCopy());
5475 /*********************************************************************
5476 *********************************************************************/
5479 OSKextExcludeLevel startOpt
,
5480 OSKextExcludeLevel startMatchingOpt
,
5481 OSArray
* personalityNames
)
5483 OSReturn result
= kOSReturnError
;
5484 OSKextExcludeLevel dependenciesStartOpt
= startOpt
;
5485 OSKextExcludeLevel dependenciesStartMatchingOpt
= startMatchingOpt
;
5486 unsigned int i
, count
;
5487 Boolean alreadyLoaded
= false;
5488 OSKext
* lastLoadedKext
= NULL
; // do not release
5490 if (isInExcludeList()) {
5492 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5494 "Kext %s is in exclude list, not loadable",
5495 getIdentifierCString());
5497 result
= kOSKextReturnNotLoadable
;
5500 if (!isLoadable()) {
5502 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5504 "Kext %s is not loadable",
5505 getIdentifierCString());
5507 result
= kOSKextReturnNotLoadable
;
5512 alreadyLoaded
= true;
5513 result
= kOSReturnSuccess
;
5516 kOSKextLogDebugLevel
|
5517 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5518 "Kext %s is already loaded.",
5519 getIdentifierCString());
5523 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5525 if (current_task() != kernel_task
) {
5528 * On non-kxld systems, only check the mac-hook for kexts in the
5529 * Pageable and Aux KCs. This means on Apple silicon devices that
5530 * the mac hook will only be useful to block 3rd party kexts.
5532 * Note that this should _not_ be called on kexts loaded from the
5533 * kernel bootstrap thread as the kernel proc's cred struct is not
5534 * yet initialized! This won't happen on macOS because all the kexts
5535 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5537 if (kc_type
!= KCKindPrimary
&& kc_type
!= KCKindUnknown
) {
5538 #endif /* CONFIG_KXLD */
5539 int macCheckResult
= 0;
5540 kauth_cred_t cred
= NULL
;
5542 cred
= kauth_cred_get_with_ref();
5543 macCheckResult
= mac_kext_check_load(cred
, getIdentifierCString());
5544 kauth_cred_unref(&cred
);
5546 if (macCheckResult
!= 0) {
5547 result
= kOSReturnError
;
5549 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5550 "Failed to load kext %s (MAC policy error 0x%x).",
5551 getIdentifierCString(), macCheckResult
);
5557 if (!sLoadEnabled
) {
5559 kOSKextLogErrorLevel
|
5561 "Kext loading is disabled (attempt to load kext %s).",
5562 getIdentifierCString());
5563 result
= kOSKextReturnDisabled
;
5567 /* If we've pushed the next available load tag to the invalid value,
5568 * we can't load any more kexts.
5570 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
5572 kOSKextLogErrorLevel
|
5574 "Can't load kext %s - no more load tags to assign.",
5575 getIdentifierCString());
5576 result
= kOSKextReturnNoResources
;
5580 /* This is a bit of a hack, because we shouldn't be handling
5581 * personalities within the load function.
5583 if (!declaresExecutable()) {
5584 /* There is a special case where a non-executable kext can be loaded: the
5585 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5586 * load its metadata into the global data structures, if appropriate
5588 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID
) == 0) {
5589 boolean_t updated
= updateExcludeList(infoDict
.get());
5592 kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
5593 "KextExcludeList was updated to version: %lld", sExcludeListVersion
);
5597 if (isDriverKit()) {
5599 sLoadedDriverKitKexts
->setObject(this);
5600 loadTag
= sNextLoadTag
++;
5603 result
= kOSReturnSuccess
;
5607 /* Are we in safe boot?
5609 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
5611 kOSKextLogErrorLevel
|
5613 "Can't load kext %s - not loadable during safe boot.",
5614 getIdentifierCString());
5615 result
= kOSKextReturnBootLevel
;
5620 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5622 getIdentifierCString());
5624 #if !VM_MAPPED_KEXTS
5625 if (isPrelinked() == false) {
5627 kOSKextLogErrorLevel
|
5629 "Can't load kext %s - not in a kext collection.",
5630 getIdentifierCString());
5631 result
= kOSKextReturnDisabled
;
5634 #endif /* defined(__x86_64__) */
5637 if (!sKxldContext
) {
5638 kern_return_t kxldResult
;
5639 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
5640 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
5641 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5644 kOSKextLogErrorLevel
|
5645 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
5646 "Can't load kext %s - failed to create link context.",
5647 getIdentifierCString());
5648 result
= kOSKextReturnNoMemory
;
5652 #endif // CONFIG_KXLD
5654 /* We only need to resolve dependencies once for the whole graph, but
5655 * resolveDependencies will just return if there's no work to do, so it's
5656 * safe to call it more than once.
5658 if (!resolveDependencies()) {
5659 // xxx - check resolveDependencies() for log msg
5661 kOSKextLogErrorLevel
|
5662 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5663 "Can't load kext %s - failed to resolve library dependencies.",
5664 getIdentifierCString());
5665 result
= kOSKextReturnDependencies
;
5669 /* If we are excluding just the kext being loaded now (and not its
5670 * dependencies), drop the exclusion level to none so dependencies
5671 * start and/or add their personalities.
5673 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
5674 dependenciesStartOpt
= kOSKextExcludeNone
;
5677 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
5678 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
5681 /* Load the dependencies, recursively.
5683 count
= getNumDependencies();
5684 for (i
= 0; i
< count
; i
++) {
5685 OSKext
* dependency
= OSDynamicCast(OSKext
,
5686 dependencies
->getObject(i
));
5687 if (dependency
== NULL
) {
5689 kOSKextLogErrorLevel
|
5690 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5691 "Internal error loading kext %s; dependency disappeared.",
5692 getIdentifierCString());
5693 result
= kOSKextReturnInternalError
;
5697 /* Dependencies must be started accorting to the opt,
5698 * but not given the personality names of the main kext.
5700 result
= dependency
->load(dependenciesStartOpt
,
5701 dependenciesStartMatchingOpt
,
5702 /* personalityNames */ NULL
);
5703 if (result
!= KERN_SUCCESS
) {
5705 kOSKextLogErrorLevel
|
5706 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5707 "Dependency %s of kext %s failed to load.",
5708 dependency
->getIdentifierCString(),
5709 getIdentifierCString());
5711 OSKext::removeKext(dependency
,
5712 /* terminateService/removePersonalities */ true);
5713 result
= kOSKextReturnDependencyLoadError
;
5719 result
= loadExecutable();
5720 if (result
!= KERN_SUCCESS
) {
5724 pendingPgoHead
.next
= &pendingPgoHead
;
5725 pendingPgoHead
.prev
= &pendingPgoHead
;
5727 // The kernel PRNG is not initialized when the first kext is
5728 // loaded, so use early random
5729 uuid_generate_early_random(instance_uuid
);
5730 account
= IONew(OSKextAccount
, 1);
5732 result
= KERN_MEMORY_ERROR
;
5735 bzero(account
, sizeof(*account
));
5736 account
->loadTag
= kmod_info
->id
;
5737 account
->site
.refcount
= 0;
5738 account
->site
.flags
= VM_TAG_KMOD
;
5739 account
->kext
= this;
5740 if (gIOSurfaceIdentifier
== bundleID
) {
5741 vm_tag_alloc(&account
->site
);
5742 gIOSurfaceTag
= account
->site
.tag
;
5745 flags
.loaded
= true;
5747 /* Add the kext to the list of loaded kexts and update the kmod_info
5748 * struct to point to that of the last loaded kext (which is the way
5749 * it's always been done, though I'd rather do them in order now).
5751 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5752 sLoadedKexts
->setObject(this);
5754 /* Keep the kernel itself out of the kmod list.
5756 if (lastLoadedKext
->isKernel()) {
5757 lastLoadedKext
= NULL
;
5760 if (lastLoadedKext
) {
5761 kmod_info
->next
= lastLoadedKext
->kmod_info
;
5764 notifyKextLoadObservers(this, kmod_info
);
5766 /* Make the global kmod list point at the just-loaded kext. Note that the
5767 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5768 * although we do report it in kextstat these days by using the newer
5769 * OSArray of loaded kexts, which does contain it.
5771 * (The OSKext object representing the kernel doesn't even have a kmod_info
5772 * struct, though I suppose we could stick a pointer to it from the
5773 * static struct in OSRuntime.cpp.)
5777 /* Save the list of loaded kexts in case we panic.
5779 OSKext::saveLoadedKextPanicList();
5781 if (isExecutable()) {
5782 OSKext::updateLoadedKextSummaries();
5783 savePanicString(/* isLoading */ true);
5786 registerWithDTrace();
5788 jettisonLinkeditSegment();
5789 #endif /* CONFIG_DTRACE */
5791 #if !VM_MAPPED_KEXTS
5792 /* If there is a page (or more) worth of padding after the end
5793 * of the last data section but before the end of the data segment
5794 * then free it in the same manner the LinkeditSegment is freed
5796 jettisonDATASegmentPadding();
5801 if (isExecutable() && !flags
.started
) {
5802 if (startOpt
== kOSKextExcludeNone
) {
5804 if (result
!= kOSReturnSuccess
) {
5806 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5807 "Kext %s start failed (result 0x%x).",
5808 getIdentifierCString(), result
);
5809 result
= kOSKextReturnStartStopError
;
5814 /* If not excluding matching, send the personalities to the kernel.
5815 * This never affects the result of the load operation.
5816 * This is a bit of a hack, because we shouldn't be handling
5817 * personalities within the load function.
5819 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
5820 result
= sendPersonalitiesToCatalog(true, personalityNames
);
5825 if (result
!= kOSReturnSuccess
) {
5827 kOSKextLogErrorLevel
|
5829 "Kext %s failed to load (0x%x).",
5830 getIdentifierCString(), (int)result
);
5831 } else if (!alreadyLoaded
) {
5833 kOSKextLogProgressLevel
|
5836 getIdentifierCString());
5838 queueKextNotification(kKextRequestPredicateLoadNotification
,
5839 OSDynamicCast(OSString
, bundleID
.get()));
5845 /*********************************************************************
5847 *********************************************************************/
5849 strdup(const char * string
)
5851 char * result
= NULL
;
5858 size
= 1 + strlen(string
);
5859 result
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, size
,
5860 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
5865 memcpy(result
, string
, size
);
5870 #endif // CONFIG_KXLD
5872 /*********************************************************************
5874 *********************************************************************/
5877 OSKext::lookupSection(const char *segname
, const char *secname
)
5879 kernel_section_t
* found_section
= NULL
;
5880 kernel_mach_header_t
* mh
= NULL
;
5881 kernel_segment_command_t
* seg
= NULL
;
5882 kernel_section_t
* sec
= NULL
;
5884 if (!linkedExecutable
) {
5888 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5890 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5891 if (0 != strncmp(seg
->segname
, segname
, sizeof(seg
->segname
))) {
5895 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
5896 if (0 == strncmp(sec
->sectname
, secname
, sizeof(sec
->sectname
))) {
5897 found_section
= sec
;
5904 return found_section
;
5907 /*********************************************************************
5909 *********************************************************************/
5912 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides
)
5914 OSReturn result
= kOSKextReturnBadData
;
5915 kernel_mach_header_t
* mh
= NULL
;
5916 kernel_segment_command_t
* seg
= NULL
;
5917 kernel_segment_command_t
* linkeditSeg
= NULL
;
5918 kernel_section_t
* sec
= NULL
;
5919 char * linkeditBase
= NULL
;
5920 bool haveLinkeditBase
= false;
5921 char * relocBase
= NULL
;
5922 bool haveRelocBase
= false;
5923 struct dysymtab_command
* dysymtab
= NULL
;
5924 struct linkedit_data_command
* segmentSplitInfo
= NULL
;
5925 struct symtab_command
* symtab
= NULL
;
5926 kernel_nlist_t
* sym
= NULL
;
5927 struct relocation_info
* reloc
= NULL
;
5930 vm_offset_t new_kextsize
;
5932 if (linkedExecutable
== NULL
|| flags
.builtin
) {
5933 result
= kOSReturnSuccess
;
5937 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5938 if (kernel_mach_header_is_in_fileset(mh
)) {
5939 // kexts in filesets are slid as part of collection sliding
5940 result
= kOSReturnSuccess
;
5944 segmentSplitInfo
= (struct linkedit_data_command
*) getcommandfromheader(mh
, LC_SEGMENT_SPLIT_INFO
);
5946 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5951 seg
->vmaddr
= ml_static_slide(seg
->vmaddr
);
5953 #if KASLR_KEXT_DEBUG
5954 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5956 (unsigned long)ml_static_unslide(seg
->vmaddr
),
5957 (unsigned long)seg
->vmaddr
);
5960 if (!haveRelocBase
) {
5961 relocBase
= (char *) seg
->vmaddr
;
5962 haveRelocBase
= true;
5964 if (!strcmp(seg
->segname
, "__LINKEDIT")) {
5965 linkeditBase
= (char *) seg
->vmaddr
- seg
->fileoff
;
5966 haveLinkeditBase
= true;
5969 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
5970 sec
->addr
= ml_static_slide(sec
->addr
);
5972 #if KASLR_KEXT_DEBUG
5973 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5975 (unsigned long)ml_static_unslide(sec
->addr
),
5976 (unsigned long)sec
->addr
);
5981 dysymtab
= (struct dysymtab_command
*) getcommandfromheader(mh
, LC_DYSYMTAB
);
5983 symtab
= (struct symtab_command
*) getcommandfromheader(mh
, LC_SYMTAB
);
5985 if (symtab
!= NULL
&& doCoalescedSlides
== false) {
5986 /* Some pseudo-kexts have symbol tables without segments.
5988 if (symtab
->nsyms
> 0 && haveLinkeditBase
) {
5989 sym
= (kernel_nlist_t
*) (linkeditBase
+ symtab
->symoff
);
5990 for (i
= 0; i
< symtab
->nsyms
; i
++) {
5991 if (sym
[i
].n_type
& N_STAB
) {
5994 sym
[i
].n_value
= ml_static_slide(sym
[i
].n_value
);
5996 #if KASLR_KEXT_DEBUG
5997 #define MAX_SYMS_TO_LOG 5
5998 if (i
< MAX_SYMS_TO_LOG
) {
5999 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6000 (unsigned long)ml_static_unslide(sym
[i
].n_value
),
6001 (unsigned long)sym
[i
].n_value
);
6008 if (dysymtab
!= NULL
&& doCoalescedSlides
== false) {
6009 if (dysymtab
->nextrel
> 0) {
6011 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6013 "Sliding kext %s: External relocations found.",
6014 getIdentifierCString());
6018 if (dysymtab
->nlocrel
> 0) {
6019 if (!haveLinkeditBase
) {
6021 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6023 "Sliding kext %s: No linkedit segment.",
6024 getIdentifierCString());
6028 if (!haveRelocBase
) {
6030 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6033 "Sliding kext %s: No writable segments.",
6035 "Sliding kext %s: No segments.",
6037 getIdentifierCString());
6041 reloc
= (struct relocation_info
*) (linkeditBase
+ dysymtab
->locreloff
);
6042 reloc_size
= dysymtab
->nlocrel
* sizeof(struct relocation_info
);
6044 for (i
= 0; i
< dysymtab
->nlocrel
; i
++) {
6045 if (reloc
[i
].r_extern
!= 0
6046 || reloc
[i
].r_type
!= 0
6047 || reloc
[i
].r_length
!= (sizeof(void *) == 8 ? 3 : 2)
6050 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6052 "Sliding kext %s: Unexpected relocation found.",
6053 getIdentifierCString());
6056 if (reloc
[i
].r_pcrel
!= 0) {
6059 uintptr_t *relocAddr
= (uintptr_t*)(relocBase
+ reloc
[i
].r_address
);
6060 *relocAddr
= ml_static_slide(*relocAddr
);
6062 #if KASLR_KEXT_DEBUG
6063 #define MAX_DYSYMS_TO_LOG 5
6064 if (i
< MAX_DYSYMS_TO_LOG
) {
6065 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6066 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr
))),
6067 (unsigned long)*((uintptr_t *)(relocBase
+ reloc
[i
].r_address
)));
6072 /* We should free these relocations, not just delete the reference to them.
6073 * <rdar://problem/10535549> Free relocations from PIE kexts.
6075 * For now, we do not free LINKEDIT for kexts with split segments.
6077 new_kextsize
= round_page(kmod_info
->size
- reloc_size
);
6078 if (new_kextsize
> UINT_MAX
) {
6080 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6082 "Kext %s: new kext size is too large.",
6083 getIdentifierCString());
6086 if (((kmod_info
->size
- new_kextsize
) > PAGE_SIZE
) && (!segmentSplitInfo
)) {
6087 vm_offset_t endofkext
= kmod_info
->address
+ kmod_info
->size
;
6088 vm_offset_t new_endofkext
= kmod_info
->address
+ new_kextsize
;
6089 vm_offset_t endofrelocInfo
= (vm_offset_t
) (((uint8_t *)reloc
) + reloc_size
);
6090 size_t bytes_remaining
= endofkext
- endofrelocInfo
;
6091 OSSharedPtr
<OSData
> new_osdata
;
6093 /* fix up symbol offsets if they are after the dsymtab local relocs */
6095 if (dysymtab
->locreloff
< symtab
->symoff
) {
6096 symtab
->symoff
-= reloc_size
;
6098 if (dysymtab
->locreloff
< symtab
->stroff
) {
6099 symtab
->stroff
-= reloc_size
;
6102 if (dysymtab
->locreloff
< dysymtab
->extreloff
) {
6103 dysymtab
->extreloff
-= reloc_size
;
6106 /* move data behind reloc info down to new offset */
6107 if (endofrelocInfo
< endofkext
) {
6108 memcpy(reloc
, (void *)endofrelocInfo
, bytes_remaining
);
6111 /* Create a new OSData for the smaller kext object and reflect
6112 * new linkedit segment size.
6114 linkeditSeg
->vmsize
= round_page(linkeditSeg
->vmsize
- reloc_size
);
6115 linkeditSeg
->filesize
= linkeditSeg
->vmsize
;
6117 new_osdata
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)new_kextsize
);
6119 /* Fix up kmod info and linkedExecutable.
6121 kmod_info
->size
= new_kextsize
;
6123 new_osdata
->setDeallocFunction(osdata_kext_free
);
6125 new_osdata
->setDeallocFunction(osdata_phys_free
);
6127 linkedExecutable
->setDeallocFunction(NULL
);
6128 linkedExecutable
= os::move(new_osdata
);
6131 kext_free(new_endofkext
, (endofkext
- new_endofkext
));
6133 ml_static_mfree(new_endofkext
, (endofkext
- new_endofkext
));
6137 dysymtab
->nlocrel
= 0;
6138 dysymtab
->locreloff
= 0;
6142 result
= kOSReturnSuccess
;
6147 /*********************************************************************
6148 * called only by load()
6149 *********************************************************************/
6151 OSKext::loadExecutable()
6153 OSReturn result
= kOSReturnError
;
6154 OSSharedPtr
<OSArray
> linkDependencies
;
6155 uint32_t num_kmod_refs
= 0;
6156 OSData
* theExecutable
= NULL
; // do not release
6157 OSString
* versString
= NULL
; // do not release
6158 const char * versCString
= NULL
; // do not free
6159 const char * string
= NULL
; // do not free
6163 uint32_t numDirectDependencies
= 0;
6164 kern_return_t kxldResult
;
6165 KXLDDependency
* kxlddeps
= NULL
; // must kfree
6166 uint32_t num_kxlddeps
= 0;
6167 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
6168 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
6169 #endif // CONFIG_KXLD
6171 /* We need the version string for a variety of bits below.
6173 versString
= OSDynamicCast(OSString
,
6174 getPropertyForHostArch(kCFBundleVersionKey
));
6178 versCString
= versString
->getCStringNoCopy();
6180 if (isKernelComponent()) {
6181 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
6182 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
6184 kOSKextLogErrorLevel
|
6186 "Kernel component %s has incorrect version %s; "
6188 getIdentifierCString(),
6189 versCString
, KERNEL6_VERSION
);
6190 result
= kOSKextReturnInternalError
;
6192 } else if (strcmp(versCString
, osrelease
)) {
6194 kOSKextLogErrorLevel
|
6196 "Kernel component %s has incorrect version %s; "
6198 getIdentifierCString(),
6199 versCString
, osrelease
);
6200 result
= kOSKextReturnInternalError
;
6206 #if defined(__x86_64__) || defined(__i386__)
6207 if (flags
.resetSegmentsFromVnode
) {
6208 /* Fixup the chains and slide the mach headers */
6209 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6211 if (i386_slide_individual_kext(mh
, PE_get_kc_slide(kc_type
)) != KERN_SUCCESS
) {
6212 result
= kOSKextReturnValidation
;
6216 #endif //(__x86_64__) || defined(__i386__)
6218 if (isPrelinked()) {
6222 /* <rdar://problem/21444003> all callers must be entitled */
6223 if (FALSE
== IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
)) {
6225 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6226 "Not entitled to link kext '%s'",
6227 getIdentifierCString());
6228 result
= kOSKextReturnNotPrivileged
;
6232 theExecutable
= getExecutable();
6233 if (!theExecutable
) {
6234 if (declaresExecutable()) {
6236 kOSKextLogErrorLevel
|
6238 "Can't load kext %s - executable is missing.",
6239 getIdentifierCString());
6240 result
= kOSKextReturnValidation
;
6246 if (isInterface()) {
6247 OSSharedPtr
<OSData
> executableCopy
= OSData::withData(theExecutable
);
6248 if (executableCopy
) {
6249 setLinkedExecutable(executableCopy
.get());
6255 numDirectDependencies
= getNumDependencies();
6257 if (flags
.hasBleedthrough
) {
6258 linkDependencies
= dependencies
;
6260 linkDependencies
= OSArray::withArray(dependencies
.get());
6261 if (!linkDependencies
) {
6263 kOSKextLogErrorLevel
|
6264 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6265 "Can't allocate link dependencies to load kext %s.",
6266 getIdentifierCString());
6270 for (i
= 0; i
< numDirectDependencies
; ++i
) {
6271 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
6272 dependencies
->getObject(i
));
6273 dependencyKext
->addBleedthroughDependencies(linkDependencies
.get());
6277 num_kxlddeps
= linkDependencies
->getCount();
6278 if (!num_kxlddeps
) {
6280 kOSKextLogErrorLevel
|
6281 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
6282 "Can't load kext %s - it has no library dependencies.",
6283 getIdentifierCString());
6287 kxlddeps
= (KXLDDependency
*)kalloc_tag(num_kxlddeps
* sizeof(*kxlddeps
), VM_KERN_MEMORY_OSKEXT
);
6290 kOSKextLogErrorLevel
|
6291 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6292 "Can't allocate link context to load kext %s.",
6293 getIdentifierCString());
6296 bzero(kxlddeps
, num_kxlddeps
* sizeof(*kxlddeps
));
6298 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6299 OSKext
* dependency
= OSDynamicCast(OSKext
, linkDependencies
->getObject(i
));
6301 if (dependency
->isInterface()) {
6302 OSKext
*interfaceTargetKext
= NULL
; //do not release
6303 OSData
* interfaceTarget
= NULL
; //do not release
6305 if (dependency
->isKernelComponent()) {
6306 interfaceTargetKext
= sKernelKext
;
6307 interfaceTarget
= sKernelKext
->linkedExecutable
.get();
6309 interfaceTargetKext
= OSDynamicCast(OSKext
,
6310 dependency
->dependencies
->getObject(0));
6312 interfaceTarget
= interfaceTargetKext
->linkedExecutable
.get();
6315 if (!interfaceTarget
) {
6320 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6321 * it will be useful to have them in the debugger.
6322 * strdup() failing isn't critical right here so we don't check that.
6324 kxlddeps
[i
].kext
= (u_char
*) interfaceTarget
->getBytesNoCopy();
6325 kxlddeps
[i
].kext_size
= interfaceTarget
->getLength();
6326 kxlddeps
[i
].kext_name
= strdup(interfaceTargetKext
->getIdentifierCString());
6328 if (dependency
->linkedExecutable
!= NULL
) {
6329 kxlddeps
[i
].interface
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6330 kxlddeps
[i
].interface_size
= dependency
->linkedExecutable
->getLength();
6332 kxlddeps
[i
].interface
= (u_char
*) NULL
;
6333 kxlddeps
[i
].interface_size
= 0;
6335 kxlddeps
[i
].interface_name
= strdup(dependency
->getIdentifierCString());
6337 kxlddeps
[i
].kext
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6338 kxlddeps
[i
].kext_size
= dependency
->linkedExecutable
->getLength();
6339 kxlddeps
[i
].kext_name
= strdup(dependency
->getIdentifierCString());
6342 kxlddeps
[i
].is_direct_dependency
= (i
< numDirectDependencies
);
6345 kxldHeaderPtr
= &kxld_header
;
6349 kOSKextLogExplicitLevel
|
6350 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6351 "Kext %s - calling kxld_link_file:\n"
6352 " kxld_context: %p\n"
6353 " executable: %p executable_length: %d\n"
6355 " kxld_dependencies: %p num_dependencies: %d\n"
6356 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6357 getIdentifierCString(), sKxldContext
,
6358 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
6359 this, kxlddeps
, num_kxlddeps
,
6360 kxldHeaderPtr
, &kmod_info
);
6363 /* After this call, the linkedExecutable instance variable
6366 kxldResult
= kxld_link_file(sKxldContext
,
6367 (u_char
*)theExecutable
->getBytesNoCopy(),
6368 theExecutable
->getLength(),
6369 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
6370 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
);
6372 if (kxldResult
!= KERN_SUCCESS
) {
6373 // xxx - add kxldResult here?
6375 kOSKextLogErrorLevel
|
6377 "Can't load kext %s - link failed.",
6378 getIdentifierCString());
6379 result
= kOSKextReturnLinkError
;
6383 /* We've written data & instructions into kernel memory, so flush the data
6384 * cache and invalidate the instruction cache.
6385 * I/D caches are coherent on x86
6387 #if !defined(__i386__) && !defined(__x86_64__)
6388 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
6389 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
6392 #else // !CONFIG_KXLD
6393 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6394 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6395 result
= kOSKextReturnLinkError
;
6397 #endif // CONFIG_KXLD
6401 if (isInterface()) {
6402 /* Whip up a fake kmod_info entry for the interface kext.
6404 kmod_info
= (kmod_info_t
*)kalloc_tag(sizeof(kmod_info_t
), VM_KERN_MEMORY_OSKEXT
);
6406 result
= KERN_MEMORY_ERROR
;
6410 /* A pseudokext has almost nothing in its kmod_info struct.
6412 bzero(kmod_info
, sizeof(kmod_info_t
));
6414 kmod_info
->info_version
= KMOD_INFO_VERSION
;
6416 /* An interface kext doesn't have a linkedExecutable, so save a
6417 * copy of the UUID out of the original executable via copyUUID()
6418 * while we still have the original executable.
6420 interfaceUUID
= copyUUID();
6423 kmod_info
->id
= loadTag
= sNextLoadTag
++;
6424 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
6426 /* Stamp the bundle ID and version from the OSKext over anything
6427 * resident inside the kmod_info.
6429 string
= getIdentifierCString();
6430 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
6432 string
= versCString
;
6433 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
6435 /* Add the dependencies' kmod_info structs as kmod_references.
6437 num_kmod_refs
= getNumDependencies();
6438 if (num_kmod_refs
) {
6439 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc_tag(
6440 num_kmod_refs
* sizeof(kmod_reference_t
), VM_KERN_MEMORY_OSKEXT
);
6441 if (!kmod_info
->reference_list
) {
6442 result
= KERN_MEMORY_ERROR
;
6445 bzero(kmod_info
->reference_list
,
6446 num_kmod_refs
* sizeof(kmod_reference_t
));
6447 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
6448 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
6449 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
6450 ref
->info
= refKext
->kmod_info
;
6451 ref
->info
->reference_count
++;
6453 if (refIndex
+ 1 < num_kmod_refs
) {
6454 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
6459 if (kmod_info
->hdr_size
> UINT32_MAX
) {
6461 kOSKextLogErrorLevel
|
6464 "Kext %s header size is too large (%lu > UINT32_MAX).",
6466 "Kext %s header size is too large (%u > UINT32_MAX).",
6469 kmod_info
->hdr_size
);
6470 result
= KERN_FAILURE
;
6474 if (kmod_info
->size
> UINT32_MAX
) {
6476 kOSKextLogErrorLevel
|
6479 "Kext %s size is too large (%lu > UINT32_MAX).",
6481 "Kext %s size is too large (%u > UINT32_MAX).",
6485 result
= KERN_FAILURE
;
6489 if (!isInterface() && linkedExecutable
) {
6491 kOSKextLogProgressLevel
|
6493 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6495 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
6496 (unsigned long)ml_static_unslide(kmod_info
->address
),
6497 (unsigned)kmod_info
->id
);
6500 /* VM protections and wiring for the Aux KC are done at collection loading time */
6501 if (kc_type
!= KCKindAuxiliary
|| flags
.resetSegmentsFromVnode
) {
6502 /* if prelinked and primary KC, VM protections are already set */
6503 result
= setVMAttributes(!isPrelinked() || flags
.resetSegmentsFromVnode
, true);
6504 if (result
!= KERN_SUCCESS
) {
6510 if (linkedExecutable
) {
6511 kasan_load_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(),
6512 linkedExecutable
->getLength(), getIdentifierCString());
6515 if (lookupSection(KASAN_GLOBAL_SEGNAME
, KASAN_GLOBAL_SECTNAME
)) {
6517 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6518 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6519 getIdentifierCString()
6521 result
= KERN_FAILURE
;
6526 result
= kOSReturnSuccess
;
6531 /* Clear up locally allocated dependency info.
6533 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6536 if (kxlddeps
[i
].kext_name
) {
6537 size
= 1 + strlen(kxlddeps
[i
].kext_name
);
6538 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].kext_name
, size
);
6540 if (kxlddeps
[i
].interface_name
) {
6541 size
= 1 + strlen(kxlddeps
[i
].interface_name
);
6542 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].interface_name
, size
);
6546 kfree(kxlddeps
, (num_kxlddeps
* sizeof(*kxlddeps
)));
6548 #endif // CONFIG_KXLD
6550 /* We no longer need the unrelocated executable (which the linker
6551 * has altered anyhow).
6553 setExecutable(NULL
);
6555 if (result
!= kOSReturnSuccess
) {
6557 kOSKextLogErrorLevel
|
6559 "Failed to load executable for kext %s.",
6560 getIdentifierCString());
6562 if (kmod_info
&& kmod_info
->reference_list
) {
6563 kfree(kmod_info
->reference_list
,
6564 num_kmod_refs
* sizeof(kmod_reference_t
));
6566 if (isInterface()) {
6567 kfree(kmod_info
, sizeof(kmod_info_t
));
6570 if (kc_type
== KCKindUnknown
) {
6572 if (linkedExecutable
) {
6573 linkedExecutable
.reset();
6584 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t
*mh
)
6586 kernel_segment_command_t
*linkeditseg
= NULL
;
6588 linkeditseg
= getsegbynamefromheader(mh
, SEG_LINKEDIT
);
6589 assert(linkeditseg
!= NULL
);
6591 /* BootKC on x86_64 is not vm mapped */
6592 ml_static_mfree(linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6594 OSKextLog(/* kext */ NULL
,
6595 kOSKextLogProgressLevel
|
6596 kOSKextLogGeneralFlag
,
6597 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6598 linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6600 #endif /* VM_MAPPED_KEXTS */
6602 /*********************************************************************
6603 * The linkedit segment is used by the kext linker for dependency
6604 * resolution, and by dtrace for probe initialization. We can free it
6605 * for non-library kexts, since no kexts depend on non-library kexts
6606 * by definition, once dtrace has been initialized.
6607 *********************************************************************/
6609 OSKext::jettisonLinkeditSegment(void)
6611 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
6612 kernel_segment_command_t
* linkedit
= NULL
;
6614 vm_size_t linkeditsize
, kextsize
;
6615 OSSharedPtr
<OSData
> data
;
6617 if (isInFileset()) {
6622 /* We can free symbol tables for all embedded kexts because we don't
6623 * support runtime kext linking.
6625 if (sKeepSymbols
|| !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6627 if (sKeepSymbols
|| isLibrary() || !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6632 /* Find the linkedit segment. If it's not the last segment, then freeing
6633 * it will fragment the kext into multiple VM regions, which OSKext is not
6634 * designed to handle, so we'll have to skip it.
6636 linkedit
= getsegbynamefromheader(machhdr
, SEG_LINKEDIT
);
6641 if (round_page(kmod_info
->address
+ kmod_info
->size
) !=
6642 round_page(linkedit
->vmaddr
+ linkedit
->vmsize
)) {
6646 /* Create a new OSData for the smaller kext object.
6648 linkeditsize
= round_page(linkedit
->vmsize
);
6649 kextsize
= kmod_info
->size
- linkeditsize
;
6650 start
= linkedit
->vmaddr
;
6652 if (kextsize
> UINT_MAX
) {
6655 data
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)kextsize
);
6660 /* Fix the kmod info and linkedExecutable.
6662 kmod_info
->size
= kextsize
;
6665 data
->setDeallocFunction(osdata_kext_free
);
6667 data
->setDeallocFunction(osdata_phys_free
);
6669 linkedExecutable
->setDeallocFunction(NULL
);
6670 linkedExecutable
= os::move(data
);
6671 flags
.jettisonLinkeditSeg
= 1;
6673 /* Free the linkedit segment.
6676 kext_free(start
, linkeditsize
);
6678 ml_static_mfree(start
, linkeditsize
);
6685 /*********************************************************************
6686 * If there are whole pages that are unused betweem the last section
6687 * of the DATA segment and the end of the DATA segment then we can free
6689 *********************************************************************/
6691 OSKext::jettisonDATASegmentPadding(void)
6693 kernel_mach_header_t
* mh
;
6694 kernel_segment_command_t
* dataSeg
;
6695 kernel_section_t
* sec
, * lastSec
;
6696 vm_offset_t dataSegEnd
, lastSecEnd
;
6699 if (flags
.builtin
) {
6702 mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6704 if (isInFileset()) {
6708 dataSeg
= getsegbynamefromheader(mh
, SEG_DATA
);
6709 if (dataSeg
== NULL
) {
6714 sec
= firstsect(dataSeg
);
6715 while (sec
!= NULL
) {
6717 sec
= nextsect(dataSeg
, sec
);
6720 if (lastSec
== NULL
) {
6724 if ((dataSeg
->vmaddr
!= round_page(dataSeg
->vmaddr
)) ||
6725 (dataSeg
->vmsize
!= round_page(dataSeg
->vmsize
))) {
6729 dataSegEnd
= dataSeg
->vmaddr
+ dataSeg
->vmsize
;
6730 lastSecEnd
= round_page(lastSec
->addr
+ lastSec
->size
);
6732 if (dataSegEnd
<= lastSecEnd
) {
6736 padSize
= dataSegEnd
- lastSecEnd
;
6738 if (padSize
>= PAGE_SIZE
) {
6740 kext_free(lastSecEnd
, padSize
);
6742 ml_static_mfree(lastSecEnd
, padSize
);
6747 /*********************************************************************
6748 *********************************************************************/
6750 OSKext::setLinkedExecutable(OSData
* anExecutable
)
6752 if (linkedExecutable
) {
6753 panic("Attempt to set linked executable on kext "
6754 "that already has one (%s).\n",
6755 getIdentifierCString());
6757 linkedExecutable
.reset(anExecutable
, OSRetain
);
6762 /*********************************************************************
6763 * Go through all loaded kexts and tell them to register with dtrace.
6764 * The instance method only registers if necessary.
6765 *********************************************************************/
6768 OSKext::registerKextsWithDTrace(void)
6770 uint32_t count
= sLoadedKexts
->getCount();
6773 IORecursiveLockLock(sKextLock
);
6775 for (i
= 0; i
< count
; i
++) {
6776 OSKext
* thisKext
= NULL
; // do not release
6778 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6779 if (!thisKext
|| !thisKext
->isExecutable()) {
6783 thisKext
->registerWithDTrace();
6786 IORecursiveLockUnlock(sKextLock
);
6792 extern int (*dtrace_modload
)(struct kmod_info
*, uint32_t);
6793 extern int (*dtrace_modunload
)(struct kmod_info
*);
6796 /*********************************************************************
6797 *********************************************************************/
6799 OSKext::registerWithDTrace(void)
6801 /* Register kext with dtrace. A dtrace_modload failure should not
6802 * prevent a kext from loading, so we ignore the return code.
6804 if (!flags
.dtraceInitialized
&& (dtrace_modload
!= NULL
)) {
6805 uint32_t modflag
= 0;
6806 OSObject
* forceInit
= getPropertyForHostArch("OSBundleForceDTraceInit");
6809 if (!sKeepSymbols
&& kc_type
== KCKindPrimary
) {
6810 if (forceInit
== kOSBooleanTrue
) {
6811 /* Make sure the kext is not from the Boot KC */
6812 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6814 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6815 modflag
|= KMOD_DTRACE_NO_KERNEL_SYMS
;
6818 #endif /* VM_MAPPED_KEXTS */
6819 if (forceInit
== kOSBooleanTrue
) {
6820 modflag
|= KMOD_DTRACE_FORCE_INIT
;
6822 if (flags
.builtin
) {
6823 modflag
|= KMOD_DTRACE_STATIC_KEXT
;
6826 (void)(*dtrace_modload
)(kmod_info
, modflag
);
6827 flags
.dtraceInitialized
= true;
6828 jettisonLinkeditSegment();
6832 /*********************************************************************
6833 *********************************************************************/
6835 OSKext::unregisterWithDTrace(void)
6837 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6838 * prevent a kext from loading, so we ignore the return code.
6840 if (flags
.dtraceInitialized
&& (dtrace_modunload
!= NULL
)) {
6841 (void)(*dtrace_modunload
)(kmod_info
);
6842 flags
.dtraceInitialized
= false;
6846 #endif /* CONFIG_DTRACE */
6849 /*********************************************************************
6850 * called only by loadExecutable()
6851 *********************************************************************/
6852 #if !VM_MAPPED_KEXTS
6853 #if defined(__arm__) || defined(__arm64__)
6854 static inline kern_return_t
6856 kernel_mach_header_t
*kext_mh
,
6858 vm_map_offset_t start
,
6859 vm_map_offset_t end
,
6864 #pragma unused(kext_mh,map,kc_type)
6865 assert(map
== kernel_map
); // we can handle KEXTs arising from the PRELINK segment and no others
6866 assert(start
<= end
);
6868 return KERN_SUCCESS
; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6869 } else if (set_max
) {
6870 return KERN_SUCCESS
; // Punt set_max, as there's no mechanism to record that state
6872 return ml_static_protect(start
, end
- start
, new_prot
);
6876 static inline kern_return_t
6878 kernel_mach_header_t
*kext_mh
,
6880 vm_map_offset_t start
,
6881 vm_map_offset_t end
,
6882 vm_prot_t access_type
,
6883 boolean_t user_wire
,
6886 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6887 return KERN_SUCCESS
; // No-op as PRELINK kexts are cemented into physical memory at boot
6890 #error Unrecognized architecture
6893 static inline kern_return_t
6895 kernel_mach_header_t
*kext_mh
,
6897 vm_map_offset_t start
,
6898 vm_map_offset_t end
,
6903 if (start
== end
) { // 10538581
6904 return KERN_SUCCESS
;
6906 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6908 * XXX: This will probably need to be different for AuxKC and
6911 return ml_static_protect(start
, end
- start
, new_prot
);
6913 return vm_map_protect(map
, start
, end
, new_prot
, set_max
);
6916 static inline kern_return_t
6918 kernel_mach_header_t
*kext_mh
,
6920 vm_map_offset_t start
,
6921 vm_map_offset_t end
,
6922 vm_prot_t access_type
,
6923 boolean_t user_wire
,
6926 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6927 /* TODO: we may need to hook this for the pageableKC */
6928 return KERN_SUCCESS
;
6930 return vm_map_wire_kernel(map
, start
, end
, access_type
, VM_KERN_MEMORY_KEXT
, user_wire
);
6935 OSKext::setVMAttributes(bool protect
, bool wire
)
6937 vm_map_t kext_map
= NULL
;
6938 kernel_segment_command_t
* seg
= NULL
;
6939 vm_map_offset_t start_protect
= 0;
6940 vm_map_offset_t start_wire
= 0;
6941 vm_map_offset_t end_protect
= 0;
6942 vm_map_offset_t end_wire
= 0;
6943 OSReturn result
= kOSReturnError
;
6945 if (isInterface() || !declaresExecutable() || flags
.builtin
) {
6946 result
= kOSReturnSuccess
;
6950 /* Get the kext's vm map */
6951 kext_map
= kext_get_vm_map(kmod_info
);
6953 result
= KERN_MEMORY_ERROR
;
6957 #if !VM_MAPPED_KEXTS
6958 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
)) {
6959 /* This is a split kext in a prelinked kernelcache; we'll let the
6960 * platform code take care of protecting it. It is already wired.
6962 /* TODO: Should this still allow protections for the first segment
6963 * to go through, in the event that we have a mix of split and
6966 result
= KERN_SUCCESS
;
6970 if (isInFileset() && kc_type
!= KCKindPageable
) {
6971 // kexts in filesets have protections setup as part of collection loading
6972 result
= KERN_SUCCESS
;
6977 /* Protect the headers as read-only; they do not need to be wired */
6978 result
= (protect
) ? OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
6979 kext_map
, kmod_info
->address
,
6980 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
, kc_type
)
6982 if (result
!= KERN_SUCCESS
) {
6986 /* Set the VM protections and wire down each of the segments */
6987 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
6990 /* We build all ARM kexts, so we can ensure they are aligned */
6991 assert((seg
->vmaddr
& PAGE_MASK
) == 0);
6992 assert((seg
->vmsize
& PAGE_MASK
) == 0);
6996 * For the non page aligned segments, the range calculation for protection
6997 * and wiring differ as follows:
6999 * Protection: The non page aligned data at the start or at the end of the
7000 * segment is excluded from the protection. This exclusion is needed to make
7001 * sure OSKext_protect is not called twice on same page, if the page is shared
7002 * between two segments.
7004 * Wiring: The non page aligned data at the start or at the end of the
7005 * segment is included in the wiring range, this inclusion is needed to make sure
7006 * all the data of the segment is wired.
7008 start_protect
= round_page(seg
->vmaddr
);
7009 end_protect
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
7011 start_wire
= trunc_page(seg
->vmaddr
);
7012 end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7015 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7016 * across kexts and data from kexts is not page aligned
7018 if (protect
&& (end_protect
> start_protect
) &&
7019 ((strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0 &&
7020 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) != 0) ||
7021 (kc_type
!= KCKindPageable
&& kc_type
!= KCKindAuxiliary
))) {
7022 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7023 kext_map
, start_protect
, end_protect
, seg
->maxprot
, TRUE
, kc_type
);
7024 if (result
!= KERN_SUCCESS
) {
7026 kOSKextLogErrorLevel
|
7028 "Kext %s failed to set maximum VM protections "
7029 "for segment %s - 0x%x.",
7030 getIdentifierCString(), seg
->segname
, (int)result
);
7034 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7035 kext_map
, start_protect
, end_protect
, seg
->initprot
, FALSE
, kc_type
);
7036 if (result
!= KERN_SUCCESS
) {
7038 kOSKextLogErrorLevel
|
7040 "Kext %s failed to set initial VM protections "
7041 "for segment %s - 0x%x.",
7042 getIdentifierCString(), seg
->segname
, (int)result
);
7047 if (segmentShouldBeWired(seg
) && wire
) {
7048 result
= OSKext_wire((kernel_mach_header_t
*)kmod_info
->address
,
7049 kext_map
, start_wire
, end_wire
, seg
->initprot
, FALSE
, kc_type
);
7050 if (result
!= KERN_SUCCESS
) {
7055 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7062 /*********************************************************************
7063 *********************************************************************/
7065 OSKext::segmentShouldBeWired(kernel_segment_command_t
*seg
)
7067 return sKeepSymbols
|| (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) &&
7068 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)));
7071 /*********************************************************************
7072 *********************************************************************/
7074 OSKext::validateKextMapping(bool startFlag
)
7076 OSReturn result
= kOSReturnError
;
7077 const char * whichOp
= startFlag
? "start" : "stop";
7078 kern_return_t kern_result
= 0;
7079 vm_map_t kext_map
= NULL
;
7080 kernel_segment_command_t
* seg
= NULL
;
7081 mach_vm_address_t address
= 0;
7082 mach_vm_size_t size
= 0;
7084 uint64_t kext_segbase
= 0;
7085 uint64_t kext_segsize
= 0;
7086 mach_msg_type_number_t count
;
7087 vm_region_submap_short_info_data_64_t info
;
7088 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
7090 if (flags
.builtin
) {
7091 return kOSReturnSuccess
;
7094 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
7095 bzero(&info
, sizeof(info
));
7097 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7098 // xxx - sufficient?
7100 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7104 kOSKextLogErrorLevel
|
7106 "Kext %s - NULL kmod_info pointer.",
7107 getIdentifierCString());
7108 result
= kOSKextReturnBadData
;
7113 address
= (mach_vm_address_t
)kmod_info
->start
;
7115 address
= (mach_vm_address_t
)kmod_info
->stop
;
7120 kOSKextLogErrorLevel
|
7122 "Kext %s - NULL module %s pointer.",
7123 getIdentifierCString(), whichOp
);
7124 result
= kOSKextReturnBadData
;
7128 kext_map
= kext_get_vm_map(kmod_info
);
7129 depth
= (kernel_map
== kext_map
) ? 1 : 2;
7130 if (isInFileset()) {
7131 #if defined(HAS_APPLE_PAC)
7132 address
= (mach_vm_address_t
)ptrauth_auth_data((void*)address
, ptrauth_key_function_pointer
, 0);
7133 #endif /* defined(HAS_APPLE_PAC) */
7136 /* Verify that the start/stop function lies within the kext's address range.
7138 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
) ||
7140 /* This will likely be how we deal with split kexts; walk the segments to
7141 * check that the function lies inside one of the segments of this kext.
7143 for (seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7145 seg
= nextsegfromheader((kernel_mach_header_t
*)kmod_info
->address
, seg
)) {
7146 if ((address
>= seg
->vmaddr
) && address
< (seg
->vmaddr
+ seg
->vmsize
)) {
7147 kext_segbase
= seg
->vmaddr
;
7148 kext_segsize
= seg
->vmsize
;
7155 kOSKextLogErrorLevel
|
7157 "Kext %s module %s pointer is outside of kext range "
7158 "(%s %p - kext starts at %p).",
7159 getIdentifierCString(),
7162 (void *)(((uintptr_t)address
) - kext_slide
),
7163 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
));
7164 result
= kOSKextReturnBadData
;
7170 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
7171 kmod_info
->address
+ kmod_info
->size
<= address
) {
7173 kOSKextLogErrorLevel
|
7175 "Kext %s module %s pointer is outside of kext range "
7176 "(%s %p - kext at %p-%p).",
7177 getIdentifierCString(),
7180 (void *)(((uintptr_t)address
) - kext_slide
),
7181 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
),
7182 (void *)((((uintptr_t)kmod_info
->address
) - kext_slide
) + kmod_info
->size
));
7183 result
= kOSKextReturnBadData
;
7188 /* Only do these checks before calling the start function;
7189 * If anything goes wrong with the mapping while the kext is running,
7190 * we'll likely have panicked well before any attempt to stop the kext.
7193 if (!isInFileset() || kc_type
!= KCKindPrimary
) {
7195 * Verify that the start/stop function is executable.
7197 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
7198 (vm_region_recurse_info_t
)&info
, &count
);
7199 if (kern_result
!= KERN_SUCCESS
) {
7201 kOSKextLogErrorLevel
|
7203 "Kext %s - bad %s pointer %p.",
7204 getIdentifierCString(),
7205 whichOp
, (void *)ml_static_unslide(address
));
7206 result
= kOSKextReturnBadData
;
7211 * Since kexts loaded from the primary KC are held in memory
7212 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7213 * discover that memory's protection flags. Instead, we need to
7214 * get that information from the kernel pmap itself. Above, we
7215 * (potentially) saved the size of the segment in which the address
7216 * in question was located. If we have a non-zero size, verify
7217 * that all pages in the (address, address + kext_segsize) range
7218 * are marked executable. If we somehow did not record the size
7219 * (or the base) just verify the single page that includes the address.
7221 if (kext_segbase
== 0 || kext_segsize
== 0) {
7222 kext_segbase
= address
& ~(uint64_t)PAGE_MASK
;
7223 kext_segsize
= PAGE_SIZE
;
7228 if (((!isInFileset() || kc_type
!= KCKindPrimary
) && !(info
.protection
& VM_PROT_EXECUTE
)) ||
7229 ((isInFileset() && kc_type
== KCKindPrimary
) &&
7230 ml_static_verify_page_protections(kext_segbase
, kext_segsize
, VM_PROT_EXECUTE
) != KERN_SUCCESS
)) {
7232 kOSKextLogErrorLevel
|
7234 "Kext %s - memory region containing module %s function "
7235 "is not executable.",
7236 getIdentifierCString(), whichOp
);
7237 result
= kOSKextReturnBadData
;
7242 /* Verify that the kext's segments are backed by physical memory.
7244 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7246 if (!verifySegmentMapping(seg
)) {
7247 result
= kOSKextReturnBadData
;
7251 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7255 result
= kOSReturnSuccess
;
7260 /*********************************************************************
7261 *********************************************************************/
7263 OSKext::verifySegmentMapping(kernel_segment_command_t
*seg
)
7265 mach_vm_address_t address
= 0;
7267 if (seg
->vmsize
> UINT32_MAX
) {
7271 if (!segmentShouldBeWired(seg
)) {
7275 for (address
= seg
->vmaddr
;
7276 address
< round_page(seg
->vmaddr
+ seg
->vmsize
);
7277 address
+= PAGE_SIZE
) {
7278 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
7280 kOSKextLogErrorLevel
|
7282 "Kext %s - page %p is not backed by physical memory.",
7283 getIdentifierCString(),
7292 /*********************************************************************
7293 *********************************************************************/
7295 OSKextLogKextInfo(OSKext
*aKext
, uint64_t address
, uint64_t size
, firehose_tracepoint_code_t code
)
7298 firehose_tracepoint_id_u trace_id
;
7299 struct firehose_trace_uuid_info_s uuid_info_s
;
7300 firehose_trace_uuid_info_t uuid_info
= &uuid_info_s
;
7301 size_t uuid_info_len
= sizeof(struct firehose_trace_uuid_info_s
);
7302 OSSharedPtr
<OSData
> uuid_data
;
7304 stamp
= firehose_tracepoint_time(firehose_activity_flags_default
);
7305 trace_id
.ftid_value
= FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata
, _firehose_tracepoint_type_metadata_kext
, (firehose_tracepoint_flags_t
)0, code
);
7307 uuid_data
= aKext
->copyTextUUID();
7309 memcpy(uuid_info
->ftui_uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_info
->ftui_uuid
));
7312 uuid_info
->ftui_size
= size
;
7313 if (aKext
->isDriverKit()) {
7314 uuid_info
->ftui_address
= address
;
7316 uuid_info
->ftui_address
= ml_static_unslide(address
);
7318 firehose_trace_metadata(firehose_stream_metadata
, trace_id
, stamp
, uuid_info
, uuid_info_len
);
7323 OSKext::OSKextLogDriverKitInfoLoad(OSKext
*kext
)
7325 OSKextLogKextInfo(kext
, kext
->getLoadTag(), 1, firehose_tracepoint_code_load
);
7328 /*********************************************************************
7329 *********************************************************************/
7331 OSKext::start(bool startDependenciesFlag
)
7333 OSReturn result
= kOSReturnError
;
7334 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
7335 unsigned int i
, count
;
7336 void * kmodStartData
= NULL
;
7338 if (isStarted() || isInterface() || isKernelComponent()) {
7339 result
= kOSReturnSuccess
;
7345 kOSKextLogErrorLevel
|
7347 "Attempt to start nonloaded kext %s.",
7348 getIdentifierCString());
7349 result
= kOSKextReturnInvalidArgument
;
7353 if (!sLoadEnabled
) {
7355 kOSKextLogErrorLevel
|
7357 "Kext loading is disabled (attempt to start kext %s).",
7358 getIdentifierCString());
7359 result
= kOSKextReturnDisabled
;
7363 result
= validateKextMapping(/* start? */ true);
7364 if (result
!= kOSReturnSuccess
) {
7368 startfunc
= kmod_info
->start
;
7370 count
= getNumDependencies();
7371 for (i
= 0; i
< count
; i
++) {
7372 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
7373 if (dependency
== NULL
) {
7375 kOSKextLogErrorLevel
|
7377 "Kext %s start - internal error, dependency disappeared.",
7378 getIdentifierCString());
7381 if (!dependency
->isStarted()) {
7382 if (startDependenciesFlag
) {
7383 OSReturn dependencyResult
=
7384 dependency
->start(startDependenciesFlag
);
7385 if (dependencyResult
!= KERN_SUCCESS
) {
7387 kOSKextLogErrorLevel
|
7389 "Kext %s start - dependency %s failed to start (error 0x%x).",
7390 getIdentifierCString(),
7391 dependency
->getIdentifierCString(),
7397 kOSKextLogErrorLevel
|
7399 "Not starting %s - dependency %s not started yet.",
7400 getIdentifierCString(),
7401 dependency
->getIdentifierCString());
7402 result
= kOSKextReturnStartStopError
; // xxx - make new return?
7409 kOSKextLogDetailLevel
|
7411 "Kext %s calling module start function.",
7412 getIdentifierCString());
7416 // Drop a log message so logd can grab the needed information to decode this kext
7417 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_load
);
7418 result
= OSRuntimeInitializeCPP(this);
7419 if (result
== KERN_SUCCESS
) {
7420 result
= startfunc(kmod_info
, kmodStartData
);
7425 /* On success overlap the setting of started/starting. On failure just
7428 if (result
== KERN_SUCCESS
) {
7431 // xxx - log start error from kernel?
7433 kOSKextLogProgressLevel
|
7435 "Kext %s is now started.",
7436 getIdentifierCString());
7438 invokeOrCancelRequestCallbacks(
7439 /* result not actually used */ kOSKextReturnStartStopError
,
7440 /* invokeFlag */ false);
7442 kOSKextLogWarningLevel
|
7444 "Kext %s did not start (return code 0x%x).",
7445 getIdentifierCString(), result
);
7452 /*********************************************************************
7453 *********************************************************************/
7456 OSKext::canUnloadKextWithIdentifier(
7457 OSString
* kextIdentifier
,
7458 bool checkClassesFlag
)
7460 bool result
= false;
7461 OSKext
* aKext
= NULL
; // do not release
7463 IORecursiveLockLock(sKextLock
);
7465 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
7468 goto finish
; // can't unload what's not loaded
7471 if (aKext
->isLoaded()) {
7472 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
7475 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
7483 IORecursiveLockUnlock(sKextLock
);
7487 /*********************************************************************
7488 *********************************************************************/
7492 OSReturn result
= kOSReturnError
;
7493 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
7495 if (!isStarted() || isInterface()) {
7496 result
= kOSReturnSuccess
;
7502 kOSKextLogErrorLevel
|
7504 "Attempt to stop nonloaded kext %s.",
7505 getIdentifierCString());
7506 result
= kOSKextReturnInvalidArgument
;
7510 /* Refuse to stop if we have clients or instances. It is up to
7511 * the caller to make sure those aren't true.
7513 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7515 kOSKextLogErrorLevel
|
7517 "Kext %s - C++ instances; can't stop.",
7518 getIdentifierCString());
7519 result
= kOSKextReturnInUse
;
7523 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7525 kOSKextLogErrorLevel
|
7527 "Kext %s - has references (linkage or tracking object); "
7529 getIdentifierCString());
7530 result
= kOSKextReturnInUse
;
7534 /* Note: If validateKextMapping fails on the stop & unload path,
7535 * we are in serious trouble and a kernel panic is likely whether
7536 * we stop & unload the kext or not.
7538 result
= validateKextMapping(/* start? */ false);
7539 if (result
!= kOSReturnSuccess
) {
7543 stopfunc
= kmod_info
->stop
;
7546 kOSKextLogDetailLevel
|
7548 "Kext %s calling module stop function.",
7549 getIdentifierCString());
7553 result
= stopfunc(kmod_info
, /* userData */ NULL
);
7554 if (result
== KERN_SUCCESS
) {
7555 result
= OSRuntimeFinalizeCPP(this);
7560 if (result
== KERN_SUCCESS
) {
7564 kOSKextLogDetailLevel
|
7566 "Kext %s is now stopped and ready to unload.",
7567 getIdentifierCString());
7570 kOSKextLogErrorLevel
|
7572 "Kext %s did not stop (return code 0x%x).",
7573 getIdentifierCString(), result
);
7574 result
= kOSKextReturnStartStopError
;
7579 // Drop a log message so logd can update this kext's metadata
7580 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_unload
);
7584 /*********************************************************************
7585 *********************************************************************/
7587 OSKext::unload(void)
7589 OSReturn result
= kOSReturnError
;
7591 uint32_t num_kmod_refs
= 0;
7592 OSKextAccount
* freeAccount
;
7593 bool in_fileset
= false;
7595 if (!sUnloadEnabled
) {
7597 kOSKextLogErrorLevel
|
7599 "Kext unloading is disabled (%s).",
7600 this->getIdentifierCString());
7602 result
= kOSKextReturnDisabled
;
7606 // cache this result so we don't need to access the kmod_info after
7607 // it's been potentially free'd
7608 in_fileset
= isInFileset();
7610 /* Refuse to unload if we have clients or instances. It is up to
7611 * the caller to make sure those aren't true.
7613 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7614 // xxx - Don't log under errors? this is more of an info thing
7616 kOSKextLogErrorLevel
|
7617 kOSKextLogKextBookkeepingFlag
,
7618 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7619 getIdentifierCString());
7620 result
= kOSKextReturnInUse
;
7624 if (isDriverKit()) {
7625 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7626 if (index
!= (unsigned int)-1) {
7627 sLoadedDriverKitKexts
->removeObject(index
);
7628 OSKextLogKextInfo(this, loadTag
, 1, firehose_tracepoint_code_unload
);
7634 result
= kOSReturnSuccess
;
7638 if (isKernelComponent()) {
7639 result
= kOSKextReturnInvalidArgument
;
7643 if (metaClasses
&& !OSMetaClass::removeClasses(metaClasses
.get())) {
7645 kOSKextLogErrorLevel
|
7646 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
7647 "Can't unload kext %s; classes have instances:",
7648 getIdentifierCString());
7649 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
7650 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
7651 result
= kOSKextReturnInUse
;
7655 /* Note that the kext is unloading before running any code that
7656 * might be in the kext (request callbacks, module stop function).
7657 * We will deny certain requests made against a kext in the process
7660 flags
.unloading
= 1;
7662 /* Update the string describing the last kext to unload in case we panic.
7664 savePanicString(/* isLoading */ false);
7668 if (result
!= KERN_SUCCESS
) {
7670 kOSKextLogErrorLevel
|
7672 "Kext %s can't unload - module stop returned 0x%x.",
7673 getIdentifierCString(), (unsigned)result
);
7674 result
= kOSKextReturnStartStopError
;
7680 kOSKextLogProgressLevel
|
7682 "Kext %s unloading.",
7683 getIdentifierCString());
7686 struct list_head
*p
;
7687 struct list_head
*prev
;
7688 struct list_head
*next
;
7689 for (p
= pendingPgoHead
.next
; p
!= &pendingPgoHead
; p
= next
) {
7690 OSKextGrabPgoStruct
*s
= container_of(p
, OSKextGrabPgoStruct
, list_head
);
7691 s
->err
= OSKextGrabPgoDataLocked(this, s
->metadata
, instance_uuid
, s
->pSize
, s
->pBuffer
, s
->bufferSize
);
7698 IORecursiveLockWakeup(sKextLock
, s
, false);
7703 /* Even if we don't call the stop function, we want to be sure we
7704 * have no OSMetaClass references before unloading the kext executable
7705 * from memory. OSMetaClasses may have pointers into the kext executable
7706 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7709 metaClasses
->flushCollection();
7711 (void) OSRuntimeFinalizeCPP(this);
7713 /* Remove the kext from the list of loaded kexts, patch the gap
7714 * in the kmod_info_t linked list, and reset "kmod" to point to the
7715 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7717 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7718 if (index
!= (unsigned int)-1) {
7719 sLoadedKexts
->removeObject(index
);
7721 OSKext
* nextKext
= OSDynamicCast(OSKext
,
7722 sLoadedKexts
->getObject(index
));
7726 OSKext
* gapKext
= OSDynamicCast(OSKext
,
7727 sLoadedKexts
->getObject(index
- 1));
7729 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
7730 } else { /* index == 0 */
7731 nextKext
->kmod_info
->next
= NULL
;
7735 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
7736 if (lastKext
&& !lastKext
->isKernel()) {
7737 kmod
= lastKext
->kmod_info
;
7739 kmod
= NULL
; // clear the global kmod variable
7743 /* Clear out the kmod references that we're keeping for compatibility
7744 * with current panic backtrace code & kgmacros.
7745 * xxx - will want to update those bits sometime and remove this.
7747 num_kmod_refs
= getNumDependencies();
7748 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
7749 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
7750 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
7751 ref
->info
->reference_count
--;
7753 kfree(kmod_info
->reference_list
,
7754 num_kmod_refs
* sizeof(kmod_reference_t
));
7758 unregisterWithDTrace();
7759 #endif /* CONFIG_DTRACE */
7761 notifyKextUnloadObservers(this);
7764 IOSimpleLockLock(sKextAccountsLock
);
7765 account
->kext
= NULL
;
7766 if (account
->site
.tag
) {
7767 account
->site
.flags
|= VM_TAG_UNLOAD
;
7769 freeAccount
= account
;
7771 IOSimpleLockUnlock(sKextAccountsLock
);
7773 IODelete(freeAccount
, OSKextAccount
, 1);
7776 /* Unwire and free the linked executable.
7778 if (linkedExecutable
) {
7780 kasan_unload_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(), linkedExecutable
->getLength());
7784 if (!isInterface() && (!in_fileset
|| flags
.resetSegmentsFromVnode
)) {
7785 kernel_segment_command_t
*seg
= NULL
;
7786 vm_map_t kext_map
= kext_get_vm_map(kmod_info
);
7790 kOSKextLogErrorLevel
|
7792 "Failed to free kext %s; couldn't find the kext map.",
7793 getIdentifierCString());
7794 result
= kOSKextReturnInternalError
;
7799 kOSKextLogProgressLevel
|
7801 "Kext %s unwiring and unmapping linked executable.",
7802 getIdentifierCString());
7804 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7806 if (segmentShouldBeWired(seg
)) {
7807 vm_map_offset_t start_wire
= trunc_page(seg
->vmaddr
);
7808 vm_map_offset_t end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7810 result
= vm_map_unwire(kext_map
, start_wire
,
7812 if (result
!= KERN_SUCCESS
) {
7814 kOSKextLogErrorLevel
|
7816 "Failed to unwire kext %s.",
7817 getIdentifierCString());
7818 result
= kOSKextReturnInternalError
;
7823 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7825 #if defined(__x86_64__) || defined(__i386__)
7826 if (in_fileset
&& flags
.resetSegmentsFromVnode
) {
7827 IORecursiveLockLock(sKextLock
);
7828 resetKCFileSetSegments();
7829 IORecursiveLockUnlock(sKextLock
);
7831 #endif // (__x86_64__) || defined(__i386__)
7833 #endif /* VM_MAPPED_KEXTS */
7834 if (flags
.resetSegmentsFromImmutableCopy
) {
7835 result
= resetMutableSegments();
7836 if (result
!= kOSReturnSuccess
) {
7838 kOSKextLogErrorLevel
|
7840 "Failed to reset kext %s.",
7841 getIdentifierCString());
7842 result
= kOSKextReturnInternalError
;
7846 if (kc_type
== KCKindUnknown
) {
7847 linkedExecutable
.reset();
7851 /* An interface kext has a fake kmod_info that was allocated,
7852 * so we have to free it.
7854 if (isInterface()) {
7855 kfree(kmod_info
, sizeof(kmod_info_t
));
7863 flags
.loaded
= false;
7864 flushDependencies();
7866 /* save a copy of the bundle ID for us to check when deciding to
7867 * rebuild the kernel cache file. If a kext was already in the kernel
7868 * cache and unloaded then later loaded we do not need to rebuild the
7869 * kernel cache. 9055303
7871 if (isPrelinked()) {
7872 if (!_OSKextInUnloadedPrelinkedKexts(bundleID
.get())) {
7873 IORecursiveLockLock(sKextLock
);
7874 if (sUnloadedPrelinkedKexts
) {
7875 sUnloadedPrelinkedKexts
->setObject(bundleID
.get());
7877 IORecursiveLockUnlock(sKextLock
);
7882 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
7883 "Kext %s unloaded.", getIdentifierCString());
7885 queueKextNotification(kKextRequestPredicateUnloadNotification
,
7886 OSDynamicCast(OSString
, bundleID
.get()));
7889 OSKext::saveLoadedKextPanicList();
7890 OSKext::updateLoadedKextSummaries();
7892 flags
.unloading
= 0;
7896 /*********************************************************************
7897 * Assumes sKextLock is held.
7898 *********************************************************************/
7901 OSKext::queueKextNotification(
7902 const char * notificationName
,
7903 OSString
* kextIdentifier
)
7905 OSReturn result
= kOSReturnError
;
7906 OSSharedPtr
<OSDictionary
> loadRequest
;
7908 if (!kextIdentifier
) {
7909 result
= kOSKextReturnInvalidArgument
;
7913 /* Create a new request unless one is already sitting
7914 * in sKernelRequests for this bundle identifier
7916 result
= _OSKextCreateRequest(notificationName
, loadRequest
);
7917 if (result
!= kOSReturnSuccess
) {
7920 if (!_OSKextSetRequestArgument(loadRequest
.get(),
7921 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
7922 result
= kOSKextReturnNoMemory
;
7925 if (!sKernelRequests
->setObject(loadRequest
.get())) {
7926 result
= kOSKextReturnNoMemory
;
7930 /* We might want to only queue the notification if the IOKit daemon is active,
7931 * but that wouldn't work for embedded. Note that we don't care if
7932 * the ping immediately succeeds here so don't do anything with the
7933 * result of this call.
7935 OSKext::pingIOKitDaemon();
7937 result
= kOSReturnSuccess
;
7945 /*********************************************************************
7946 *********************************************************************/
7948 _OSKextConsiderDestroyingLinkContext(
7949 __unused thread_call_param_t p0
,
7950 __unused thread_call_param_t p1
)
7952 /* Take multiple locks in the correct order.
7954 IORecursiveLockLock(sKextLock
);
7955 IORecursiveLockLock(sKextInnerLock
);
7957 /* The first time we destroy the kxldContext is in the first
7958 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
7959 * before calling this function. Thereafter any call to this function
7960 * will actually destroy the context.
7962 if (sConsiderUnloadsCalled
&& sKxldContext
) {
7963 kxld_destroy_context(sKxldContext
);
7964 sKxldContext
= NULL
;
7967 /* Free the thread_call that was allocated to execute this function.
7969 if (sDestroyLinkContextThread
) {
7970 if (!thread_call_free(sDestroyLinkContextThread
)) {
7971 OSKextLog(/* kext */ NULL
,
7972 kOSKextLogErrorLevel
|
7973 kOSKextLogGeneralFlag
,
7974 "thread_call_free() failed for kext link context.");
7976 sDestroyLinkContextThread
= NULL
;
7979 IORecursiveLockUnlock(sKextInnerLock
);
7980 IORecursiveLockUnlock(sKextLock
);
7985 /*********************************************************************
7986 * Destroying the kxldContext requires checking variables under both
7987 * sKextInnerLock and sKextLock, so we do it on a separate thread
7988 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
7989 * call relationship.
7991 * This function must be invoked with sKextInnerLock held.
7992 * Do not call any function that takes sKextLock here!
7993 *********************************************************************/
7996 OSKext::considerDestroyingLinkContext(void)
7998 IORecursiveLockLock(sKextInnerLock
);
8000 /* If we have already queued a thread to destroy the link context,
8001 * don't bother resetting; that thread will take care of it.
8003 if (sDestroyLinkContextThread
) {
8007 /* The function to be invoked in the thread will deallocate
8008 * this thread_call, so don't share it around.
8010 sDestroyLinkContextThread
= thread_call_allocate(
8011 &_OSKextConsiderDestroyingLinkContext
, NULL
);
8012 if (!sDestroyLinkContextThread
) {
8013 OSKextLog(/* kext */ NULL
,
8014 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
8015 "Can't create thread to destroy kext link context.");
8019 thread_call_enter(sDestroyLinkContextThread
);
8022 IORecursiveLockUnlock(sKextInnerLock
);
8026 #else // !CONFIG_KXLD
8030 OSKext::considerDestroyingLinkContext(void)
8035 #endif // CONFIG_KXLD
8038 #pragma mark Autounload
8040 /*********************************************************************
8041 * This is a static method because the kext will be deallocated if it
8043 *********************************************************************/
8046 OSKext::autounloadKext(OSKext
* aKext
)
8048 OSReturn result
= kOSKextReturnInUse
;
8052 * Do not unload prelinked kexts on platforms that do not have an
8053 * IOKit daemon as there is no way to reload the kext or restart
8056 if (aKext
->isPrelinked()) {
8059 #endif /* defined(__x86_64__) */
8061 /* Check for external references to this kext (usu. dependents),
8062 * instances of defined classes (or classes derived from them),
8063 * outstanding requests.
8065 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
8066 !aKext
->flags
.autounloadEnabled
||
8067 aKext
->isKernelComponent()) {
8071 /* Skip a delay-autounload kext, once.
8073 if (aKext
->flags
.delayAutounload
) {
8075 kOSKextLogProgressLevel
|
8076 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
8077 "Kext %s has delayed autounload set; skipping and clearing flag.",
8078 aKext
->getIdentifierCString());
8079 aKext
->flags
.delayAutounload
= 0;
8083 if (aKext
->hasOSMetaClassInstances() ||
8084 aKext
->countRequestCallbacks()) {
8088 result
= OSKext::removeKext(aKext
);
8094 /*********************************************************************
8095 *********************************************************************/
8097 _OSKextConsiderUnloads(
8098 __unused thread_call_param_t p0
,
8099 __unused thread_call_param_t p1
)
8101 bool didUnload
= false;
8102 unsigned int count
, i
;
8104 /* Take multiple locks in the correct order
8105 * (note also sKextSummaries lock further down).
8107 IORecursiveLockLock(sKextLock
);
8108 IORecursiveLockLock(sKextInnerLock
);
8110 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8112 /* If the system is powering down, don't try to unload anything.
8118 OSKextLog(/* kext */ NULL
,
8119 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
8120 "Checking for unused kexts to autounload.");
8123 * Remove any request callbacks marked as stale,
8124 * and mark as stale any currently in flight.
8126 count
= sRequestCallbackRecords
->getCount();
8130 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
8131 sRequestCallbackRecords
->getObject(i
));
8132 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
8133 callbackRecord
->getObject(kKextRequestStaleKey
));
8135 if (stale
== kOSBooleanTrue
) {
8136 OSKext::invokeRequestCallback(callbackRecord
,
8137 kOSKextReturnTimeout
);
8139 callbackRecord
->setObject(kKextRequestStaleKey
,
8146 * Make multiple passes through the array of loaded kexts until
8147 * we don't unload any. This handles unwinding of dependency
8148 * chains. We have to go *backwards* through the array because
8149 * kexts are removed from it when unloaded, and we cannot make
8150 * a copy or we'll mess up the retain counts we rely on to
8151 * check whether a kext will unload. If only we could have
8152 * nonretaining collections like CF has....
8157 count
= sLoadedKexts
->getCount();
8161 OSKext
* thisKext
= OSDynamicCast(OSKext
,
8162 sLoadedKexts
->getObject(i
));
8163 didUnload
|= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
8166 } while (didUnload
);
8169 sConsiderUnloadsPending
= false;
8170 sConsiderUnloadsExecuted
= true;
8172 (void) OSKext::considerRebuildOfPrelinkedKernel();
8174 IORecursiveLockUnlock(sKextInnerLock
);
8175 IORecursiveLockUnlock(sKextLock
);
8180 /*********************************************************************
8181 * Do not call any function that takes sKextLock here!
8182 *********************************************************************/
8184 OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
8188 IORecursiveLockLock(sKextInnerLock
);
8190 if (!sUnloadCallout
) {
8191 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, NULL
);
8194 /* we only reset delay value for unloading if we already have something
8195 * pending. rescheduleOnlyFlag should not start the count down.
8197 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
8201 thread_call_cancel(sUnloadCallout
);
8202 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8204 && sIOKitDaemonActive
8207 clock_interval_to_deadline(sConsiderUnloadDelay
,
8208 1000 * 1000 * 1000, &when
);
8210 OSKextLog(/* kext */ NULL
,
8211 kOSKextLogProgressLevel
|
8213 "%scheduling %sscan for unused kexts in %lu seconds.",
8214 sConsiderUnloadsPending
? "Res" : "S",
8215 sConsiderUnloadsCalled
? "" : "initial ",
8216 (unsigned long)sConsiderUnloadDelay
);
8218 sConsiderUnloadsPending
= true;
8219 thread_call_enter_delayed(sUnloadCallout
, when
);
8223 /* The kxld context should be reused throughout boot. We mark the end of
8224 * period as the first time considerUnloads() is called, and we destroy
8225 * the first kxld context in that function. Afterwards, it will be
8226 * destroyed in flushNonloadedKexts.
8228 if (!sConsiderUnloadsCalled
) {
8229 sConsiderUnloadsCalled
= true;
8230 OSKext::considerDestroyingLinkContext();
8233 IORecursiveLockUnlock(sKextInnerLock
);
8237 /*********************************************************************
8238 * Do not call any function that takes sKextLock here!
8239 *********************************************************************/
8241 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
);
8243 OSKextSystemSleepOrWake(UInt32 messageType
)
8245 IORecursiveLockLock(sKextInnerLock
);
8247 /* If the system is going to sleep, cancel the reaper thread timer,
8248 * and note that we're in a sleep state in case it just fired but hasn't
8249 * taken the lock yet. If we are coming back from sleep, just
8250 * clear the sleep flag; IOService's normal operation will cause
8251 * unloads to be considered soon enough.
8253 if (messageType
== kIOMessageSystemWillSleep
) {
8254 if (sUnloadCallout
) {
8255 thread_call_cancel(sUnloadCallout
);
8257 sSystemSleep
= true;
8258 AbsoluteTime_to_scalar(&sLastWakeTime
) = 0;
8259 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
8260 sSystemSleep
= false;
8261 clock_get_uptime(&sLastWakeTime
);
8263 IORecursiveLockUnlock(sKextInnerLock
);
8265 return kIOReturnSuccess
;
8271 #pragma mark Prelinked Kernel
8275 /*********************************************************************
8276 * Do not access sConsiderUnloads... variables other than
8277 * sConsiderUnloadsExecuted in this function. They are guarded by a
8279 *********************************************************************/
8282 OSKext::considerRebuildOfPrelinkedKernel(void)
8284 static bool requestedPrelink
= false;
8285 OSReturn checkResult
= kOSReturnError
;
8286 OSSharedPtr
<OSDictionary
> prelinkRequest
;
8287 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
8288 const OSSymbol
* thisID
= NULL
; // do not release
8289 bool doRebuild
= false;
8290 AbsoluteTime my_abstime
;
8294 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8295 if (requestedPrelink
|| !sPrelinkBoot
) {
8299 /* no direct return from this point */
8300 IORecursiveLockLock(sKextLock
);
8302 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8303 * and any new startup kexts loaded.
8305 if (!sConsiderUnloadsExecuted
||
8306 !sDeferredLoadSucceeded
) {
8310 /* we really only care about boot / system start up related kexts so bail
8311 * if we're here after REBUILD_MAX_TIME.
8313 if (!_OSKextInPrelinkRebuildWindow()) {
8314 OSKextLog(/* kext */ NULL
,
8315 kOSKextLogArchiveFlag
,
8316 "%s prebuild rebuild has expired",
8318 requestedPrelink
= true;
8322 /* we do not want to trigger a rebuild if we get here too close to waking
8323 * up. (see radar 10233768)
8325 IORecursiveLockLock(sKextInnerLock
);
8327 clock_get_uptime(&my_abstime
);
8328 delta_secs
= MINIMUM_WAKEUP_SECONDS
+ 1;
8329 if (AbsoluteTime_to_scalar(&sLastWakeTime
) != 0) {
8330 SUB_ABSOLUTETIME(&my_abstime
, &sLastWakeTime
);
8331 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
8332 delta_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
8334 IORecursiveLockUnlock(sKextInnerLock
);
8336 if (delta_secs
< MINIMUM_WAKEUP_SECONDS
) {
8337 /* too close to time of last wake from sleep */
8340 requestedPrelink
= true;
8342 /* Now it's time to see if we have a reason to rebuild. We may have done
8343 * some loads and unloads but the kernel cache didn't actually change.
8344 * We will rebuild if any kext is not marked prelinked AND is not in our
8345 * list of prelinked kexts that got unloaded. (see radar 9055303)
8347 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
8348 if (!kextIterator
) {
8352 while ((thisID
= OSDynamicCast(OSSymbol
, kextIterator
->getNextObject()))) {
8353 OSKext
* thisKext
; // do not release
8355 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
8356 if (!thisKext
|| thisKext
->isPrelinked() || thisKext
->isKernel()) {
8360 if (_OSKextInUnloadedPrelinkedKexts(thisKext
->bundleID
.get())) {
8363 /* kext is loaded and was not in current kernel cache so let's rebuild
8366 OSKextLog(/* kext */ NULL
,
8367 kOSKextLogArchiveFlag
,
8368 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8369 thisKext
->bundleID
->getCStringNoCopy());
8372 sUnloadedPrelinkedKexts
->flushCollection();
8378 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
8380 if (checkResult
!= kOSReturnSuccess
) {
8384 if (!sKernelRequests
->setObject(prelinkRequest
.get())) {
8388 OSKext::pingIOKitDaemon();
8391 IORecursiveLockUnlock(sKextLock
);
8396 #else /* !CONFIG_KXLD */
8399 OSKext::considerRebuildOfPrelinkedKernel(void)
8401 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8405 #endif /* CONFIG_KXLD */
8408 #pragma mark Dependencies
8410 /*********************************************************************
8411 *********************************************************************/
8413 OSKext::resolveDependencies(
8414 OSArray
* loopStack
)
8416 bool result
= false;
8417 OSSharedPtr
<OSArray
> localLoopStack
;
8418 bool addedToLoopStack
= false;
8419 OSDictionary
* libraries
= NULL
; // do not release
8420 OSSharedPtr
<OSCollectionIterator
> libraryIterator
;
8421 OSString
* libraryID
= NULL
; // do not release
8422 OSKext
* libraryKext
= NULL
; // do not release
8423 bool hasRawKernelDependency
= false;
8424 bool hasKernelDependency
= false;
8425 bool hasKPIDependency
= false;
8426 bool hasPrivateKPIDependency
= false;
8430 OSString
* infoString
= NULL
; // do not release
8431 OSString
* readableString
= NULL
; // do not release
8432 #endif // CONFIG_KXLD
8434 /* A kernel component will automatically have this flag set,
8435 * and a loaded kext should also have it set (as should all its
8436 * loaded dependencies).
8438 if (flags
.hasAllDependencies
) {
8443 /* Check for loops in the dependency graph.
8446 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8448 kOSKextLogErrorLevel
|
8449 kOSKextLogDependenciesFlag
,
8450 "Kext %s has a dependency loop; can't resolve dependencies.",
8451 getIdentifierCString());
8456 kOSKextLogStepLevel
|
8457 kOSKextLogDependenciesFlag
,
8458 "Kext %s resolving dependencies.",
8459 getIdentifierCString());
8461 localLoopStack
= OSArray::withCapacity(6); // any small capacity will do
8462 if (!localLoopStack
) {
8464 kOSKextLogErrorLevel
|
8465 kOSKextLogDependenciesFlag
,
8466 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8467 getIdentifierCString());
8470 loopStack
= localLoopStack
.get();
8472 if (!loopStack
->setObject(this)) {
8474 kOSKextLogErrorLevel
|
8475 kOSKextLogDependenciesFlag
,
8476 "Kext %s - internal error resolving dependencies.",
8477 getIdentifierCString());
8480 addedToLoopStack
= true;
8482 /* Purge any existing kexts in the dependency list and start over.
8484 flushDependencies();
8487 kOSKextLogErrorLevel
|
8488 kOSKextLogDependenciesFlag
,
8489 "Kext %s - internal error resolving dependencies.",
8490 getIdentifierCString());
8493 libraries
= OSDynamicCast(OSDictionary
,
8494 getPropertyForHostArch(kOSBundleLibrariesKey
));
8495 if (libraries
== NULL
|| libraries
->getCount() == 0) {
8497 kOSKextLogErrorLevel
|
8498 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8499 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8500 getIdentifierCString(), kOSBundleLibrariesKey
);
8504 /* Make a new array to hold the dependencies (flush freed the old one).
8506 dependencies
= OSArray::withCapacity(libraries
->getCount());
8507 if (!dependencies
) {
8509 kOSKextLogErrorLevel
|
8510 kOSKextLogDependenciesFlag
,
8511 "Kext %s - can't allocate dependencies array.",
8512 getIdentifierCString());
8516 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8517 // xxx - compat: if none were declared.
8519 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
8520 if (!libraryIterator
) {
8522 kOSKextLogErrorLevel
|
8523 kOSKextLogDependenciesFlag
,
8524 "Kext %s - can't allocate dependencies iterator.",
8525 getIdentifierCString());
8529 while ((libraryID
= OSDynamicCast(OSString
,
8530 libraryIterator
->getNextObject()))) {
8531 const char * library_id
= libraryID
->getCStringNoCopy();
8533 OSString
* libraryVersion
= OSDynamicCast(OSString
,
8534 libraries
->getObject(libraryID
));
8535 if (libraryVersion
== NULL
) {
8537 kOSKextLogErrorLevel
|
8538 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8539 "Kext %s - illegal type in OSBundleLibraries.",
8540 getIdentifierCString());
8544 OSKextVersion libraryVers
=
8545 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
8546 if (libraryVers
== -1) {
8548 kOSKextLogErrorLevel
|
8549 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8550 "Kext %s - invalid library version %s.",
8551 getIdentifierCString(),
8552 libraryVersion
->getCStringNoCopy());
8556 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
8557 if (libraryKext
== NULL
) {
8559 kOSKextLogErrorLevel
|
8560 kOSKextLogDependenciesFlag
,
8561 "Kext %s - library kext %s not found.",
8562 getIdentifierCString(), library_id
);
8566 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
8568 kOSKextLogErrorLevel
|
8569 kOSKextLogDependenciesFlag
,
8570 "Kext %s - library kext %s not compatible "
8571 "with requested version %s.",
8572 getIdentifierCString(), library_id
,
8573 libraryVersion
->getCStringNoCopy());
8577 /* If a nonprelinked library somehow got into the mix for a
8578 * prelinked kext, at any point in the chain, we must fail
8579 * because the prelinked relocs for the library will be all wrong.
8581 if (this->isPrelinked() &&
8582 libraryKext
->declaresExecutable() &&
8583 !libraryKext
->isPrelinked()) {
8585 kOSKextLogErrorLevel
|
8586 kOSKextLogDependenciesFlag
,
8587 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8588 getIdentifierCString(), library_id
,
8589 libraryVersion
->getCStringNoCopy());
8593 if (!libraryKext
->resolveDependencies(loopStack
)) {
8597 /* Add the library directly only if it has an executable to link.
8598 * Otherwise it's just used to collect other dependencies, so put
8599 * *its* dependencies on the list for this kext.
8601 // xxx - We are losing info here; would like to make fake entries or
8602 // xxx - keep these in the dependency graph for loaded kexts.
8603 // xxx - I really want to make kernel components not a special case!
8604 if (libraryKext
->declaresExecutable() ||
8605 libraryKext
->isInterface()) {
8606 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
8607 dependencies
->setObject(libraryKext
);
8610 kOSKextLogDetailLevel
|
8611 kOSKextLogDependenciesFlag
,
8612 "Kext %s added dependency %s.",
8613 getIdentifierCString(),
8614 libraryKext
->getIdentifierCString());
8617 int numLibDependencies
= libraryKext
->getNumDependencies();
8618 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
8621 if (numLibDependencies
) {
8622 // xxx - this msg level should be 1 lower than the per-kext one
8624 kOSKextLogDetailLevel
|
8625 kOSKextLogDependenciesFlag
,
8626 "Kext %s pulling %d dependencies from codeless library %s.",
8627 getIdentifierCString(),
8629 libraryKext
->getIdentifierCString());
8631 for (index
= 0; index
< numLibDependencies
; index
++) {
8632 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
8633 libraryDependencies
->getObject(index
));
8634 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
8635 dependencies
->setObject(thisLibDependency
);
8637 kOSKextLogDetailLevel
|
8638 kOSKextLogDependenciesFlag
,
8639 "Kext %s added dependency %s from codeless library %s.",
8640 getIdentifierCString(),
8641 thisLibDependency
->getIdentifierCString(),
8642 libraryKext
->getIdentifierCString());
8647 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
8648 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
) - 1)) {
8649 hasRawKernelDependency
= true;
8650 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
8651 hasKernelDependency
= true;
8652 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
8653 hasKPIDependency
= true;
8654 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
) - 1)) {
8655 hasPrivateKPIDependency
= true;
8660 if (hasRawKernelDependency
) {
8662 kOSKextLogErrorLevel
|
8663 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8664 "Error - kext %s declares a dependency on %s, which is not permitted.",
8665 getIdentifierCString(), KERNEL_LIB
);
8669 if (hasKernelDependency
) {
8671 kOSKextLogErrorLevel
|
8672 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8673 "Error - kext %s declares %s dependencies. "
8674 "Only %s* dependencies are supported for 64-bit kexts.",
8675 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8678 if (!hasKPIDependency
) {
8680 kOSKextLogWarningLevel
|
8681 kOSKextLogDependenciesFlag
,
8682 "Warning - kext %s declares no %s* dependencies. "
8683 "If it uses any KPIs, the link may fail with undefined symbols.",
8684 getIdentifierCString(), KPI_LIB_PREFIX
);
8686 #else /* __LP64__ */
8687 // xxx - will change to flatly disallow "kernel" dependencies at some point
8688 // xxx - is it invalid to do both "com.apple.kernel" and any
8689 // xxx - "com.apple.kernel.*"?
8691 if (hasKernelDependency
&& hasKPIDependency
) {
8693 kOSKextLogWarningLevel
|
8694 kOSKextLogDependenciesFlag
,
8695 "Warning - kext %s has immediate dependencies on both "
8696 "%s* and %s* components; use only one style.",
8697 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8700 if (!hasKernelDependency
&& !hasKPIDependency
) {
8701 // xxx - do we want to use validation flag for these too?
8703 kOSKextLogWarningLevel
|
8704 kOSKextLogDependenciesFlag
,
8705 "Warning - %s declares no kernel dependencies; using %s.",
8706 getIdentifierCString(), KERNEL6_LIB
);
8707 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
8708 sKextsByID
->getObject(KERNEL6_LIB
));
8710 dependencies
->setObject(kernelKext
);
8713 kOSKextLogErrorLevel
|
8714 kOSKextLogDependenciesFlag
,
8715 "Error - Library %s not found for %s.",
8716 KERNEL6_LIB
, getIdentifierCString());
8720 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8721 * its indirect dependencies to simulate old-style linking. XXX - Should
8722 * check for duplicates.
8724 if (!hasKPIDependency
) {
8727 flags
.hasBleedthrough
= true;
8729 count
= getNumDependencies();
8731 /* We add to the dependencies array in this loop, but do not iterate
8732 * past its original count.
8734 for (i
= 0; i
< count
; i
++) {
8735 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
8736 dependencies
->getObject(i
));
8737 dependencyKext
->addBleedthroughDependencies(dependencies
.get());
8740 #endif /* __LP64__ */
8744 * If we're not dynamically linking kexts, then we don't need to check
8745 * copyright strings. The linker in user space has already done this.
8747 if (hasPrivateKPIDependency
) {
8748 bool hasApplePrefix
= false;
8749 bool infoCopyrightIsValid
= false;
8750 bool readableCopyrightIsValid
= false;
8752 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
8755 infoString
= OSDynamicCast(OSString
,
8756 getPropertyForHostArch("CFBundleGetInfoString"));
8758 infoCopyrightIsValid
=
8759 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
8762 readableString
= OSDynamicCast(OSString
,
8763 getPropertyForHostArch("NSHumanReadableCopyright"));
8764 if (readableString
) {
8765 readableCopyrightIsValid
=
8766 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
8769 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
8771 kOSKextLogErrorLevel
|
8772 kOSKextLogDependenciesFlag
,
8773 "Error - kext %s declares a dependency on %s. "
8774 "Only Apple kexts may declare a dependency on %s.",
8775 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
8779 #endif // CONFIG_KXLD
8782 flags
.hasAllDependencies
= 1;
8786 if (addedToLoopStack
) {
8787 count
= loopStack
->getCount();
8788 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
8789 loopStack
->removeObject(count
- 1);
8792 kOSKextLogErrorLevel
|
8793 kOSKextLogDependenciesFlag
,
8794 "Kext %s - internal error resolving dependencies.",
8795 getIdentifierCString());
8799 if (result
&& localLoopStack
) {
8801 kOSKextLogStepLevel
|
8802 kOSKextLogDependenciesFlag
,
8803 "Kext %s successfully resolved dependencies.",
8804 getIdentifierCString());
8810 /*********************************************************************
8811 *********************************************************************/
8813 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
8815 bool result
= false;
8816 unsigned int dependencyIndex
, dependencyCount
;
8818 dependencyCount
= getNumDependencies();
8820 for (dependencyIndex
= 0;
8821 dependencyIndex
< dependencyCount
;
8822 dependencyIndex
++) {
8823 OSKext
* dependency
= OSDynamicCast(OSKext
,
8824 dependencies
->getObject(dependencyIndex
));
8827 kOSKextLogErrorLevel
|
8828 kOSKextLogDependenciesFlag
,
8829 "Kext %s - internal error propagating compatibility dependencies.",
8830 getIdentifierCString());
8833 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
8834 anArray
->setObject(dependency
);
8836 dependency
->addBleedthroughDependencies(anArray
);
8845 /*********************************************************************
8846 *********************************************************************/
8848 OSKext::flushDependencies(bool forceFlag
)
8850 bool result
= false;
8852 /* Only clear the dependencies if the kext isn't loaded;
8853 * we need the info for loaded kexts to track references.
8855 if (!isLoaded() || forceFlag
) {
8857 // xxx - check level
8859 kOSKextLogProgressLevel
|
8860 kOSKextLogDependenciesFlag
,
8861 "Kext %s flushing dependencies.",
8862 getIdentifierCString());
8863 dependencies
.reset();
8865 if (!isKernelComponent()) {
8866 flags
.hasAllDependencies
= 0;
8874 /*********************************************************************
8875 *********************************************************************/
8877 OSKext::getNumDependencies(void)
8879 if (!dependencies
) {
8882 return dependencies
->getCount();
8885 /*********************************************************************
8886 *********************************************************************/
8888 OSKext::getDependencies(void)
8890 return dependencies
.get();
8894 OSKext::hasDependency(const OSSymbol
* depID
)
8896 bool result __block
;
8898 if (depID
== getIdentifier()) {
8901 if (!dependencies
) {
8905 dependencies
->iterateObjects(^bool (OSObject
* obj
) {
8907 kext
= OSDynamicCast(OSKext
, obj
);
8911 result
= (depID
== kext
->getIdentifier());
8918 #pragma mark OSMetaClass Support
8920 /*********************************************************************
8921 *********************************************************************/
8924 OSMetaClass
* aClass
,
8925 uint32_t numClasses
)
8927 OSReturn result
= kOSMetaClassNoInsKModSet
;
8930 metaClasses
= OSSet::withCapacity(numClasses
);
8936 if (metaClasses
->containsObject(aClass
)) {
8938 kOSKextLogWarningLevel
|
8940 "Notice - kext %s has already registered class %s.",
8941 getIdentifierCString(),
8942 aClass
->getClassName());
8943 result
= kOSReturnSuccess
;
8947 if (!metaClasses
->setObject(aClass
)) {
8951 kOSKextLogDetailLevel
|
8953 "Kext %s registered class %s.",
8954 getIdentifierCString(),
8955 aClass
->getClassName());
8958 if (!flags
.autounloadEnabled
) {
8959 const OSMetaClass
* metaScan
= NULL
; // do not release
8961 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
8962 if (metaScan
== OSTypeID(IOService
)) {
8964 kOSKextLogProgressLevel
|
8966 "Kext %s has IOService subclass %s; enabling autounload.",
8967 getIdentifierCString(),
8968 aClass
->getClassName());
8970 flags
.autounloadEnabled
= 1;
8976 notifyAddClassObservers(this, aClass
, flags
);
8978 result
= kOSReturnSuccess
;
8981 if (result
!= kOSReturnSuccess
) {
8983 kOSKextLogErrorLevel
|
8985 "Kext %s failed to register class %s.",
8986 getIdentifierCString(),
8987 aClass
->getClassName());
8993 /*********************************************************************
8994 *********************************************************************/
8996 OSKext::removeClass(
8997 OSMetaClass
* aClass
)
8999 OSReturn result
= kOSMetaClassNoKModSet
;
9005 if (!metaClasses
->containsObject(aClass
)) {
9007 kOSKextLogWarningLevel
|
9009 "Notice - kext %s asked to unregister unknown class %s.",
9010 getIdentifierCString(),
9011 aClass
->getClassName());
9012 result
= kOSReturnSuccess
;
9017 kOSKextLogDetailLevel
|
9019 "Kext %s unregistering class %s.",
9020 getIdentifierCString(),
9021 aClass
->getClassName());
9023 metaClasses
->removeObject(aClass
);
9025 notifyRemoveClassObservers(this, aClass
, flags
);
9027 result
= kOSReturnSuccess
;
9030 if (result
!= kOSReturnSuccess
) {
9032 kOSKextLogErrorLevel
|
9034 "Failed to unregister kext %s class %s.",
9035 getIdentifierCString(),
9036 aClass
->getClassName());
9041 /*********************************************************************
9042 *********************************************************************/
9044 OSKext::getMetaClasses(void)
9046 return metaClasses
.get();
9049 /*********************************************************************
9050 *********************************************************************/
9052 OSKext::hasOSMetaClassInstances(void)
9054 bool result
= false;
9055 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9056 OSMetaClass
* checkClass
= NULL
; // do not release
9062 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9063 if (!classIterator
) {
9064 // xxx - log alloc failure?
9067 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9068 if (checkClass
->getInstanceCount()) {
9078 /*********************************************************************
9079 *********************************************************************/
9082 OSKext::reportOSMetaClassInstances(
9083 const char * kextIdentifier
,
9084 OSKextLogSpec msgLogSpec
)
9086 OSSharedPtr
<OSKext
> theKext
;
9088 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
9093 theKext
->reportOSMetaClassInstances(msgLogSpec
);
9098 /*********************************************************************
9099 *********************************************************************/
9101 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
9103 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9104 OSMetaClass
* checkClass
= NULL
; // do not release
9110 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9111 if (!classIterator
) {
9114 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9115 if (checkClass
->getInstanceCount()) {
9118 " Kext %s class %s has %d instance%s.",
9119 getIdentifierCString(),
9120 checkClass
->getClassName(),
9121 checkClass
->getInstanceCount(),
9122 checkClass
->getInstanceCount() == 1 ? "" : "s");
9131 #pragma mark User-Space Requests
9134 static kern_return_t
9135 patchDextLaunchRequests(task_t calling_task
, OSArray
*requests
)
9137 OSReturn result
= kOSReturnSuccess
;
9138 for (uint32_t requestIndex
= 0; requestIndex
< requests
->getCount(); requestIndex
++) {
9139 OSDictionary
* request
= NULL
; //do not release
9140 IOUserServerCheckInToken
* token
= NULL
; //do not release
9141 OSString
* requestPredicate
= NULL
; //do not release
9142 OSSharedPtr
<OSNumber
> portNameNumber
;
9143 mach_port_name_t portName
= 0;
9144 request
= OSDynamicCast(OSDictionary
, requests
->getObject(requestIndex
));
9146 OSKextLog(/* kext */ NULL
,
9147 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9148 "Elements of request should be of type OSDictionary");
9149 result
= kOSKextReturnInternalError
;
9152 requestPredicate
= _OSKextGetRequestPredicate(request
);
9153 if (!requestPredicate
) {
9154 OSKextLog(/* kext */ NULL
,
9155 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9156 "Failed to get request predicate");
9157 result
= kOSKextReturnInternalError
;
9160 // is this a dext launch?
9161 if (requestPredicate
->isEqualTo(kKextRequestPredicateRequestDaemonLaunch
)) {
9162 token
= OSDynamicCast(IOUserServerCheckInToken
, _OSKextGetRequestArgument(request
, kKextRequestArgumentCheckInToken
));
9164 OSKextLog(/* kext */ NULL
,
9165 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9166 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9167 result
= kOSKextReturnInternalError
;
9170 portName
= iokit_make_send_right(calling_task
, token
, IKOT_IOKIT_IDENT
);
9171 if (portName
== 0 || portName
== MACH_PORT_DEAD
) {
9172 OSKextLog(/* kext */ NULL
,
9173 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9174 "Could not create send right for object.");
9175 result
= kOSKextReturnInternalError
;
9178 // Store the mach port name as a OSNumber
9179 portNameNumber
= OSNumber::withNumber(portName
, CHAR_BIT
* sizeof(portName
));
9180 if (!portNameNumber
) {
9181 OSKextLog(/* kext */ NULL
,
9182 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9183 "Could not create OSNumber object.");
9184 result
= kOSKextReturnNoMemory
;
9187 if (!_OSKextSetRequestArgument(request
, kKextRequestArgumentCheckInToken
, portNameNumber
.get())) {
9188 OSKextLog(/* kext */ NULL
,
9189 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9190 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken
);
9191 result
= kOSKextReturnNoMemory
;
9196 if (result
!= kOSReturnSuccess
) {
9203 /*********************************************************************
9204 * XXX - this function is a big ugly mess
9205 *********************************************************************/
9208 OSKext::handleRequest(
9209 host_priv_t hostPriv
,
9210 OSKextLogSpec clientLogFilter
,
9211 char * requestBuffer
,
9212 uint32_t requestLength
,
9213 char ** responseOut
,
9214 uint32_t * responseLengthOut
,
9216 uint32_t * logInfoLengthOut
)
9218 OSReturn result
= kOSReturnError
;
9219 kern_return_t kmem_result
= KERN_FAILURE
;
9221 char * response
= NULL
; // returned by reference
9222 uint32_t responseLength
= 0;
9224 bool taskCanManageAllKCs
= false;
9225 bool taskOnlyManagesBootKC
= false;
9227 OSSharedPtr
<OSObject
> parsedXML
;
9228 OSDictionary
* requestDict
= NULL
; // do not release
9229 OSSharedPtr
<OSString
> errorString
;
9231 OSSharedPtr
<OSObject
> responseObject
;
9233 OSSharedPtr
<OSSerialize
> serializer
;
9235 OSSharedPtr
<OSArray
> logInfoArray
;
9237 OSString
* predicate
= NULL
; // do not release
9238 OSString
* kextIdentifier
= NULL
; // do not release
9239 OSArray
* kextIdentifiers
= NULL
; // do not release
9240 OSKext
* theKext
= NULL
; // do not release
9241 OSBoolean
* boolArg
= NULL
; // do not release
9243 IORecursiveLockLock(sKextLock
);
9246 *responseOut
= NULL
;
9247 *responseLengthOut
= 0;
9251 *logInfoLengthOut
= 0;
9254 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
9256 /* XML must be nul-terminated.
9258 if (requestBuffer
[requestLength
- 1] != '\0') {
9259 OSKextLog(/* kext */ NULL
,
9260 kOSKextLogErrorLevel
|
9262 "Invalid request from user space (not nul-terminated).");
9263 result
= kOSKextReturnBadData
;
9266 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, errorString
);
9268 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9271 const char * errorCString
= "(unknown error)";
9273 if (errorString
&& errorString
->getCStringNoCopy()) {
9274 errorCString
= errorString
->getCStringNoCopy();
9275 } else if (parsedXML
) {
9276 errorCString
= "not a dictionary";
9278 OSKextLog(/* kext */ NULL
,
9279 kOSKextLogErrorLevel
|
9281 "Error unserializing request from user space: %s.",
9283 result
= kOSKextReturnSerialization
;
9287 predicate
= _OSKextGetRequestPredicate(requestDict
);
9289 OSKextLog(/* kext */ NULL
,
9290 kOSKextLogErrorLevel
|
9292 "Recieved kext request from user space with no predicate.");
9293 result
= kOSKextReturnInvalidArgument
;
9297 OSKextLog(/* kext */ NULL
,
9298 kOSKextLogDebugLevel
|
9300 "Received '%s' request from user space.",
9301 predicate
->getCStringNoCopy());
9304 * All management of file sets requires an entitlement
9306 result
= kOSKextReturnNotPrivileged
;
9307 if (predicate
->isEqualTo(kKextRequestPredicateUnload
) ||
9308 predicate
->isEqualTo(kKextRequestPredicateStart
) ||
9309 predicate
->isEqualTo(kKextRequestPredicateStop
) ||
9310 predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9311 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9312 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9313 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9314 predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
) ||
9315 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9316 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9317 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9318 if (hostPriv
== HOST_PRIV_NULL
) {
9319 OSKextLog(/* kext */ NULL
,
9320 kOSKextLogErrorLevel
|
9322 "Access Failure - must be root user.");
9325 taskCanManageAllKCs
= IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
) == TRUE
;
9326 taskOnlyManagesBootKC
= IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement
) == TRUE
;
9328 if (!taskCanManageAllKCs
&& !taskOnlyManagesBootKC
) {
9329 OSKextLog(/* kext */ NULL
,
9330 kOSKextLogErrorLevel
|
9332 "Access Failure - client not entitled to manage file sets.");
9337 * The OnlyBootKC entitlement restricts the
9338 * collection-management entitlement to only managing kexts in
9339 * the BootKC. All other predicates that alter global state or
9340 * add new KCs are disallowed.
9342 if (taskOnlyManagesBootKC
&&
9343 (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9344 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9345 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9346 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9347 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9348 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9349 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
))) {
9350 OSKextLog(/* kext */ NULL
,
9351 kOSKextLogErrorLevel
|
9353 "Access Failure - client not entitled to manage non-primary KCs");
9358 * If we get here, then the process either has the full KC
9359 * management entitlement, or it has the BootKC-only
9360 * entitlement and the request is about the BootKC.
9364 /* Get common args in anticipation of use.
9366 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
9367 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9368 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
9369 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9370 if (kextIdentifier
) {
9371 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
9373 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
9374 requestDict
, kKextRequestArgumentValueKey
));
9376 if (taskOnlyManagesBootKC
&&
9378 theKext
->isInFileset() &&
9379 theKext
->kc_type
!= KCKindPrimary
) {
9380 OSKextLog(/* kext */ NULL
,
9381 kOSKextLogErrorLevel
|
9383 "Access Failure - client not entitled to manage kext in non-primary KC");
9384 result
= kOSKextReturnNotPrivileged
;
9388 result
= kOSKextReturnInvalidArgument
;
9390 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
9391 if (!kextIdentifier
) {
9392 OSKextLog(/* kext */ NULL
,
9393 kOSKextLogErrorLevel
|
9395 "Invalid arguments to kext start request.");
9396 } else if (!theKext
) {
9397 OSKextLog(/* kext */ NULL
,
9398 kOSKextLogErrorLevel
|
9400 "Kext %s not found for start request.",
9401 kextIdentifier
->getCStringNoCopy());
9402 result
= kOSKextReturnNotFound
;
9404 result
= theKext
->start();
9406 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
9407 if (!kextIdentifier
) {
9408 OSKextLog(/* kext */ NULL
,
9409 kOSKextLogErrorLevel
|
9411 "Invalid arguments to kext stop request.");
9412 } else if (!theKext
) {
9413 OSKextLog(/* kext */ NULL
,
9414 kOSKextLogErrorLevel
|
9416 "Kext %s not found for stop request.",
9417 kextIdentifier
->getCStringNoCopy());
9418 result
= kOSKextReturnNotFound
;
9420 result
= theKext
->stop();
9422 } else if (predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
)) {
9423 result
= OSKext::setMissingAuxKCBundles(requestDict
);
9424 } else if (predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
)) {
9425 if (!kextIdentifier
) {
9426 OSKextLog(/* kext */ NULL
,
9427 kOSKextLogErrorLevel
|
9429 "Invalid arguments to AuxKC Bundle Available request.");
9431 result
= OSKext::setAuxKCBundleAvailable(kextIdentifier
, requestDict
);
9433 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
)) {
9434 if (!kextIdentifier
) {
9435 OSKextLog(/* kext */ NULL
,
9436 kOSKextLogErrorLevel
|
9438 "Invalid arguments to kext load from KC request.");
9439 } else if (!theKext
) {
9440 OSKextLog(/* kext */ NULL
,
9441 kOSKextLogErrorLevel
|
9443 "Kext %s not found for load from KC request.",
9444 kextIdentifier
->getCStringNoCopy());
9445 result
= kOSKextReturnNotFound
;
9446 } else if (!theKext
->isInFileset()) {
9447 OSKextLog(/* kext */ NULL
,
9448 kOSKextLogErrorLevel
|
9450 "Kext %s does not exist in a KC: refusing to load.",
9451 kextIdentifier
->getCStringNoCopy());
9452 result
= kOSKextReturnNotLoadable
;
9454 result
= OSKext::loadKextFromKC(theKext
, requestDict
);
9456 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
)) {
9457 if (!kextIdentifier
) {
9458 OSKextLog(/* kext */ NULL
,
9459 kOSKextLogErrorLevel
|
9461 "Invalid arguments to codeless kext load interface (missing identifier).");
9463 result
= OSKext::loadCodelessKext(kextIdentifier
, requestDict
);
9465 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
9466 if (!kextIdentifier
) {
9467 OSKextLog(/* kext */ NULL
,
9468 kOSKextLogErrorLevel
|
9470 "Invalid arguments to kext unload request.");
9471 } else if (!theKext
) {
9472 OSKextLog(/* kext */ NULL
,
9473 kOSKextLogErrorLevel
|
9475 "Kext %s not found for unload request.",
9476 kextIdentifier
->getCStringNoCopy());
9477 result
= kOSKextReturnNotFound
;
9479 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
9480 _OSKextGetRequestArgument(requestDict
,
9481 kKextRequestArgumentTerminateIOServicesKey
));
9482 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
9484 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
9485 result
= OSKext::dispatchResource(requestDict
);
9486 } else if (predicate
->isEqualTo(kKextRequestPredicateGetUUIDByAddress
)) {
9487 OSNumber
*lookupNum
= NULL
;
9488 lookupNum
= OSDynamicCast(OSNumber
,
9489 _OSKextGetRequestArgument(requestDict
,
9490 kKextRequestArgumentLookupAddressKey
));
9492 responseObject
= OSKext::copyKextUUIDForAddress(lookupNum
);
9493 if (responseObject
) {
9494 result
= kOSReturnSuccess
;
9498 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) ||
9499 predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
) ||
9500 predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9501 OSBoolean
* delayAutounloadBool
= NULL
;
9502 OSObject
* infoKeysRaw
= NULL
;
9503 OSArray
* infoKeys
= NULL
;
9504 uint32_t infoKeysCount
= 0;
9506 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
9507 _OSKextGetRequestArgument(requestDict
,
9508 kKextRequestArgumentDelayAutounloadKey
));
9510 /* If asked to delay autounload, reset the timer if it's currently set.
9511 * (That is, don't schedule an unload if one isn't already pending.
9513 if (delayAutounloadBool
== kOSBooleanTrue
) {
9514 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9517 infoKeysRaw
= _OSKextGetRequestArgument(requestDict
,
9518 kKextRequestArgumentInfoKeysKey
);
9519 infoKeys
= OSDynamicCast(OSArray
, infoKeysRaw
);
9520 if (infoKeysRaw
&& !infoKeys
) {
9521 OSKextLog(/* kext */ NULL
,
9522 kOSKextLogErrorLevel
|
9524 "Invalid arguments to kext info request.");
9529 infoKeysCount
= infoKeys
->getCount();
9530 for (uint32_t i
= 0; i
< infoKeysCount
; i
++) {
9531 if (!OSDynamicCast(OSString
, infoKeys
->getObject(i
))) {
9532 OSKextLog(/* kext */ NULL
,
9533 kOSKextLogErrorLevel
|
9535 "Invalid arguments to kext info request.");
9541 if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
9542 responseObject
= OSKext::copyLoadedKextInfo(kextIdentifiers
, infoKeys
);
9543 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
)) {
9544 responseObject
= OSKext::copyLoadedKextInfoByUUID(kextIdentifiers
, infoKeys
);
9545 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9546 responseObject
= OSKext::copyKextCollectionInfo(requestDict
, infoKeys
);
9549 if (!responseObject
) {
9550 result
= kOSKextReturnInternalError
;
9552 OSKextLog(/* kext */ NULL
,
9553 kOSKextLogDebugLevel
|
9555 "Returning loaded kext info.");
9556 result
= kOSReturnSuccess
;
9558 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9559 /* Hand the current sKernelRequests array to the caller
9560 * (who must release it), and make a new one.
9562 responseObject
= os::move(sKernelRequests
);
9563 sKernelRequests
= OSArray::withCapacity(0);
9564 sPostedKextLoadIdentifiers
->flushCollection();
9565 OSKextLog(/* kext */ NULL
,
9566 kOSKextLogDebugLevel
|
9568 "Returning kernel requests.");
9569 result
= kOSReturnSuccess
;
9570 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
9571 /* Return the set of all requested bundle identifiers */
9572 responseObject
= sAllKextLoadIdentifiers
;
9573 OSKextLog(/* kext */ NULL
,
9574 kOSKextLogDebugLevel
|
9576 "Returning load requests.");
9577 result
= kOSReturnSuccess
;
9578 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
)) {
9579 printf("KextLog: Loading FileSet KC(s)\n");
9580 result
= OSKext::loadFileSetKexts(requestDict
);
9581 } else if (predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9582 printf("KextLog: " kIOKitDaemonName
" is %s\n", sIOKitDaemonActive
? "active" : "not active");
9583 result
= (sIOKitDaemonActive
&& !sOSKextWasResetAfterUserspaceReboot
) ? kOSReturnSuccess
: kIOReturnNotReady
;
9585 OSKextLog(/* kext */ NULL
,
9586 kOSKextLogDebugLevel
|
9588 "Received '%s' invalid request from user space.",
9589 predicate
->getCStringNoCopy());
9594 * Now we have handle the request, or not. Gather up the response & logging
9595 * info to ship to user space.
9598 /* Note: Nothing in OSKext is supposed to retain requestDict,
9599 * but you never know....
9601 if (requestDict
->getRetainCount() > 1) {
9602 OSKextLog(/* kext */ NULL
,
9603 kOSKextLogWarningLevel
|
9605 "Request from user space still retained by a kext; "
9606 "probable memory leak.");
9609 if (responseOut
&& responseObject
) {
9610 serializer
= OSSerialize::withCapacity(0);
9612 result
= kOSKextReturnNoMemory
;
9616 * Before serializing the kernel requests, patch the dext launch requests so
9617 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9618 * IOUserServerCheckInToken kernel object.
9620 if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9621 OSArray
* requests
= OSDynamicCast(OSArray
, responseObject
.get());
9622 task_t calling_task
= current_task();
9624 OSKextLog(/* kext */ NULL
,
9625 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9626 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests
);
9627 result
= kOSKextReturnInternalError
;
9630 result
= patchDextLaunchRequests(calling_task
, requests
);
9631 if (result
!= kOSReturnSuccess
) {
9632 OSKextLog(/* kext */ NULL
,
9633 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9634 "Failed to patch dext launch requests.");
9639 if (!responseObject
->serialize(serializer
.get())) {
9640 OSKextLog(/* kext */ NULL
,
9641 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9642 "Failed to serialize response to request from user space.");
9643 result
= kOSKextReturnSerialization
;
9647 response
= (char *)serializer
->text();
9648 responseLength
= serializer
->getLength();
9651 if (responseOut
&& response
) {
9654 /* This kmem_alloc sets the return value of the function.
9656 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
9657 round_page(responseLength
), VM_KERN_MEMORY_OSKEXT
);
9658 if (kmem_result
!= KERN_SUCCESS
) {
9659 OSKextLog(/* kext */ NULL
,
9660 kOSKextLogErrorLevel
|
9662 "Failed to copy response to request from user space.");
9663 result
= kmem_result
;
9666 /* 11981737 - clear uninitialized data in last page */
9667 bzero((void *)(buffer
+ responseLength
),
9668 (round_page(responseLength
) - responseLength
));
9669 memcpy(buffer
, response
, responseLength
);
9670 *responseOut
= buffer
;
9671 *responseLengthOut
= responseLength
;
9677 /* Gather up the collected log messages for user space. Any messages
9678 * messages past this call will not make it up as log messages but
9679 * will be in the system log. Note that we ignore the return of the
9680 * serialize; it has no bearing on the operation at hand even if we
9681 * fail to get the log messages.
9683 logInfoArray
= OSKext::clearUserSpaceLogFilter();
9685 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
9686 (void)OSKext::serializeLogInfo(logInfoArray
.get(),
9687 logInfoOut
, logInfoLengthOut
);
9690 IORecursiveLockUnlock(sKextLock
);
9696 #pragma mark Linked Kext Collection Support
9700 __whereIsAddr(vm_offset_t theAddr
, unsigned long *segSizes
, vm_offset_t
*segAddrs
, int segCount
)
9702 for (int i
= 0; i
< segCount
; i
++) {
9703 vm_offset_t segStart
= segAddrs
[i
];
9704 vm_offset_t segEnd
= segStart
+ (vm_offset_t
)segSizes
[i
];
9706 if (theAddr
>= segStart
&& theAddr
< segEnd
) {
9714 __slideOldKaslrOffsets(kernel_mach_header_t
*mh
,
9715 kernel_segment_command_t
*kextTextSeg
,
9716 OSData
*kaslrOffsets
)
9718 static const char *plk_segNames
[] = {
9732 static const size_t num_plk_seg
= (size_t)(sizeof(plk_segNames
) / sizeof(plk_segNames
[0]));
9734 unsigned long plk_segSizes
[num_plk_seg
];
9735 vm_offset_t plk_segAddrs
[num_plk_seg
];
9737 for (size_t i
= 0; i
< num_plk_seg
; i
++) {
9738 plk_segSizes
[i
] = 0;
9739 plk_segAddrs
[i
] = (vm_offset_t
)getsegdatafromheader(mh
, plk_segNames
[i
], &plk_segSizes
[i
]);
9742 uint64_t kextTextStart
= (uint64_t)kextTextSeg
->vmaddr
;
9744 int slidKextAddrCount
= 0;
9745 int badSlideAddr
= 0;
9746 int badSlideTarget
= 0;
9748 struct kaslrPackedOffsets
{
9749 uint32_t count
; /* number of offsets */
9750 uint32_t offsetsArray
[]; /* offsets to slide */
9752 const struct kaslrPackedOffsets
*myOffsets
= NULL
;
9753 myOffsets
= (const struct kaslrPackedOffsets
*)kaslrOffsets
->getBytesNoCopy();
9755 for (uint32_t j
= 0; j
< myOffsets
->count
; j
++) {
9756 uint64_t slideOffset
= (uint64_t)myOffsets
->offsetsArray
[j
];
9757 vm_offset_t
*slideAddr
= (vm_offset_t
*)((uint64_t)kextTextStart
+ slideOffset
);
9758 int slideAddrSegIndex
= -1;
9759 int addrToSlideSegIndex
= -1;
9761 slideAddrSegIndex
= __whereIsAddr((vm_offset_t
)slideAddr
, &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9762 if (slideAddrSegIndex
>= 0) {
9763 addrToSlideSegIndex
= __whereIsAddr(ml_static_slide(*slideAddr
), &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9764 if (addrToSlideSegIndex
< 0) {
9773 slidKextAddrCount
++;
9774 *slideAddr
= ml_static_slide(*slideAddr
);
9780 /********************************************************************
9781 * addKextsFromKextCollection
9783 * Input: MachO header of kext collection. The MachO is assumed to
9784 * have a section named 'info_seg_name,info_sect_name' that
9785 * contains a serialized XML info dictionary. This dictionary
9786 * contains a UUID, possibly a set of relocations (for older
9787 * kxld-built binaries), and an array of kext personalities.
9789 ********************************************************************/
9791 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9792 OSDictionary
*infoDict
, const char *text_seg_name
,
9793 OSData
**kcUUID
, kc_kind_t type
)
9795 bool result
= false;
9797 OSArray
*kextArray
= NULL
; // do not release
9798 OSData
*infoDictKCUUID
= NULL
; // do not release
9799 OSData
*kaslrOffsets
= NULL
; // do not release
9801 IORegistryEntry
*registryRoot
= NULL
; // do not release
9802 OSSharedPtr
<OSNumber
> kcKextCount
;
9804 /* extract the KC UUID from the dictionary */
9805 infoDictKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
9806 if (infoDictKCUUID
) {
9807 if (infoDictKCUUID
->getLength() != sizeof(uuid_t
)) {
9808 panic("kcUUID length is %d, expected %lu",
9809 infoDictKCUUID
->getLength(), sizeof(uuid_t
));
9813 /* locate the array of kext dictionaries */
9814 kextArray
= OSDynamicCast(OSArray
, infoDict
->getObject(kPrelinkInfoDictionaryKey
));
9816 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9817 "The given KC has no kext info dictionaries");
9822 * old-style KASLR offsets may be present in the info dictionary. If
9823 * we find them, use them and eventually slide them.
9825 kaslrOffsets
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkLinkKASLROffsetsKey
));
9828 * Before processing any kexts, locate the special kext bundle which
9829 * contains a list of kexts that we are to prevent from loading.
9831 createExcludeListFromPrelinkInfo(kextArray
);
9834 * Create OSKext objects for each kext we find in the array of kext
9835 * info plist dictionaries.
9837 for (int i
= 0; i
< (int)kextArray
->getCount(); ++i
) {
9838 OSDictionary
*kextDict
= NULL
;
9839 kextDict
= OSDynamicCast(OSDictionary
, kextArray
->getObject(i
));
9841 OSKextLog(/* kext */ NULL
,
9842 kOSKextLogErrorLevel
|
9843 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9844 "Kext info dictionary for kext #%d isn't a dictionary?", i
);
9849 * Create the kext for the entry, then release it, because the
9850 * kext system keeps a reference around until the kext is
9851 * explicitly removed. Any creation/registration failures are
9852 * already logged for us.
9854 withPrelinkedInfoDict(kextDict
, (kaslrOffsets
? TRUE
: FALSE
), type
);
9858 * slide old-style kxld relocations
9859 * NOTE: this is still used on embedded KCs built with kcgen
9860 * TODO: Remove this once we use the new kext linker everywhere!
9862 if (kaslrOffsets
&& vm_kernel_slide
> 0) {
9863 kernel_segment_command_t
*text_segment
= NULL
;
9864 text_segment
= getsegbynamefromheader(mh
, text_seg_name
);
9865 if (!text_segment
) {
9866 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9867 "Can't find a TEXT segment named '%s' in macho header", text_seg_name
);
9871 __slideOldKaslrOffsets(mh
, text_segment
, kaslrOffsets
);
9872 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9873 setAllVMAttributes();
9876 /* Store the number of prelinked kexts in the registry so we can tell
9877 * when the system has been started from a prelinked kernel.
9879 registryRoot
= IORegistryEntry::getRegistryRoot();
9880 assert(registryRoot
);
9882 kcKextCount
= OSNumber::withNumber((unsigned long long)infoDict
->getCount(), 8 * sizeof(uint32_t));
9883 assert(kcKextCount
);
9885 OSSharedPtr
<OSObject
> prop
= registryRoot
->copyProperty(kOSPrelinkKextCountKey
);
9887 num
= OSDynamicCast(OSNumber
, prop
.get());
9889 kcKextCount
->addValue(num
->unsigned64BitValue());
9891 registryRoot
->setProperty(kOSPrelinkKextCountKey
, kcKextCount
.get());
9894 OSKextLog(/* kext */ NULL
,
9895 kOSKextLogProgressLevel
|
9896 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
9897 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9898 "%u prelinked kexts", infoDict
->getCount());
9901 if (kcUUID
&& infoDictKCUUID
) {
9902 *kcUUID
= OSData::withData(infoDictKCUUID
).detach();
9912 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9913 OSDictionary
*infoDict
, const char *text_seg_name
,
9914 OSSharedPtr
<OSData
> &kcUUID
, kc_kind_t type
)
9916 OSData
*result
= NULL
;
9917 bool success
= addKextsFromKextCollection(mh
,
9923 kcUUID
.reset(result
, OSNoRetain
);
9928 static OSSharedPtr
<OSObject
> deferredAuxKCXML
;
9930 OSKext::registerDeferredKextCollection(kernel_mach_header_t
*mh
,
9931 OSSharedPtr
<OSObject
> &parsedXML
, kc_kind_t type
)
9933 if (type
!= KCKindAuxiliary
) {
9937 kernel_mach_header_t
*_mh
;
9938 _mh
= (kernel_mach_header_t
*)PE_get_kc_header(type
);
9939 if (!_mh
|| _mh
!= mh
) {
9943 if (deferredAuxKCXML
) {
9944 /* only allow this to be called once */
9945 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9946 "An Aux KC has already been registered for deferred processing.");
9950 OSDictionary
*infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9952 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9953 "The Aux KC has info dictionary");
9957 OSData
*kcUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
9958 if (!kcUUID
|| kcUUID
->getLength() != sizeof(uuid_t
)) {
9959 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9960 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey
);
9965 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
9966 * sysctl can return the UUID to user space which will check this
9969 memcpy((void *)&auxkc_uuid
, (const void *)kcUUID
->getBytesNoCopy(),
9970 kcUUID
->getLength());
9971 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
9972 auxkc_uuid_valid
= TRUE
;
9974 deferredAuxKCXML
= parsedXML
;
9979 OSSharedPtr
<OSObject
>
9980 OSKext::consumeDeferredKextCollection(kc_kind_t type
)
9982 if (type
!= KCKindAuxiliary
|| !deferredAuxKCXML
) {
9986 return os::move(deferredAuxKCXML
);
9990 #pragma mark Profile-Guided-Optimization Support
9993 // #include <InstrProfiling.h>
9995 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin
,
9996 const char *DataEnd
,
9997 const char *CountersBegin
,
9998 const char *CountersEnd
,
9999 const char *NamesBegin
,
10000 const char *NamesEnd
);
10001 int __llvm_profile_write_buffer_internal(char *Buffer
,
10002 const char *DataBegin
,
10003 const char *DataEnd
,
10004 const char *CountersBegin
,
10005 const char *CountersEnd
,
10006 const char *NamesBegin
,
10007 const char *NamesEnd
);
10013 OSKextPgoMetadataPut(char *pBuffer
,
10016 uint32_t *num_pairs
,
10020 size_t strlen_key
= strlen(key
);
10021 size_t strlen_value
= strlen(value
);
10022 size_t len
= strlen(key
) + 1 + strlen(value
) + 1;
10023 char *pos
= pBuffer
+ *position
;
10025 if (pBuffer
&& bufferSize
&& *position
<= bufferSize
) {
10026 memcpy(pos
, key
, strlen_key
); pos
+= strlen_key
;
10028 memcpy(pos
, value
, strlen_value
); pos
+= strlen_value
;
10039 OSKextPgoMetadataPutMax(size_t *position
, const char *key
, size_t value_max
)
10041 *position
+= strlen(key
) + 1 + value_max
+ 1;
10047 OSKextPgoMetadataPutAll(OSKext
*kext
,
10048 uuid_t instance_uuid
,
10052 uint32_t *num_pairs
)
10054 _static_assert_1_arg(sizeof(clock_sec_t
) % 2 == 0);
10055 //log_10 2^16 ≈ 4.82
10056 const size_t max_secs_string_size
= 5 * sizeof(clock_sec_t
) / 2;
10057 const size_t max_timestamp_string_size
= max_secs_string_size
+ 1 + 6;
10060 OSKextPgoMetadataPutMax(position
, "INSTANCE", 36);
10061 OSKextPgoMetadataPutMax(position
, "UUID", 36);
10062 OSKextPgoMetadataPutMax(position
, "TIMESTAMP", max_timestamp_string_size
);
10064 uuid_string_t instance_uuid_string
;
10065 uuid_unparse(instance_uuid
, instance_uuid_string
);
10066 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10067 "INSTANCE", instance_uuid_string
);
10069 OSSharedPtr
<OSData
> uuid_data
;
10071 uuid_string_t uuid_string
;
10072 uuid_data
= kext
->copyUUID();
10074 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
10075 uuid_unparse(uuid
, uuid_string
);
10076 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10077 "UUID", uuid_string
);
10081 clock_usec_t usecs
;
10082 clock_get_calendar_microtime(&secs
, &usecs
);
10083 assert(usecs
< 1000000);
10084 char timestamp
[max_timestamp_string_size
+ 1];
10085 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t
));
10086 snprintf(timestamp
, sizeof(timestamp
), "%lu.%06d", (unsigned long)secs
, (int)usecs
);
10087 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10088 "TIMESTAMP", timestamp
);
10091 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10092 "NAME", kext
->getIdentifierCString());
10094 char versionCString
[kOSKextVersionMaxLength
];
10095 OSKextVersionGetString(kext
->getVersion(), versionCString
, kOSKextVersionMaxLength
);
10096 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10097 "VERSION", versionCString
);
10102 OSKextPgoMetadataSize(OSKext
*kext
)
10104 size_t position
= 0;
10105 uuid_t fakeuuid
= {};
10106 OSKextPgoMetadataPutAll(kext
, fakeuuid
, NULL
, &position
, 0, NULL
);
10111 OSKextGrabPgoDataLocked(OSKext
*kext
,
10113 uuid_t instance_uuid
,
10116 uint64_t bufferSize
)
10120 kernel_section_t
*sect_prf_data
= NULL
;
10121 kernel_section_t
*sect_prf_name
= NULL
;
10122 kernel_section_t
*sect_prf_cnts
= NULL
;
10124 size_t metadata_size
= 0;
10125 size_t offset_to_pairs
= 0;
10127 sect_prf_data
= kext
->lookupSection("__DATA", "__llvm_prf_data");
10128 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_names");
10129 if (!sect_prf_name
) {
10130 // kextcache sometimes truncates the section name to 15 chars
10131 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10132 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_name");
10134 sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10136 if (!sect_prf_data
|| !sect_prf_name
|| !sect_prf_cnts
) {
10141 size
= __llvm_profile_get_size_for_buffer_internal(
10142 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10143 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10144 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10147 metadata_size
= OSKextPgoMetadataSize(kext
);
10148 size
+= metadata_size
;
10149 size
+= sizeof(pgo_metadata_footer
);
10157 if (pBuffer
&& bufferSize
) {
10158 if (bufferSize
< size
) {
10163 err
= __llvm_profile_write_buffer_internal(
10165 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10166 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10167 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10175 offset_to_pairs
= sizeof(struct pgo_metadata_footer
) + metadata_size
;
10176 if (offset_to_pairs
> UINT32_MAX
) {
10181 char *end_of_buffer
= pBuffer
+ size
;
10182 struct pgo_metadata_footer
*footerp
= (struct pgo_metadata_footer
*) (end_of_buffer
- sizeof(struct pgo_metadata_footer
));
10183 char *metadata_buffer
= end_of_buffer
- (sizeof(struct pgo_metadata_footer
) + metadata_size
);
10185 size_t metadata_position
= 0;
10186 uint32_t num_pairs
= 0;
10187 OSKextPgoMetadataPutAll(kext
, instance_uuid
, metadata_buffer
, &metadata_position
, metadata_size
, &num_pairs
);
10188 while (metadata_position
< metadata_size
) {
10189 metadata_buffer
[metadata_position
++] = 0;
10192 struct pgo_metadata_footer footer
;
10193 footer
.magic
= htonl(0x6d657461);
10194 footer
.number_of_pairs
= htonl( num_pairs
);
10195 footer
.offset_to_pairs
= htonl((uint32_t)offset_to_pairs
);
10196 memcpy(footerp
, &footer
, sizeof(footer
));
10206 OSKextGrabPgoData(uuid_t uuid
,
10209 uint64_t bufferSize
,
10210 int wait_for_unload
,
10214 OSSharedPtr
<OSKext
> kext
;
10217 IORecursiveLockLock(sKextLock
);
10219 kext
= OSKext::lookupKextWithUUID(uuid
);
10225 if (wait_for_unload
) {
10226 OSKextGrabPgoStruct s
;
10228 s
.metadata
= metadata
;
10230 s
.pBuffer
= pBuffer
;
10231 s
.bufferSize
= bufferSize
;
10234 struct list_head
*prev
= &kext
->pendingPgoHead
;
10235 struct list_head
*next
= kext
->pendingPgoHead
.next
;
10237 s
.list_head
.prev
= prev
;
10238 s
.list_head
.next
= next
;
10240 prev
->next
= &s
.list_head
;
10241 next
->prev
= &s
.list_head
;
10245 IORecursiveLockSleep(sKextLock
, &s
, THREAD_ABORTSAFE
);
10247 prev
= s
.list_head
.prev
;
10248 next
= s
.list_head
.next
;
10255 err
= OSKextGrabPgoDataLocked(kext
.get(), metadata
, kext
->instance_uuid
, pSize
, pBuffer
, bufferSize
);
10260 IORecursiveLockUnlock(sKextLock
);
10266 OSKextResetPgoCountersLock()
10268 IORecursiveLockLock(sKextLock
);
10272 OSKextResetPgoCountersUnlock()
10274 IORecursiveLockUnlock(sKextLock
);
10278 extern unsigned int not_in_kdp
;
10281 OSKextResetPgoCounters()
10283 assert(!not_in_kdp
);
10284 uint32_t count
= sLoadedKexts
->getCount();
10285 for (uint32_t i
= 0; i
< count
; i
++) {
10286 OSKext
*kext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
10287 kernel_section_t
*sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10288 if (!sect_prf_cnts
) {
10291 memset((void*)sect_prf_cnts
->addr
, 0, sect_prf_cnts
->size
);
10295 OSSharedPtr
<OSDictionary
>
10296 OSKext::copyLoadedKextInfoByUUID(
10297 OSArray
* kextIdentifiers
,
10298 OSArray
* infoKeys
)
10300 OSSharedPtr
<OSDictionary
> result
;
10301 OSSharedPtr
<OSDictionary
> kextInfo
;
10302 uint32_t max_count
, i
, j
;
10303 uint32_t idCount
= 0;
10304 uint32_t idIndex
= 0;
10305 IORecursiveLockLock(sKextLock
);
10306 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
10307 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
10310 /* Is the calling process allowed to query kext info? */
10311 if (current_task() != kernel_task
) {
10312 int macCheckResult
= 0;
10313 kauth_cred_t cred
= NULL
;
10315 cred
= kauth_cred_get_with_ref();
10316 macCheckResult
= mac_kext_check_query(cred
);
10317 kauth_cred_unref(&cred
);
10319 if (macCheckResult
!= 0) {
10320 OSKextLog(/* kext */ NULL
,
10321 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10322 "Failed to query kext info (MAC policy error 0x%x).",
10329 /* Empty list of UUIDs is equivalent to no list (get all).
10331 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10332 kextIdentifiers
= NULL
;
10333 } else if (kextIdentifiers
) {
10334 idCount
= kextIdentifiers
->getCount();
10339 if (infoKeys
&& !infoKeys
->getCount()) {
10343 max_count
= count
[0] + count
[1];
10344 result
= OSDictionary::withCapacity(max_count
);
10349 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
10350 for (i
= 0; i
< count
[j
]; i
++) {
10351 OSKext
*thisKext
= NULL
; // do not release
10352 Boolean includeThis
= true;
10353 uuid_t thisKextUUID
;
10354 uuid_t thisKextTextUUID
;
10355 OSSharedPtr
<OSData
> uuid_data
;
10356 uuid_string_t uuid_key
;
10358 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
10363 uuid_data
= thisKext
->copyUUID();
10368 memcpy(&thisKextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextUUID
));
10370 uuid_unparse(thisKextUUID
, uuid_key
);
10372 uuid_data
= thisKext
->copyTextUUID();
10376 memcpy(&thisKextTextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextTextUUID
));
10378 /* Skip current kext if we have a list of UUIDs and
10379 * it isn't in the list.
10381 if (kextIdentifiers
) {
10382 includeThis
= false;
10384 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10385 const OSString
* wantedUUID
= OSDynamicCast(OSString
,
10386 kextIdentifiers
->getObject(idIndex
));
10389 uuid_parse(wantedUUID
->getCStringNoCopy(), uuid
);
10391 if ((0 == uuid_compare(uuid
, thisKextUUID
))
10392 || (0 == uuid_compare(uuid
, thisKextTextUUID
))) {
10393 includeThis
= true;
10394 /* Only need to find the first kext if multiple match,
10395 * ie. asking for the kernel uuid does not need to find
10396 * interface kexts or builtin static kexts.
10398 kextIdentifiers
->removeObject(idIndex
);
10399 uuid_unparse(uuid
, uuid_key
);
10405 if (!includeThis
) {
10409 kextInfo
= thisKext
->copyInfo(infoKeys
);
10411 result
->setObject(uuid_key
, kextInfo
.get());
10414 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10421 IORecursiveLockUnlock(sKextLock
);
10426 /*********************************************************************
10427 *********************************************************************/
10429 OSSharedPtr
<OSDictionary
>
10430 OSKext::copyKextCollectionInfo(
10431 OSDictionary
*requestDict
,
10434 OSSharedPtr
<OSDictionary
> result
;
10435 OSString
*collectionType
= NULL
;
10436 OSObject
*rawLoadedState
= NULL
;
10437 OSString
*loadedState
= NULL
;
10439 kc_kind_t kc_request_kind
= KCKindUnknown
;
10440 bool onlyLoaded
= false;
10441 bool onlyUnloaded
= false;
10444 /* Is the calling process allowed to query kext info? */
10445 if (current_task() != kernel_task
) {
10446 int macCheckResult
= 0;
10447 kauth_cred_t cred
= NULL
;
10449 cred
= kauth_cred_get_with_ref();
10450 macCheckResult
= mac_kext_check_query(cred
);
10451 kauth_cred_unref(&cred
);
10453 if (macCheckResult
!= 0) {
10454 OSKextLog(/* kext */ NULL
,
10455 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10456 "Failed to query kext info (MAC policy error 0x%x).",
10463 if (infoKeys
&& !infoKeys
->getCount()) {
10467 collectionType
= OSDynamicCast(OSString
,
10468 _OSKextGetRequestArgument(requestDict
,
10469 kKextRequestArgumentCollectionTypeKey
));
10470 if (!collectionType
) {
10471 OSKextLog(/* kext */ NULL
,
10472 kOSKextLogErrorLevel
|
10474 "Invalid '%s' argument to kext collection info request.",
10475 kKextRequestArgumentCollectionTypeKey
);
10478 if (collectionType
->isEqualTo(kKCTypePrimary
)) {
10479 kc_request_kind
= KCKindPrimary
;
10480 } else if (collectionType
->isEqualTo(kKCTypeSystem
)) {
10481 kc_request_kind
= KCKindPageable
;
10482 } else if (collectionType
->isEqualTo(kKCTypeAuxiliary
)) {
10483 kc_request_kind
= KCKindAuxiliary
;
10484 } else if (collectionType
->isEqualTo(kKCTypeCodeless
)) {
10485 kc_request_kind
= KCKindNone
;
10486 } else if (!collectionType
->isEqualTo(kKCTypeAny
)) {
10487 OSKextLog(/* kext */ NULL
,
10488 kOSKextLogErrorLevel
|
10490 "Invalid '%s' argument value '%s' to kext collection info request.",
10491 kKextRequestArgumentCollectionTypeKey
,
10492 collectionType
->getCStringNoCopy());
10496 rawLoadedState
= _OSKextGetRequestArgument(requestDict
,
10497 kKextRequestArgumentLoadedStateKey
);
10498 if (rawLoadedState
) {
10499 loadedState
= OSDynamicCast(OSString
, rawLoadedState
);
10500 if (!loadedState
) {
10501 OSKextLog(/* kext */ NULL
,
10502 kOSKextLogErrorLevel
|
10504 "Invalid '%s' argument to kext collection info request.",
10505 kKextRequestArgumentLoadedStateKey
);
10510 if (loadedState
->isEqualTo("Loaded")) {
10512 } else if (loadedState
->isEqualTo("Unloaded")) {
10513 onlyUnloaded
= true;
10514 } else if (!loadedState
->isEqualTo("Any")) {
10515 OSKextLog(/* kext */ NULL
,
10516 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10517 "Invalid '%s' argument value '%s' for '%s' collection info",
10518 kKextRequestArgumentLoadedStateKey
,
10519 loadedState
->getCStringNoCopy(),
10520 collectionType
->getCStringNoCopy());
10525 result
= OSDictionary::withCapacity(sKextsByID
->getCount());
10530 IORecursiveLockLock(sKextLock
);
10531 { // start block scope
10532 sKextsByID
->iterateObjects(^bool (const OSSymbol
*thisKextID
, OSObject
*obj
)
10534 OSKext
*thisKext
= NULL
; // do not release
10535 OSSharedPtr
<OSDictionary
> kextInfo
;
10539 thisKext
= OSDynamicCast(OSKext
, obj
);
10545 * skip the kext if it came from the wrong collection type
10546 * (and the caller requested a specific type)
10548 if ((kc_request_kind
!= KCKindUnknown
) && (thisKext
->kc_type
!= kc_request_kind
)) {
10553 * respect the caller's desire to find only loaded or
10556 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10559 if (onlyUnloaded
&& (-1U != sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10563 kextInfo
= thisKext
->copyInfo(infoKeys
);
10565 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10569 } // end block scope
10570 IORecursiveLockUnlock(sKextLock
);
10576 /*********************************************************************
10577 *********************************************************************/
10579 OSSharedPtr
<OSDictionary
>
10580 OSKext::copyLoadedKextInfo(
10581 OSArray
* kextIdentifiers
,
10582 OSArray
* infoKeys
)
10584 OSSharedPtr
<OSDictionary
> result
;
10585 uint32_t idCount
= 0;
10588 IORecursiveLockLock(sKextLock
);
10591 /* Is the calling process allowed to query kext info? */
10592 if (current_task() != kernel_task
) {
10593 int macCheckResult
= 0;
10594 kauth_cred_t cred
= NULL
;
10596 cred
= kauth_cred_get_with_ref();
10597 macCheckResult
= mac_kext_check_query(cred
);
10598 kauth_cred_unref(&cred
);
10600 if (macCheckResult
!= 0) {
10601 OSKextLog(/* kext */ NULL
,
10602 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10603 "Failed to query kext info (MAC policy error 0x%x).",
10610 /* Empty list of bundle ids is equivalent to no list (get all).
10612 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10613 kextIdentifiers
= NULL
;
10614 } else if (kextIdentifiers
) {
10615 idCount
= kextIdentifiers
->getCount();
10620 if (infoKeys
&& !infoKeys
->getCount()) {
10624 onlyLoaded
= (!infoKeys
|| !_OSArrayContainsCString(infoKeys
, kOSBundleAllPrelinkedKey
));
10626 result
= OSDictionary::withCapacity(128);
10632 OSKextLog(/* kext */ NULL
,
10633 kOSKextLogErrorLevel
|
10634 kOSKextLogGeneralFlag
,
10635 "kaslr: vm_kernel_slide 0x%lx \n",
10637 OSKextLog(/* kext */ NULL
,
10638 kOSKextLogErrorLevel
|
10639 kOSKextLogGeneralFlag
,
10640 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10641 vm_kernel_stext
, vm_kernel_etext
);
10642 OSKextLog(/* kext */ NULL
,
10643 kOSKextLogErrorLevel
|
10644 kOSKextLogGeneralFlag
,
10645 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10646 vm_kernel_base
, vm_kernel_top
);
10647 OSKextLog(/* kext */ NULL
,
10648 kOSKextLogErrorLevel
|
10649 kOSKextLogGeneralFlag
,
10650 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10651 vm_kext_base
, vm_kext_top
);
10652 OSKextLog(/* kext */ NULL
,
10653 kOSKextLogErrorLevel
|
10654 kOSKextLogGeneralFlag
,
10655 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10656 vm_prelink_stext
, vm_prelink_etext
);
10657 OSKextLog(/* kext */ NULL
,
10658 kOSKextLogErrorLevel
|
10659 kOSKextLogGeneralFlag
,
10660 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10661 vm_prelink_sinfo
, vm_prelink_einfo
);
10662 OSKextLog(/* kext */ NULL
,
10663 kOSKextLogErrorLevel
|
10664 kOSKextLogGeneralFlag
,
10665 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10666 vm_slinkedit
, vm_elinkedit
);
10668 { // start block scope
10669 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisKextID
, OSObject
* obj
)
10671 OSKext
* thisKext
= NULL
; // do not release
10672 Boolean includeThis
= true;
10673 OSSharedPtr
<OSDictionary
> kextInfo
;
10675 thisKext
= OSDynamicCast(OSKext
, obj
);
10680 /* Skip current kext if not yet started and caller didn't request all.
10682 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10686 /* Skip current kext if we have a list of bundle IDs and
10687 * it isn't in the list.
10689 if (kextIdentifiers
) {
10690 includeThis
= false;
10692 for (uint32_t idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10693 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
10694 kextIdentifiers
->getObject(idIndex
));
10695 if (thisKextID
->isEqualTo(thisRequestID
)) {
10696 includeThis
= true;
10702 if (!includeThis
) {
10706 kextInfo
= thisKext
->copyInfo(infoKeys
);
10708 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10712 } // end block scope
10715 IORecursiveLockUnlock(sKextLock
);
10720 /*********************************************************************
10721 * Any info that needs to do allocations must goto finish on alloc
10722 * failure. Info that is just a lookup should just not set the object
10723 * if the info does not exist.
10724 *********************************************************************/
10725 #define _OSKextLoadInfoDictCapacity (12)
10727 OSSharedPtr
<OSDictionary
>
10728 OSKext::copyInfo(OSArray
* infoKeys
)
10730 OSSharedPtr
<OSDictionary
> result
;
10731 bool success
= false;
10732 OSSharedPtr
<OSData
> headerData
;
10733 OSSharedPtr
<OSData
> logData
;
10734 OSSharedPtr
<OSNumber
> cpuTypeNumber
;
10735 OSSharedPtr
<OSNumber
> cpuSubtypeNumber
;
10736 OSString
* versionString
= NULL
; // do not release
10737 OSString
* bundleType
= NULL
; // do not release
10738 uint32_t executablePathCStringSize
= 0;
10739 char * executablePathCString
= NULL
; // must kfree
10740 OSSharedPtr
<OSString
> executablePathString
;
10741 OSSharedPtr
<OSData
> uuid
;
10742 OSSharedPtr
<OSArray
> dependencyLoadTags
;
10743 OSSharedPtr
<OSCollectionIterator
> metaClassIterator
;
10744 OSSharedPtr
<OSArray
> metaClassInfo
;
10745 OSSharedPtr
<OSDictionary
> metaClassDict
;
10746 OSMetaClass
* thisMetaClass
= NULL
; // do not release
10747 OSSharedPtr
<OSString
> metaClassName
;
10748 OSSharedPtr
<OSString
> superclassName
;
10749 kc_format_t kcformat
;
10752 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
10758 /* Empty keys means no keys, but NULL is quicker to check.
10760 if (infoKeys
&& !infoKeys
->getCount()) {
10764 if (!PE_get_primary_kc_format(&kcformat
)) {
10768 /* Headers, CPU type, and CPU subtype.
10771 _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
) ||
10772 _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
) ||
10773 _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
) ||
10774 _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10775 if (linkedExecutable
&& !isInterface()) {
10776 kernel_mach_header_t
*kext_mach_hdr
= (kernel_mach_header_t
*)
10777 linkedExecutable
->getBytesNoCopy();
10779 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10780 // do not return macho header info on shipping embedded - 19095897
10781 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
)) {
10782 kernel_mach_header_t
* temp_kext_mach_hdr
;
10783 struct load_command
* lcp
;
10785 headerData
= OSData::withBytes(kext_mach_hdr
,
10786 (u_int
) (sizeof(*kext_mach_hdr
) + kext_mach_hdr
->sizeofcmds
));
10791 // unslide any vmaddrs we return to userspace - 10726716
10792 temp_kext_mach_hdr
= (kernel_mach_header_t
*)
10793 headerData
->getBytesNoCopy();
10794 if (temp_kext_mach_hdr
== NULL
) {
10798 lcp
= (struct load_command
*) (temp_kext_mach_hdr
+ 1);
10799 for (i
= 0; i
< temp_kext_mach_hdr
->ncmds
; i
++) {
10800 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
10801 kernel_segment_command_t
* segp
;
10802 kernel_section_t
* secp
;
10804 segp
= (kernel_segment_command_t
*) lcp
;
10805 // 10543468 - if we jettisoned __LINKEDIT clear size info
10806 if (flags
.jettisonLinkeditSeg
) {
10807 if (strncmp(segp
->segname
, SEG_LINKEDIT
, sizeof(segp
->segname
)) == 0) {
10810 segp
->filesize
= 0;
10814 #if __arm__ || __arm64__
10815 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10816 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10817 if (segp
->vmsize
== 0 && segp
->vmaddr
< gVirtBase
) {
10818 segp
->vmaddr
= gVirtBase
;
10819 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10820 secp
->size
= 0; // paranoia :)
10821 secp
->addr
= gVirtBase
;
10827 OSKextLog(/* kext */ NULL
,
10828 kOSKextLogErrorLevel
|
10829 kOSKextLogGeneralFlag
,
10830 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10831 __FUNCTION__
, segp
->segname
, segp
->vmaddr
,
10832 VM_KERNEL_UNSLIDE(segp
->vmaddr
),
10833 segp
->vmsize
, segp
->nsects
);
10834 if ((VM_KERNEL_IS_SLID(segp
->vmaddr
) == false) &&
10835 (VM_KERNEL_IS_KEXT(segp
->vmaddr
) == false) &&
10836 (VM_KERNEL_IS_PRELINKTEXT(segp
->vmaddr
) == false) &&
10837 (VM_KERNEL_IS_PRELINKINFO(segp
->vmaddr
) == false) &&
10838 (VM_KERNEL_IS_KEXT_LINKEDIT(segp
->vmaddr
) == false)) {
10839 OSKextLog(/* kext */ NULL
,
10840 kOSKextLogErrorLevel
|
10841 kOSKextLogGeneralFlag
,
10842 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10843 __FUNCTION__
, segp
->vmaddr
, vm_kext_base
, vm_kext_top
);
10846 segp
->vmaddr
= ml_static_unslide(segp
->vmaddr
);
10848 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10849 secp
->addr
= ml_static_unslide(secp
->addr
);
10852 lcp
= (struct load_command
*)((caddr_t
)lcp
+ lcp
->cmdsize
);
10854 result
->setObject(kOSBundleMachOHeadersKey
, headerData
.get());
10856 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10858 if (_OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10859 osLogDataHeaderRef
*header
;
10860 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10862 void *os_log_data
= NULL
;
10863 void *cstring_data
= NULL
;
10864 unsigned long os_log_size
= 0;
10865 unsigned long cstring_size
= 0;
10866 uint32_t os_log_offset
= 0;
10867 uint32_t cstring_offset
= 0;
10870 os_log_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__os_log", &os_log_size
);
10871 os_log_offset
= (uintptr_t)os_log_data
- (uintptr_t)kext_mach_hdr
;
10872 cstring_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__cstring", &cstring_size
);
10873 cstring_offset
= (uintptr_t)cstring_data
- (uintptr_t)kext_mach_hdr
;
10875 header
= (osLogDataHeaderRef
*) headerBytes
;
10876 header
->version
= OS_LOG_HDR_VERSION
;
10877 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10878 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= os_log_offset
;
10879 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) os_log_size
;
10880 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= cstring_offset
;
10881 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) cstring_size
;
10884 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10888 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10893 res
= logData
->appendBytes(os_log_data
, (u_int
)header
->sections
[OS_LOG_SECT_IDX
].sect_size
);
10898 if (cstring_data
) {
10899 res
= logData
->appendBytes(cstring_data
, (u_int
)header
->sections
[CSTRING_SECT_IDX
].sect_size
);
10904 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10907 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
)) {
10908 cpuTypeNumber
= OSNumber::withNumber(
10909 (uint64_t) kext_mach_hdr
->cputype
,
10910 8 * sizeof(kext_mach_hdr
->cputype
));
10911 if (!cpuTypeNumber
) {
10914 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
.get());
10917 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10918 cpuSubtypeNumber
= OSNumber::withNumber(
10919 (uint64_t) kext_mach_hdr
->cpusubtype
,
10920 8 * sizeof(kext_mach_hdr
->cpusubtype
));
10921 if (!cpuSubtypeNumber
) {
10924 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
.get());
10927 if (isDriverKit() && _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10928 osLogDataHeaderRef
*header
;
10929 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10932 header
= (osLogDataHeaderRef
*) headerBytes
;
10933 header
->version
= OS_LOG_HDR_VERSION
;
10934 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10935 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= 0;
10936 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) 0;
10937 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= 0;
10938 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) 0;
10940 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10944 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10948 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10953 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10955 result
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
10957 /* CFBundlePackageType
10959 bundleType
= infoDict
? OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
)): NULL
;
10961 result
->setObject(kCFBundlePackageTypeKey
, bundleType
);
10964 /* CFBundleVersion.
10966 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kCFBundleVersionKey
)) {
10967 versionString
= OSDynamicCast(OSString
,
10968 getPropertyForHostArch(kCFBundleVersionKey
));
10969 if (versionString
) {
10970 result
->setObject(kCFBundleVersionKey
, versionString
);
10974 /* OSBundleCompatibleVersion.
10976 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCompatibleVersionKey
)) {
10977 versionString
= OSDynamicCast(OSString
,
10978 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
10979 if (versionString
) {
10980 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
10986 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePathKey
)) {
10988 result
->setObject(kOSBundlePathKey
, path
.get());
10993 /* OSBundleExecutablePath.
10995 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecutablePathKey
)) {
10996 if (path
&& executableRelPath
) {
10997 uint32_t pathLength
= path
->getLength(); // gets incremented below
10999 // +1 for slash, +1 for \0
11000 executablePathCStringSize
= pathLength
+ executableRelPath
->getLength() + 2;
11002 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11003 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
); // +1 for \0
11004 if (!executablePathCString
) {
11007 strlcpy(executablePathCString
, path
->getCStringNoCopy(),
11008 executablePathCStringSize
);
11009 executablePathCString
[pathLength
++] = '/';
11010 executablePathCString
[pathLength
++] = '\0';
11011 strlcat(executablePathCString
, executableRelPath
->getCStringNoCopy(),
11012 executablePathCStringSize
);
11014 executablePathString
= OSString::withCString(executablePathCString
);
11016 if (!executablePathString
) {
11020 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11021 } else if (flags
.builtin
) {
11022 result
->setObject(kOSBundleExecutablePathKey
, bundleID
.get());
11023 } else if (isDriverKit()) {
11025 // +1 for slash, +1 for \0
11026 uint32_t pathLength
= path
->getLength();
11027 executablePathCStringSize
= pathLength
+ 2;
11029 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11030 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
11031 if (!executablePathCString
) {
11034 strlcpy(executablePathCString
, path
->getCStringNoCopy(), executablePathCStringSize
);
11035 executablePathCString
[pathLength
++] = '/';
11036 executablePathCString
[pathLength
++] = '\0';
11038 executablePathString
= OSString::withCString(executablePathCString
);
11040 if (!executablePathString
) {
11044 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11049 /* UUID, if the kext has one.
11051 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
11054 result
->setObject(kOSBundleUUIDKey
, uuid
.get());
11057 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleTextUUIDKey
)) {
11058 uuid
= copyTextUUID();
11060 result
->setObject(kOSBundleTextUUIDKey
, uuid
.get());
11065 * Info.plist digest
11067 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextInfoPlistDigestKey
)) {
11069 digest
= infoDict
? OSDynamicCast(OSData
, infoDict
->getObject(kOSKextInfoPlistDigestKey
)) : NULL
;
11071 result
->setObject(kOSKextInfoPlistDigestKey
, digest
);
11078 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextBundleCollectionTypeKey
)) {
11079 result
->setObject(kOSKextBundleCollectionTypeKey
, OSString::withCString(getKCTypeString()));
11083 * Collection availability
11085 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextAuxKCAvailabilityKey
)) {
11086 result
->setObject(kOSKextAuxKCAvailabilityKey
,
11087 isLoadable() ? kOSBooleanTrue
: kOSBooleanFalse
);
11093 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleAllowUserLoadKey
)) {
11094 OSBoolean
*allowUserLoad
= OSDynamicCast(OSBoolean
, getPropertyForHostArch(kOSBundleAllowUserLoadKey
));
11095 if (allowUserLoad
) {
11096 result
->setObject(kOSBundleAllowUserLoadKey
, allowUserLoad
);
11101 * Bundle Dependencies (OSBundleLibraries)
11103 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLibrariesKey
)) {
11104 OSDictionary
*libraries
= OSDynamicCast(OSDictionary
, getPropertyForHostArch(kOSBundleLibrariesKey
));
11106 result
->setObject(kOSBundleLibrariesKey
, libraries
);
11111 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11113 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKernelResourceKey
)) {
11114 result
->setObject(kOSKernelResourceKey
,
11115 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
11118 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleIsInterfaceKey
)) {
11119 result
->setObject(kOSBundleIsInterfaceKey
,
11120 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
11123 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePrelinkedKey
)) {
11124 result
->setObject(kOSBundlePrelinkedKey
,
11125 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
11128 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleStartedKey
)) {
11129 result
->setObject(kOSBundleStartedKey
,
11130 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
11133 /* LoadTag (Index).
11135 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadTagKey
)) {
11136 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
11137 /* numBits */ 8 * sizeof(loadTag
));
11138 if (!scratchNumber
) {
11141 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
.get());
11144 /* LoadAddress, LoadSize.
11147 _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
) ||
11148 _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
) ||
11149 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
) ||
11150 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
) ||
11151 _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11152 bool is_dext
= isDriverKit();
11153 if (isInterface() || flags
.builtin
|| linkedExecutable
|| is_dext
) {
11154 /* These go to userspace via serialization, so we don't want any doubts
11155 * about their size.
11157 uint64_t loadAddress
= 0;
11158 uint32_t loadSize
= 0;
11159 uint32_t wiredSize
= 0;
11160 uint64_t execLoadAddress
= 0;
11161 uint32_t execLoadSize
= 0;
11163 /* Interfaces always report 0 load address & size.
11164 * Just the way they roll.
11166 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11167 * xxx - shouldn't have one!
11170 if (flags
.builtin
|| linkedExecutable
) {
11171 kernel_mach_header_t
*mh
= NULL
;
11172 kernel_segment_command_t
*seg
= NULL
;
11174 if (flags
.builtin
) {
11175 loadAddress
= kmod_info
->address
;
11176 loadSize
= (uint32_t)kmod_info
->size
;
11178 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
11179 loadSize
= linkedExecutable
->getLength();
11181 mh
= (kernel_mach_header_t
*)loadAddress
;
11182 loadAddress
= ml_static_unslide(loadAddress
);
11184 /* Walk through the kext, looking for the first executable
11185 * segment in case we were asked for its size/address.
11187 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
11188 if (seg
->initprot
& VM_PROT_EXECUTE
) {
11189 execLoadAddress
= ml_static_unslide(seg
->vmaddr
);
11190 execLoadSize
= (uint32_t)seg
->vmsize
;
11195 /* If we have a kmod_info struct, calculated the wired size
11196 * from that. Otherwise it's the full load size.
11199 wiredSize
= loadSize
- (uint32_t)kmod_info
->hdr_size
;
11201 wiredSize
= loadSize
;
11203 } else if (is_dext
) {
11205 * DriverKit userspace executables do not have a kernel linkedExecutable,
11206 * so we "fake" their address range with the LoadTag.
11209 loadAddress
= execLoadAddress
= loadTag
;
11210 loadSize
= execLoadSize
= 1;
11214 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
)) {
11215 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11216 (unsigned long long)(loadAddress
),
11217 /* numBits */ 8 * sizeof(loadAddress
));
11218 if (!scratchNumber
) {
11221 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
.get());
11223 if (kcformat
== KCFormatStatic
|| kcformat
== KCFormatKCGEN
) {
11224 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCacheLoadAddressKey
))
11225 && loadAddress
&& loadSize
) {
11226 void *baseAddress
= PE_get_kc_baseaddress(KCKindPrimary
);
11227 if (!baseAddress
) {
11231 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11232 (unsigned long long)ml_static_unslide((vm_offset_t
)baseAddress
),
11233 /* numBits */ 8 * sizeof(loadAddress
));
11234 if (!scratchNumber
) {
11237 result
->setObject(kOSBundleCacheLoadAddressKey
, scratchNumber
.get());
11239 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleKextsInKernelTextKey
))
11240 && (this == sKernelKext
) && gBuiltinKmodsCount
) {
11241 result
->setObject(kOSBundleKextsInKernelTextKey
, kOSBooleanTrue
);
11245 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
)) {
11246 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11247 (unsigned long long)(execLoadAddress
),
11248 /* numBits */ 8 * sizeof(execLoadAddress
));
11249 if (!scratchNumber
) {
11252 result
->setObject(kOSBundleExecLoadAddressKey
, scratchNumber
.get());
11254 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
)) {
11255 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11256 (unsigned long long)(loadSize
),
11257 /* numBits */ 8 * sizeof(loadSize
));
11258 if (!scratchNumber
) {
11261 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
.get());
11263 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
)) {
11264 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11265 (unsigned long long)(execLoadSize
),
11266 /* numBits */ 8 * sizeof(execLoadSize
));
11267 if (!scratchNumber
) {
11270 result
->setObject(kOSBundleExecLoadSizeKey
, scratchNumber
.get());
11272 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11273 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11274 (unsigned long long)(wiredSize
),
11275 /* numBits */ 8 * sizeof(wiredSize
));
11276 if (!scratchNumber
) {
11279 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
.get());
11284 /* OSBundleDependencies. In descending order for
11285 * easy compatibility with kextstat(8).
11287 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleDependenciesKey
)) {
11288 if ((count
= getNumDependencies())) {
11289 dependencyLoadTags
= OSArray::withCapacity(count
);
11290 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
.get());
11294 OSKext
* dependency
= OSDynamicCast(OSKext
,
11295 dependencies
->getObject(i
));
11300 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11301 (unsigned long long)dependency
->getLoadTag(),
11302 /* numBits*/ 8 * sizeof(loadTag
));
11303 if (!scratchNumber
) {
11306 dependencyLoadTags
->setObject(scratchNumber
.get());
11311 /* OSBundleMetaClasses.
11313 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleClassesKey
)) {
11314 if (metaClasses
&& metaClasses
->getCount()) {
11315 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
11316 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
11317 if (!metaClassIterator
|| !metaClassInfo
) {
11320 result
->setObject(kOSBundleClassesKey
, metaClassInfo
.get());
11322 while ((thisMetaClass
= OSDynamicCast(OSMetaClass
,
11323 metaClassIterator
->getNextObject()))) {
11324 metaClassDict
= OSDictionary::withCapacity(3);
11325 if (!metaClassDict
) {
11329 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
11330 if (thisMetaClass
->getSuperClass()) {
11331 superclassName
= OSString::withCString(
11332 thisMetaClass
->getSuperClass()->getClassName());
11334 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
11335 8 * sizeof(unsigned int));
11337 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11340 if (!metaClassDict
|| !metaClassName
|| !scratchNumber
) {
11344 metaClassInfo
->setObject(metaClassDict
.get());
11345 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
.get());
11346 if (superclassName
) {
11347 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
.get());
11349 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
.get());
11354 /* OSBundleRetainCount.
11356 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleRetainCountKey
)) {
11358 int kextRetainCount
= getRetainCount() - 1;
11362 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11363 (int)kextRetainCount
,
11364 /* numBits*/ 8 * sizeof(int));
11365 if (scratchNumber
) {
11366 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
.get());
11374 if (executablePathCString
) {
11375 kheap_free(KHEAP_TEMP
, executablePathCString
, executablePathCStringSize
);
11383 /*********************************************************************
11384 *********************************************************************/
11387 OSKext::copyUserExecutablePath(const OSSymbol
* bundleID
, char * pathResult
, size_t pathSize
)
11390 OSSharedPtr
<OSKext
> kext
;
11392 IORecursiveLockLock(sKextLock
);
11393 kext
.reset(OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
)), OSRetain
);
11394 IORecursiveLockUnlock(sKextLock
);
11396 if (!kext
|| !kext
->path
|| !kext
->userExecutableRelPath
) {
11399 snprintf(pathResult
, pathSize
, "%s/Contents/MacOS/%s",
11400 kext
->path
->getCStringNoCopy(),
11401 kext
->userExecutableRelPath
->getCStringNoCopy());
11407 /*********************************************************************
11408 *********************************************************************/
11411 OSKext::requestResource(
11412 const char * kextIdentifierCString
,
11413 const char * resourceNameCString
,
11414 OSKextRequestResourceCallback callback
,
11416 OSKextRequestTag
* requestTagOut
)
11418 OSReturn result
= kOSReturnError
;
11419 OSSharedPtr
<OSKext
> callbackKext
; // looked up
11421 OSKextRequestTag requestTag
= -1;
11422 OSSharedPtr
<OSNumber
> requestTagNum
;
11423 OSSharedPtr
<OSDictionary
> requestDict
;
11424 OSSharedPtr
<OSString
> kextIdentifier
;
11425 OSSharedPtr
<OSString
> resourceName
;
11427 OSSharedPtr
<OSDictionary
> callbackRecord
;
11428 OSSharedPtr
<OSData
> callbackWrapper
;
11430 OSSharedPtr
<OSData
> contextWrapper
;
11432 IORecursiveLockLock(sKextLock
);
11434 if (requestTagOut
) {
11435 *requestTagOut
= kOSKextRequestTagInvalid
;
11438 /* If requests to user space are disabled, don't go any further */
11439 if (!sKernelRequestsEnabled
) {
11440 OSKextLog(/* kext */ NULL
,
11441 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11442 "Can't request resource %s for %s - requests to user space are disabled.",
11443 resourceNameCString
,
11444 kextIdentifierCString
);
11445 result
= kOSKextReturnDisabled
;
11449 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
11450 result
= kOSKextReturnInvalidArgument
;
11454 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
11455 if (!callbackKext
) {
11456 OSKextLog(/* kext */ NULL
,
11457 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11458 "Resource request has bad callback address.");
11459 result
= kOSKextReturnInvalidArgument
;
11462 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
11463 OSKextLog(/* kext */ NULL
,
11464 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11465 "Resource request callback is in a kext that is not started.");
11466 result
= kOSKextReturnInvalidArgument
;
11470 /* Do not allow any new requests to be made on a kext that is unloading.
11472 if (callbackKext
->flags
.stopping
) {
11473 result
= kOSKextReturnStopping
;
11477 /* If we're wrapped the next available request tag around to the negative
11478 * numbers, we can't service any more requests.
11480 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
11481 OSKextLog(/* kext */ NULL
,
11482 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11483 "No more request tags available; restart required.");
11484 result
= kOSKextReturnNoResources
;
11487 requestTag
= sNextRequestTag
++;
11489 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
11491 if (result
!= kOSReturnSuccess
) {
11495 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
11496 resourceName
= OSString::withCString(resourceNameCString
);
11497 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11498 8 * sizeof(requestTag
));
11499 if (!kextIdentifier
||
11502 !_OSKextSetRequestArgument(requestDict
.get(),
11503 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
.get()) ||
11504 !_OSKextSetRequestArgument(requestDict
.get(),
11505 kKextRequestArgumentNameKey
, resourceName
.get()) ||
11506 !_OSKextSetRequestArgument(requestDict
.get(),
11507 kKextRequestArgumentRequestTagKey
, requestTagNum
.get())) {
11508 result
= kOSKextReturnNoMemory
;
11512 callbackRecord
= OSDynamicPtrCast
<OSDictionary
>(requestDict
->copyCollection());
11513 if (!callbackRecord
) {
11514 result
= kOSKextReturnNoMemory
;
11517 // we validate callback address at call time
11518 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
11520 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
11522 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11523 kKextRequestArgumentCallbackKey
, callbackWrapper
.get())) {
11524 result
= kOSKextReturnNoMemory
;
11529 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11530 kKextRequestArgumentContextKey
, contextWrapper
.get())) {
11531 result
= kOSKextReturnNoMemory
;
11536 /* Only post the requests after all the other potential failure points
11537 * have been passed.
11539 if (!sKernelRequests
->setObject(requestDict
.get()) ||
11540 !sRequestCallbackRecords
->setObject(callbackRecord
.get())) {
11541 result
= kOSKextReturnNoMemory
;
11545 OSKext::pingIOKitDaemon();
11547 result
= kOSReturnSuccess
;
11548 if (requestTagOut
) {
11549 *requestTagOut
= requestTag
;
11554 /* If we didn't succeed, yank the request & callback
11555 * from their holding arrays.
11557 if (result
!= kOSReturnSuccess
) {
11558 unsigned int index
;
11560 index
= sKernelRequests
->getNextIndexOfObject(requestDict
.get(), 0);
11561 if (index
!= (unsigned int)-1) {
11562 sKernelRequests
->removeObject(index
);
11564 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
.get(), 0);
11565 if (index
!= (unsigned int)-1) {
11566 sRequestCallbackRecords
->removeObject(index
);
11570 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11572 IORecursiveLockUnlock(sKextLock
);
11578 OSKext::requestDaemonLaunch(
11579 OSString
*kextIdentifier
,
11580 OSString
*serverName
,
11581 OSNumber
*serverTag
,
11582 OSSharedPtr
<IOUserServerCheckInToken
> &checkInToken
)
11585 IOUserServerCheckInToken
* checkInTokenRaw
= NULL
;
11587 result
= requestDaemonLaunch(kextIdentifier
, serverName
,
11588 serverTag
, &checkInTokenRaw
);
11590 if (kOSReturnSuccess
== result
) {
11591 checkInToken
.reset(checkInTokenRaw
, OSNoRetain
);
11598 OSKext::requestDaemonLaunch(
11599 OSString
*kextIdentifier
,
11600 OSString
*serverName
,
11601 OSNumber
*serverTag
,
11602 IOUserServerCheckInToken
** checkInToken
)
11604 OSReturn result
= kOSReturnError
;
11605 OSSharedPtr
<OSDictionary
> requestDict
;
11606 OSSharedPtr
<IOUserServerCheckInToken
> token
;
11608 if (!kextIdentifier
|| !serverName
|| !serverTag
) {
11609 result
= kOSKextReturnInvalidArgument
;
11613 IORecursiveLockLock(sKextLock
);
11615 OSKextLog(/* kext */ NULL
,
11616 kOSKextLogDebugLevel
|
11617 kOSKextLogGeneralFlag
,
11618 "Requesting daemon launch for %s with serverName %s and tag %llu",
11619 kextIdentifier
->getCStringNoCopy(),
11620 serverName
->getCStringNoCopy(),
11621 serverTag
->unsigned64BitValue()
11624 result
= _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch
, requestDict
);
11625 if (result
!= kOSReturnSuccess
) {
11629 token
.reset(IOUserServerCheckInToken::create(), OSNoRetain
);
11631 result
= kOSKextReturnNoMemory
;
11635 if (!_OSKextSetRequestArgument(requestDict
.get(),
11636 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
11637 !_OSKextSetRequestArgument(requestDict
.get(),
11638 kKextRequestArgumentDriverExtensionServerName
, serverName
) ||
11639 !_OSKextSetRequestArgument(requestDict
.get(),
11640 kKextRequestArgumentDriverExtensionServerTag
, serverTag
) ||
11641 !_OSKextSetRequestArgument(requestDict
.get(),
11642 kKextRequestArgumentCheckInToken
, token
.get())) {
11643 result
= kOSKextReturnNoMemory
;
11647 /* Only post the requests after all the other potential failure points
11648 * have been passed.
11650 if (!sKernelRequests
->setObject(requestDict
.get())) {
11651 result
= kOSKextReturnNoMemory
;
11654 *checkInToken
= token
.detach();
11655 OSKext::pingIOKitDaemon();
11657 result
= kOSReturnSuccess
;
11659 IORecursiveLockUnlock(sKextLock
);
11663 /*********************************************************************
11664 * Assumes sKextLock is held.
11665 *********************************************************************/
11668 OSKext::dequeueCallbackForRequestTag(
11669 OSKextRequestTag requestTag
,
11670 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11672 OSDictionary
* callbackRecordOutRaw
= NULL
;
11675 result
= dequeueCallbackForRequestTag(requestTag
,
11676 &callbackRecordOutRaw
);
11678 if (kOSReturnSuccess
== result
) {
11679 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11685 OSKext::dequeueCallbackForRequestTag(
11686 OSKextRequestTag requestTag
,
11687 OSDictionary
** callbackRecordOut
)
11689 OSReturn result
= kOSReturnError
;
11690 OSSharedPtr
<OSNumber
> requestTagNum
;
11692 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11693 8 * sizeof(requestTag
));
11694 if (!requestTagNum
) {
11698 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
.get(),
11699 callbackRecordOut
);
11705 /*********************************************************************
11706 * Assumes sKextLock is held.
11707 *********************************************************************/
11710 OSKext::dequeueCallbackForRequestTag(
11711 OSNumber
* requestTagNum
,
11712 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11714 OSDictionary
* callbackRecordOutRaw
= NULL
;
11717 result
= dequeueCallbackForRequestTag(requestTagNum
,
11718 &callbackRecordOutRaw
);
11720 if (kOSReturnSuccess
== result
) {
11721 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11727 OSKext::dequeueCallbackForRequestTag(
11728 OSNumber
* requestTagNum
,
11729 OSDictionary
** callbackRecordOut
)
11731 OSReturn result
= kOSKextReturnInvalidArgument
;
11732 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
11733 OSNumber
* callbackTagNum
= NULL
; // do not release
11734 unsigned int count
, i
;
11736 result
= kOSReturnError
;
11737 count
= sRequestCallbackRecords
->getCount();
11738 for (i
= 0; i
< count
; i
++) {
11739 callbackRecord
= OSDynamicCast(OSDictionary
,
11740 sRequestCallbackRecords
->getObject(i
));
11741 if (!callbackRecord
) {
11745 /* If we don't find a tag, we basically have a leak here. Maybe
11746 * we should just remove it.
11748 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
11749 callbackRecord
, kKextRequestArgumentRequestTagKey
));
11750 if (!callbackTagNum
) {
11754 /* We could be even more paranoid and check that all the incoming
11755 * args match what's in the callback record.
11757 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
11758 if (callbackRecordOut
) {
11759 *callbackRecordOut
= callbackRecord
;
11760 callbackRecord
->retain();
11762 sRequestCallbackRecords
->removeObject(i
);
11763 result
= kOSReturnSuccess
;
11767 result
= kOSKextReturnNotFound
;
11774 /*********************************************************************
11775 * Busy timeout triage
11776 *********************************************************************/
11779 OSKext::pendingIOKitDaemonRequests(void)
11781 return sRequestCallbackRecords
&& sRequestCallbackRecords
->getCount();
11784 /*********************************************************************
11785 * Acquires and releases sKextLock
11787 * This function is designed to be called exactly once on boot by
11788 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11789 * kext and dext personalities, and then attempts to map a System
11790 * (pageable) KC and an Auxiliary (aux) KC.
11792 * Even if the pageable or aux KC fail to load - this function will
11793 * not allow a second call. This avoids security issues where
11794 * kernelmanagerd has been compromised or the pageable kc has been
11795 * tampered with and the attacker attempts to re-load a malicious
11798 * Return: if a KC fails to load the return value will contain:
11799 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11800 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11801 * Similarly, if the aux kc load fails, the return value will
11802 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11803 * compose with each other and with kOSKextReturnKCLoadFailure.
11804 *********************************************************************/
11807 OSKext::loadFileSetKexts(OSDictionary
* requestDict __unused
)
11809 static bool daemon_ready
= false;
11811 OSReturn ret
= kOSKextReturnInvalidArgument
;
11812 OSReturn kcerr
= 0;
11813 bool start_matching
= false;
11815 bool allow_fileset_load
= !daemon_ready
;
11816 #if !(defined(__x86_64__) || defined(__i386__))
11817 /* never allow KCs full of kexts on non-x86 machines */
11818 allow_fileset_load
= false;
11822 * Get the args from the request. Right now we need the file
11823 * name for the pageable and the aux kext collection file sets.
11825 OSDictionary
* requestArgs
= NULL
; // do not release
11826 OSString
* pageable_filepath
= NULL
; // do not release
11827 OSString
* aux_filepath
= NULL
; // do not release
11828 OSArray
* codeless_kexts
= NULL
; // do not release
11830 kernel_mach_header_t
*akc_mh
= NULL
;
11832 requestArgs
= OSDynamicCast(OSDictionary
,
11833 requestDict
->getObject(kKextRequestArgumentsKey
));
11835 if (requestArgs
== NULL
) {
11836 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11837 "KextLog: No arguments in plist for loading fileset kext\n");
11838 printf("KextLog: No arguments in plist for loading fileset kext\n");
11842 ret
= kOSKextReturnDisabled
;
11844 IORecursiveLockLock(sKextLock
);
11846 pageable_filepath
= OSDynamicCast(OSString
,
11847 requestArgs
->getObject(kKextRequestArgumentPageableKCFilename
));
11849 if (allow_fileset_load
&& pageable_filepath
!= NULL
) {
11850 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath
->getCStringNoCopy());
11852 ret
= OSKext::loadKCFileSet(pageable_filepath
->getCStringNoCopy(), KCKindPageable
);
11854 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11855 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11857 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11858 ret
= kOSKextReturnKCLoadFailure
;
11859 kcerr
|= kOSKextReturnKCLoadFailureSystemKC
;
11863 * Even if the AuxKC fails to load, we still want to send
11864 * the System KC personalities to the catalog for matching
11866 start_matching
= true;
11867 } else if (pageable_filepath
!= NULL
) {
11868 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11869 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath
->getCStringNoCopy());
11870 ret
= kOSKextReturnUnsupported
;
11874 akc_mh
= (kernel_mach_header_t
*)PE_get_kc_header(KCKindAuxiliary
);
11877 * If we try to load a deferred AuxKC, then don't ever attempt
11878 * a filesystem map of a file
11880 allow_fileset_load
= false;
11883 * This function is only called once per boot, so we haven't
11884 * yet loaded an AuxKC. If we have registered the AuxKC mach
11885 * header, that means that the kext collection has been placed
11886 * in memory for us by the booter, and is waiting for us to
11887 * process it. Grab the deferred XML plist of info
11888 * dictionaries and add all the kexts.
11890 OSSharedPtr
<OSObject
> parsedXML
;
11891 OSSharedPtr
<OSData
> loaded_kcUUID
;
11892 OSDictionary
*infoDict
;
11893 parsedXML
= consumeDeferredKextCollection(KCKindAuxiliary
);
11894 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
11897 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11898 added
= OSKext::addKextsFromKextCollection(akc_mh
, infoDict
,
11899 kPrelinkTextSegment
, loaded_kcUUID
, KCKindAuxiliary
);
11900 if (!loaded_kcUUID
) {
11901 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11902 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11903 } else if (!added
) {
11904 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11905 "KextLog: WARNING: Failed to load AuxKC from memory.");
11907 /* only return success if the pageable load (above) was successful */
11908 if (ret
!= kOSKextReturnKCLoadFailure
) {
11909 ret
= kOSReturnSuccess
;
11911 /* the registration of the AuxKC parsed out the KC's UUID already */
11913 if (daemon_ready
) {
11915 * Complain, but don't return an error if this isn't the first time the
11916 * IOKit daemon is checking in. If the daemon ever restarts, we will
11917 * hit this case because we've already consumed the deferred personalities.
11918 * We return success here so that a call to this function from a restarted
11919 * daemon with no codeless kexts will succeed.
11921 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11922 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
11923 if (ret
!= kOSKextReturnKCLoadFailure
) {
11924 ret
= kOSReturnSuccess
;
11927 /* this is a real error case */
11928 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11929 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
11930 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
11931 ret
= kOSKextReturnKCLoadFailure
;
11932 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
11937 aux_filepath
= OSDynamicCast(OSString
,
11938 requestArgs
->getObject(kKextRequestArgumentAuxKCFilename
));
11939 if (allow_fileset_load
&& aux_filepath
!= NULL
) {
11940 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath
->getCStringNoCopy());
11942 ret
= OSKext::loadKCFileSet(aux_filepath
->getCStringNoCopy(), KCKindAuxiliary
);
11944 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11945 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
11947 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
11948 ret
= kOSKextReturnKCLoadFailure
;
11949 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
11952 start_matching
= true;
11953 } else if (aux_filepath
!= NULL
) {
11954 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11955 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath
->getCStringNoCopy());
11956 if (ret
!= kOSKextReturnKCLoadFailure
) {
11957 ret
= kOSKextReturnUnsupported
;
11963 * Load codeless kexts last so that there is no possibilty of a
11964 * codeless kext bundle ID preventing a kext in the system KC from
11967 codeless_kexts
= OSDynamicCast(OSArray
,
11968 requestArgs
->getObject(kKextRequestArgumentCodelessPersonalities
));
11969 if (codeless_kexts
!= NULL
) {
11970 uint32_t count
= codeless_kexts
->getCount();
11971 OSKextLog(NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11972 "KextLog: loading %d codeless kexts/dexts", count
);
11973 for (uint32_t i
= 0; i
< count
; i
++) {
11974 OSDictionary
*infoDict
;
11975 infoDict
= OSDynamicCast(OSDictionary
,
11976 codeless_kexts
->getObject(i
));
11980 // instantiate a new kext, and don't hold a reference
11981 // (the kext subsystem will hold one implicitly)
11982 OSKext::withCodelessInfo(infoDict
);
11984 /* ignore errors that are not KC load failures */
11985 if (ret
!= kOSKextReturnKCLoadFailure
) {
11986 ret
= kOSReturnSuccess
;
11988 start_matching
= true;
11991 /* send personalities to the IOCatalog once */
11992 if (ret
== kOSReturnSuccess
|| start_matching
|| sOSKextWasResetAfterUserspaceReboot
) {
11993 OSKext::sendAllKextPersonalitiesToCatalog(true);
11995 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
11996 * things as active and start all the delayed matching: the
11997 * dext and codeless kext personalities should have all been
11998 * delivered via this one call.
12000 if (!daemon_ready
) {
12001 OSKext::setIOKitDaemonActive();
12002 OSKext::setDeferredLoadSucceeded(TRUE
);
12003 IOService::iokitDaemonLaunched();
12005 if (sOSKextWasResetAfterUserspaceReboot
) {
12006 sOSKextWasResetAfterUserspaceReboot
= false;
12007 OSKext::setIOKitDaemonActive();
12008 IOService::startDeferredMatches();
12012 if (ret
== kOSKextReturnKCLoadFailure
) {
12017 * Only allow this function to attempt to load the pageable and
12018 * aux KCs once per boot.
12020 daemon_ready
= true;
12022 IORecursiveLockUnlock(sKextLock
);
12028 OSKext::resetMutableSegments(void)
12030 kernel_segment_command_t
*seg
= NULL
;
12031 kernel_mach_header_t
*k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12033 OSKextSavedMutableSegment
*savedSegment
= NULL
;
12034 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
12037 if (!savedMutableSegments
) {
12038 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
12039 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12040 err
= kOSKextReturnInternalError
;
12044 for (seg
= firstsegfromheader(k_mh
), index
= 0; seg
; seg
= nextsegfromheader(k_mh
, seg
)) {
12045 if (!segmentIsMutable(seg
)) {
12048 uint64_t unslid_vmaddr
= seg
->vmaddr
- kext_slide
;
12049 uint64_t vmsize
= seg
->vmsize
;
12050 err
= kOSKextReturnInternalError
;
12051 for (index
= 0; index
< savedMutableSegments
->getCount(); index
++) {
12052 savedSegment
= OSDynamicCast(OSKextSavedMutableSegment
, savedMutableSegments
->getObject(index
));
12053 assert(savedSegment
);
12054 if (savedSegment
->getVMAddr() == seg
->vmaddr
&& savedSegment
->getVMSize() == seg
->vmsize
) {
12055 OSKextLog(this, kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
12056 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg
->segname
, sizeof(seg
->segname
)), seg
->segname
, unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12057 err
= savedSegment
->restoreContents(seg
);
12058 if (err
!= kOSReturnSuccess
) {
12059 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12063 if (err
!= kOSReturnSuccess
) {
12064 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12067 err
= kOSReturnSuccess
;
12073 /*********************************************************************
12074 * Assumes sKextLock is held.
12075 *********************************************************************/
12078 OSKext::loadKCFileSet(
12079 const char *filepath
,
12082 #if VM_MAPPED_KEXTS
12083 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12085 struct vnode
*vp
= NULL
;
12086 void *fileset_control
;
12088 bool pageable
= (type
== KCKindPageable
);
12090 if ((pageable
&& pageableKCloaded
) ||
12091 (!pageable
&& auxKCloaded
)) {
12092 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12093 "KC FileSet of type %s is already loaded", (pageable
? "Pageable" : "Aux"));
12095 return kOSKextReturnInvalidArgument
;
12098 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12099 if (!pageable
&& !pageableKCloaded
) {
12100 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12101 "Trying to load the Aux KC without loading the Pageable KC");
12102 return kOSKextReturnInvalidArgument
;
12105 fileset_control
= ubc_getobject_from_filename(filepath
, &vp
, &fsize
);
12107 if (fileset_control
== NULL
) {
12108 printf("Could not get memory control object for file %s", filepath
);
12110 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12111 "Could not get memory control object for file %s", filepath
);
12112 return kOSKextReturnInvalidArgument
;
12115 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12116 "Could not find vnode for file %s", filepath
);
12117 return kOSKextReturnInvalidArgument
;
12120 kernel_mach_header_t
*mh
= NULL
;
12121 uintptr_t slide
= 0;
12125 * When SIP is enabled, the KC we map must be SIP-protected
12127 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS
) != 0) {
12128 struct vnode_attr va
;
12131 VATTR_WANTED(&va
, va_flags
);
12132 error
= vnode_getattr(vp
, &va
, vfs_context_current());
12134 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12135 "vnode_getattr(%s) failed (error=%d)", filepath
, error
);
12136 err
= kOSKextReturnInternalError
;
12139 if (!(va
.va_flags
& SF_RESTRICTED
)) {
12140 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12141 "Path to KC '%s' is not SIP-protected", filepath
);
12142 err
= kOSKextReturnInvalidArgument
;
12148 err
= OSKext::mapKCFileSet(fileset_control
, (vm_size_t
)fsize
, &mh
, 0, &slide
, pageable
, NULL
);
12150 printf("KextLog: mapKCFileSet returned %d\n", err
);
12152 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12153 "mapKCFileSet returned %d\n", err
);
12155 err
= kOSKextReturnInvalidArgument
;
12161 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12162 assert(vp
!= NULL
);
12163 if (err
== kOSReturnSuccess
) {
12164 PE_set_kc_vp(type
, vp
);
12166 pageableKCloaded
= true;
12168 auxKCloaded
= true;
12178 return kOSKextReturnUnsupported
;
12179 #endif // VM_MAPPED_KEXTS
12182 #if defined(__x86_64__) || defined(__i386__)
12183 /*********************************************************************
12184 * Assumes sKextLock is held.
12185 *********************************************************************/
12188 OSKext::mapKCFileSet(
12191 kernel_mach_header_t
**mhp
,
12195 void *map_entry_list
)
12197 bool fileset_load
= false;
12200 kernel_section_t
*infoPlistSection
= NULL
;
12201 OSDictionary
*infoDict
= NULL
;
12203 OSSharedPtr
<OSObject
> parsedXML
;
12204 OSSharedPtr
<OSString
> errorString
;
12205 OSSharedPtr
<OSData
> loaded_kcUUID
;
12207 /* Check if initial load for file set */
12208 if (*mhp
== NULL
) {
12209 fileset_load
= true;
12211 /* Get a page aligned address from kext map to map the file */
12212 vm_map_offset_t pagealigned_addr
= get_address_from_kext_map(fsize
);
12213 if (pagealigned_addr
== 0) {
12214 return kOSKextReturnNoMemory
;
12217 *mhp
= (kernel_mach_header_t
*)pagealigned_addr
;
12219 /* Allocate memory for bailout mechanism */
12220 map_entry_list
= allocate_kcfileset_map_entry_list();
12221 if (map_entry_list
== NULL
) {
12222 return kOSKextReturnNoMemory
;
12226 uintptr_t *slideptr
= fileset_load
? slidep
: NULL
;
12227 err
= mapKCTextSegment(control
, mhp
, file_offset
, slideptr
, map_entry_list
);
12228 /* mhp and slideptr are updated by mapKCTextSegment */
12230 if (fileset_load
) {
12231 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12236 /* Initialize the kc header globals */
12237 if (fileset_load
) {
12239 PE_set_kc_header(KCKindPageable
, *mhp
, *slidep
);
12241 PE_set_kc_header(KCKindAuxiliary
, *mhp
, *slidep
);
12245 /* Iterate through all the segments and map necessary segments */
12246 struct load_command
*lcp
= (struct load_command
*) (*mhp
+ 1);
12247 for (unsigned int i
= 0; i
< (*mhp
)->ncmds
; i
++, lcp
= (struct load_command
*)((uintptr_t)lcp
+ lcp
->cmdsize
)) {
12248 vm_map_offset_t start
;
12249 kernel_mach_header_t
*k_mh
= NULL
;
12250 kernel_segment_command_t
* seg
= NULL
;
12251 struct fileset_entry_command
*fse
= NULL
;
12253 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
12254 seg
= (kernel_segment_command_t
*)lcp
;
12255 start
= ((uintptr_t)(seg
->vmaddr
)) + *slidep
;
12256 } else if (lcp
->cmd
== LC_FILESET_ENTRY
) {
12257 fse
= (struct fileset_entry_command
*)lcp
;
12258 k_mh
= (kernel_mach_header_t
*)(((uintptr_t)(fse
->vmaddr
)) + *slidep
);
12260 /* Map the segments of the mach-o binary */
12261 err
= OSKext::mapKCFileSet(control
, 0, &k_mh
, fse
->fileoff
, slidep
, pageable
, map_entry_list
);
12263 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12264 return kOSKextReturnInvalidArgument
;
12267 } else if (lcp
->cmd
== LC_DYLD_CHAINED_FIXUPS
) {
12268 /* Check if the Aux KC is built pageable style */
12269 if (!pageable
&& !fileset_load
&& !auxKCloaded
) {
12270 resetAuxKCSegmentOnUnload
= true;
12277 if (fileset_load
) {
12278 if (seg
->vmsize
== 0) {
12282 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12283 if (strncmp(seg
->segname
, kPrelinkInfoSegment
, sizeof(seg
->segname
)) != 0 &&
12284 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) != 0 &&
12285 strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) != 0 &&
12286 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0) {
12290 if (seg
->vmsize
== 0) {
12294 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12295 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12296 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12297 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12302 ret
= vm_map_kcfileset_segment(
12303 &start
, seg
->vmsize
,
12304 (memory_object_control_t
)control
, seg
->fileoff
, seg
->maxprot
);
12306 if (ret
!= KERN_SUCCESS
) {
12307 if (fileset_load
) {
12308 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12310 return kOSKextReturnInvalidArgument
;
12312 add_kcfileset_map_entry(map_entry_list
, start
, seg
->vmsize
);
12315 /* Return if regular mach-o */
12316 if (!fileset_load
) {
12321 * Fixup for the Pageable KC and the Aux KC is done by
12322 * i386_slide_kext_collection_mh_addrs, but it differs in
12325 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12326 * The fixup of kext segments and kext load commands are done at kext
12327 * load time by calling i386_slide_individual_kext.
12329 * AuxKC old style: Fixup all the segments and all the load commands.
12331 * AuxKC pageable style: Same as the Pageable KC.
12333 bool adjust_mach_header
= (pageable
? true : ((resetAuxKCSegmentOnUnload
) ? true : false));
12334 ret
= i386_slide_kext_collection_mh_addrs(*mhp
, *slidep
, adjust_mach_header
);
12335 if (ret
!= KERN_SUCCESS
) {
12336 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12337 return kOSKextReturnInvalidArgument
;
12340 /* Get the prelink info dictionary */
12341 infoPlistSection
= getsectbynamefromheader(*mhp
, kPrelinkInfoSegment
, kPrelinkInfoSection
);
12342 parsedXML
= OSUnserializeXML((const char *)infoPlistSection
->addr
, errorString
);
12344 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
12348 const char *errorCString
= "(unknown error)";
12350 if (errorString
&& errorString
->getCStringNoCopy()) {
12351 errorCString
= errorString
->getCStringNoCopy();
12352 } else if (parsedXML
) {
12353 errorCString
= "not a dictionary";
12355 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12356 "Error unserializing kext info plist section: %s.", errorCString
);
12357 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12358 return kOSKextReturnInvalidArgument
;
12361 /* Validate that the Kext Collection is prelinked to the loaded KC */
12362 err
= OSKext::validateKCFileSetUUID(infoDict
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12364 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12365 return kOSKextReturnInvalidArgument
;
12368 /* Set Protection of Segments */
12369 OSKext::protectKCFileSet(*mhp
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12371 OSKext::addKextsFromKextCollection(*mhp
,
12372 infoDict
, kPrelinkTextSegment
,
12373 loaded_kcUUID
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12375 /* Copy in the KC UUID */
12376 if (!loaded_kcUUID
) {
12377 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12378 "WARNING: did not find UUID in prelinked %s KC!", pageable
? "Pageable" : "Aux");
12379 } else if (pageable
) {
12380 pageablekc_uuid_valid
= TRUE
;
12381 memcpy((void *)&pageablekc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12382 uuid_unparse_upper(pageablekc_uuid
, pageablekc_uuid_string
);
12384 auxkc_uuid_valid
= TRUE
;
12385 memcpy((void *)&auxkc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12386 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
12389 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, FALSE
, pageable
);
12394 /*********************************************************************
12395 * Assumes sKextLock is held.
12396 *********************************************************************/
12399 OSKext::mapKCTextSegment(
12401 kernel_mach_header_t
**mhp
,
12404 void *map_entry_list
)
12407 vm_map_offset_t mach_header_map_size
= vm_map_round_page(sizeof(kernel_mach_header_t
),
12409 vm_map_offset_t load_command_map_size
= 0;
12410 kernel_mach_header_t
*base_mh
= *mhp
;
12412 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12413 ret
= vm_map_kcfileset_segment(
12414 (vm_map_offset_t
*)&base_mh
, mach_header_map_size
,
12415 (memory_object_control_t
)control
, file_offset
, (VM_PROT_READ
| VM_PROT_WRITE
));
12417 if (ret
!= KERN_SUCCESS
) {
12418 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret
);
12420 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12421 "Failed to map mach header of kc fileset with error %d", ret
);
12422 return kOSKextReturnInvalidArgument
;
12426 /* Verify that it's an MH_FILESET */
12427 if (base_mh
->filetype
!= MH_FILESET
) {
12428 printf("Kext Log: mapKCTextSegment mach header filetype"
12429 " is not an MH_FILESET, it is %x", base_mh
->filetype
);
12431 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12432 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh
->filetype
);
12434 /* Unmap the mach header */
12435 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12436 return kOSKextReturnInvalidArgument
;
12440 /* Map the remaining pages of load commands */
12441 if (base_mh
->sizeofcmds
> mach_header_map_size
) {
12442 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12443 load_command_map_size
= base_mh
->sizeofcmds
- mach_header_map_size
;
12445 /* Map the load commands */
12446 ret
= vm_map_kcfileset_segment(
12447 &load_command_addr
, load_command_map_size
,
12448 (memory_object_control_t
)control
, file_offset
+ mach_header_map_size
,
12449 (VM_PROT_READ
| VM_PROT_WRITE
));
12451 if (ret
!= KERN_SUCCESS
) {
12452 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret
);
12453 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12454 "Failed to map load commands of kc fileset with error %d", ret
);
12456 /* Unmap the mach header */
12457 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12458 return kOSKextReturnInvalidArgument
;
12462 kernel_segment_command_t
*text_seg
;
12463 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)base_mh
, SEG_TEXT
);
12465 /* Calculate the slide and vm addr of mach header */
12467 *mhp
= (kernel_mach_header_t
*)((uintptr_t)base_mh
+ text_seg
->vmaddr
);
12468 *slidep
= ((uintptr_t)*mhp
) - text_seg
->vmaddr
;
12471 /* Cache the text segment size and file offset before unmapping */
12472 vm_map_offset_t text_segment_size
= text_seg
->vmsize
;
12473 vm_object_offset_t text_segment_fileoff
= text_seg
->fileoff
;
12474 vm_prot_t text_maxprot
= text_seg
->maxprot
;
12476 /* Unmap the first page and loadcommands and map the text segment */
12477 ret
= vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12478 assert(ret
== KERN_SUCCESS
);
12480 if (load_command_map_size
) {
12481 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12482 ret
= vm_unmap_kcfileset_segment(&load_command_addr
, load_command_map_size
);
12483 assert(ret
== KERN_SUCCESS
);
12486 /* Map the text segment at actual vm addr specified in fileset */
12487 ret
= vm_map_kcfileset_segment((vm_map_offset_t
*)mhp
, text_segment_size
,
12488 (memory_object_control_t
)control
, text_segment_fileoff
, text_maxprot
);
12489 if (ret
!= KERN_SUCCESS
) {
12490 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12491 "Failed to map Text segment of kc fileset with error %d", ret
);
12492 return kOSKextReturnInvalidArgument
;
12495 add_kcfileset_map_entry(map_entry_list
, (vm_map_offset_t
)*mhp
, text_segment_size
);
12499 /*********************************************************************
12500 * Assumes sKextLock is held.
12501 *********************************************************************/
12504 OSKext::protectKCFileSet(
12505 kernel_mach_header_t
*mh
,
12508 vm_map_t kext_map
= g_kext_map
;
12509 kernel_segment_command_t
* seg
= NULL
;
12510 vm_map_offset_t start
= 0;
12511 vm_map_offset_t end
= 0;
12514 /* Set VM permissions */
12515 seg
= firstsegfromheader((kernel_mach_header_t
*)mh
);
12517 start
= round_page(seg
->vmaddr
);
12518 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
12521 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12522 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12523 * for the Aux KC as well.
12525 if (strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) == 0 ||
12526 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) == 0 ||
12527 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0 ||
12528 (type
== KCKindAuxiliary
&& !resetAuxKCSegmentOnUnload
&&
12529 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0)) {
12530 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12531 kext_map
, start
, end
, seg
->maxprot
, TRUE
, type
);
12532 if (ret
!= KERN_SUCCESS
) {
12533 printf("OSKext protect failed with error %d", ret
);
12534 return kOSKextReturnInvalidArgument
;
12537 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12538 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12539 if (ret
!= KERN_SUCCESS
) {
12540 printf("OSKext protect failed with error %d", ret
);
12541 return kOSKextReturnInvalidArgument
;
12544 ret
= OSKext_wire((kernel_mach_header_t
*)mh
,
12545 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12546 if (ret
!= KERN_SUCCESS
) {
12547 printf("OSKext wire failed with error %d", ret
);
12548 return kOSKextReturnInvalidArgument
;
12552 seg
= nextsegfromheader((kernel_mach_header_t
*) mh
, seg
);
12558 /*********************************************************************
12559 * Assumes sKextLock is held.
12560 *********************************************************************/
12563 OSKext::freeKCFileSetcontrol(void)
12565 PE_reset_all_kc_vp();
12568 /*********************************************************************
12569 * Assumes sKextLock is held.
12571 * resetKCFileSetSegments: Kext start function expects data segment to
12572 * be pristine on every load, unmap the dirty segments on unload and
12573 * remap them from FileSet on disk. Remap all segments of kext since
12574 * fixups are done per kext and not per segment.
12575 *********************************************************************/
12577 OSKext::resetKCFileSetSegments(void)
12579 kernel_segment_command_t
*seg
= NULL
;
12580 kernel_segment_command_t
*text_seg
;
12581 uint32_t text_fileoff
;
12582 kernel_mach_header_t
*k_mh
= NULL
;
12584 struct vnode
*vp
= NULL
;
12585 void *fileset_control
= NULL
;
12586 bool pageable
= (kc_type
== KCKindPageable
);
12590 /* Check the vnode reference is still available */
12591 vp
= (struct vnode
*)PE_get_kc_vp(kc_type
);
12593 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12594 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12595 return kOSKextReturnInternalError
;
12598 fileset_control
= ubc_getobject(vp
, 0);
12599 assert(fileset_control
!= NULL
);
12601 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12602 "Kext %s resetting all segments", getIdentifierCString());
12604 k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12605 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)kmod_info
->address
, SEG_TEXT
);
12606 text_fileoff
= text_seg
->fileoff
;
12607 slide
= PE_get_kc_slide(kc_type
);
12609 seg
= firstsegfromheader((kernel_mach_header_t
*)k_mh
);
12611 if (seg
->vmsize
== 0) {
12612 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12616 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12617 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12618 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12619 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12620 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12624 kr
= vm_unmap_kcfileset_segment(&seg
->vmaddr
, seg
->vmsize
);
12625 assert(kr
== KERN_SUCCESS
);
12626 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12629 /* Unmap the text segment */
12630 kr
= vm_unmap_kcfileset_segment(&text_seg
->vmaddr
, text_seg
->vmsize
);
12631 assert(kr
== KERN_SUCCESS
);
12633 /* Map all the segments of the kext */
12634 err
= OSKext::mapKCFileSet(fileset_control
, 0, &k_mh
, text_fileoff
, &slide
, pageable
, NULL
);
12636 panic("Could not reset segments of a mapped kext, error %x", err
);
12639 /* Update address in kmod_info, since it has been reset */
12640 if (kmod_info
->address
) {
12641 kmod_info
->address
= (((uintptr_t)(kmod_info
->address
)) + slide
);
12647 /*********************************************************************
12648 * Mechanism to track all segment mapping while mapping KC fileset.
12649 *********************************************************************/
12651 struct kcfileset_map_entry
{
12652 vm_map_offset_t me_start
;
12653 vm_map_offset_t me_size
;
12656 struct kcfileset_map_entry_list
{
12657 int kme_list_count
;
12658 int kme_list_index
;
12659 struct kcfileset_map_entry kme_list
[];
12662 #define KCFILESET_MAP_ENTRY_MAX (16380)
12665 allocate_kcfileset_map_entry_list(void)
12667 struct kcfileset_map_entry_list
*entry_list
;
12669 entry_list
= (struct kcfileset_map_entry_list
*)kalloc(sizeof(struct kcfileset_map_entry_list
) +
12670 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12672 entry_list
->kme_list_count
= KCFILESET_MAP_ENTRY_MAX
;
12673 entry_list
->kme_list_index
= 0;
12678 add_kcfileset_map_entry(
12679 void *map_entry_list
,
12680 vm_map_offset_t start
,
12681 vm_map_offset_t size
)
12683 if (map_entry_list
== NULL
) {
12687 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12689 if (entry_list
->kme_list_index
>= entry_list
->kme_list_count
) {
12690 panic("Ran out of map kc fileset list\n");
12693 entry_list
->kme_list
[entry_list
->kme_list_index
].me_start
= start
;
12694 entry_list
->kme_list
[entry_list
->kme_list_index
].me_size
= size
;
12696 entry_list
->kme_list_index
++;
12700 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12701 void *map_entry_list
,
12702 boolean_t unmap_entries
,
12705 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12707 if (unmap_entries
) {
12708 for (int i
= 0; i
< entry_list
->kme_list_index
; i
++) {
12710 ret
= vm_unmap_kcfileset_segment(
12711 &(entry_list
->kme_list
[i
].me_start
),
12712 entry_list
->kme_list
[i
].me_size
);
12713 assert(ret
== KERN_SUCCESS
);
12716 PE_reset_kc_header(pageable
? KCKindPageable
: KCKindAuxiliary
);
12719 kfree(entry_list
, sizeof(struct kcfileset_map_entry_list
) +
12720 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12723 /*********************************************************************
12724 * Mechanism to map kext segment.
12725 *********************************************************************/
12728 vm_map_kcfileset_segment(
12729 vm_map_offset_t
*start
,
12730 vm_map_offset_t size
,
12732 vm_object_offset_t fileoffset
,
12733 vm_prot_t max_prot
)
12735 vm_map_kernel_flags_t vmk_flags
;
12736 vmk_flags
.vmkf_no_copy_on_read
= 1;
12737 vmk_flags
.vmkf_cs_enforcement
= 0;
12738 vmk_flags
.vmkf_cs_enforcement_override
= 1;
12741 /* Add Write to max prot to allow fixups */
12742 max_prot
= max_prot
| VM_PROT_WRITE
;
12745 * Map the segments from file as COPY mappings to
12746 * make sure changes on disk to the file does not affect
12749 ret
= vm_map_enter_mem_object_control(
12753 (mach_vm_offset_t
)0,
12756 VM_KERN_MEMORY_OSKEXT
,
12757 (memory_object_control_t
)control
,
12760 (VM_PROT_READ
| VM_PROT_WRITE
), max_prot
,
12767 vm_unmap_kcfileset_segment(
12768 vm_map_offset_t
*start
,
12769 vm_map_offset_t size
)
12771 return mach_vm_deallocate(g_kext_map
, *start
, size
);
12774 #endif //(__x86_64__) || defined(__i386__)
12776 /*********************************************************************
12777 * Assumes sKextLock is held.
12778 *********************************************************************/
12781 OSKext::validateKCFileSetUUID(
12782 OSDictionary
*infoDict
,
12785 OSReturn ret
= kOSReturnSuccess
;
12787 if (!kernelcache_uuid_valid
) {
12788 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12789 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12790 ret
= kOSKextReturnInvalidArgument
;
12793 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid
, type
, infoDict
, kPrelinkInfoBootKCIDKey
);
12798 #if defined(__x86_64__) || defined(__i386__)
12799 /* Check if the Aux KC is prelinked to correct Pageable KC */
12800 if (type
== KCKindAuxiliary
) {
12801 if (!pageablekc_uuid_valid
) {
12802 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12803 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12804 ret
= kOSKextReturnInvalidArgument
;
12807 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid
, type
, infoDict
, kPrelinkInfoPageableKCIDKey
);
12812 #endif //(__x86_64__) || defined(__i386__)
12814 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12819 /*********************************************************************
12820 * Assumes sKextLock is held.
12821 *********************************************************************/
12824 OSKext::validateKCUUIDfromPrelinkInfo(
12825 uuid_t
*loaded_kcuuid
,
12827 OSDictionary
*infoDict
,
12828 const char *uuid_key
)
12830 /* extract the UUID from the dictionary */
12831 OSData
*prelinkinfoKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(uuid_key
));
12832 if (!prelinkinfoKCUUID
) {
12833 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12834 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key
);
12835 return kOSKextReturnInvalidArgument
;
12838 if (prelinkinfoKCUUID
->getLength() != sizeof(uuid_t
)) {
12839 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12840 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key
, prelinkinfoKCUUID
->getLength());
12841 return kOSKextReturnInvalidArgument
;
12844 if (memcmp((void *)loaded_kcuuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(),
12845 prelinkinfoKCUUID
->getLength())) {
12846 OSData
*info_dict_uuid
;
12847 uuid_string_t info_dict_uuid_str
= {};
12848 uuid_string_t expected_uuid_str
= {};
12849 uuid_string_t given_uuid_str
= {};
12852 /* extract the KC UUID from the dictionary */
12853 info_dict_uuid
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
12854 if (info_dict_uuid
&& info_dict_uuid
->getLength() == sizeof(uuid_t
)) {
12856 memcpy(tmp_uuid
, (const void *)info_dict_uuid
->getBytesNoCopy(), sizeof(tmp_uuid
));
12857 uuid_unparse(tmp_uuid
, info_dict_uuid_str
);
12860 uuid_unparse(*loaded_kcuuid
, expected_uuid_str
);
12861 memcpy(given_uuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(), sizeof(given_uuid
));
12862 uuid_unparse(given_uuid
, given_uuid_str
);
12864 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12865 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12866 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12867 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12868 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12869 if (type
== KCKindPageable
&& sPanicOnKCMismatch
) {
12870 panic("System KC UUID %s linked against %s, but %s is loaded",
12871 info_dict_uuid_str
, given_uuid_str
, expected_uuid_str
);
12873 return kOSKextReturnInvalidArgument
;
12879 /*********************************************************************
12880 * Assumes sKextLock is held.
12881 *********************************************************************/
12884 OSKext::dispatchResource(OSDictionary
* requestDict
)
12886 OSReturn result
= kOSReturnError
;
12887 OSSharedPtr
<OSDictionary
> callbackRecord
;
12888 OSNumber
* requestTag
= NULL
; // do not release
12889 OSNumber
* requestResult
= NULL
; // do not release
12890 OSData
* dataObj
= NULL
; // do not release
12891 uint32_t dataLength
= 0;
12892 const void * dataPtr
= NULL
; // do not free
12893 OSData
* callbackWrapper
= NULL
; // do not release
12894 OSKextRequestResourceCallback callback
= NULL
;
12895 OSData
* contextWrapper
= NULL
; // do not release
12896 void * context
= NULL
; // do not free
12897 OSSharedPtr
<OSKext
> callbackKext
;
12899 /* Get the args from the request. Right now we need the tag
12900 * to look up the callback record, and the result for invoking the callback.
12902 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12903 kKextRequestArgumentRequestTagKey
));
12904 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12905 kKextRequestArgumentResultKey
));
12906 if (!requestTag
|| !requestResult
) {
12907 result
= kOSKextReturnInvalidArgument
;
12911 /* Look for a callback record matching this request's tag.
12913 result
= dequeueCallbackForRequestTag(requestTag
, callbackRecord
);
12914 if (result
!= kOSReturnSuccess
) {
12919 * Get the context pointer of the callback record (if there is one).
12921 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
.get(),
12922 kKextRequestArgumentContextKey
));
12923 context
= _OSKextExtractPointer(contextWrapper
);
12924 if (contextWrapper
&& !context
) {
12928 callbackWrapper
= OSDynamicCast(OSData
,
12929 _OSKextGetRequestArgument(callbackRecord
.get(),
12930 kKextRequestArgumentCallbackKey
));
12931 callback
= _OSKextExtractCallbackPointer(callbackWrapper
);
12936 /* Check for a data obj. We might not have one and that's ok, that means
12937 * we didn't find the requested resource, and we still have to tell the
12938 * caller that via the callback.
12940 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
12941 kKextRequestArgumentValueKey
));
12943 dataPtr
= dataObj
->getBytesNoCopy();
12944 dataLength
= dataObj
->getLength();
12947 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
12948 if (!callbackKext
) {
12949 OSKextLog(/* kext */ NULL
,
12950 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
12951 "Can't invoke callback for resource request; ");
12954 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
12955 OSKextLog(/* kext */ NULL
,
12956 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
12957 "Can't invoke kext resource callback; ");
12961 (void)callback(requestTag
->unsigned32BitValue(),
12962 (OSReturn
)requestResult
->unsigned32BitValue(),
12963 dataPtr
, dataLength
, context
);
12965 result
= kOSReturnSuccess
;
12971 /*********************************************************************
12972 * Assumes sKextLock is held.
12973 *********************************************************************/
12976 OSKext::setMissingAuxKCBundles(OSDictionary
* requestDict
)
12978 OSSharedPtr
<OSDictionary
> missingIDs
;
12979 OSArray
*bundleIDList
= NULL
; // do not release
12981 bundleIDList
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
12982 requestDict
, kKextRequestArgumentMissingBundleIDs
));
12983 if (!bundleIDList
) {
12984 return kOSKextReturnInvalidArgument
;
12987 missingIDs
= OSDictionary::withCapacity(bundleIDList
->getCount());
12989 return kOSKextReturnNoMemory
;
12993 count
= bundleIDList
->getCount();
12994 for (i
= 0; i
< count
; i
++) {
12995 OSString
*thisID
= OSDynamicCast(OSString
, bundleIDList
->getObject(i
));
12997 missingIDs
->setObject(thisID
, kOSBooleanFalse
);
13001 sNonLoadableKextsByID
.reset(missingIDs
.get(), OSRetain
);
13003 return kOSReturnSuccess
;
13006 /*********************************************************************
13007 * Assumes sKextLock is held.
13008 *********************************************************************/
13011 OSKext::setAuxKCBundleAvailable(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
13013 bool loadable
= true;
13014 if (!kextIdentifier
) {
13015 return kOSKextReturnInvalidArgument
;
13019 OSBoolean
*loadableArg
;
13020 loadableArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
13021 requestDict
, kKextRequestArgumentBundleAvailability
));
13022 /* If we find the "Bundle Available" arg, and it's false, then
13023 * mark the bundle ID as _not_ loadable
13025 if (loadableArg
&& !loadableArg
->getValue()) {
13030 if (!sNonLoadableKextsByID
) {
13031 sNonLoadableKextsByID
= OSDictionary::withCapacity(1);
13034 sNonLoadableKextsByID
->setObject(kextIdentifier
, OSBoolean::withBoolean(loadable
));
13036 OSKextLog(/* kext */ NULL
,
13037 kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
13038 "KextLog: AuxKC bundle %s marked as %s",
13039 kextIdentifier
->getCStringNoCopy(),
13040 (loadable
? "loadable" : "NOT loadable"));
13042 return kOSReturnSuccess
;
13045 /*********************************************************************
13046 *********************************************************************/
13049 OSKext::invokeRequestCallback(
13050 OSDictionary
* callbackRecord
,
13051 OSReturn callbackResult
)
13053 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
13054 OSSharedPtr
<OSNumber
> resultNum
;
13060 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
13061 8 * sizeof(callbackResult
));
13066 /* Insert the result into the callback record and dispatch it as if it
13067 * were the reply coming down from user space.
13069 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
13072 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
13073 /* This removes the pending callback record.
13075 OSKext::dispatchResource(callbackRecord
);
13082 /*********************************************************************
13083 * Assumes sKextLock is held.
13084 *********************************************************************/
13087 OSKext::cancelRequest(
13088 OSKextRequestTag requestTag
,
13089 void ** contextOut
)
13091 OSReturn result
= kOSKextReturnNoMemory
;
13092 OSSharedPtr
<OSDictionary
> callbackRecord
;
13093 OSData
* contextWrapper
= NULL
; // do not release
13095 IORecursiveLockLock(sKextLock
);
13096 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
13098 IORecursiveLockUnlock(sKextLock
);
13100 if (result
== kOSReturnSuccess
&& contextOut
) {
13101 contextWrapper
= OSDynamicCast(OSData
,
13102 _OSKextGetRequestArgument(callbackRecord
.get(),
13103 kKextRequestArgumentContextKey
));
13104 *contextOut
= _OSKextExtractPointer(contextWrapper
);
13110 /*********************************************************************
13111 * Assumes sKextLock is held.
13112 *********************************************************************/
13114 OSKext::invokeOrCancelRequestCallbacks(
13115 OSReturn callbackResult
,
13118 unsigned int count
, i
;
13120 count
= sRequestCallbackRecords
->getCount();
13127 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13128 sRequestCallbackRecords
->getObject(i
));
13133 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13134 _OSKextGetRequestArgument(request
,
13135 kKextRequestArgumentCallbackKey
));
13137 if (!callbackWrapper
) {
13138 sRequestCallbackRecords
->removeObject(i
);
13142 vm_address_t callbackAddress
= (vm_address_t
)
13143 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13145 if ((kmod_info
->address
<= callbackAddress
) &&
13146 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13148 /* This removes the callback record.
13150 invokeRequestCallback(request
, callbackResult
);
13152 sRequestCallbackRecords
->removeObject(i
);
13161 /*********************************************************************
13162 * Assumes sKextLock is held.
13163 *********************************************************************/
13165 OSKext::countRequestCallbacks(void)
13167 uint32_t result
= 0;
13168 unsigned int count
, i
;
13170 count
= sRequestCallbackRecords
->getCount();
13177 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13178 sRequestCallbackRecords
->getObject(i
));
13183 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13184 _OSKextGetRequestArgument(request
,
13185 kKextRequestArgumentCallbackKey
));
13187 if (!callbackWrapper
) {
13191 vm_address_t callbackAddress
= (vm_address_t
)
13192 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13194 if ((kmod_info
->address
<= callbackAddress
) &&
13195 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13204 /*********************************************************************
13205 *********************************************************************/
13207 _OSKextCreateRequest(
13208 const char * predicate
,
13209 OSSharedPtr
<OSDictionary
> & requestR
)
13211 OSReturn result
= kOSKextReturnNoMemory
;
13212 OSSharedPtr
<OSDictionary
> request
;
13214 request
= OSDictionary::withCapacity(2);
13218 result
= _OSDictionarySetCStringValue(request
.get(),
13219 kKextRequestPredicateKey
, predicate
);
13220 if (result
!= kOSReturnSuccess
) {
13223 result
= kOSReturnSuccess
;
13226 if (result
== kOSReturnSuccess
) {
13227 requestR
= os::move(request
);
13233 /*********************************************************************
13234 *********************************************************************/
13236 _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
13238 return OSDynamicCast(OSString
,
13239 requestDict
->getObject(kKextRequestPredicateKey
));
13242 /*********************************************************************
13243 *********************************************************************/
13245 _OSKextGetRequestArgument(
13246 OSDictionary
* requestDict
,
13247 const char * argName
)
13249 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13250 requestDict
->getObject(kKextRequestArgumentsKey
));
13252 return args
->getObject(argName
);
13257 /*********************************************************************
13258 *********************************************************************/
13260 _OSKextSetRequestArgument(
13261 OSDictionary
* requestDict
,
13262 const char * argName
,
13265 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13266 requestDict
->getObject(kKextRequestArgumentsKey
));
13267 OSSharedPtr
<OSDictionary
> newArgs
;
13269 newArgs
= OSDictionary::withCapacity(2);
13270 args
= newArgs
.get();
13274 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
13277 return args
->setObject(argName
, value
);
13283 /*********************************************************************
13284 *********************************************************************/
13286 _OSKextExtractPointer(OSData
* wrapper
)
13288 void * result
= NULL
;
13289 const void * resultPtr
= NULL
;
13294 resultPtr
= wrapper
->getBytesNoCopy();
13295 result
= *(void **)resultPtr
;
13300 /*********************************************************************
13301 *********************************************************************/
13302 static OSKextRequestResourceCallback
13303 _OSKextExtractCallbackPointer(OSData
* wrapper
)
13305 OSKextRequestResourceCallback result
= NULL
;
13306 const void * resultPtr
= NULL
;
13311 resultPtr
= wrapper
->getBytesNoCopy();
13312 result
= *(OSKextRequestResourceCallback
*)resultPtr
;
13318 /*********************************************************************
13319 *********************************************************************/
13321 _OSDictionarySetCStringValue(
13322 OSDictionary
* dict
,
13324 const char * cValue
)
13326 OSReturn result
= kOSKextReturnNoMemory
;
13327 OSSharedPtr
<const OSSymbol
> key
;
13328 OSSharedPtr
<OSString
> value
;
13330 key
= OSSymbol::withCString(cKey
);
13331 value
= OSString::withCString(cValue
);
13332 if (!key
|| !value
) {
13335 if (dict
->setObject(key
.get(), value
.get())) {
13336 result
= kOSReturnSuccess
;
13343 /*********************************************************************
13344 *********************************************************************/
13346 _OSArrayContainsCString(
13348 const char * cString
)
13350 bool result
= false;
13351 OSSharedPtr
<const OSSymbol
> symbol
;
13354 if (!array
|| !cString
) {
13358 symbol
= OSSymbol::withCStringNoCopy(cString
);
13363 count
= array
->getCount();
13364 for (i
= 0; i
< count
; i
++) {
13365 OSObject
* thisObject
= array
->getObject(i
);
13366 if (symbol
->isEqualTo(thisObject
)) {
13377 /*********************************************************************
13378 * We really only care about boot / system start up related kexts.
13379 * We return true if we're less than REBUILD_MAX_TIME since start up,
13380 * otherwise return false.
13381 *********************************************************************/
13383 _OSKextInPrelinkRebuildWindow(void)
13385 static bool outside_the_window
= false;
13386 AbsoluteTime my_abstime
;
13390 if (outside_the_window
) {
13393 clock_get_uptime(&my_abstime
);
13394 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
13395 my_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
13396 if (my_secs
> REBUILD_MAX_TIME
) {
13397 outside_the_window
= true;
13402 #endif /* CONFIG_KXLD */
13404 /*********************************************************************
13405 *********************************************************************/
13407 _OSKextInUnloadedPrelinkedKexts( const OSSymbol
* theBundleID
)
13409 int unLoadedCount
, i
;
13410 bool result
= false;
13412 IORecursiveLockLock(sKextLock
);
13414 if (sUnloadedPrelinkedKexts
== NULL
) {
13417 unLoadedCount
= sUnloadedPrelinkedKexts
->getCount();
13418 if (unLoadedCount
== 0) {
13422 for (i
= 0; i
< unLoadedCount
; i
++) {
13423 const OSSymbol
* myBundleID
; // do not release
13425 myBundleID
= OSDynamicCast(OSSymbol
, sUnloadedPrelinkedKexts
->getObject(i
));
13429 if (theBundleID
->isEqualTo(myBundleID
->getCStringNoCopy())) {
13435 IORecursiveLockUnlock(sKextLock
);
13440 #pragma mark Personalities (IOKit Drivers)
13442 /*********************************************************************
13443 *********************************************************************/
13445 OSSharedPtr
<OSArray
>
13446 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
13448 OSSharedPtr
<OSArray
> result
;
13449 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
13450 OSSharedPtr
<OSArray
> personalities
;
13452 OSString
* kextID
= NULL
; // do not release
13453 OSKext
* theKext
= NULL
; // do not release
13455 IORecursiveLockLock(sKextLock
);
13457 /* Let's conservatively guess that any given kext has around 3
13458 * personalities for now.
13460 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
13465 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
13466 if (!kextIterator
) {
13470 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
13471 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
13472 if (theKext
->flags
.requireExplicitLoad
) {
13474 kOSKextLogDebugLevel
|
13475 kOSKextLogLoadFlag
,
13476 "Kext %s requires an explicit kextload; "
13477 "omitting its personalities.",
13478 theKext
->getIdentifierCString());
13479 } else if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
13480 personalities
= theKext
->copyPersonalitiesArray();
13481 if (!personalities
) {
13484 result
->merge(personalities
.get());
13486 // xxx - check for better place to put this log msg
13488 kOSKextLogWarningLevel
|
13489 kOSKextLogLoadFlag
,
13490 "Kext %s is not loadable during safe boot; "
13491 "omitting its personalities.",
13492 theKext
->getIdentifierCString());
13497 IORecursiveLockUnlock(sKextLock
);
13502 /*********************************************************************
13503 *********************************************************************/
13506 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
13508 int numPersonalities
= 0;
13510 OSKextLog(/* kext */ NULL
,
13511 kOSKextLogStepLevel
|
13512 kOSKextLogLoadFlag
,
13513 "Sending all eligible registered kexts' personalities "
13514 "to the IOCatalogue %s.",
13515 startMatching
? "and starting matching" : "but not starting matching");
13517 OSSharedPtr
<OSArray
> personalities
= OSKext::copyAllKextPersonalities(
13518 /* filterSafeBootFlag */ true);
13520 if (personalities
) {
13521 gIOCatalogue
->addDrivers(personalities
.get(), startMatching
);
13522 numPersonalities
= personalities
->getCount();
13525 OSKextLog(/* kext */ NULL
,
13526 kOSKextLogStepLevel
|
13527 kOSKextLogLoadFlag
,
13528 "%d kext personalit%s sent to the IOCatalogue; %s.",
13529 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
13530 startMatching
? "matching started" : "matching not started");
13534 /*********************************************************************
13535 * Do not make a deep copy, just convert the IOKitPersonalities dict
13536 * to an array for sending to the IOCatalogue.
13537 *********************************************************************/
13538 OSSharedPtr
<OSArray
>
13539 OSKext::copyPersonalitiesArray(void)
13541 OSSharedPtr
<OSArray
> result
;
13542 OSDictionary
* personalities
= NULL
; // do not release
13543 OSSharedPtr
<OSCollectionIterator
> personalitiesIterator
;
13545 OSString
* personalityName
= NULL
; // do not release
13546 OSString
* personalityBundleIdentifier
= NULL
; // do not release
13548 personalities
= OSDynamicCast(OSDictionary
,
13549 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13550 if (!personalities
) {
13554 result
= OSArray::withCapacity(personalities
->getCount());
13559 personalitiesIterator
=
13560 OSCollectionIterator::withCollection(personalities
);
13561 if (!personalitiesIterator
) {
13564 while ((personalityName
= OSDynamicCast(OSString
,
13565 personalitiesIterator
->getNextObject()))) {
13566 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13567 personalities
->getObject(personalityName
));
13570 * If the personality doesn't have a CFBundleIdentifier, or if it
13571 * differs from the kext's, insert the kext's ID so we can find it.
13572 * The publisher ID is used to remove personalities from bundles
13575 personalityBundleIdentifier
= OSDynamicCast(OSString
,
13576 personality
->getObject(kCFBundleIdentifierKey
));
13578 if (!personalityBundleIdentifier
) {
13579 personality
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
13580 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
.get())) {
13581 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
.get());
13584 result
->setObject(personality
);
13591 /*********************************************************************
13592 * Might want to change this to a bool return?
13593 *********************************************************************/
13595 OSKext::sendPersonalitiesToCatalog(
13596 bool startMatching
,
13597 OSArray
* personalityNames
)
13599 OSReturn result
= kOSReturnSuccess
;
13600 OSSharedPtr
<OSArray
> personalitiesToSend
;
13601 OSDictionary
* kextPersonalities
= NULL
; // do not release
13604 if (!sLoadEnabled
) {
13606 kOSKextLogErrorLevel
|
13607 kOSKextLogLoadFlag
,
13608 "Kext loading is disabled (attempt to start matching for kext %s).",
13609 getIdentifierCString());
13610 result
= kOSKextReturnDisabled
;
13614 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
13616 kOSKextLogErrorLevel
|
13617 kOSKextLogLoadFlag
,
13618 "Kext %s is not loadable during safe boot; "
13619 "not sending personalities to the IOCatalogue.",
13620 getIdentifierCString());
13621 result
= kOSKextReturnNotLoadable
;
13625 if (!personalityNames
|| !personalityNames
->getCount()) {
13626 personalitiesToSend
= copyPersonalitiesArray();
13628 kextPersonalities
= OSDynamicCast(OSDictionary
,
13629 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13630 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
13634 personalitiesToSend
= OSArray::withCapacity(0);
13635 if (!personalitiesToSend
) {
13636 result
= kOSKextReturnNoMemory
;
13639 count
= personalityNames
->getCount();
13640 for (i
= 0; i
< count
; i
++) {
13641 OSString
* name
= OSDynamicCast(OSString
,
13642 personalityNames
->getObject(i
));
13646 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13647 kextPersonalities
->getObject(name
));
13649 personalitiesToSend
->setObject(personality
);
13653 if (personalitiesToSend
) {
13654 unsigned numPersonalities
= personalitiesToSend
->getCount();
13656 kOSKextLogStepLevel
|
13657 kOSKextLogLoadFlag
,
13658 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13659 getIdentifierCString(),
13661 numPersonalities
> 1 ? "ies" : "y",
13662 startMatching
? " and starting matching" : " but not starting matching");
13663 gIOCatalogue
->addDrivers(personalitiesToSend
.get(), startMatching
);
13669 /*********************************************************************
13670 * xxx - We should allow removing the kext's declared personalities,
13671 * xxx - even with other bundle identifiers.
13672 *********************************************************************/
13674 OSKext::removePersonalitiesFromCatalog(void)
13676 OSSharedPtr
<OSDictionary
> personality
;
13678 personality
= OSDictionary::withCapacity(1);
13679 if (!personality
) {
13682 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
13685 kOSKextLogStepLevel
|
13686 kOSKextLogLoadFlag
,
13687 "Kext %s removing all personalities naming it from the IOCatalogue.",
13688 getIdentifierCString());
13690 /* Have the IOCatalog remove all personalities matching this kext's
13691 * bundle ID and trigger matching anew.
13693 gIOCatalogue
->removeDrivers(personality
.get(), /* startMatching */ true);
13701 #pragma mark Logging
13703 /*********************************************************************
13704 * Do not call any function that takes sKextLock here!
13705 *********************************************************************/
13708 OSKext::setUserSpaceLogFilter(
13709 OSKextLogSpec newUserLogFilter
,
13712 OSKextLogSpec result
;
13713 bool allocError
= false;
13715 /* Do not call any function that takes sKextLoggingLock during
13716 * this critical block. That means do logging after.
13718 IOLockLock(sKextLoggingLock
);
13720 result
= sUserSpaceKextLogFilter
;
13721 sUserSpaceKextLogFilter
= newUserLogFilter
;
13723 if (newUserLogFilter
&& captureFlag
&&
13724 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
13725 // xxx - do some measurements for a good initial capacity?
13726 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
13727 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
13729 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
13734 IOLockUnlock(sKextLoggingLock
);
13736 /* If the config flag itself is changing, log the state change
13737 * going both ways, before setting up the user-space log arrays,
13738 * so that this is only logged in the kernel.
13740 if (result
!= newUserLogFilter
) {
13741 OSKextLog(/* kext */ NULL
,
13742 kOSKextLogDebugLevel
|
13743 kOSKextLogGeneralFlag
,
13744 "User-space log flags changed from 0x%x to 0x%x.",
13745 result
, newUserLogFilter
);
13748 OSKextLog(/* kext */ NULL
,
13749 kOSKextLogErrorLevel
|
13750 kOSKextLogGeneralFlag
,
13751 "Failed to allocate user-space log message arrays.");
13757 /*********************************************************************
13758 * Do not call any function that takes sKextLock here!
13759 *********************************************************************/
13761 OSSharedPtr
<OSArray
>
13762 OSKext::clearUserSpaceLogFilter(void)
13764 OSSharedPtr
<OSArray
> result
;
13765 OSKextLogSpec oldLogFilter
;
13766 OSKextLogSpec newLogFilter
= kOSKextLogSilentFilter
;
13768 /* Do not call any function that takes sKextLoggingLock during
13769 * this critical block. That means do logging after.
13771 IOLockLock(sKextLoggingLock
);
13773 result
= OSArray::withCapacity(2);
13775 result
->setObject(sUserSpaceLogSpecArray
.get());
13776 result
->setObject(sUserSpaceLogMessageArray
.get());
13778 sUserSpaceLogSpecArray
.reset();
13779 sUserSpaceLogMessageArray
.reset();
13781 oldLogFilter
= sUserSpaceKextLogFilter
;
13782 sUserSpaceKextLogFilter
= newLogFilter
;
13784 IOLockUnlock(sKextLoggingLock
);
13786 /* If the config flag itself is changing, log the state change
13787 * going both ways, after tearing down the user-space log
13788 * arrays, so this is only logged within the kernel.
13790 if (oldLogFilter
!= newLogFilter
) {
13791 OSKextLog(/* kext */ NULL
,
13792 kOSKextLogDebugLevel
|
13793 kOSKextLogGeneralFlag
,
13794 "User-space log flags changed from 0x%x to 0x%x.",
13795 oldLogFilter
, newLogFilter
);
13802 /*********************************************************************
13803 * Do not call any function that takes sKextLock here!
13804 *********************************************************************/
13807 OSKext::getUserSpaceLogFilter(void)
13809 OSKextLogSpec result
;
13811 IOLockLock(sKextLoggingLock
);
13812 result
= sUserSpaceKextLogFilter
;
13813 IOLockUnlock(sKextLoggingLock
);
13818 /*********************************************************************
13819 * This function is called by OSMetaClass during kernel C++ setup.
13820 * Be careful what you access here; assume only OSKext::initialize()
13823 * Do not call any function that takes sKextLock here!
13824 *********************************************************************/
13825 #define VTRESET "\033[0m"
13827 #define VTBOLD "\033[1m"
13828 #define VTUNDER "\033[4m"
13830 #define VTRED "\033[31m"
13831 #define VTGREEN "\033[32m"
13832 #define VTYELLOW "\033[33m"
13833 #define VTBLUE "\033[34m"
13834 #define VTMAGENTA "\033[35m"
13835 #define VTCYAN "\033[36m"
13837 inline const char *
13838 colorForFlags(OSKextLogSpec flags
)
13840 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
13842 switch (logLevel
) {
13843 case kOSKextLogErrorLevel
:
13844 return VTRED VTBOLD
;
13845 case kOSKextLogWarningLevel
:
13847 case kOSKextLogBasicLevel
:
13848 return VTYELLOW VTUNDER
;
13849 case kOSKextLogProgressLevel
:
13851 case kOSKextLogStepLevel
:
13853 case kOSKextLogDetailLevel
:
13855 case kOSKextLogDebugLevel
:
13858 return ""; // white
13864 OSKextLogSpec msgLogSpec
,
13865 OSKextLogSpec logFilter
)
13867 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
13868 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
13869 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
13871 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
13872 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
13873 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
13875 /* Explicit messages always get logged.
13877 if (msgLevel
== kOSKextLogExplicitLevel
) {
13881 /* Warnings and errors are logged regardless of the flags.
13883 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
13887 /* A verbose message that isn't for a logging-enabled kext and isn't global
13888 * does *not* get logged.
13890 if (!msgKextGlobal
&& !filterKextGlobal
) {
13894 /* Warnings and errors are logged regardless of the flags.
13895 * All other messages must fit the flags and
13896 * have a level at or below the filter.
13899 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
13909 OSKextLogSpec msgLogSpec
,
13910 const char * format
, ...)
13914 va_start(argList
, format
);
13915 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
13922 OSKextLogSpec msgLogSpec
,
13923 const char * format
,
13924 va_list srcArgList
)
13926 extern int disableConsoleOutput
;
13928 bool logForKernel
= false;
13929 bool logForUser
= false;
13931 char stackBuffer
[120];
13932 uint32_t length
= 0;
13933 char * allocBuffer
= NULL
; // must kfree
13934 OSSharedPtr
<OSNumber
> logSpecNum
;
13935 OSSharedPtr
<OSString
> logString
;
13936 char * buffer
= stackBuffer
; // do not free
13938 IOLockLock(sKextLoggingLock
);
13940 /* Set the kext/global bit in the message spec if we have no
13941 * kext or if the kext requests logging.
13943 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
13944 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
13947 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
13948 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
13949 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
13952 if (!(logForKernel
|| logForUser
)) {
13956 /* No goto from here until past va_end()!
13958 va_copy(argList
, srcArgList
);
13959 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
13962 if (length
+ 1 >= sizeof(stackBuffer
)) {
13963 allocBuffer
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
13964 length
+ 1, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
13965 if (!allocBuffer
) {
13969 /* No goto from here until past va_end()!
13971 va_copy(argList
, srcArgList
);
13972 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
13975 buffer
= allocBuffer
;
13978 /* If user space wants the log message, queue it up.
13980 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
13981 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
13982 logString
= OSString::withCString(buffer
);
13983 if (logSpecNum
&& logString
) {
13984 sUserSpaceLogSpecArray
->setObject(logSpecNum
.get());
13985 sUserSpaceLogMessageArray
->setObject(logString
.get());
13989 /* Always log messages from the kernel according to the kernel's
13992 if (logForKernel
) {
13993 /* If we are in console mode and have a custom log filter,
13994 * colorize the log message.
13996 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
13997 const char * color
= ""; // do not free
13998 color
= colorForFlags(msgLogSpec
);
13999 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
14000 buffer
, color
[0] ? VTRESET
: "");
14002 printf("%s\n", buffer
);
14007 IOLockUnlock(sKextLoggingLock
);
14010 kheap_free(KHEAP_TEMP
, allocBuffer
, (length
+ 1) * sizeof(char));
14015 #if KASLR_IOREG_DEBUG
14017 #define IOLOG_INDENT( the_indention ) \
14020 for ( i = 0; i < (the_indention); i++ ) { \
14025 extern vm_offset_t vm_kernel_stext
;
14026 extern vm_offset_t vm_kernel_etext
;
14027 extern mach_vm_offset_t kext_alloc_base
;
14028 extern mach_vm_offset_t kext_alloc_max
;
14030 bool ScanForAddrInObject(OSObject
* theObject
,
14034 ScanForAddrInObject(OSObject
* theObject
,
14037 const OSMetaClass
* myTypeID
;
14038 OSSharedPtr
<OSCollectionIterator
> myIter
;
14040 OSObject
* myValue
;
14041 bool myResult
= false;
14043 if (theObject
== NULL
) {
14044 IOLog("%s: theObject is NULL \n",
14049 myTypeID
= OSTypeIDInst(theObject
);
14051 if (myTypeID
== OSTypeID(OSDictionary
)) {
14052 OSDictionary
* myDictionary
;
14054 myDictionary
= OSDynamicCast(OSDictionary
, theObject
);
14055 myIter
= OSCollectionIterator::withCollection( myDictionary
);
14056 if (myIter
== NULL
) {
14060 // !! reset the iterator
14063 while ((myKey
= OSDynamicCast(OSSymbol
, myIter
->getNextObject()))) {
14066 myValue
= myDictionary
->getObject(myKey
);
14067 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14068 if (myTempResult
) {
14069 // if we ever get a true result return true
14071 IOLOG_INDENT(indent
);
14072 IOLog("OSDictionary key \"%s\" \n", myKey
->getCStringNoCopy());
14076 // !! release the iterator
14078 } else if (myTypeID
== OSTypeID(OSArray
)) {
14081 myArray
= OSDynamicCast(OSArray
, theObject
);
14082 myIter
= OSCollectionIterator::withCollection(myArray
);
14083 if (myIter
== NULL
) {
14086 // !! reset the iterator
14089 while ((myValue
= myIter
->getNextObject())) {
14091 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14092 if (myTempResult
) {
14093 // if we ever get a true result return true
14095 IOLOG_INDENT(indent
);
14096 IOLog("OSArray: \n");
14099 // !! release the iterator
14101 } else if (myTypeID
== OSTypeID(OSString
) || myTypeID
== OSTypeID(OSSymbol
)) {
14102 // should we look for addresses in strings?
14103 } else if (myTypeID
== OSTypeID(OSData
)) {
14105 unsigned int myLen
;
14106 OSData
* myDataObj
;
14108 myDataObj
= OSDynamicCast(OSData
, theObject
);
14109 myPtrPtr
= (void * *) myDataObj
->getBytesNoCopy();
14110 myLen
= myDataObj
->getLength();
14112 if (myPtrPtr
&& myLen
&& myLen
> 7) {
14114 int myPtrCount
= (myLen
/ sizeof(void *));
14116 for (i
= 0; i
< myPtrCount
; i
++) {
14117 UInt64 numberValue
= (UInt64
) * (myPtrPtr
);
14119 if (kext_alloc_max
!= 0 &&
14120 numberValue
>= kext_alloc_base
&&
14121 numberValue
< kext_alloc_max
) {
14122 OSSharedPtr
<OSKext
> myKext
;
14123 // IOLog("found OSData %p in kext map %p to %p \n",
14125 // (void *) kext_alloc_base,
14126 // (void *) kext_alloc_max);
14128 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) *(myPtrPtr
));
14130 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14132 myKext
->getIdentifierCString());
14136 if (vm_kernel_etext
!= 0 &&
14137 numberValue
>= vm_kernel_stext
&&
14138 numberValue
< vm_kernel_etext
) {
14139 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14141 (void *) vm_kernel_stext
,
14142 (void *) vm_kernel_etext
);
14148 } else if (myTypeID
== OSTypeID(OSBoolean
)) {
14149 // do nothing here...
14150 } else if (myTypeID
== OSTypeID(OSNumber
)) {
14151 OSNumber
* number
= OSDynamicCast(OSNumber
, theObject
);
14153 UInt64 numberValue
= number
->unsigned64BitValue();
14155 if (kext_alloc_max
!= 0 &&
14156 numberValue
>= kext_alloc_base
&&
14157 numberValue
< kext_alloc_max
) {
14158 OSSharedPtr
<OSKext
> myKext
;
14159 IOLog("found OSNumber in kext map %p to %p \n",
14160 (void *) kext_alloc_base
,
14161 (void *) kext_alloc_max
);
14162 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14164 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) numberValue
);
14166 IOLog("found in kext \"%s\" \n",
14167 myKext
->getIdentifierCString());
14172 if (vm_kernel_etext
!= 0 &&
14173 numberValue
>= vm_kernel_stext
&&
14174 numberValue
< vm_kernel_etext
) {
14175 IOLog("found OSNumber in kernel text segment %p to %p \n",
14176 (void *) vm_kernel_stext
,
14177 (void *) vm_kernel_etext
);
14178 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14184 const OSMetaClass
* myMetaClass
= NULL
;
14186 myMetaClass
= theObject
->getMetaClass();
14188 IOLog("class %s \n", myMetaClass
->getClassName());
14190 IOLog("Unknown object \n" );
14197 #endif // KASLR_KEXT_DEBUG
14198 }; /* extern "C" */
14201 #pragma mark Backtrace Dump & kmod_get_info() support
14203 /*********************************************************************
14204 * This function must be safe to call in panic context.
14205 *********************************************************************/
14208 OSKext::printKextsInBacktrace(
14209 vm_offset_t
* addr __unused
,
14210 unsigned int cnt __unused
,
14211 int (* printf_func
)(const char *fmt
, ...) __unused
,
14212 uint32_t flags __unused
)
14214 addr64_t summary_page
= 0;
14215 addr64_t last_summary_page
= 0;
14216 bool found_kmod
= false;
14219 if (kPrintKextsLock
& flags
) {
14220 if (!sKextSummariesLock
) {
14223 IOLockLock(sKextSummariesLock
);
14226 if (!gLoadedKextSummaries
) {
14227 (*printf_func
)(" can't perform kext scan: no kext summary");
14231 summary_page
= trunc_page((addr64_t
)(uintptr_t)gLoadedKextSummaries
);
14232 last_summary_page
= round_page(summary_page
+ sLoadedKextSummariesAllocSize
);
14233 for (; summary_page
< last_summary_page
; summary_page
+= PAGE_SIZE
) {
14234 if (pmap_find_phys(kernel_pmap
, summary_page
) == 0) {
14235 (*printf_func
)(" can't perform kext scan: "
14236 "missing kext summary page %p", summary_page
);
14241 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14242 OSKextLoadedKextSummary
* summary
;
14244 summary
= gLoadedKextSummaries
->summaries
+ i
;
14245 if (!summary
->address
) {
14249 if (!summaryIsInBacktrace(summary
, addr
, cnt
)) {
14254 if (!(kPrintKextsTerse
& flags
)) {
14255 (*printf_func
)(" Kernel Extensions in backtrace:\n");
14260 printSummary(summary
, printf_func
, flags
);
14264 if (kPrintKextsLock
& flags
) {
14265 IOLockUnlock(sKextSummariesLock
);
14271 /*********************************************************************
14272 * This function must be safe to call in panic context.
14273 *********************************************************************/
14276 OSKext::summaryIsInBacktrace(
14277 OSKextLoadedKextSummary
* summary
,
14278 vm_offset_t
* addr
,
14283 for (i
= 0; i
< cnt
; i
++) {
14284 vm_offset_t kscan_addr
= addr
[i
];
14285 #if __has_feature(ptrauth_calls)
14286 kscan_addr
= (vm_offset_t
)VM_KERNEL_STRIP_PTR(kscan_addr
);
14287 #endif /* __has_feature(ptrauth_calls) */
14288 if ((kscan_addr
>= summary
->text_exec_address
) &&
14289 (kscan_addr
< (summary
->text_exec_address
+ summary
->text_exec_size
))) {
14298 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14299 * sKextSummariesLock held.
14301 OSKextLoadedKextSummary
*
14302 OSKext::summaryForAddress(uintptr_t addr
)
14304 #if __has_feature(ptrauth_calls)
14305 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14306 #endif /* __has_feature(ptrauth_calls) */
14307 for (unsigned i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14308 OSKextLoadedKextSummary
*summary
= &gLoadedKextSummaries
->summaries
[i
];
14309 if (!summary
->address
) {
14313 #if VM_MAPPED_KEXTS
14314 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14315 * support split kexts, but we also may unmap the kexts, which can
14316 * race with the above codepath (see OSKext::unload). As such,
14317 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14319 if ((addr
>= summary
->address
) && (addr
< (summary
->address
+ summary
->size
))) {
14323 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)summary
->address
;
14324 kernel_segment_command_t
*seg
;
14326 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
14327 if ((addr
>= seg
->vmaddr
) && (addr
< (seg
->vmaddr
+ seg
->vmsize
))) {
14334 /* addr did not map to any kext */
14340 OSKext::kextForAddress(const void *address
)
14342 void * image
= NULL
;
14343 OSKextActiveAccount
* active
;
14344 OSKext
* kext
= NULL
;
14347 uintptr_t addr
= (uintptr_t) address
;
14353 #if __has_feature(ptrauth_calls)
14354 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14355 #endif /* __has_feature(ptrauth_calls) */
14357 if (sKextAccountsCount
) {
14358 IOSimpleLockLock(sKextAccountsLock
);
14359 // bsearch sKextAccounts list
14360 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
14361 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
14362 if ((addr
>= active
->address
) && (addr
< active
->address_end
)) {
14363 kext
= active
->account
->kext
;
14364 if (kext
&& kext
->kmod_info
) {
14365 image
= (void *) kext
->kmod_info
->address
;
14368 } else if (addr
> active
->address
) {
14370 baseIdx
+= (lim
>> 1) + 1;
14375 IOSimpleLockUnlock(sKextAccountsLock
);
14377 if (!image
&& (addr
>= vm_kernel_stext
) && (addr
< vm_kernel_etext
)) {
14378 image
= (void *) &_mh_execute_header
;
14380 if (!image
&& gLoadedKextSummaries
) {
14381 IOLockLock(sKextSummariesLock
);
14382 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; i
++) {
14383 OSKextLoadedKextSummary
*summary
= gLoadedKextSummaries
->summaries
+ i
;
14384 if (addr
>= summary
->address
&& addr
< summary
->address
+ summary
->size
) {
14385 image
= (void *)summary
->address
;
14388 IOLockUnlock(sKextSummariesLock
);
14395 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14396 * Safe to call in panic context.
14398 static OSKextLoadedKextSummary
*
14399 findSummary(uint32_t tagID
)
14401 OSKextLoadedKextSummary
* summary
;
14402 for (size_t i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14403 summary
= gLoadedKextSummaries
->summaries
+ i
;
14404 if (summary
->loadTag
== tagID
) {
14411 /*********************************************************************
14412 * This function must be safe to call in panic context.
14413 *********************************************************************/
14415 OSKext::printSummary(
14416 OSKextLoadedKextSummary
* summary
,
14417 int (* printf_func
)(const char *fmt
, ...),
14420 kmod_reference_t
* kmod_ref
= NULL
;
14421 uuid_string_t uuid
;
14422 char version
[kOSKextVersionMaxLength
];
14425 OSKextLoadedKextSummary
*dependencySummary
;
14427 if (!OSKextVersionGetString(summary
->version
, version
, sizeof(version
))) {
14428 strlcpy(version
, "unknown version", sizeof(version
));
14430 (void) uuid_unparse(summary
->uuid
, uuid
);
14432 #if defined(__arm__) || defined(__arm64__)
14433 tmpAddr
= summary
->text_exec_address
;
14434 tmpSize
= summary
->text_exec_size
;
14436 tmpAddr
= summary
->address
;
14437 tmpSize
= summary
->size
;
14439 if (kPrintKextsUnslide
& flags
) {
14440 tmpAddr
= ml_static_unslide(tmpAddr
);
14442 (*printf_func
)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14443 (kPrintKextsTerse
& flags
) ? "" : " ",
14444 summary
->name
, version
, uuid
,
14445 tmpAddr
, tmpAddr
+ tmpSize
- 1);
14447 if (kPrintKextsTerse
& flags
) {
14451 /* print dependency info */
14452 for (kmod_ref
= (kmod_reference_t
*) summary
->reference_list
;
14454 kmod_ref
= kmod_ref
->next
) {
14455 kmod_info_t
* rinfo
;
14457 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_ref
)) == 0) {
14458 (*printf_func
)(" kmod dependency scan stopped "
14459 "due to missing dependency page: %p\n",
14460 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)kmod_ref
) : kmod_ref
);
14463 rinfo
= kmod_ref
->info
;
14465 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
14466 (*printf_func
)(" kmod dependency scan stopped "
14467 "due to missing kmod page: %p\n",
14468 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)rinfo
) : rinfo
);
14472 if (!rinfo
->address
) {
14473 continue; // skip fake entries for built-ins
14476 dependencySummary
= findSummary(rinfo
->id
);
14478 tmpAddr
= rinfo
->address
;
14479 tmpSize
= rinfo
->size
;
14480 if (dependencySummary
) {
14481 (void) uuid_unparse(dependencySummary
->uuid
, uuid
);
14482 #if defined(__arm__) || defined(__arm64__)
14483 tmpAddr
= dependencySummary
->text_exec_address
;
14484 tmpSize
= dependencySummary
->text_exec_size
;
14488 if (kPrintKextsUnslide
& flags
) {
14489 tmpAddr
= ml_static_unslide(tmpAddr
);
14491 (*printf_func
)(" dependency: %s(%s)[%s]@%p->%p\n",
14492 rinfo
->name
, rinfo
->version
, uuid
, tmpAddr
, tmpAddr
+ tmpSize
- 1);
14498 #if !defined(__arm__) && !defined(__arm64__)
14499 /*******************************************************************************
14500 * substitute() looks at an input string (a pointer within a larger buffer)
14501 * for a match to a substring, and on match it writes the marker & substitution
14502 * character to an output string, updating the scan (from) and
14503 * output (to) indexes as appropriate.
14504 *******************************************************************************/
14505 static int substitute(
14506 const char * scan_string
,
14508 uint32_t * to_index
,
14509 uint32_t * from_index
,
14510 const char * substring
,
14512 char substitution
);
14514 /* string_out must be at least KMOD_MAX_NAME bytes.
14518 const char * scan_string
,
14520 uint32_t * to_index
,
14521 uint32_t * from_index
,
14522 const char * substring
,
14526 size_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
14528 /* On a substring match, append the marker (if there is one) and then
14529 * the substitution character, updating the output (to) index accordingly.
14530 * Then update the input (from) length by the length of the substring
14531 * that got replaced.
14533 if (!strncmp(scan_string
, substring
, substring_length
)) {
14535 string_out
[(*to_index
)++] = marker
;
14537 string_out
[(*to_index
)++] = substitution
;
14538 (*from_index
) += substring_length
;
14544 /*******************************************************************************
14545 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14546 * KMOD_MAX_NAME characters and performs various substitutions of common
14547 * prefixes & substrings as defined by tables in kext_panic_report.h.
14548 *******************************************************************************/
14549 static void compactIdentifier(
14550 const char * identifier
,
14551 char * identifier_out
,
14552 char ** identifier_out_end
);
14556 const char * identifier
,
14557 char * identifier_out
,
14558 char ** identifier_out_end
)
14560 uint32_t from_index
, to_index
;
14561 uint32_t scan_from_index
= 0;
14562 uint32_t scan_to_index
= 0;
14563 subs_entry_t
* subs_entry
= NULL
;
14566 from_index
= to_index
= 0;
14567 identifier_out
[0] = '\0';
14569 /* Replace certain identifier prefixes with shorter @+character sequences.
14570 * Check the return value of substitute() so we only replace the prefix.
14572 for (subs_entry
= &kext_identifier_prefix_subs
[0];
14573 subs_entry
->substring
&& !did_sub
;
14575 did_sub
= substitute(identifier
, identifier_out
,
14576 &scan_to_index
, &scan_from_index
,
14577 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
14581 /* Now scan through the identifier looking for the common substrings
14582 * and replacing them with shorter !+character sequences via substitute().
14584 for (/* see above */;
14585 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
14587 const char * scan_string
= &identifier
[scan_from_index
];
14591 if (scan_from_index
) {
14592 for (subs_entry
= &kext_identifier_substring_subs
[0];
14593 subs_entry
->substring
&& !did_sub
;
14595 did_sub
= substitute(scan_string
, identifier_out
,
14596 &scan_to_index
, &scan_from_index
,
14597 subs_entry
->substring
, '!', subs_entry
->substitute
);
14601 /* If we didn't substitute, copy the input character to the output.
14604 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
14608 identifier_out
[scan_to_index
] = '\0';
14609 if (identifier_out_end
) {
14610 *identifier_out_end
= &identifier_out
[scan_to_index
];
14615 #endif /* !defined(__arm__) && !defined(__arm64__) */
14617 /*******************************************************************************
14618 * assemble_identifier_and_version() adds to a string buffer a compacted
14619 * bundle identifier followed by a version string.
14620 *******************************************************************************/
14622 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14624 static size_t assemble_identifier_and_version(
14625 kmod_info_t
* kmod_info
,
14626 char * identPlusVers
,
14630 assemble_identifier_and_version(
14631 kmod_info_t
* kmod_info
,
14632 char * identPlusVers
,
14637 #if defined(__arm__) || defined(__arm64__)
14638 result
= strlcpy(identPlusVers
, kmod_info
->name
, KMOD_MAX_NAME
);
14640 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
14641 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
14643 identPlusVers
[result
++] = '\t'; // increment for real char
14644 identPlusVers
[result
] = '\0'; // don't increment for nul char
14645 result
= strlcat(identPlusVers
, kmod_info
->version
, bufSize
);
14646 if (result
>= bufSize
) {
14647 identPlusVers
[bufSize
- 1] = '\0';
14648 result
= bufSize
- 1;
14654 /*******************************************************************************
14655 * Assumes sKextLock is held.
14656 *******************************************************************************/
14659 OSKext::saveLoadedKextPanicListTyped(
14660 const char * prefix
,
14664 uint32_t list_size
)
14667 unsigned int count
, i
;
14669 count
= sLoadedKexts
->getCount();
14676 OSObject
* rawKext
= sLoadedKexts
->getObject(i
);
14677 OSKext
* theKext
= OSDynamicCast(OSKext
, rawKext
);
14679 size_t identPlusVersLength
;
14681 char identPlusVers
[2 * KMOD_MAX_NAME
];
14684 printf("OSKext::saveLoadedKextPanicListTyped - "
14685 "NULL kext in loaded kext list; continuing\n");
14690 printf("OSKext::saveLoadedKextPanicListTyped - "
14691 "Kext type cast failed in loaded kext list; continuing\n");
14695 /* Skip all built-in kexts.
14697 if (theKext
->isKernelComponent()) {
14701 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
14703 /* Filter for kmod name (bundle identifier).
14705 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
14706 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
14710 /* Filter for libraries (kexts that have a compatible version).
14712 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
14713 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
14718 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
14719 printf("kext scan stopped due to missing kmod_info page: %p\n",
14724 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
14726 sizeof(identPlusVers
));
14727 if (!identPlusVersLength
) {
14728 printf("error saving loaded kext info\n");
14732 /* make sure everything fits and we null terminate.
14734 tempLen
= strlcat(paniclist
, identPlusVers
, list_size
);
14735 if (tempLen
>= list_size
) {
14736 // panic list is full, keep it and null terminate
14737 paniclist
[list_size
- 1] = 0x00;
14741 tempLen
= strlcat(paniclist
, "\n", list_size
);
14742 if (tempLen
>= list_size
) {
14743 // panic list is full, keep it and null terminate
14744 paniclist
[list_size
- 1] = 0x00;
14756 /*********************************************************************
14757 *********************************************************************/
14760 OSKext::saveLoadedKextPanicList(void)
14762 char * newlist
= NULL
;
14763 uint32_t newlist_size
= 0;
14765 newlist_size
= KEXT_PANICLIST_SIZE
;
14766 newlist
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, newlist_size
,
14767 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
14770 OSKextLog(/* kext */ NULL
,
14771 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
14772 "Couldn't allocate kext panic log buffer.");
14778 // non-"com.apple." kexts
14779 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14780 /* libs? */ -1, newlist
, newlist_size
) != 0) {
14783 // "com.apple." nonlibrary kexts
14784 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14785 /* libs? */ 0, newlist
, newlist_size
) != 0) {
14788 // "com.apple." library kexts
14789 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14790 /* libs? */ 1, newlist
, newlist_size
) != 0) {
14794 if (loaded_kext_paniclist
) {
14795 kheap_free(KHEAP_DATA_BUFFERS
, loaded_kext_paniclist
,
14796 loaded_kext_paniclist_size
);
14798 loaded_kext_paniclist
= newlist
;
14800 loaded_kext_paniclist_size
= newlist_size
;
14804 kheap_free(KHEAP_TEMP
, newlist
, newlist_size
);
14809 /*********************************************************************
14810 * Assumes sKextLock is held.
14811 *********************************************************************/
14813 OSKext::savePanicString(bool isLoading
)
14818 return; // do not goto finish here b/c of lock
14821 len
= assemble_identifier_and_version( kmod_info
,
14822 (isLoading
) ? last_loaded_str_buf
: last_unloaded_str_buf
,
14823 (isLoading
) ? sizeof(last_loaded_str_buf
) : sizeof(last_unloaded_str_buf
));
14825 printf("error saving unloaded kext info\n");
14830 last_loaded_strlen
= len
;
14831 last_loaded_address
= (void *)kmod_info
->address
;
14832 last_loaded_size
= kmod_info
->size
;
14833 clock_get_uptime(&last_loaded_timestamp
);
14835 last_unloaded_strlen
= len
;
14836 last_unloaded_address
= (void *)kmod_info
->address
;
14837 last_unloaded_size
= kmod_info
->size
;
14838 clock_get_uptime(&last_unloaded_timestamp
);
14845 /*********************************************************************
14846 *********************************************************************/
14849 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
14851 if (last_loaded_strlen
) {
14852 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14853 AbsoluteTime_to_scalar(&last_loaded_timestamp
),
14854 last_loaded_strlen
, last_loaded_str_buf
,
14855 last_loaded_address
, last_loaded_size
);
14858 if (last_unloaded_strlen
) {
14859 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14860 AbsoluteTime_to_scalar(&last_unloaded_timestamp
),
14861 last_unloaded_strlen
, last_unloaded_str_buf
,
14862 last_unloaded_address
, last_unloaded_size
);
14865 printf_func("loaded kexts:\n");
14866 if (loaded_kext_paniclist
&&
14867 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
14868 loaded_kext_paniclist
[0]) {
14869 printf_func("%.*s",
14870 strnlen(loaded_kext_paniclist
, loaded_kext_paniclist_size
),
14871 loaded_kext_paniclist
);
14873 printf_func("(none)\n");
14878 /*********************************************************************
14879 * Assumes sKextLock is held.
14880 *********************************************************************/
14883 OSKext::updateLoadedKextSummaries(void)
14885 kern_return_t result
= KERN_FAILURE
;
14886 OSKextLoadedKextSummaryHeader
*summaryHeader
= NULL
;
14887 OSKextLoadedKextSummaryHeader
*summaryHeaderAlloc
= NULL
;
14889 vm_map_offset_t start
, end
;
14890 size_t summarySize
= 0;
14895 OSKextActiveAccount
* accountingList
;
14896 OSKextActiveAccount
* prevAccountingList
;
14897 uint32_t idx
, accountingListAlloc
, accountingListCount
, prevAccountingListCount
;
14899 prevAccountingList
= NULL
;
14900 prevAccountingListCount
= 0;
14902 #if DEVELOPMENT || DEBUG
14903 if (IORecursiveLockHaveLock(sKextLock
) == false) {
14904 panic("sKextLock must be held");
14908 IOLockLock(sKextSummariesLock
);
14910 count
= sLoadedKexts
->getCount();
14911 for (i
= 0, maxKexts
= 0; i
< count
; ++i
) {
14912 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14913 maxKexts
+= (aKext
&& aKext
->isExecutable());
14919 if (maxKexts
< kOSKextTypicalLoadCount
) {
14920 maxKexts
= kOSKextTypicalLoadCount
;
14923 /* Calculate the size needed for the new summary headers.
14926 size
= sizeof(*gLoadedKextSummaries
);
14927 size
+= maxKexts
* sizeof(*gLoadedKextSummaries
->summaries
);
14928 size
= round_page(size
);
14930 if (gLoadedKextSummaries
== NULL
|| sLoadedKextSummariesAllocSize
< size
) {
14931 if (gLoadedKextSummaries
) {
14932 kmem_free(kernel_map
, (vm_offset_t
)gLoadedKextSummaries
, sLoadedKextSummariesAllocSize
);
14933 gLoadedKextSummaries
= NULL
;
14934 gLoadedKextSummariesTimestamp
= mach_absolute_time();
14935 sLoadedKextSummariesAllocSize
= 0;
14937 result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&summaryHeaderAlloc
, size
, VM_KERN_MEMORY_OSKEXT
);
14938 if (result
!= KERN_SUCCESS
) {
14941 summaryHeader
= summaryHeaderAlloc
;
14942 summarySize
= size
;
14944 summaryHeader
= gLoadedKextSummaries
;
14945 summarySize
= sLoadedKextSummariesAllocSize
;
14947 start
= (vm_map_offset_t
) summaryHeader
;
14948 end
= start
+ summarySize
;
14949 result
= vm_map_protect(kernel_map
,
14954 if (result
!= KERN_SUCCESS
) {
14959 /* Populate the summary header.
14962 bzero(summaryHeader
, summarySize
);
14963 summaryHeader
->version
= kOSKextLoadedKextSummaryVersion
;
14964 summaryHeader
->entry_size
= sizeof(OSKextLoadedKextSummary
);
14966 /* Populate each kext summary.
14969 count
= sLoadedKexts
->getCount();
14970 accountingListAlloc
= 0;
14971 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
14972 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14973 if (!aKext
|| !aKext
->isExecutable()) {
14977 aKext
->updateLoadedKextSummary(&summaryHeader
->summaries
[j
++]);
14978 summaryHeader
->numSummaries
++;
14979 accountingListAlloc
++;
14982 accountingList
= IONew(typeof(accountingList
[0]), accountingListAlloc
);
14983 accountingListCount
= 0;
14984 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
14985 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14986 if (!aKext
|| !aKext
->isExecutable()) {
14990 OSKextActiveAccount activeAccount
;
14991 aKext
->updateActiveAccount(&activeAccount
);
14992 // order by address
14993 for (idx
= 0; idx
< accountingListCount
; idx
++) {
14994 if (activeAccount
.address
< accountingList
[idx
].address
) {
14998 bcopy(&accountingList
[idx
], &accountingList
[idx
+ 1], (accountingListCount
- idx
) * sizeof(accountingList
[0]));
14999 accountingList
[idx
] = activeAccount
;
15000 accountingListCount
++;
15002 assert(accountingListCount
== accountingListAlloc
);
15003 /* Write protect the buffer and move it into place.
15006 start
= (vm_map_offset_t
) summaryHeader
;
15007 end
= start
+ summarySize
;
15009 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_READ
, FALSE
);
15010 if (result
!= KERN_SUCCESS
) {
15014 gLoadedKextSummaries
= summaryHeader
;
15015 gLoadedKextSummariesTimestamp
= mach_absolute_time();
15016 sLoadedKextSummariesAllocSize
= summarySize
;
15017 summaryHeaderAlloc
= NULL
;
15019 /* Call the magic breakpoint function through a static function pointer so
15020 * the compiler can't optimize the function away.
15022 if (sLoadedKextSummariesUpdated
) {
15023 (*sLoadedKextSummariesUpdated
)();
15026 IOSimpleLockLock(sKextAccountsLock
);
15027 prevAccountingList
= sKextAccounts
;
15028 prevAccountingListCount
= sKextAccountsCount
;
15029 sKextAccounts
= accountingList
;
15030 sKextAccountsCount
= accountingListCount
;
15031 IOSimpleLockUnlock(sKextAccountsLock
);
15034 IOLockUnlock(sKextSummariesLock
);
15036 /* If we had to allocate a new buffer but failed to generate the summaries,
15039 if (summaryHeaderAlloc
) {
15040 kmem_free(kernel_map
, (vm_offset_t
)summaryHeaderAlloc
, summarySize
);
15042 if (prevAccountingList
) {
15043 IODelete(prevAccountingList
, typeof(accountingList
[0]), prevAccountingListCount
);
15049 /*********************************************************************
15050 *********************************************************************/
15052 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary
*summary
)
15054 OSSharedPtr
<OSData
> uuid
;
15056 strlcpy(summary
->name
, getIdentifierCString(),
15057 sizeof(summary
->name
));
15061 memcpy(summary
->uuid
, uuid
->getBytesNoCopy(), sizeof(summary
->uuid
));
15064 if (flags
.builtin
) {
15065 // this value will stop lldb from parsing the mach-o header
15066 // summary->address = UINT64_MAX;
15067 // summary->size = 0;
15068 summary
->address
= kmod_info
->address
;
15069 summary
->size
= kmod_info
->size
;
15071 summary
->address
= kmod_info
->address
;
15072 summary
->size
= kmod_info
->size
;
15074 summary
->version
= getVersion();
15075 summary
->loadTag
= kmod_info
->id
;
15076 summary
->flags
= 0;
15077 summary
->reference_list
= (uint64_t) kmod_info
->reference_list
;
15079 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT_EXEC", &summary
->text_exec_size
);
15080 if (summary
->text_exec_address
== 0) {
15081 // Fallback to __TEXT
15082 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT", &summary
->text_exec_size
);
15087 /*********************************************************************
15088 *********************************************************************/
15091 OSKext::updateActiveAccount(OSKextActiveAccount
*accountp
)
15093 kernel_mach_header_t
*hdr
= NULL
;
15094 kernel_segment_command_t
*seg
= NULL
;
15096 bzero(accountp
, sizeof(*accountp
));
15098 hdr
= (kernel_mach_header_t
*)kmod_info
->address
;
15099 if (getcommandfromheader(hdr
, LC_SEGMENT_SPLIT_INFO
) || isInFileset()) {
15101 * If this kext supports split segments (or is in a new
15102 * MH_FILESET kext collection), use the first
15103 * executable segment as the range for instructions
15104 * (and thus for backtracing.
15106 for (seg
= firstsegfromheader(hdr
); seg
!= NULL
; seg
= nextsegfromheader(hdr
, seg
)) {
15107 if (seg
->initprot
& VM_PROT_EXECUTE
) {
15113 accountp
->address
= seg
->vmaddr
;
15114 if (accountp
->address
) {
15115 accountp
->address_end
= seg
->vmaddr
+ seg
->vmsize
;
15118 /* For non-split kexts and for kexts without executable
15119 * segments, just use the kmod_info range (as the kext
15120 * is either all in one range or should not show up in
15121 * instruction backtraces).
15123 accountp
->address
= kmod_info
->address
;
15124 if (accountp
->address
) {
15125 accountp
->address_end
= kmod_info
->address
+ kmod_info
->size
;
15129 accountp
->account
= this->account
;
15133 OSKext::isDriverKit(void)
15135 OSString
*bundleType
;
15138 bundleType
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
));
15139 if (bundleType
&& bundleType
->isEqualTo(kOSKextBundlePackageTypeDriverKit
)) {
15147 OSKext::isInFileset(void)
15150 goto check_prelinked
;
15153 if (kmod_info
->address
&& kernel_mach_header_is_in_fileset((kernel_mach_header_t
*)kmod_info
->address
)) {
15158 if (isPrelinked()) {
15160 * If we haven't setup kmod_info yet, but we know
15161 * we're loading a prelinked kext in an MH_FILESET KC,
15164 kc_format_t kc_format
;
15165 if (PE_get_primary_kc_format(&kc_format
) && kc_format
== KCFormatFileset
) {
15173 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t
*seg
)
15175 kern_return_t result
;
15176 if (!super::init()) {
15179 if (seg
== nullptr) {
15182 result
= kmem_alloc_pageable(kernel_map
, (vm_offset_t
*)&data
, seg
->vmsize
, VM_KERN_MEMORY_KEXT
);
15183 if (result
!= KERN_SUCCESS
) {
15186 memcpy((void *)data
, (const void *)seg
->vmaddr
, seg
->vmsize
);
15187 savedSegment
= seg
;
15188 vmsize
= seg
->vmsize
;
15189 vmaddr
= seg
->vmaddr
;
15193 OSSharedPtr
<OSKextSavedMutableSegment
>
15194 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t
*seg
)
15196 OSSharedPtr
<OSKextSavedMutableSegment
> me
= OSMakeShared
<OSKextSavedMutableSegment
>();
15197 if (me
&& !me
->initWithSegment(seg
)) {
15204 OSKextSavedMutableSegment::free(void)
15207 kmem_free(kernel_map
, (vm_offset_t
)data
, vmsize
);
15212 OSKextSavedMutableSegment::getVMAddr() const
15218 OSKextSavedMutableSegment::getVMSize() const
15224 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t
*seg
)
15226 if (seg
!= savedSegment
) {
15227 return kOSKextReturnInvalidArgument
;
15229 if (seg
->vmaddr
!= vmaddr
|| seg
->vmsize
!= vmsize
) {
15230 return kOSKextReturnInvalidArgument
;
15232 memcpy((void *)seg
->vmaddr
, data
, vmsize
);
15233 return kOSReturnSuccess
;
15236 extern "C" const vm_allocation_site_t
*
15237 OSKextGetAllocationSiteForCaller(uintptr_t address
)
15239 OSKextActiveAccount
* active
;
15240 vm_allocation_site_t
* site
;
15241 vm_allocation_site_t
* releasesite
;
15245 #if __has_feature(ptrauth_calls)
15246 address
= (uintptr_t)VM_KERNEL_STRIP_PTR(address
);
15247 #endif /* __has_feature(ptrauth_calls) */
15249 IOSimpleLockLock(sKextAccountsLock
);
15250 site
= releasesite
= NULL
;
15252 // bsearch sKextAccounts list
15253 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
15254 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
15255 if ((address
>= active
->address
) && (address
< active
->address_end
)) {
15256 site
= &active
->account
->site
;
15258 vm_tag_alloc_locked(site
, &releasesite
);
15261 } else if (address
> active
->address
) {
15263 baseIdx
+= (lim
>> 1) + 1;
15268 IOSimpleLockUnlock(sKextAccountsLock
);
15270 kern_allocation_name_release(releasesite
);
15276 extern "C" uint32_t
15277 OSKextGetKmodIDForSite(const vm_allocation_site_t
* site
, char * name
, vm_size_t namelen
)
15279 OSKextAccount
* account
= (typeof(account
))site
;
15280 const char * kname
;
15283 if (account
->kext
) {
15284 kname
= account
->kext
->getIdentifierCString();
15288 strlcpy(name
, kname
, namelen
);
15291 return account
->loadTag
;
15295 OSKextFreeSite(vm_allocation_site_t
* site
)
15297 OSKextAccount
* freeAccount
= (typeof(freeAccount
))site
;
15298 IODelete(freeAccount
, OSKextAccount
, 1);
15301 /*********************************************************************
15302 *********************************************************************/
15304 #if CONFIG_IMAGEBOOT
15306 OSKextGetUUIDForName(const char *name
, uuid_t uuid
)
15308 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithIdentifier(name
);
15313 OSSharedPtr
<OSData
> uuid_data
= kext
->copyUUID();
15315 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_t
));
15324 sysctl_willuserspacereboot
15325 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
15327 int new_value
= 0, old_value
= 0, changed
= 0;
15328 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
15333 OSKext::willUserspaceReboot();
15338 static SYSCTL_PROC(_kern
, OID_AUTO
, willuserspacereboot
,
15339 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
15340 NULL
, 0, sysctl_willuserspacereboot
, "I", "");