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 vm_address_t originalAddress
;
3832 #if defined(__arm64__)
3833 uint64_t textExecBase
;
3834 size_t textExecSize
;
3835 #endif /* defined(__arm64__) */
3837 originalAddress
= address
;
3838 #if __has_feature(ptrauth_calls)
3839 address
= (vm_address_t
)VM_KERNEL_STRIP_PTR(address
);
3840 #endif /* __has_feature(ptrauth_calls) */
3842 IORecursiveLockLock(sKextLock
);
3844 count
= sLoadedKexts
->getCount();
3845 for (i
= 0; i
< count
; i
++) {
3846 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
3847 if (thisKext
== sKernelKext
) {
3850 if (thisKext
->kmod_info
&& thisKext
->kmod_info
->address
) {
3851 kmod_info
= thisKext
->kmod_info
;
3852 vm_address_t kext_start
= kmod_info
->address
;
3853 vm_address_t kext_end
= kext_start
+ kmod_info
->size
;
3854 if ((kext_start
<= address
) && (address
< kext_end
)) {
3855 foundKext
.reset(thisKext
, OSRetain
);
3858 #if defined(__arm64__)
3859 textExecBase
= (uintptr_t) getsegdatafromheader((kernel_mach_header_t
*)kmod_info
->address
, "__TEXT_EXEC", &textExecSize
);
3860 if ((textExecBase
<= address
) && (address
< textExecBase
+ textExecSize
)) {
3861 foundKext
.reset(thisKext
, OSRetain
);
3864 #endif /* defined (__arm64__) */
3867 if ((address
>= vm_kernel_stext
) && (address
< vm_kernel_etext
)) {
3868 foundKext
.reset(sKernelKext
, OSRetain
);
3872 * DriverKit userspace executables do not have a kernel linkedExecutable,
3873 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3874 * here, so use the original address passed to this method.
3876 * This is supposed to be used for logging reasons only. When logd
3877 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3878 * remove it here before checking it against the LoadTag.
3879 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3882 address
= originalAddress
& ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK
| FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT
);
3883 count
= sLoadedDriverKitKexts
->getCount();
3884 for (i
= 0; i
< count
; i
++) {
3885 OSKext
* thisKext
= OSDynamicCast(OSKext
, sLoadedDriverKitKexts
->getObject(i
));
3886 if (thisKext
->getLoadTag() == address
) {
3887 foundKext
.reset(thisKext
, OSRetain
);
3892 IORecursiveLockUnlock(sKextLock
);
3898 OSKext::copyKextUUIDForAddress(OSNumber
*address
)
3900 OSSharedPtr
<OSData
> uuid
;
3901 OSSharedPtr
<OSKext
> kext
;
3908 /* Is the calling process allowed to query kext info? */
3909 if (current_task() != kernel_task
) {
3910 int macCheckResult
= 0;
3911 kauth_cred_t cred
= NULL
;
3913 cred
= kauth_cred_get_with_ref();
3914 macCheckResult
= mac_kext_check_query(cred
);
3915 kauth_cred_unref(&cred
);
3917 if (macCheckResult
!= 0) {
3918 OSKextLog(/* kext */ NULL
,
3919 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
3920 "Failed to query kext UUID (MAC policy error 0x%x).",
3927 uintptr_t slidAddress
= ml_static_slide((uintptr_t)address
->unsigned64BitValue());
3928 if (slidAddress
!= 0) {
3929 kext
= lookupKextWithAddress(slidAddress
);
3931 uuid
= kext
->copyTextUUID();
3937 * If we still don't have a UUID, then we failed to match the slid + stripped address with
3938 * a kext. This might have happened because the log message came from a dext.
3940 * Try again with the original address.
3942 kext
= lookupKextWithAddress((vm_address_t
)address
->unsigned64BitValue());
3943 if (kext
&& kext
->isDriverKit()) {
3944 uuid
= kext
->copyTextUUID();
3951 /*********************************************************************
3952 *********************************************************************/
3954 OSKext::lookupKextWithUUID(uuid_t wanted
)
3956 OSSharedPtr
<OSKext
> foundKext
; // returned
3958 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
3959 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
3962 IORecursiveLockLock(sKextLock
);
3964 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
3965 for (i
= 0; i
< count
[j
]; i
++) {
3966 OSKext
* thisKext
= NULL
;
3968 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
3973 OSSharedPtr
<OSData
> uuid_data
= thisKext
->copyUUID();
3979 memcpy(&uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
3981 if (0 == uuid_compare(wanted
, uuid
)) {
3982 foundKext
.reset(thisKext
, OSRetain
);
3988 IORecursiveLockUnlock(sKextLock
);
3996 /*********************************************************************
3997 *********************************************************************/
4000 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier
)
4002 bool result
= false;
4003 OSKext
* foundKext
= NULL
; // returned
4005 IORecursiveLockLock(sKextLock
);
4007 foundKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
4008 if (foundKext
&& foundKext
->isLoaded()) {
4012 IORecursiveLockUnlock(sKextLock
);
4017 /*********************************************************************
4018 * xxx - should spawn a separate thread so a kext can safely have
4019 * xxx - itself unloaded.
4020 *********************************************************************/
4028 bool terminateServicesAndRemovePersonalitiesFlag
)
4032 kOSKextLogErrorLevel
|
4033 kOSKextLogKextBookkeepingFlag
,
4034 "removeKext() called for %s, not supported on embedded",
4035 aKext
->getIdentifier() ? aKext
->getIdentifierCString() : "unknown kext");
4037 return kOSReturnSuccess
;
4038 #else /* CONFIG_EMBEDDED */
4040 OSReturn result
= kOSKextReturnInUse
;
4041 OSKext
* checkKext
= NULL
; // do not release
4043 int macCheckResult
= 0;
4044 kauth_cred_t cred
= NULL
;
4047 IORecursiveLockLock(sKextLock
);
4049 /* If the kext has no identifier, it failed to init
4050 * so isn't in sKextsByID and it isn't loaded.
4052 if (!aKext
->getIdentifier()) {
4053 result
= kOSReturnSuccess
;
4057 checkKext
= OSDynamicCast(OSKext
,
4058 sKextsByID
->getObject(aKext
->getIdentifier()));
4059 if (checkKext
!= aKext
) {
4060 result
= kOSKextReturnNotFound
;
4064 if (aKext
->isLoaded()) {
4066 if (current_task() != kernel_task
) {
4067 cred
= kauth_cred_get_with_ref();
4068 macCheckResult
= mac_kext_check_unload(cred
, aKext
->getIdentifierCString());
4069 kauth_cred_unref(&cred
);
4072 if (macCheckResult
!= 0) {
4073 result
= kOSReturnError
;
4075 kOSKextLogErrorLevel
|
4076 kOSKextLogKextBookkeepingFlag
,
4077 "Failed to remove kext %s (MAC policy error 0x%x).",
4078 aKext
->getIdentifierCString(), macCheckResult
);
4083 /* make sure there are no resource requests in flight - 17187548 */
4084 if (aKext
->countRequestCallbacks()) {
4088 /* If we are terminating, send the request to the IOCatalogue
4089 * (which will actually call us right back but that's ok we have
4090 * a recursive lock don't you know) but do not ask the IOCatalogue
4091 * to call back with an unload, we'll do that right here.
4093 if (terminateServicesAndRemovePersonalitiesFlag
) {
4094 result
= gIOCatalogue
->terminateDriversForModule(
4095 aKext
->getIdentifierCString(), /* unload */ false);
4096 if (result
!= kOSReturnSuccess
) {
4098 kOSKextLogErrorLevel
|
4099 kOSKextLogKextBookkeepingFlag
,
4100 "Can't remove kext %s; services failed to terminate - 0x%x.",
4101 aKext
->getIdentifierCString(), result
);
4106 result
= aKext
->unload();
4107 if (result
!= kOSReturnSuccess
) {
4112 /* Remove personalities as requested. This is a bit redundant for a loaded
4113 * kext as IOCatalogue::terminateDriversForModule() removes driver
4114 * personalities, but it doesn't restart matching, which we always want
4115 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4118 if (terminateServicesAndRemovePersonalitiesFlag
) {
4119 aKext
->removePersonalitiesFromCatalog();
4122 if (aKext
->isInFileset()) {
4124 kOSKextLogProgressLevel
|
4125 kOSKextLogKextBookkeepingFlag
,
4126 "Fileset kext %s unloaded.",
4127 aKext
->getIdentifierCString());
4130 kOSKextLogProgressLevel
|
4131 kOSKextLogKextBookkeepingFlag
,
4132 "Removing kext %s.",
4133 aKext
->getIdentifierCString());
4135 sKextsByID
->removeObject(aKext
->getIdentifier());
4137 result
= kOSReturnSuccess
;
4140 IORecursiveLockUnlock(sKextLock
);
4142 #endif /* CONFIG_EMBEDDED */
4145 /*********************************************************************
4146 *********************************************************************/
4149 OSKext::removeKextWithIdentifier(
4150 const char * kextIdentifier
,
4151 bool terminateServicesAndRemovePersonalitiesFlag
)
4153 OSReturn result
= kOSReturnError
;
4155 IORecursiveLockLock(sKextLock
);
4157 OSKext
* aKext
= OSDynamicCast(OSKext
,
4158 sKextsByID
->getObject(kextIdentifier
));
4160 result
= kOSKextReturnNotFound
;
4161 OSKextLog(/* kext */ NULL
,
4162 kOSKextLogErrorLevel
|
4163 kOSKextLogKextBookkeepingFlag
,
4164 "Can't remove kext %s - not found.",
4169 result
= OSKext::removeKext(aKext
,
4170 terminateServicesAndRemovePersonalitiesFlag
);
4173 IORecursiveLockUnlock(sKextLock
);
4178 /*********************************************************************
4179 *********************************************************************/
4182 OSKext::removeKextWithLoadTag(
4183 OSKextLoadTag loadTag
,
4184 bool terminateServicesAndRemovePersonalitiesFlag
)
4186 OSReturn result
= kOSReturnError
;
4187 OSKext
* foundKext
= NULL
;
4189 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
4190 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
4193 IORecursiveLockLock(sKextLock
);
4195 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
4196 for (i
= 0; i
< count
[j
]; i
++) {
4197 OSKext
* thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
4198 if (thisKext
->loadTag
== loadTag
) {
4199 foundKext
= thisKext
;
4206 result
= kOSKextReturnNotFound
;
4207 OSKextLog(/* kext */ NULL
,
4208 kOSKextLogErrorLevel
|
4209 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
4210 "Can't remove kext with load tag %d - not found.",
4215 result
= OSKext::removeKext(foundKext
,
4216 terminateServicesAndRemovePersonalitiesFlag
);
4219 IORecursiveLockUnlock(sKextLock
);
4224 /*********************************************************************
4225 *********************************************************************/
4226 OSSharedPtr
<OSDictionary
>
4227 OSKext::copyKexts(void)
4229 OSSharedPtr
<OSDictionary
> result
;
4231 IORecursiveLockLock(sKextLock
);
4232 result
= OSDynamicPtrCast
<OSDictionary
>(sKextsByID
->copyCollection());
4233 IORecursiveLockUnlock(sKextLock
);
4238 /*********************************************************************
4239 *********************************************************************/
4240 #define BOOTER_KEXT_PREFIX "Driver-"
4242 typedef struct _DeviceTreeBuffer
{
4245 } _DeviceTreeBuffer
;
4247 /*********************************************************************
4248 * Create a dictionary of excluded kexts from the given booter data.
4249 *********************************************************************/
4252 OSKext::createExcludeListFromBooterData(
4253 OSDictionary
* theDictionary
,
4254 OSCollectionIterator
* theIterator
)
4256 OSString
* deviceTreeName
= NULL
; // do not release
4257 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not release
4258 char * booterDataPtr
= NULL
; // do not release
4259 _BooterKextFileInfo
* kextFileInfo
= NULL
; // do not release
4260 char * infoDictAddr
= NULL
; // do not release
4261 OSSharedPtr
<OSObject
> parsedXML
;
4262 OSDictionary
* theInfoDict
= NULL
; // do not release
4264 theIterator
->reset();
4266 /* look for AppleKextExcludeList.kext */
4267 while ((deviceTreeName
=
4268 OSDynamicCast(OSString
, theIterator
->getNextObject()))) {
4269 const char * devTreeNameCString
;
4270 OSData
* deviceTreeEntry
; // do not release
4271 OSString
* myBundleID
; // do not release
4274 OSDynamicCast(OSData
, theDictionary
->getObject(deviceTreeName
));
4275 if (!deviceTreeEntry
) {
4279 /* Make sure it is a kext */
4280 devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
4281 if (strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
4282 (sizeof(BOOTER_KEXT_PREFIX
) - 1)) != 0) {
4284 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4285 "\"%s\" not a kext",
4286 devTreeNameCString
);
4290 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
4291 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
4292 if (!deviceTreeBuffer
) {
4296 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
4297 if (!booterDataPtr
) {
4301 kextFileInfo
= (_BooterKextFileInfo
*) booterDataPtr
;
4302 if (!kextFileInfo
->infoDictPhysAddr
||
4303 !kextFileInfo
->infoDictLength
) {
4307 infoDictAddr
= (char *)
4308 ml_static_ptovirt(kextFileInfo
->infoDictPhysAddr
);
4309 if (!infoDictAddr
) {
4313 parsedXML
= OSUnserializeXML(infoDictAddr
);
4318 theInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
4324 OSDynamicCast(OSString
,
4325 theInfoDict
->getObject(kCFBundleIdentifierKey
));
4327 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4328 boolean_t updated
= updateExcludeList(theInfoDict
);
4331 panic("Missing OSKextExcludeList dictionary\n");
4335 } // while ( (deviceTreeName = ...) )
4340 /*********************************************************************
4341 * Create a dictionary of excluded kexts from the given prelink
4342 * info (kernelcache).
4343 *********************************************************************/
4346 OSKext::createExcludeListFromPrelinkInfo( OSArray
* theInfoArray
)
4348 OSDictionary
* myInfoDict
= NULL
; // do not release
4349 OSString
* myBundleID
; // do not release
4352 /* Find the Apple Kext Exclude List. */
4353 for (i
= 0; i
< theInfoArray
->getCount(); i
++) {
4354 myInfoDict
= OSDynamicCast(OSDictionary
, theInfoArray
->getObject(i
));
4359 OSDynamicCast(OSString
,
4360 myInfoDict
->getObject(kCFBundleIdentifierKey
));
4362 strcmp( myBundleID
->getCStringNoCopy(), kIOExcludeListBundleID
) == 0) {
4363 boolean_t updated
= updateExcludeList(myInfoDict
);
4366 panic("Missing OSKextExcludeList dictionary\n");
4370 } // for (i = 0; i < theInfoArray->getCount()...
4377 OSKext::updateExcludeList(OSDictionary
*infoDict
)
4379 OSDictionary
*myTempDict
= NULL
; // do not free
4380 OSString
*myTempString
= NULL
; // do not free
4381 OSKextVersion newVersion
= 0;
4382 boolean_t updated
= false;
4388 myTempDict
= OSDynamicCast(OSDictionary
, infoDict
->getObject("OSKextExcludeList"));
4393 myTempString
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundleVersionKey
));
4394 if (!myTempString
) {
4398 newVersion
= OSKextParseVersionString(myTempString
->getCStringNoCopy());
4399 if (newVersion
== 0) {
4403 IORecursiveLockLock(sKextLock
);
4405 if (newVersion
> sExcludeListVersion
) {
4406 sExcludeListByID
= OSDictionary::withDictionary(myTempDict
, 0);
4407 sExcludeListVersion
= newVersion
;
4411 IORecursiveLockUnlock(sKextLock
);
4416 #pragma mark Accessors
4418 /*********************************************************************
4419 *********************************************************************/
4421 OSKext::getIdentifier(void)
4423 return bundleID
.get();
4426 /*********************************************************************
4427 * A kext must have a bundle identifier to even survive initialization;
4428 * this is guaranteed to exist past then.
4429 *********************************************************************/
4431 OSKext::getIdentifierCString(void)
4433 return bundleID
->getCStringNoCopy();
4436 /*********************************************************************
4437 *********************************************************************/
4439 OSKext::getVersion(void)
4444 /*********************************************************************
4445 *********************************************************************/
4447 OSKext::getCompatibleVersion(void)
4449 return compatibleVersion
;
4452 /*********************************************************************
4453 *********************************************************************/
4455 OSKext::isLibrary(void)
4457 return getCompatibleVersion() > 0;
4460 /*********************************************************************
4461 *********************************************************************/
4463 OSKext::isCompatibleWithVersion(OSKextVersion aVersion
)
4465 if ((compatibleVersion
> -1 && version
> -1) &&
4466 (compatibleVersion
<= version
&& aVersion
<= version
)) {
4472 /*********************************************************************
4473 *********************************************************************/
4475 OSKext::declaresExecutable(void)
4477 if (isDriverKit()) {
4480 return getPropertyForHostArch(kCFBundleExecutableKey
) != NULL
;
4483 /*********************************************************************
4484 *********************************************************************/
4486 OSKext::getExecutable(void)
4488 OSData
* result
= NULL
;
4489 OSSharedPtr
<OSData
> extractedExecutable
;
4491 if (flags
.builtin
) {
4492 return sKernelKext
->linkedExecutable
.get();
4495 result
= OSDynamicCast(OSData
, infoDict
->getObject(_kOSKextExecutableKey
));
4501 OSData
* mkextExecutableRef
= NULL
; // do not release
4502 mkextExecutableRef
= OSDynamicCast(OSData
,
4503 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey
));
4505 if (mkextExecutableRef
) {
4506 MkextEntryRef
* mkextEntryRef
= (MkextEntryRef
*)
4507 mkextExecutableRef
->getBytesNoCopy();
4508 uint32_t mkextVersion
= MKEXT_GET_VERSION(mkextEntryRef
->mkext
);
4509 if (mkextVersion
== MKEXT_VERS_2
) {
4510 mkext2_file_entry
* fileinfo
=
4511 (mkext2_file_entry
*)mkextEntryRef
->fileinfo
;
4512 uint32_t compressedSize
= MKEXT2_GET_ENTRY_COMPSIZE(fileinfo
);
4513 uint32_t fullSize
= MKEXT2_GET_ENTRY_FULLSIZE(fileinfo
);
4514 extractedExecutable
= extractMkext2FileData(
4515 MKEXT2_GET_ENTRY_DATA(fileinfo
), "executable",
4516 compressedSize
, fullSize
);
4518 OSKextLog(this, kOSKextLogErrorLevel
|
4519 kOSKextLogArchiveFlag
,
4520 "Kext %s - unknown mkext version 0x%x for executable.",
4521 getIdentifierCString(), mkextVersion
);
4524 /* Regardless of success, remove the mkext executable,
4525 * and drop one reference on the mkext. (setExecutable() does not
4526 * replace, it removes, or panics if asked to replace.)
4528 infoDict
->removeObject(_kOSKextMkextExecutableReferenceKey
);
4529 infoDict
->removeObject(_kOSKextExecutableExternalDataKey
);
4531 if (extractedExecutable
&& extractedExecutable
->getLength()) {
4532 if (!setExecutable(extractedExecutable
.get())) {
4535 result
= extractedExecutable
.get();
4542 #endif // CONFIG_KXLD
4546 /*********************************************************************
4547 *********************************************************************/
4549 OSKext::isInterface(void)
4551 return flags
.interface
;
4554 /*********************************************************************
4555 *********************************************************************/
4557 OSKext::isKernel(void)
4559 return this == sKernelKext
;
4562 /*********************************************************************
4563 *********************************************************************/
4565 OSKext::isKernelComponent(void)
4567 return flags
.kernelComponent
? true : false;
4570 /*********************************************************************
4571 *********************************************************************/
4573 OSKext::isExecutable(void)
4575 return !isKernel() && !isInterface() && declaresExecutable();
4578 /*********************************************************************
4579 * We might want to check this recursively for all dependencies,
4580 * since a subtree of dependencies could get loaded before we hit
4581 * a dependency that isn't safe-boot-loadable.
4583 * xxx - Might want to return false if OSBundleEnableKextLogging or
4584 * OSBundleDebugLevel
4585 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4586 * the point except it's usually development drivers, which might
4587 * cause panics on startup, that have those properties). Heh; could
4588 * use a "kx" boot-arg!
4589 *********************************************************************/
4591 OSKext::isLoadableInSafeBoot(void)
4593 bool result
= false;
4594 OSString
* required
= NULL
; // do not release
4601 if (isDriverKit()) {
4606 required
= OSDynamicCast(OSString
,
4607 getPropertyForHostArch(kOSBundleRequiredKey
));
4611 if (required
->isEqualTo(kOSBundleRequiredRoot
) ||
4612 required
->isEqualTo(kOSBundleRequiredLocalRoot
) ||
4613 required
->isEqualTo(kOSBundleRequiredNetworkRoot
) ||
4614 required
->isEqualTo(kOSBundleRequiredSafeBoot
) ||
4615 required
->isEqualTo(kOSBundleRequiredConsole
)) {
4623 /*********************************************************************
4624 *********************************************************************/
4626 OSKext::isPrelinked(void)
4628 return flags
.prelinked
? true : false;
4631 /*********************************************************************
4632 *********************************************************************/
4634 OSKext::isLoaded(void)
4636 return flags
.loaded
? true : false;
4639 /*********************************************************************
4640 *********************************************************************/
4642 OSKext::isStarted(void)
4644 return flags
.started
? true : false;
4647 /*********************************************************************
4648 *********************************************************************/
4650 OSKext::isCPPInitialized(void)
4652 return flags
.CPPInitialized
;
4655 /*********************************************************************
4656 *********************************************************************/
4658 OSKext::setCPPInitialized(bool initialized
)
4660 flags
.CPPInitialized
= initialized
;
4663 /*********************************************************************
4664 *********************************************************************/
4666 OSKext::getLoadTag(void)
4671 /*********************************************************************
4672 *********************************************************************/
4674 OSKext::getSizeInfo(uint32_t *loadSize
, uint32_t *wiredSize
)
4676 if (linkedExecutable
) {
4677 *loadSize
= linkedExecutable
->getLength();
4679 /* If we have a kmod_info struct, calculated the wired size
4680 * from that. Otherwise it's the full load size.
4683 *wiredSize
= *loadSize
- (uint32_t)kmod_info
->hdr_size
;
4685 *wiredSize
= *loadSize
;
4693 /*********************************************************************
4694 *********************************************************************/
4696 OSKext::copyUUID(void)
4698 OSSharedPtr
<OSData
> result
;
4699 OSData
* theExecutable
= NULL
; // do not release
4700 const kernel_mach_header_t
* header
;
4702 /* An interface kext doesn't have a linked executable with an LC_UUID,
4703 * we create one when it's linked.
4705 if (interfaceUUID
) {
4706 result
= interfaceUUID
;
4710 if (flags
.builtin
|| isInterface()) {
4711 return sKernelKext
->copyUUID();
4714 if (isDriverKit() && infoDict
) {
4715 return driverKitUUID
;
4718 /* For real kexts, try to get the UUID from the linked executable,
4719 * or if is hasn't been linked yet, the unrelocated executable.
4721 theExecutable
= linkedExecutable
.get();
4722 if (!theExecutable
) {
4723 theExecutable
= getExecutable();
4726 if (!theExecutable
) {
4730 header
= (const kernel_mach_header_t
*)theExecutable
->getBytesNoCopy();
4731 result
= copyMachoUUID(header
);
4737 /*********************************************************************
4738 *********************************************************************/
4740 OSKext::copyTextUUID(void)
4742 if (flags
.builtin
) {
4743 return copyMachoUUID((const kernel_mach_header_t
*)kmod_info
->address
);
4748 /*********************************************************************
4749 *********************************************************************/
4751 OSKext::copyMachoUUID(const kernel_mach_header_t
* header
)
4753 OSSharedPtr
<OSData
> result
;
4754 const struct load_command
* load_cmd
= NULL
;
4755 const struct uuid_command
* uuid_cmd
= NULL
;
4758 load_cmd
= (const struct load_command
*)&header
[1];
4760 if (header
->magic
!= MH_MAGIC_KERNEL
) {
4762 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4763 "%s: bad header %p",
4769 for (i
= 0; i
< header
->ncmds
; i
++) {
4770 if (load_cmd
->cmd
== LC_UUID
) {
4771 uuid_cmd
= (struct uuid_command
*)load_cmd
;
4772 result
= OSData::withBytes(uuid_cmd
->uuid
, sizeof(uuid_cmd
->uuid
));
4775 load_cmd
= (struct load_command
*)((caddr_t
)load_cmd
+ load_cmd
->cmdsize
);
4783 OSKext::setDriverKitUUID(OSData
*uuid
)
4785 if (!OSCompareAndSwapPtr(nullptr, uuid
, &driverKitUUID
)) {
4786 OSSafeReleaseNULL(uuid
);
4790 /*********************************************************************
4791 *********************************************************************/
4792 #if defined (__arm__)
4793 #include <arm/arch.h>
4796 #if defined (__x86_64__)
4797 #define ARCHNAME "x86_64"
4798 #elif defined (__arm64__)
4799 #define ARCHNAME "arm64"
4800 #elif defined (__arm__)
4802 #if defined (__ARM_ARCH_7S__)
4803 #define ARCHNAME "armv7s"
4804 #elif defined (__ARM_ARCH_7F__)
4805 #define ARCHNAME "armv7f"
4806 #elif defined (__ARM_ARCH_7K__)
4807 #define ARCHNAME "armv7k"
4808 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4809 #define ARCHNAME "armv7"
4810 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4811 #define ARCHNAME "armv6"
4814 #elif defined (__arm64__)
4815 #define ARCHNAME "arm64"
4817 #error architecture not supported
4820 #define ARCH_SEPARATOR_CHAR '_'
4823 makeHostArchKey(const char * key
, size_t * keySizeOut
)
4825 char * result
= NULL
;
4826 size_t keyLength
= strlen(key
);
4829 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4831 keySize
= 1 + 1 + keyLength
+ strlen(ARCHNAME
);
4832 result
= (char *)kheap_alloc_tag(KHEAP_TEMP
, keySize
,
4833 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
4838 strlcpy(result
, key
, keySize
);
4839 result
[keyLength
++] = ARCH_SEPARATOR_CHAR
;
4840 result
[keyLength
] = '\0';
4841 strlcat(result
, ARCHNAME
, keySize
);
4842 *keySizeOut
= keySize
;
4848 /*********************************************************************
4849 *********************************************************************/
4851 OSKext::getPropertyForHostArch(const char * key
)
4853 OSObject
* result
= NULL
;// do not release
4854 size_t hostArchKeySize
= 0;
4855 char * hostArchKey
= NULL
;// must kfree
4857 if (!key
|| !infoDict
) {
4861 /* Some properties are not allowed to be arch-variant:
4862 * - Any CFBundle... property.
4863 * - OSBundleIsInterface.
4864 * - OSKernelResource.
4866 if (STRING_HAS_PREFIX(key
, "OS") ||
4867 STRING_HAS_PREFIX(key
, "IO")) {
4868 hostArchKey
= makeHostArchKey(key
, &hostArchKeySize
);
4870 OSKextLog(/* kext (this isn't about a kext) */ NULL
,
4871 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
4872 "Allocation failure.");
4875 result
= infoDict
->getObject(hostArchKey
);
4879 result
= infoDict
->getObject(key
);
4884 kheap_free(KHEAP_TEMP
, hostArchKey
, hostArchKeySize
);
4890 #pragma mark Load/Start/Stop/Unload
4893 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4895 /*********************************************************************
4896 * sExcludeListByID is a dictionary with keys / values of:
4897 * key = bundleID string of kext we will not allow to load
4898 * value = version string(s) of the kext that is to be denied loading.
4899 * The version strings can be comma delimited. For example if kext
4900 * com.foocompany.fookext has two versions that we want to deny
4901 * loading then the version strings might look like:
4903 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4904 * not load the kext.
4906 * Value may also be in the form of "LE 2.0.0" (version numbers
4907 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4908 * number less than 2.0.0 will not load)
4910 * NOTE - we cannot use the characters "<=" or "<" because we have code
4911 * that serializes plists and treats '<' as a special character.
4912 *********************************************************************/
4914 OSKext::isInExcludeList(void)
4916 OSString
* versionString
= NULL
; // do not release
4917 char * versionCString
= NULL
; // do not free
4919 boolean_t wantLessThan
= false;
4920 boolean_t wantLessThanEqualTo
= false;
4921 boolean_t isInExcludeList
= true;
4924 IORecursiveLockLock(sKextLock
);
4926 if (!sExcludeListByID
) {
4927 isInExcludeList
= false;
4929 /* look up by bundleID in our exclude list and if found get version
4930 * string (or strings) that we will not allow to load
4932 versionString
= OSDynamicCast(OSString
, sExcludeListByID
->getObject(bundleID
.get()));
4933 if (versionString
== NULL
|| versionString
->getLength() > (sizeof(myBuffer
) - 1)) {
4934 isInExcludeList
= false;
4938 IORecursiveLockUnlock(sKextLock
);
4940 if (!isInExcludeList
) {
4944 /* parse version strings */
4945 versionCString
= (char *) versionString
->getCStringNoCopy();
4947 /* look for "LT" or "LE" form of version string, must be in first two
4950 if (*versionCString
== 'L' && *(versionCString
+ 1) == 'T') {
4951 wantLessThan
= true;
4952 versionCString
+= 2;
4953 } else if (*versionCString
== 'L' && *(versionCString
+ 1) == 'E') {
4954 wantLessThanEqualTo
= true;
4955 versionCString
+= 2;
4958 for (i
= 0; *versionCString
!= 0x00; versionCString
++) {
4959 /* skip whitespace */
4960 if (isWhiteSpace(*versionCString
)) {
4964 /* peek ahead for version string separator or null terminator */
4965 if (*(versionCString
+ 1) == ',' || *(versionCString
+ 1) == 0x00) {
4966 /* OK, we have a version string */
4967 myBuffer
[i
++] = *versionCString
;
4970 OSKextVersion excludeVers
;
4971 excludeVers
= OSKextParseVersionString(myBuffer
);
4973 if (wantLessThanEqualTo
) {
4974 if (version
<= excludeVers
) {
4977 } else if (wantLessThan
) {
4978 if (version
< excludeVers
) {
4981 } else if (version
== excludeVers
) {
4985 /* reset for the next (if any) version string */
4987 wantLessThan
= false;
4988 wantLessThanEqualTo
= false;
4990 /* save valid version character */
4991 myBuffer
[i
++] = *versionCString
;
4993 /* make sure bogus version string doesn't overrun local buffer */
4994 if (i
>= sizeof(myBuffer
)) {
5003 /*********************************************************************
5004 * sNonLoadableKextsByID is a dictionary with keys / values of:
5005 * key = bundleID string of kext we will not allow to load
5006 * value = boolean (true == loadable, false == not loadable)
5008 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5009 * i.e., the value for the kext's bundleID will be false. All kexts in
5010 * the primary and system KCs will always be marked as "loadable."
5012 * This list ultimately comes from kexts which have been uninstalled
5013 * in user space by deleting the kext from disk, but which have not
5014 * yet been removed from the AuxKC. Because the user could choose to
5015 * re-install the exact same version of the kext, we need to keep
5016 * a dictionary of boolean values so that user space only needs to
5017 * keep a simple list of "uninstalled" or "missing" bundles. When
5018 * a bundle is re-installed, the iokit daemon can use the
5019 * AucKCBundleAvailable predicate to set the individual kext's
5020 * availability to true.
5021 *********************************************************************/
5023 OSKext::isLoadable(void)
5025 bool isLoadable
= true;
5027 if (kc_type
!= KCKindAuxiliary
) {
5028 /* this filtering only applies to kexts in the auxkc */
5032 IORecursiveLockLock(sKextLock
);
5034 if (sNonLoadableKextsByID
) {
5035 /* look up by bundleID in our exclude list and if found get version
5036 * string (or strings) that we will not allow to load
5038 OSBoolean
*loadableVal
;
5039 loadableVal
= OSDynamicCast(OSBoolean
, sNonLoadableKextsByID
->getObject(bundleID
.get()));
5040 if (loadableVal
&& !loadableVal
->getValue()) {
5044 IORecursiveLockUnlock(sKextLock
);
5049 /*********************************************************************
5050 *********************************************************************/
5053 OSKext::loadKextWithIdentifier(
5054 const char * kextIdentifierCString
,
5055 Boolean allowDeferFlag
,
5056 Boolean delayAutounloadFlag
,
5057 OSKextExcludeLevel startOpt
,
5058 OSKextExcludeLevel startMatchingOpt
,
5059 OSArray
* personalityNames
)
5061 OSReturn result
= kOSReturnError
;
5062 OSSharedPtr
<OSString
> kextIdentifier
;
5064 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
5065 if (!kextIdentifier
) {
5066 result
= kOSKextReturnNoMemory
;
5069 result
= OSKext::loadKextWithIdentifier(kextIdentifier
.get(),
5071 allowDeferFlag
, delayAutounloadFlag
,
5072 startOpt
, startMatchingOpt
, personalityNames
);
5079 OSKext::loadKextWithIdentifier(
5080 OSString
* kextIdentifier
,
5081 OSSharedPtr
<OSObject
> &kextRef
,
5082 Boolean allowDeferFlag
,
5083 Boolean delayAutounloadFlag
,
5084 OSKextExcludeLevel startOpt
,
5085 OSKextExcludeLevel startMatchingOpt
,
5086 OSArray
* personalityNames
)
5088 OSObject
* kextRefRaw
= NULL
;
5091 result
= loadKextWithIdentifier(kextIdentifier
,
5094 delayAutounloadFlag
,
5098 if ((kOSReturnSuccess
== result
) && kextRefRaw
) {
5099 kextRef
.reset(kextRefRaw
, OSNoRetain
);
5104 /*********************************************************************
5105 *********************************************************************/
5107 OSKext::loadKextWithIdentifier(
5108 OSString
* kextIdentifier
,
5109 OSObject
** kextRef
,
5110 Boolean allowDeferFlag
,
5111 Boolean delayAutounloadFlag
,
5112 OSKextExcludeLevel startOpt
,
5113 OSKextExcludeLevel startMatchingOpt
,
5114 OSArray
* personalityNames
)
5116 OSReturn result
= kOSReturnError
;
5117 OSReturn pingResult
= kOSReturnError
;
5118 OSKext
* theKext
= NULL
; // do not release
5119 OSSharedPtr
<OSDictionary
> loadRequest
;
5120 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5126 IORecursiveLockLock(sKextLock
);
5128 if (!kextIdentifier
) {
5129 result
= kOSKextReturnInvalidArgument
;
5133 OSKext::recordIdentifierRequest(kextIdentifier
);
5135 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
5137 if (!allowDeferFlag
) {
5138 OSKextLog(/* kext */ NULL
,
5139 kOSKextLogErrorLevel
|
5141 "Can't load kext %s - not found.",
5142 kextIdentifier
->getCStringNoCopy());
5146 if (!sKernelRequestsEnabled
) {
5148 kOSKextLogErrorLevel
|
5150 "Can't load kext %s - requests to user space are disabled.",
5151 kextIdentifier
->getCStringNoCopy());
5152 result
= kOSKextReturnDisabled
;
5156 /* Create a new request unless one is already sitting
5157 * in sKernelRequests for this bundle identifier
5159 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5160 if (!sPostedKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5161 result
= _OSKextCreateRequest(kKextRequestPredicateRequestLoad
,
5163 if (result
!= kOSReturnSuccess
) {
5166 if (!_OSKextSetRequestArgument(loadRequest
.get(),
5167 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
5168 result
= kOSKextReturnNoMemory
;
5171 if (!sKernelRequests
->setObject(loadRequest
.get())) {
5172 result
= kOSKextReturnNoMemory
;
5176 if (!sPostedKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5177 result
= kOSKextReturnNoMemory
;
5182 kOSKextLogDebugLevel
|
5184 "Kext %s not found; queued load request to user space.",
5185 kextIdentifier
->getCStringNoCopy());
5188 pingResult
= OSKext::pingIOKitDaemon();
5189 if (pingResult
== kOSKextReturnDisabled
) {
5190 OSKextLog(/* kext */ NULL
,
5191 ((sPrelinkBoot
) ? kOSKextLogDebugLevel
: kOSKextLogErrorLevel
) |
5193 "Kext %s might not load - " kIOKitDaemonName
" is currently unavailable.",
5194 kextIdentifier
->getCStringNoCopy());
5197 result
= kOSKextReturnDeferred
;
5201 result
= theKext
->load(startOpt
, startMatchingOpt
, personalityNames
);
5203 if (result
!= kOSReturnSuccess
) {
5205 kOSKextLogErrorLevel
|
5207 "Failed to load kext %s (error 0x%x).",
5208 kextIdentifier
->getCStringNoCopy(), (int)result
);
5210 if (theKext
->kc_type
== KCKindUnknown
) {
5211 OSKext::removeKext(theKext
,
5212 /* terminateService/removePersonalities */ true);
5217 if (delayAutounloadFlag
) {
5219 kOSKextLogProgressLevel
|
5220 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5221 "Setting delayed autounload for %s.",
5222 kextIdentifier
->getCStringNoCopy());
5223 theKext
->flags
.delayAutounload
= 1;
5227 if ((kOSReturnSuccess
== result
) && kextRef
) {
5229 theKext
->matchingRefCount
++;
5233 IORecursiveLockUnlock(sKextLock
);
5238 /*********************************************************************
5239 *********************************************************************/
5242 OSKext::loadKextFromKC(OSKext
*theKext
, OSDictionary
*requestDict
)
5244 OSReturn result
= kOSReturnError
;
5246 OSBoolean
*delayAutounloadBool
= NULL
; // do not release
5247 OSNumber
*startKextExcludeNum
= NULL
; // do not release
5248 OSNumber
*startMatchingExcludeNum
= NULL
; // do not release
5249 OSArray
*personalityNames
= NULL
; // do not release
5252 * Default values for these options:
5253 * regular autounload behavior
5255 * send all personalities to the catalog
5257 Boolean delayAutounload
= false;
5258 OSKextExcludeLevel startKextExcludeLevel
= kOSKextExcludeNone
;
5259 OSKextExcludeLevel startMatchingExcludeLevel
= kOSKextExcludeNone
;
5261 IORecursiveLockLock(sKextLock
);
5263 OSKextLog(/* kext */ NULL
,
5264 kOSKextLogDebugLevel
|
5266 "Received kext KC load request from user space.");
5268 /* Regardless of processing, the fact that we have gotten here means some
5269 * user-space program is up and talking to us, so we'll switch our kext
5270 * registration to reflect that.
5272 if (!sUserLoadsActive
) {
5273 OSKextLog(/* kext */ NULL
,
5274 kOSKextLogProgressLevel
|
5275 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5276 "Switching to late startup (user-space) kext loading policy.");
5277 sUserLoadsActive
= true;
5280 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
5281 _OSKextGetRequestArgument(requestDict
,
5282 kKextRequestArgumentDelayAutounloadKey
));
5283 startKextExcludeNum
= OSDynamicCast(OSNumber
,
5284 _OSKextGetRequestArgument(requestDict
,
5285 kKextRequestArgumentStartExcludeKey
));
5286 startMatchingExcludeNum
= OSDynamicCast(OSNumber
,
5287 _OSKextGetRequestArgument(requestDict
,
5288 kKextRequestArgumentStartMatchingExcludeKey
));
5289 personalityNames
= OSDynamicCast(OSArray
,
5290 _OSKextGetRequestArgument(requestDict
,
5291 kKextRequestArgumentPersonalityNamesKey
));
5293 if (delayAutounloadBool
) {
5294 delayAutounload
= delayAutounloadBool
->getValue();
5296 if (startKextExcludeNum
) {
5297 startKextExcludeLevel
= startKextExcludeNum
->unsigned8BitValue();
5299 if (startMatchingExcludeNum
) {
5300 startMatchingExcludeLevel
= startMatchingExcludeNum
->unsigned8BitValue();
5303 OSKextLog(/* kext */ NULL
,
5304 kOSKextLogProgressLevel
|
5306 "Received request from user space to load KC kext %s.",
5307 theKext
->getIdentifierCString());
5309 /* this could be in the Auxiliary KC, so record the load request */
5310 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, theKext
->getIdentifier()));
5315 result
= theKext
->load(startKextExcludeLevel
,
5316 startMatchingExcludeLevel
, personalityNames
);
5318 if (result
!= kOSReturnSuccess
) {
5320 kOSKextLogErrorLevel
|
5322 "Failed to load kext %s (error 0x%x).",
5323 theKext
->getIdentifierCString(), (int)result
);
5325 OSKext::removeKext(theKext
,
5326 /* terminateService/removePersonalities */ true);
5330 kOSKextLogProgressLevel
|
5332 "Kext %s Loaded successfully from %s KC",
5333 theKext
->getIdentifierCString(), theKext
->getKCTypeString());
5336 if (delayAutounload
) {
5338 kOSKextLogProgressLevel
|
5339 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5340 "Setting delayed autounload for %s.",
5341 theKext
->getIdentifierCString());
5342 theKext
->flags
.delayAutounload
= 1;
5346 IORecursiveLockUnlock(sKextLock
);
5351 /*********************************************************************
5352 *********************************************************************/
5355 OSKext::loadCodelessKext(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
5357 OSReturn result
= kOSReturnError
;
5358 OSDictionary
*anInfoDict
= NULL
; // do not release
5360 anInfoDict
= OSDynamicCast(OSDictionary
,
5361 _OSKextGetRequestArgument(requestDict
,
5362 kKextRequestArgumentCodelessInfoKey
));
5363 if (anInfoDict
== NULL
) {
5364 OSKextLog(/* kext */ NULL
,
5365 kOSKextLogErrorLevel
|
5366 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5367 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5368 kextIdentifier
->getCStringNoCopy());
5369 return kOSKextReturnInvalidArgument
;
5372 IORecursiveLockLock(sKextLock
);
5374 OSKextLog(/* kext */ NULL
,
5375 kOSKextLogProgressLevel
|
5377 "Received request from user space to load codeless kext %s.",
5378 kextIdentifier
->getCStringNoCopy());
5381 // instantiate a new kext, and don't hold a reference
5382 // (the kext subsystem will hold one implicitly)
5383 OSSharedPtr
<OSKext
> newKext
= OSKext::withCodelessInfo(anInfoDict
);
5385 OSKextLog(/* kext */ NULL
,
5386 kOSKextLogErrorLevel
|
5387 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5388 "Could not instantiate codeless kext.");
5389 result
= kOSKextReturnNotLoadable
;
5392 if (!kextIdentifier
->isEqualTo(newKext
->getIdentifierCString())) {
5393 OSKextLog(/* kext */ NULL
,
5394 kOSKextLogErrorLevel
|
5395 kOSKextLogGeneralFlag
| kOSKextLogLoadFlag
,
5396 "Codeless kext identifiers don't match '%s' != '%s'",
5397 kextIdentifier
->getCStringNoCopy(), newKext
->getIdentifierCString());
5399 OSKext::removeKext(newKext
.get(), false);
5400 result
= kOSKextReturnInvalidArgument
;
5404 /* Record the request for the codeless kext */
5405 OSKext::recordIdentifierRequest(OSDynamicCast(OSString
, newKext
->getIdentifier()));
5407 result
= kOSReturnSuccess
;
5408 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5409 result
= newKext
->sendPersonalitiesToCatalog(true, NULL
);
5413 IORecursiveLockUnlock(sKextLock
);
5418 /*********************************************************************
5419 *********************************************************************/
5422 OSKext::dropMatchingReferences(
5425 IORecursiveLockLock(sKextLock
);
5426 kexts
->iterateObjects(^bool (OSObject
* obj
) {
5427 OSKext
* thisKext
= OSDynamicCast(OSKext
, obj
);
5431 thisKext
->matchingRefCount
--;
5434 IORecursiveLockUnlock(sKextLock
);
5437 /*********************************************************************
5438 *********************************************************************/
5441 OSKext::recordIdentifierRequest(
5442 OSString
* kextIdentifier
)
5444 OSSharedPtr
<const OSSymbol
> kextIdentifierSymbol
;
5447 if (!sAllKextLoadIdentifiers
|| !kextIdentifier
) {
5451 kextIdentifierSymbol
= OSSymbol::withString(kextIdentifier
);
5452 if (!kextIdentifierSymbol
) {
5453 // xxx - this is really a basic alloc failure
5458 IORecursiveLockLock(sKextLock
);
5459 if (!sAllKextLoadIdentifiers
->containsObject(kextIdentifierSymbol
.get())) {
5460 if (!sAllKextLoadIdentifiers
->setObject(kextIdentifierSymbol
.get())) {
5463 // xxx - need to find a way to associate this whole func w/the kext
5464 OSKextLog(/* kext */ NULL
,
5465 // xxx - check level
5466 kOSKextLogStepLevel
|
5467 kOSKextLogArchiveFlag
,
5468 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5469 kextIdentifier
->getCStringNoCopy());
5472 IORecursiveLockUnlock(sKextLock
);
5477 OSKextLog(/* kext */ NULL
,
5478 kOSKextLogErrorLevel
|
5479 kOSKextLogArchiveFlag
,
5480 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5481 kextIdentifier
->getCStringNoCopy());
5486 /*********************************************************************
5487 *********************************************************************/
5490 OSKextExcludeLevel startOpt
,
5491 OSKextExcludeLevel startMatchingOpt
,
5492 OSArray
* personalityNames
)
5494 OSReturn result
= kOSReturnError
;
5495 OSKextExcludeLevel dependenciesStartOpt
= startOpt
;
5496 OSKextExcludeLevel dependenciesStartMatchingOpt
= startMatchingOpt
;
5497 unsigned int i
, count
;
5498 Boolean alreadyLoaded
= false;
5499 OSKext
* lastLoadedKext
= NULL
; // do not release
5501 if (isInExcludeList()) {
5503 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5505 "Kext %s is in exclude list, not loadable",
5506 getIdentifierCString());
5508 result
= kOSKextReturnNotLoadable
;
5511 if (!isLoadable()) {
5513 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
|
5515 "Kext %s is not loadable",
5516 getIdentifierCString());
5518 result
= kOSKextReturnNotLoadable
;
5523 alreadyLoaded
= true;
5524 result
= kOSReturnSuccess
;
5527 kOSKextLogDebugLevel
|
5528 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
5529 "Kext %s is already loaded.",
5530 getIdentifierCString());
5534 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5536 if (current_task() != kernel_task
) {
5539 * On non-kxld systems, only check the mac-hook for kexts in the
5540 * Pageable and Aux KCs. This means on Apple silicon devices that
5541 * the mac hook will only be useful to block 3rd party kexts.
5543 * Note that this should _not_ be called on kexts loaded from the
5544 * kernel bootstrap thread as the kernel proc's cred struct is not
5545 * yet initialized! This won't happen on macOS because all the kexts
5546 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5548 if (kc_type
!= KCKindPrimary
&& kc_type
!= KCKindUnknown
) {
5549 #endif /* CONFIG_KXLD */
5550 int macCheckResult
= 0;
5551 kauth_cred_t cred
= NULL
;
5553 cred
= kauth_cred_get_with_ref();
5554 macCheckResult
= mac_kext_check_load(cred
, getIdentifierCString());
5555 kauth_cred_unref(&cred
);
5557 if (macCheckResult
!= 0) {
5558 result
= kOSReturnError
;
5560 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5561 "Failed to load kext %s (MAC policy error 0x%x).",
5562 getIdentifierCString(), macCheckResult
);
5568 if (!sLoadEnabled
) {
5570 kOSKextLogErrorLevel
|
5572 "Kext loading is disabled (attempt to load kext %s).",
5573 getIdentifierCString());
5574 result
= kOSKextReturnDisabled
;
5578 /* If we've pushed the next available load tag to the invalid value,
5579 * we can't load any more kexts.
5581 if (sNextLoadTag
== kOSKextInvalidLoadTag
) {
5583 kOSKextLogErrorLevel
|
5585 "Can't load kext %s - no more load tags to assign.",
5586 getIdentifierCString());
5587 result
= kOSKextReturnNoResources
;
5591 /* This is a bit of a hack, because we shouldn't be handling
5592 * personalities within the load function.
5594 if (!declaresExecutable()) {
5595 /* There is a special case where a non-executable kext can be loaded: the
5596 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5597 * load its metadata into the global data structures, if appropriate
5599 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID
) == 0) {
5600 boolean_t updated
= updateExcludeList(infoDict
.get());
5603 kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
5604 "KextExcludeList was updated to version: %lld", sExcludeListVersion
);
5608 if (isDriverKit()) {
5610 sLoadedDriverKitKexts
->setObject(this);
5611 loadTag
= sNextLoadTag
++;
5614 result
= kOSReturnSuccess
;
5618 /* Are we in safe boot?
5620 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
5622 kOSKextLogErrorLevel
|
5624 "Can't load kext %s - not loadable during safe boot.",
5625 getIdentifierCString());
5626 result
= kOSKextReturnBootLevel
;
5631 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
5633 getIdentifierCString());
5635 #if !VM_MAPPED_KEXTS
5636 if (isPrelinked() == false) {
5638 kOSKextLogErrorLevel
|
5640 "Can't load kext %s - not in a kext collection.",
5641 getIdentifierCString());
5642 result
= kOSKextReturnDisabled
;
5645 #endif /* defined(__x86_64__) */
5648 if (!sKxldContext
) {
5649 kern_return_t kxldResult
;
5650 kxldResult
= kxld_create_context(&sKxldContext
, &kern_allocate
,
5651 &kxld_log_callback
, /* Flags */ (KXLDFlags
) 0,
5652 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5655 kOSKextLogErrorLevel
|
5656 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
5657 "Can't load kext %s - failed to create link context.",
5658 getIdentifierCString());
5659 result
= kOSKextReturnNoMemory
;
5663 #endif // CONFIG_KXLD
5665 /* We only need to resolve dependencies once for the whole graph, but
5666 * resolveDependencies will just return if there's no work to do, so it's
5667 * safe to call it more than once.
5669 if (!resolveDependencies()) {
5670 // xxx - check resolveDependencies() for log msg
5672 kOSKextLogErrorLevel
|
5673 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5674 "Can't load kext %s - failed to resolve library dependencies.",
5675 getIdentifierCString());
5676 result
= kOSKextReturnDependencies
;
5680 /* If we are excluding just the kext being loaded now (and not its
5681 * dependencies), drop the exclusion level to none so dependencies
5682 * start and/or add their personalities.
5684 if (dependenciesStartOpt
== kOSKextExcludeKext
) {
5685 dependenciesStartOpt
= kOSKextExcludeNone
;
5688 if (dependenciesStartMatchingOpt
== kOSKextExcludeKext
) {
5689 dependenciesStartMatchingOpt
= kOSKextExcludeNone
;
5692 /* Load the dependencies, recursively.
5694 count
= getNumDependencies();
5695 for (i
= 0; i
< count
; i
++) {
5696 OSKext
* dependency
= OSDynamicCast(OSKext
,
5697 dependencies
->getObject(i
));
5698 if (dependency
== NULL
) {
5700 kOSKextLogErrorLevel
|
5701 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5702 "Internal error loading kext %s; dependency disappeared.",
5703 getIdentifierCString());
5704 result
= kOSKextReturnInternalError
;
5708 /* Dependencies must be started accorting to the opt,
5709 * but not given the personality names of the main kext.
5711 result
= dependency
->load(dependenciesStartOpt
,
5712 dependenciesStartMatchingOpt
,
5713 /* personalityNames */ NULL
);
5714 if (result
!= KERN_SUCCESS
) {
5716 kOSKextLogErrorLevel
|
5717 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
5718 "Dependency %s of kext %s failed to load.",
5719 dependency
->getIdentifierCString(),
5720 getIdentifierCString());
5722 OSKext::removeKext(dependency
,
5723 /* terminateService/removePersonalities */ true);
5724 result
= kOSKextReturnDependencyLoadError
;
5730 result
= loadExecutable();
5731 if (result
!= KERN_SUCCESS
) {
5735 pendingPgoHead
.next
= &pendingPgoHead
;
5736 pendingPgoHead
.prev
= &pendingPgoHead
;
5738 // The kernel PRNG is not initialized when the first kext is
5739 // loaded, so use early random
5740 uuid_generate_early_random(instance_uuid
);
5741 account
= IONew(OSKextAccount
, 1);
5743 result
= KERN_MEMORY_ERROR
;
5746 bzero(account
, sizeof(*account
));
5747 account
->loadTag
= kmod_info
->id
;
5748 account
->site
.refcount
= 0;
5749 account
->site
.flags
= VM_TAG_KMOD
;
5750 account
->kext
= this;
5751 if (gIOSurfaceIdentifier
== bundleID
) {
5752 vm_tag_alloc(&account
->site
);
5753 gIOSurfaceTag
= account
->site
.tag
;
5756 flags
.loaded
= true;
5758 /* Add the kext to the list of loaded kexts and update the kmod_info
5759 * struct to point to that of the last loaded kext (which is the way
5760 * it's always been done, though I'd rather do them in order now).
5762 lastLoadedKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
5763 sLoadedKexts
->setObject(this);
5765 /* Keep the kernel itself out of the kmod list.
5767 if (lastLoadedKext
->isKernel()) {
5768 lastLoadedKext
= NULL
;
5771 if (lastLoadedKext
) {
5772 kmod_info
->next
= lastLoadedKext
->kmod_info
;
5775 notifyKextLoadObservers(this, kmod_info
);
5777 /* Make the global kmod list point at the just-loaded kext. Note that the
5778 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5779 * although we do report it in kextstat these days by using the newer
5780 * OSArray of loaded kexts, which does contain it.
5782 * (The OSKext object representing the kernel doesn't even have a kmod_info
5783 * struct, though I suppose we could stick a pointer to it from the
5784 * static struct in OSRuntime.cpp.)
5788 /* Save the list of loaded kexts in case we panic.
5790 OSKext::saveLoadedKextPanicList();
5792 if (isExecutable()) {
5793 OSKext::updateLoadedKextSummaries();
5794 savePanicString(/* isLoading */ true);
5797 registerWithDTrace();
5799 jettisonLinkeditSegment();
5800 #endif /* CONFIG_DTRACE */
5802 #if !VM_MAPPED_KEXTS
5803 /* If there is a page (or more) worth of padding after the end
5804 * of the last data section but before the end of the data segment
5805 * then free it in the same manner the LinkeditSegment is freed
5807 jettisonDATASegmentPadding();
5812 if (isExecutable() && !flags
.started
) {
5813 if (startOpt
== kOSKextExcludeNone
) {
5815 if (result
!= kOSReturnSuccess
) {
5817 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
5818 "Kext %s start failed (result 0x%x).",
5819 getIdentifierCString(), result
);
5820 result
= kOSKextReturnStartStopError
;
5825 /* If not excluding matching, send the personalities to the kernel.
5826 * This never affects the result of the load operation.
5827 * This is a bit of a hack, because we shouldn't be handling
5828 * personalities within the load function.
5830 if (result
== kOSReturnSuccess
&& startMatchingOpt
== kOSKextExcludeNone
) {
5831 result
= sendPersonalitiesToCatalog(true, personalityNames
);
5836 if (result
!= kOSReturnSuccess
) {
5838 kOSKextLogErrorLevel
|
5840 "Kext %s failed to load (0x%x).",
5841 getIdentifierCString(), (int)result
);
5842 } else if (!alreadyLoaded
) {
5844 kOSKextLogProgressLevel
|
5847 getIdentifierCString());
5849 queueKextNotification(kKextRequestPredicateLoadNotification
,
5850 OSDynamicCast(OSString
, bundleID
.get()));
5856 /*********************************************************************
5858 *********************************************************************/
5860 strdup(const char * string
)
5862 char * result
= NULL
;
5869 size
= 1 + strlen(string
);
5870 result
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, size
,
5871 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
5876 memcpy(result
, string
, size
);
5881 #endif // CONFIG_KXLD
5883 /*********************************************************************
5885 *********************************************************************/
5888 OSKext::lookupSection(const char *segname
, const char *secname
)
5890 kernel_section_t
* found_section
= NULL
;
5891 kernel_mach_header_t
* mh
= NULL
;
5892 kernel_segment_command_t
* seg
= NULL
;
5893 kernel_section_t
* sec
= NULL
;
5895 if (!linkedExecutable
) {
5899 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5901 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5902 if (0 != strncmp(seg
->segname
, segname
, sizeof(seg
->segname
))) {
5906 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
5907 if (0 == strncmp(sec
->sectname
, secname
, sizeof(sec
->sectname
))) {
5908 found_section
= sec
;
5915 return found_section
;
5918 /*********************************************************************
5920 *********************************************************************/
5923 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides
)
5925 OSReturn result
= kOSKextReturnBadData
;
5926 kernel_mach_header_t
* mh
= NULL
;
5927 kernel_segment_command_t
* seg
= NULL
;
5928 kernel_segment_command_t
* linkeditSeg
= NULL
;
5929 kernel_section_t
* sec
= NULL
;
5930 char * linkeditBase
= NULL
;
5931 bool haveLinkeditBase
= false;
5932 char * relocBase
= NULL
;
5933 bool haveRelocBase
= false;
5934 struct dysymtab_command
* dysymtab
= NULL
;
5935 struct linkedit_data_command
* segmentSplitInfo
= NULL
;
5936 struct symtab_command
* symtab
= NULL
;
5937 kernel_nlist_t
* sym
= NULL
;
5938 struct relocation_info
* reloc
= NULL
;
5941 vm_offset_t new_kextsize
;
5943 if (linkedExecutable
== NULL
|| flags
.builtin
) {
5944 result
= kOSReturnSuccess
;
5948 mh
= (kernel_mach_header_t
*)linkedExecutable
->getBytesNoCopy();
5949 if (kernel_mach_header_is_in_fileset(mh
)) {
5950 // kexts in filesets are slid as part of collection sliding
5951 result
= kOSReturnSuccess
;
5955 segmentSplitInfo
= (struct linkedit_data_command
*) getcommandfromheader(mh
, LC_SEGMENT_SPLIT_INFO
);
5957 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
5962 seg
->vmaddr
= ml_static_slide(seg
->vmaddr
);
5964 #if KASLR_KEXT_DEBUG
5965 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5967 (unsigned long)ml_static_unslide(seg
->vmaddr
),
5968 (unsigned long)seg
->vmaddr
);
5971 if (!haveRelocBase
) {
5972 relocBase
= (char *) seg
->vmaddr
;
5973 haveRelocBase
= true;
5975 if (!strcmp(seg
->segname
, "__LINKEDIT")) {
5976 linkeditBase
= (char *) seg
->vmaddr
- seg
->fileoff
;
5977 haveLinkeditBase
= true;
5980 for (sec
= firstsect(seg
); sec
!= NULL
; sec
= nextsect(seg
, sec
)) {
5981 sec
->addr
= ml_static_slide(sec
->addr
);
5983 #if KASLR_KEXT_DEBUG
5984 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5986 (unsigned long)ml_static_unslide(sec
->addr
),
5987 (unsigned long)sec
->addr
);
5992 dysymtab
= (struct dysymtab_command
*) getcommandfromheader(mh
, LC_DYSYMTAB
);
5994 symtab
= (struct symtab_command
*) getcommandfromheader(mh
, LC_SYMTAB
);
5996 if (symtab
!= NULL
&& doCoalescedSlides
== false) {
5997 /* Some pseudo-kexts have symbol tables without segments.
5999 if (symtab
->nsyms
> 0 && haveLinkeditBase
) {
6000 sym
= (kernel_nlist_t
*) (linkeditBase
+ symtab
->symoff
);
6001 for (i
= 0; i
< symtab
->nsyms
; i
++) {
6002 if (sym
[i
].n_type
& N_STAB
) {
6005 sym
[i
].n_value
= ml_static_slide(sym
[i
].n_value
);
6007 #if KASLR_KEXT_DEBUG
6008 #define MAX_SYMS_TO_LOG 5
6009 if (i
< MAX_SYMS_TO_LOG
) {
6010 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6011 (unsigned long)ml_static_unslide(sym
[i
].n_value
),
6012 (unsigned long)sym
[i
].n_value
);
6019 if (dysymtab
!= NULL
&& doCoalescedSlides
== false) {
6020 if (dysymtab
->nextrel
> 0) {
6022 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6024 "Sliding kext %s: External relocations found.",
6025 getIdentifierCString());
6029 if (dysymtab
->nlocrel
> 0) {
6030 if (!haveLinkeditBase
) {
6032 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6034 "Sliding kext %s: No linkedit segment.",
6035 getIdentifierCString());
6039 if (!haveRelocBase
) {
6041 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6044 "Sliding kext %s: No writable segments.",
6046 "Sliding kext %s: No segments.",
6048 getIdentifierCString());
6052 reloc
= (struct relocation_info
*) (linkeditBase
+ dysymtab
->locreloff
);
6053 reloc_size
= dysymtab
->nlocrel
* sizeof(struct relocation_info
);
6055 for (i
= 0; i
< dysymtab
->nlocrel
; i
++) {
6056 if (reloc
[i
].r_extern
!= 0
6057 || reloc
[i
].r_type
!= 0
6058 || reloc
[i
].r_length
!= (sizeof(void *) == 8 ? 3 : 2)
6061 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6063 "Sliding kext %s: Unexpected relocation found.",
6064 getIdentifierCString());
6067 if (reloc
[i
].r_pcrel
!= 0) {
6070 uintptr_t *relocAddr
= (uintptr_t*)(relocBase
+ reloc
[i
].r_address
);
6071 *relocAddr
= ml_static_slide(*relocAddr
);
6073 #if KASLR_KEXT_DEBUG
6074 #define MAX_DYSYMS_TO_LOG 5
6075 if (i
< MAX_DYSYMS_TO_LOG
) {
6076 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6077 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr
))),
6078 (unsigned long)*((uintptr_t *)(relocBase
+ reloc
[i
].r_address
)));
6083 /* We should free these relocations, not just delete the reference to them.
6084 * <rdar://problem/10535549> Free relocations from PIE kexts.
6086 * For now, we do not free LINKEDIT for kexts with split segments.
6088 new_kextsize
= round_page(kmod_info
->size
- reloc_size
);
6089 if (new_kextsize
> UINT_MAX
) {
6091 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
|
6093 "Kext %s: new kext size is too large.",
6094 getIdentifierCString());
6097 if (((kmod_info
->size
- new_kextsize
) > PAGE_SIZE
) && (!segmentSplitInfo
)) {
6098 vm_offset_t endofkext
= kmod_info
->address
+ kmod_info
->size
;
6099 vm_offset_t new_endofkext
= kmod_info
->address
+ new_kextsize
;
6100 vm_offset_t endofrelocInfo
= (vm_offset_t
) (((uint8_t *)reloc
) + reloc_size
);
6101 size_t bytes_remaining
= endofkext
- endofrelocInfo
;
6102 OSSharedPtr
<OSData
> new_osdata
;
6104 /* fix up symbol offsets if they are after the dsymtab local relocs */
6106 if (dysymtab
->locreloff
< symtab
->symoff
) {
6107 symtab
->symoff
-= reloc_size
;
6109 if (dysymtab
->locreloff
< symtab
->stroff
) {
6110 symtab
->stroff
-= reloc_size
;
6113 if (dysymtab
->locreloff
< dysymtab
->extreloff
) {
6114 dysymtab
->extreloff
-= reloc_size
;
6117 /* move data behind reloc info down to new offset */
6118 if (endofrelocInfo
< endofkext
) {
6119 memcpy(reloc
, (void *)endofrelocInfo
, bytes_remaining
);
6122 /* Create a new OSData for the smaller kext object and reflect
6123 * new linkedit segment size.
6125 linkeditSeg
->vmsize
= round_page(linkeditSeg
->vmsize
- reloc_size
);
6126 linkeditSeg
->filesize
= linkeditSeg
->vmsize
;
6128 new_osdata
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)new_kextsize
);
6130 /* Fix up kmod info and linkedExecutable.
6132 kmod_info
->size
= new_kextsize
;
6134 new_osdata
->setDeallocFunction(osdata_kext_free
);
6136 new_osdata
->setDeallocFunction(osdata_phys_free
);
6138 linkedExecutable
->setDeallocFunction(NULL
);
6139 linkedExecutable
= os::move(new_osdata
);
6142 kext_free(new_endofkext
, (endofkext
- new_endofkext
));
6144 ml_static_mfree(new_endofkext
, (endofkext
- new_endofkext
));
6148 dysymtab
->nlocrel
= 0;
6149 dysymtab
->locreloff
= 0;
6153 result
= kOSReturnSuccess
;
6158 /*********************************************************************
6159 * called only by load()
6160 *********************************************************************/
6162 OSKext::loadExecutable()
6164 OSReturn result
= kOSReturnError
;
6165 OSSharedPtr
<OSArray
> linkDependencies
;
6166 uint32_t num_kmod_refs
= 0;
6167 OSData
* theExecutable
= NULL
; // do not release
6168 OSString
* versString
= NULL
; // do not release
6169 const char * versCString
= NULL
; // do not free
6170 const char * string
= NULL
; // do not free
6174 uint32_t numDirectDependencies
= 0;
6175 kern_return_t kxldResult
;
6176 KXLDDependency
* kxlddeps
= NULL
; // must kfree
6177 uint32_t num_kxlddeps
= 0;
6178 struct mach_header
** kxldHeaderPtr
= NULL
; // do not free
6179 struct mach_header
* kxld_header
= NULL
; // xxx - need to free here?
6180 #endif // CONFIG_KXLD
6182 /* We need the version string for a variety of bits below.
6184 versString
= OSDynamicCast(OSString
,
6185 getPropertyForHostArch(kCFBundleVersionKey
));
6189 versCString
= versString
->getCStringNoCopy();
6191 if (isKernelComponent()) {
6192 if (STRING_HAS_PREFIX(versCString
, KERNEL_LIB_PREFIX
)) {
6193 if (strncmp(versCString
, KERNEL6_VERSION
, strlen(KERNEL6_VERSION
))) {
6195 kOSKextLogErrorLevel
|
6197 "Kernel component %s has incorrect version %s; "
6199 getIdentifierCString(),
6200 versCString
, KERNEL6_VERSION
);
6201 result
= kOSKextReturnInternalError
;
6203 } else if (strcmp(versCString
, osrelease
)) {
6205 kOSKextLogErrorLevel
|
6207 "Kernel component %s has incorrect version %s; "
6209 getIdentifierCString(),
6210 versCString
, osrelease
);
6211 result
= kOSKextReturnInternalError
;
6217 #if defined(__x86_64__) || defined(__i386__)
6218 if (flags
.resetSegmentsFromVnode
) {
6219 /* Fixup the chains and slide the mach headers */
6220 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6222 if (i386_slide_individual_kext(mh
, PE_get_kc_slide(kc_type
)) != KERN_SUCCESS
) {
6223 result
= kOSKextReturnValidation
;
6227 #endif //(__x86_64__) || defined(__i386__)
6229 if (isPrelinked()) {
6233 /* <rdar://problem/21444003> all callers must be entitled */
6234 if (FALSE
== IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
)) {
6236 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6237 "Not entitled to link kext '%s'",
6238 getIdentifierCString());
6239 result
= kOSKextReturnNotPrivileged
;
6243 theExecutable
= getExecutable();
6244 if (!theExecutable
) {
6245 if (declaresExecutable()) {
6247 kOSKextLogErrorLevel
|
6249 "Can't load kext %s - executable is missing.",
6250 getIdentifierCString());
6251 result
= kOSKextReturnValidation
;
6257 if (isInterface()) {
6258 OSSharedPtr
<OSData
> executableCopy
= OSData::withData(theExecutable
);
6259 if (executableCopy
) {
6260 setLinkedExecutable(executableCopy
.get());
6266 numDirectDependencies
= getNumDependencies();
6268 if (flags
.hasBleedthrough
) {
6269 linkDependencies
= dependencies
;
6271 linkDependencies
= OSArray::withArray(dependencies
.get());
6272 if (!linkDependencies
) {
6274 kOSKextLogErrorLevel
|
6275 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6276 "Can't allocate link dependencies to load kext %s.",
6277 getIdentifierCString());
6281 for (i
= 0; i
< numDirectDependencies
; ++i
) {
6282 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
6283 dependencies
->getObject(i
));
6284 dependencyKext
->addBleedthroughDependencies(linkDependencies
.get());
6288 num_kxlddeps
= linkDependencies
->getCount();
6289 if (!num_kxlddeps
) {
6291 kOSKextLogErrorLevel
|
6292 kOSKextLogLoadFlag
| kOSKextLogDependenciesFlag
,
6293 "Can't load kext %s - it has no library dependencies.",
6294 getIdentifierCString());
6298 kxlddeps
= (KXLDDependency
*)kalloc_tag(num_kxlddeps
* sizeof(*kxlddeps
), VM_KERN_MEMORY_OSKEXT
);
6301 kOSKextLogErrorLevel
|
6302 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6303 "Can't allocate link context to load kext %s.",
6304 getIdentifierCString());
6307 bzero(kxlddeps
, num_kxlddeps
* sizeof(*kxlddeps
));
6309 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6310 OSKext
* dependency
= OSDynamicCast(OSKext
, linkDependencies
->getObject(i
));
6312 if (dependency
->isInterface()) {
6313 OSKext
*interfaceTargetKext
= NULL
; //do not release
6314 OSData
* interfaceTarget
= NULL
; //do not release
6316 if (dependency
->isKernelComponent()) {
6317 interfaceTargetKext
= sKernelKext
;
6318 interfaceTarget
= sKernelKext
->linkedExecutable
.get();
6320 interfaceTargetKext
= OSDynamicCast(OSKext
,
6321 dependency
->dependencies
->getObject(0));
6323 interfaceTarget
= interfaceTargetKext
->linkedExecutable
.get();
6326 if (!interfaceTarget
) {
6331 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6332 * it will be useful to have them in the debugger.
6333 * strdup() failing isn't critical right here so we don't check that.
6335 kxlddeps
[i
].kext
= (u_char
*) interfaceTarget
->getBytesNoCopy();
6336 kxlddeps
[i
].kext_size
= interfaceTarget
->getLength();
6337 kxlddeps
[i
].kext_name
= strdup(interfaceTargetKext
->getIdentifierCString());
6339 if (dependency
->linkedExecutable
!= NULL
) {
6340 kxlddeps
[i
].interface
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6341 kxlddeps
[i
].interface_size
= dependency
->linkedExecutable
->getLength();
6343 kxlddeps
[i
].interface
= (u_char
*) NULL
;
6344 kxlddeps
[i
].interface_size
= 0;
6346 kxlddeps
[i
].interface_name
= strdup(dependency
->getIdentifierCString());
6348 kxlddeps
[i
].kext
= (u_char
*) dependency
->linkedExecutable
->getBytesNoCopy();
6349 kxlddeps
[i
].kext_size
= dependency
->linkedExecutable
->getLength();
6350 kxlddeps
[i
].kext_name
= strdup(dependency
->getIdentifierCString());
6353 kxlddeps
[i
].is_direct_dependency
= (i
< numDirectDependencies
);
6356 kxldHeaderPtr
= &kxld_header
;
6360 kOSKextLogExplicitLevel
|
6361 kOSKextLogLoadFlag
| kOSKextLogLinkFlag
,
6362 "Kext %s - calling kxld_link_file:\n"
6363 " kxld_context: %p\n"
6364 " executable: %p executable_length: %d\n"
6366 " kxld_dependencies: %p num_dependencies: %d\n"
6367 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6368 getIdentifierCString(), sKxldContext
,
6369 theExecutable
->getBytesNoCopy(), theExecutable
->getLength(),
6370 this, kxlddeps
, num_kxlddeps
,
6371 kxldHeaderPtr
, &kmod_info
);
6374 /* After this call, the linkedExecutable instance variable
6377 kxldResult
= kxld_link_file(sKxldContext
,
6378 (u_char
*)theExecutable
->getBytesNoCopy(),
6379 theExecutable
->getLength(),
6380 getIdentifierCString(), this, kxlddeps
, num_kxlddeps
,
6381 (u_char
**)kxldHeaderPtr
, (kxld_addr_t
*)&kmod_info
);
6383 if (kxldResult
!= KERN_SUCCESS
) {
6384 // xxx - add kxldResult here?
6386 kOSKextLogErrorLevel
|
6388 "Can't load kext %s - link failed.",
6389 getIdentifierCString());
6390 result
= kOSKextReturnLinkError
;
6394 /* We've written data & instructions into kernel memory, so flush the data
6395 * cache and invalidate the instruction cache.
6396 * I/D caches are coherent on x86
6398 #if !defined(__i386__) && !defined(__x86_64__)
6399 flush_dcache(kmod_info
->address
, kmod_info
->size
, false);
6400 invalidate_icache(kmod_info
->address
, kmod_info
->size
, false);
6403 #else // !CONFIG_KXLD
6404 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6405 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6406 result
= kOSKextReturnLinkError
;
6408 #endif // CONFIG_KXLD
6412 if (isInterface()) {
6413 /* Whip up a fake kmod_info entry for the interface kext.
6415 kmod_info
= (kmod_info_t
*)kalloc_tag(sizeof(kmod_info_t
), VM_KERN_MEMORY_OSKEXT
);
6417 result
= KERN_MEMORY_ERROR
;
6421 /* A pseudokext has almost nothing in its kmod_info struct.
6423 bzero(kmod_info
, sizeof(kmod_info_t
));
6425 kmod_info
->info_version
= KMOD_INFO_VERSION
;
6427 /* An interface kext doesn't have a linkedExecutable, so save a
6428 * copy of the UUID out of the original executable via copyUUID()
6429 * while we still have the original executable.
6431 interfaceUUID
= copyUUID();
6434 kmod_info
->id
= loadTag
= sNextLoadTag
++;
6435 kmod_info
->reference_count
= 0; // KMOD_DECL... sets it to -1 (invalid).
6437 /* Stamp the bundle ID and version from the OSKext over anything
6438 * resident inside the kmod_info.
6440 string
= getIdentifierCString();
6441 strlcpy(kmod_info
->name
, string
, sizeof(kmod_info
->name
));
6443 string
= versCString
;
6444 strlcpy(kmod_info
->version
, string
, sizeof(kmod_info
->version
));
6446 /* Add the dependencies' kmod_info structs as kmod_references.
6448 num_kmod_refs
= getNumDependencies();
6449 if (num_kmod_refs
) {
6450 kmod_info
->reference_list
= (kmod_reference_t
*)kalloc_tag(
6451 num_kmod_refs
* sizeof(kmod_reference_t
), VM_KERN_MEMORY_OSKEXT
);
6452 if (!kmod_info
->reference_list
) {
6453 result
= KERN_MEMORY_ERROR
;
6456 bzero(kmod_info
->reference_list
,
6457 num_kmod_refs
* sizeof(kmod_reference_t
));
6458 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
6459 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
6460 OSKext
* refKext
= OSDynamicCast(OSKext
, dependencies
->getObject(refIndex
));
6461 ref
->info
= refKext
->kmod_info
;
6462 ref
->info
->reference_count
++;
6464 if (refIndex
+ 1 < num_kmod_refs
) {
6465 ref
->next
= kmod_info
->reference_list
+ refIndex
+ 1;
6470 if (kmod_info
->hdr_size
> UINT32_MAX
) {
6472 kOSKextLogErrorLevel
|
6475 "Kext %s header size is too large (%lu > UINT32_MAX).",
6477 "Kext %s header size is too large (%u > UINT32_MAX).",
6480 kmod_info
->hdr_size
);
6481 result
= KERN_FAILURE
;
6485 if (kmod_info
->size
> UINT32_MAX
) {
6487 kOSKextLogErrorLevel
|
6490 "Kext %s size is too large (%lu > UINT32_MAX).",
6492 "Kext %s size is too large (%u > UINT32_MAX).",
6496 result
= KERN_FAILURE
;
6500 if (!isInterface() && linkedExecutable
) {
6502 kOSKextLogProgressLevel
|
6504 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6506 (unsigned)kmod_info
->size
/ PAGE_SIZE
,
6507 (unsigned long)ml_static_unslide(kmod_info
->address
),
6508 (unsigned)kmod_info
->id
);
6511 /* VM protections and wiring for the Aux KC are done at collection loading time */
6512 if (kc_type
!= KCKindAuxiliary
|| flags
.resetSegmentsFromVnode
) {
6513 /* if prelinked and primary KC, VM protections are already set */
6514 result
= setVMAttributes(!isPrelinked() || flags
.resetSegmentsFromVnode
, true);
6515 if (result
!= KERN_SUCCESS
) {
6521 if (linkedExecutable
) {
6522 kasan_load_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(),
6523 linkedExecutable
->getLength(), getIdentifierCString());
6526 if (lookupSection(KASAN_GLOBAL_SEGNAME
, KASAN_GLOBAL_SECTNAME
)) {
6528 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
6529 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6530 getIdentifierCString()
6532 result
= KERN_FAILURE
;
6537 result
= kOSReturnSuccess
;
6542 /* Clear up locally allocated dependency info.
6544 for (i
= 0; i
< num_kxlddeps
; ++i
) {
6547 if (kxlddeps
[i
].kext_name
) {
6548 size
= 1 + strlen(kxlddeps
[i
].kext_name
);
6549 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].kext_name
, size
);
6551 if (kxlddeps
[i
].interface_name
) {
6552 size
= 1 + strlen(kxlddeps
[i
].interface_name
);
6553 kheap_free(KHEAP_DATA_BUFFERS
, kxlddeps
[i
].interface_name
, size
);
6557 kfree(kxlddeps
, (num_kxlddeps
* sizeof(*kxlddeps
)));
6559 #endif // CONFIG_KXLD
6561 /* We no longer need the unrelocated executable (which the linker
6562 * has altered anyhow).
6564 setExecutable(NULL
);
6566 if (result
!= kOSReturnSuccess
) {
6568 kOSKextLogErrorLevel
|
6570 "Failed to load executable for kext %s.",
6571 getIdentifierCString());
6573 if (kmod_info
&& kmod_info
->reference_list
) {
6574 kfree(kmod_info
->reference_list
,
6575 num_kmod_refs
* sizeof(kmod_reference_t
));
6577 if (isInterface()) {
6578 kfree(kmod_info
, sizeof(kmod_info_t
));
6581 if (kc_type
== KCKindUnknown
) {
6583 if (linkedExecutable
) {
6584 linkedExecutable
.reset();
6595 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t
*mh
)
6597 kernel_segment_command_t
*linkeditseg
= NULL
;
6599 linkeditseg
= getsegbynamefromheader(mh
, SEG_LINKEDIT
);
6600 assert(linkeditseg
!= NULL
);
6602 /* BootKC on x86_64 is not vm mapped */
6603 ml_static_mfree(linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6605 OSKextLog(/* kext */ NULL
,
6606 kOSKextLogProgressLevel
|
6607 kOSKextLogGeneralFlag
,
6608 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6609 linkeditseg
->vmaddr
, linkeditseg
->vmsize
);
6611 #endif /* VM_MAPPED_KEXTS */
6613 /*********************************************************************
6614 * The linkedit segment is used by the kext linker for dependency
6615 * resolution, and by dtrace for probe initialization. We can free it
6616 * for non-library kexts, since no kexts depend on non-library kexts
6617 * by definition, once dtrace has been initialized.
6618 *********************************************************************/
6620 OSKext::jettisonLinkeditSegment(void)
6622 kernel_mach_header_t
* machhdr
= (kernel_mach_header_t
*)kmod_info
->address
;
6623 kernel_segment_command_t
* linkedit
= NULL
;
6625 vm_size_t linkeditsize
, kextsize
;
6626 OSSharedPtr
<OSData
> data
;
6628 if (isInFileset()) {
6633 /* We can free symbol tables for all embedded kexts because we don't
6634 * support runtime kext linking.
6636 if (sKeepSymbols
|| !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6638 if (sKeepSymbols
|| isLibrary() || !isExecutable() || !linkedExecutable
|| flags
.jettisonLinkeditSeg
) {
6643 /* Find the linkedit segment. If it's not the last segment, then freeing
6644 * it will fragment the kext into multiple VM regions, which OSKext is not
6645 * designed to handle, so we'll have to skip it.
6647 linkedit
= getsegbynamefromheader(machhdr
, SEG_LINKEDIT
);
6652 if (round_page(kmod_info
->address
+ kmod_info
->size
) !=
6653 round_page(linkedit
->vmaddr
+ linkedit
->vmsize
)) {
6657 /* Create a new OSData for the smaller kext object.
6659 linkeditsize
= round_page(linkedit
->vmsize
);
6660 kextsize
= kmod_info
->size
- linkeditsize
;
6661 start
= linkedit
->vmaddr
;
6663 if (kextsize
> UINT_MAX
) {
6666 data
= OSData::withBytesNoCopy((void *)kmod_info
->address
, (unsigned int)kextsize
);
6671 /* Fix the kmod info and linkedExecutable.
6673 kmod_info
->size
= kextsize
;
6676 data
->setDeallocFunction(osdata_kext_free
);
6678 data
->setDeallocFunction(osdata_phys_free
);
6680 linkedExecutable
->setDeallocFunction(NULL
);
6681 linkedExecutable
= os::move(data
);
6682 flags
.jettisonLinkeditSeg
= 1;
6684 /* Free the linkedit segment.
6687 kext_free(start
, linkeditsize
);
6689 ml_static_mfree(start
, linkeditsize
);
6696 /*********************************************************************
6697 * If there are whole pages that are unused betweem the last section
6698 * of the DATA segment and the end of the DATA segment then we can free
6700 *********************************************************************/
6702 OSKext::jettisonDATASegmentPadding(void)
6704 kernel_mach_header_t
* mh
;
6705 kernel_segment_command_t
* dataSeg
;
6706 kernel_section_t
* sec
, * lastSec
;
6707 vm_offset_t dataSegEnd
, lastSecEnd
;
6710 if (flags
.builtin
) {
6713 mh
= (kernel_mach_header_t
*)kmod_info
->address
;
6715 if (isInFileset()) {
6719 dataSeg
= getsegbynamefromheader(mh
, SEG_DATA
);
6720 if (dataSeg
== NULL
) {
6725 sec
= firstsect(dataSeg
);
6726 while (sec
!= NULL
) {
6728 sec
= nextsect(dataSeg
, sec
);
6731 if (lastSec
== NULL
) {
6735 if ((dataSeg
->vmaddr
!= round_page(dataSeg
->vmaddr
)) ||
6736 (dataSeg
->vmsize
!= round_page(dataSeg
->vmsize
))) {
6740 dataSegEnd
= dataSeg
->vmaddr
+ dataSeg
->vmsize
;
6741 lastSecEnd
= round_page(lastSec
->addr
+ lastSec
->size
);
6743 if (dataSegEnd
<= lastSecEnd
) {
6747 padSize
= dataSegEnd
- lastSecEnd
;
6749 if (padSize
>= PAGE_SIZE
) {
6751 kext_free(lastSecEnd
, padSize
);
6753 ml_static_mfree(lastSecEnd
, padSize
);
6758 /*********************************************************************
6759 *********************************************************************/
6761 OSKext::setLinkedExecutable(OSData
* anExecutable
)
6763 if (linkedExecutable
) {
6764 panic("Attempt to set linked executable on kext "
6765 "that already has one (%s).\n",
6766 getIdentifierCString());
6768 linkedExecutable
.reset(anExecutable
, OSRetain
);
6773 /*********************************************************************
6774 * Go through all loaded kexts and tell them to register with dtrace.
6775 * The instance method only registers if necessary.
6776 *********************************************************************/
6779 OSKext::registerKextsWithDTrace(void)
6781 uint32_t count
= sLoadedKexts
->getCount();
6784 IORecursiveLockLock(sKextLock
);
6786 for (i
= 0; i
< count
; i
++) {
6787 OSKext
* thisKext
= NULL
; // do not release
6789 thisKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
6790 if (!thisKext
|| !thisKext
->isExecutable()) {
6794 thisKext
->registerWithDTrace();
6797 IORecursiveLockUnlock(sKextLock
);
6803 extern int (*dtrace_modload
)(struct kmod_info
*, uint32_t);
6804 extern int (*dtrace_modunload
)(struct kmod_info
*);
6807 /*********************************************************************
6808 *********************************************************************/
6810 OSKext::registerWithDTrace(void)
6812 /* Register kext with dtrace. A dtrace_modload failure should not
6813 * prevent a kext from loading, so we ignore the return code.
6815 if (!flags
.dtraceInitialized
&& (dtrace_modload
!= NULL
)) {
6816 uint32_t modflag
= 0;
6817 OSObject
* forceInit
= getPropertyForHostArch("OSBundleForceDTraceInit");
6820 if (!sKeepSymbols
&& kc_type
== KCKindPrimary
) {
6821 if (forceInit
== kOSBooleanTrue
) {
6822 /* Make sure the kext is not from the Boot KC */
6823 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6825 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6826 modflag
|= KMOD_DTRACE_NO_KERNEL_SYMS
;
6829 #endif /* VM_MAPPED_KEXTS */
6830 if (forceInit
== kOSBooleanTrue
) {
6831 modflag
|= KMOD_DTRACE_FORCE_INIT
;
6833 if (flags
.builtin
) {
6834 modflag
|= KMOD_DTRACE_STATIC_KEXT
;
6837 (void)(*dtrace_modload
)(kmod_info
, modflag
);
6838 flags
.dtraceInitialized
= true;
6839 jettisonLinkeditSegment();
6843 /*********************************************************************
6844 *********************************************************************/
6846 OSKext::unregisterWithDTrace(void)
6848 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6849 * prevent a kext from loading, so we ignore the return code.
6851 if (flags
.dtraceInitialized
&& (dtrace_modunload
!= NULL
)) {
6852 (void)(*dtrace_modunload
)(kmod_info
);
6853 flags
.dtraceInitialized
= false;
6857 #endif /* CONFIG_DTRACE */
6860 /*********************************************************************
6861 * called only by loadExecutable()
6862 *********************************************************************/
6863 #if !VM_MAPPED_KEXTS
6864 #if defined(__arm__) || defined(__arm64__)
6865 static inline kern_return_t
6867 kernel_mach_header_t
*kext_mh
,
6869 vm_map_offset_t start
,
6870 vm_map_offset_t end
,
6875 #pragma unused(kext_mh,map,kc_type)
6876 assert(map
== kernel_map
); // we can handle KEXTs arising from the PRELINK segment and no others
6877 assert(start
<= end
);
6879 return KERN_SUCCESS
; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6880 } else if (set_max
) {
6881 return KERN_SUCCESS
; // Punt set_max, as there's no mechanism to record that state
6883 return ml_static_protect(start
, end
- start
, new_prot
);
6887 static inline kern_return_t
6889 kernel_mach_header_t
*kext_mh
,
6891 vm_map_offset_t start
,
6892 vm_map_offset_t end
,
6893 vm_prot_t access_type
,
6894 boolean_t user_wire
,
6897 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6898 return KERN_SUCCESS
; // No-op as PRELINK kexts are cemented into physical memory at boot
6901 #error Unrecognized architecture
6904 static inline kern_return_t
6906 kernel_mach_header_t
*kext_mh
,
6908 vm_map_offset_t start
,
6909 vm_map_offset_t end
,
6914 if (start
== end
) { // 10538581
6915 return KERN_SUCCESS
;
6917 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6919 * XXX: This will probably need to be different for AuxKC and
6922 return ml_static_protect(start
, end
- start
, new_prot
);
6924 return vm_map_protect(map
, start
, end
, new_prot
, set_max
);
6927 static inline kern_return_t
6929 kernel_mach_header_t
*kext_mh
,
6931 vm_map_offset_t start
,
6932 vm_map_offset_t end
,
6933 vm_prot_t access_type
,
6934 boolean_t user_wire
,
6937 if (kernel_mach_header_is_in_fileset(kext_mh
) && kc_type
== KCKindPrimary
) {
6938 /* TODO: we may need to hook this for the pageableKC */
6939 return KERN_SUCCESS
;
6941 return vm_map_wire_kernel(map
, start
, end
, access_type
, VM_KERN_MEMORY_KEXT
, user_wire
);
6946 OSKext::setVMAttributes(bool protect
, bool wire
)
6948 vm_map_t kext_map
= NULL
;
6949 kernel_segment_command_t
* seg
= NULL
;
6950 vm_map_offset_t start_protect
= 0;
6951 vm_map_offset_t start_wire
= 0;
6952 vm_map_offset_t end_protect
= 0;
6953 vm_map_offset_t end_wire
= 0;
6954 OSReturn result
= kOSReturnError
;
6956 if (isInterface() || !declaresExecutable() || flags
.builtin
) {
6957 result
= kOSReturnSuccess
;
6961 /* Get the kext's vm map */
6962 kext_map
= kext_get_vm_map(kmod_info
);
6964 result
= KERN_MEMORY_ERROR
;
6968 #if !VM_MAPPED_KEXTS
6969 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
)) {
6970 /* This is a split kext in a prelinked kernelcache; we'll let the
6971 * platform code take care of protecting it. It is already wired.
6973 /* TODO: Should this still allow protections for the first segment
6974 * to go through, in the event that we have a mix of split and
6977 result
= KERN_SUCCESS
;
6981 if (isInFileset() && kc_type
!= KCKindPageable
) {
6982 // kexts in filesets have protections setup as part of collection loading
6983 result
= KERN_SUCCESS
;
6988 /* Protect the headers as read-only; they do not need to be wired */
6989 result
= (protect
) ? OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
6990 kext_map
, kmod_info
->address
,
6991 kmod_info
->address
+ kmod_info
->hdr_size
, VM_PROT_READ
, TRUE
, kc_type
)
6993 if (result
!= KERN_SUCCESS
) {
6997 /* Set the VM protections and wire down each of the segments */
6998 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7001 /* We build all ARM kexts, so we can ensure they are aligned */
7002 assert((seg
->vmaddr
& PAGE_MASK
) == 0);
7003 assert((seg
->vmsize
& PAGE_MASK
) == 0);
7007 * For the non page aligned segments, the range calculation for protection
7008 * and wiring differ as follows:
7010 * Protection: The non page aligned data at the start or at the end of the
7011 * segment is excluded from the protection. This exclusion is needed to make
7012 * sure OSKext_protect is not called twice on same page, if the page is shared
7013 * between two segments.
7015 * Wiring: The non page aligned data at the start or at the end of the
7016 * segment is included in the wiring range, this inclusion is needed to make sure
7017 * all the data of the segment is wired.
7019 start_protect
= round_page(seg
->vmaddr
);
7020 end_protect
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
7022 start_wire
= trunc_page(seg
->vmaddr
);
7023 end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7026 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7027 * across kexts and data from kexts is not page aligned
7029 if (protect
&& (end_protect
> start_protect
) &&
7030 ((strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0 &&
7031 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) != 0) ||
7032 (kc_type
!= KCKindPageable
&& kc_type
!= KCKindAuxiliary
))) {
7033 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7034 kext_map
, start_protect
, end_protect
, seg
->maxprot
, TRUE
, kc_type
);
7035 if (result
!= KERN_SUCCESS
) {
7037 kOSKextLogErrorLevel
|
7039 "Kext %s failed to set maximum VM protections "
7040 "for segment %s - 0x%x.",
7041 getIdentifierCString(), seg
->segname
, (int)result
);
7045 result
= OSKext_protect((kernel_mach_header_t
*)kmod_info
->address
,
7046 kext_map
, start_protect
, end_protect
, seg
->initprot
, FALSE
, kc_type
);
7047 if (result
!= KERN_SUCCESS
) {
7049 kOSKextLogErrorLevel
|
7051 "Kext %s failed to set initial VM protections "
7052 "for segment %s - 0x%x.",
7053 getIdentifierCString(), seg
->segname
, (int)result
);
7058 if (segmentShouldBeWired(seg
) && wire
) {
7059 result
= OSKext_wire((kernel_mach_header_t
*)kmod_info
->address
,
7060 kext_map
, start_wire
, end_wire
, seg
->initprot
, FALSE
, kc_type
);
7061 if (result
!= KERN_SUCCESS
) {
7066 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7073 /*********************************************************************
7074 *********************************************************************/
7076 OSKext::segmentShouldBeWired(kernel_segment_command_t
*seg
)
7078 return sKeepSymbols
|| (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) &&
7079 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)));
7082 /*********************************************************************
7083 *********************************************************************/
7085 OSKext::validateKextMapping(bool startFlag
)
7087 OSReturn result
= kOSReturnError
;
7088 const char * whichOp
= startFlag
? "start" : "stop";
7089 kern_return_t kern_result
= 0;
7090 vm_map_t kext_map
= NULL
;
7091 kernel_segment_command_t
* seg
= NULL
;
7092 mach_vm_address_t address
= 0;
7093 mach_vm_size_t size
= 0;
7095 uint64_t kext_segbase
= 0;
7096 uint64_t kext_segsize
= 0;
7097 mach_msg_type_number_t count
;
7098 vm_region_submap_short_info_data_64_t info
;
7099 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
7101 if (flags
.builtin
) {
7102 return kOSReturnSuccess
;
7105 count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
7106 bzero(&info
, sizeof(info
));
7108 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7109 // xxx - sufficient?
7111 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7115 kOSKextLogErrorLevel
|
7117 "Kext %s - NULL kmod_info pointer.",
7118 getIdentifierCString());
7119 result
= kOSKextReturnBadData
;
7124 address
= (mach_vm_address_t
)kmod_info
->start
;
7126 address
= (mach_vm_address_t
)kmod_info
->stop
;
7131 kOSKextLogErrorLevel
|
7133 "Kext %s - NULL module %s pointer.",
7134 getIdentifierCString(), whichOp
);
7135 result
= kOSKextReturnBadData
;
7139 kext_map
= kext_get_vm_map(kmod_info
);
7140 depth
= (kernel_map
== kext_map
) ? 1 : 2;
7141 if (isInFileset()) {
7142 #if defined(HAS_APPLE_PAC)
7143 address
= (mach_vm_address_t
)ptrauth_auth_data((void*)address
, ptrauth_key_function_pointer
, 0);
7144 #endif /* defined(HAS_APPLE_PAC) */
7147 /* Verify that the start/stop function lies within the kext's address range.
7149 if (getcommandfromheader((kernel_mach_header_t
*)kmod_info
->address
, LC_SEGMENT_SPLIT_INFO
) ||
7151 /* This will likely be how we deal with split kexts; walk the segments to
7152 * check that the function lies inside one of the segments of this kext.
7154 for (seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7156 seg
= nextsegfromheader((kernel_mach_header_t
*)kmod_info
->address
, seg
)) {
7157 if ((address
>= seg
->vmaddr
) && address
< (seg
->vmaddr
+ seg
->vmsize
)) {
7158 kext_segbase
= seg
->vmaddr
;
7159 kext_segsize
= seg
->vmsize
;
7166 kOSKextLogErrorLevel
|
7168 "Kext %s module %s pointer is outside of kext range "
7169 "(%s %p - kext starts at %p).",
7170 getIdentifierCString(),
7173 (void *)(((uintptr_t)address
) - kext_slide
),
7174 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
));
7175 result
= kOSKextReturnBadData
;
7181 if (address
< kmod_info
->address
+ kmod_info
->hdr_size
||
7182 kmod_info
->address
+ kmod_info
->size
<= address
) {
7184 kOSKextLogErrorLevel
|
7186 "Kext %s module %s pointer is outside of kext range "
7187 "(%s %p - kext at %p-%p).",
7188 getIdentifierCString(),
7191 (void *)(((uintptr_t)address
) - kext_slide
),
7192 (void *)(((uintptr_t)kmod_info
->address
) - kext_slide
),
7193 (void *)((((uintptr_t)kmod_info
->address
) - kext_slide
) + kmod_info
->size
));
7194 result
= kOSKextReturnBadData
;
7199 /* Only do these checks before calling the start function;
7200 * If anything goes wrong with the mapping while the kext is running,
7201 * we'll likely have panicked well before any attempt to stop the kext.
7204 if (!isInFileset() || kc_type
!= KCKindPrimary
) {
7206 * Verify that the start/stop function is executable.
7208 kern_result
= mach_vm_region_recurse(kernel_map
, &address
, &size
, &depth
,
7209 (vm_region_recurse_info_t
)&info
, &count
);
7210 if (kern_result
!= KERN_SUCCESS
) {
7212 kOSKextLogErrorLevel
|
7214 "Kext %s - bad %s pointer %p.",
7215 getIdentifierCString(),
7216 whichOp
, (void *)ml_static_unslide(address
));
7217 result
= kOSKextReturnBadData
;
7222 * Since kexts loaded from the primary KC are held in memory
7223 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7224 * discover that memory's protection flags. Instead, we need to
7225 * get that information from the kernel pmap itself. Above, we
7226 * (potentially) saved the size of the segment in which the address
7227 * in question was located. If we have a non-zero size, verify
7228 * that all pages in the (address, address + kext_segsize) range
7229 * are marked executable. If we somehow did not record the size
7230 * (or the base) just verify the single page that includes the address.
7232 if (kext_segbase
== 0 || kext_segsize
== 0) {
7233 kext_segbase
= address
& ~(uint64_t)PAGE_MASK
;
7234 kext_segsize
= PAGE_SIZE
;
7239 if (((!isInFileset() || kc_type
!= KCKindPrimary
) && !(info
.protection
& VM_PROT_EXECUTE
)) ||
7240 ((isInFileset() && kc_type
== KCKindPrimary
) &&
7241 ml_static_verify_page_protections(kext_segbase
, kext_segsize
, VM_PROT_EXECUTE
) != KERN_SUCCESS
)) {
7243 kOSKextLogErrorLevel
|
7245 "Kext %s - memory region containing module %s function "
7246 "is not executable.",
7247 getIdentifierCString(), whichOp
);
7248 result
= kOSKextReturnBadData
;
7253 /* Verify that the kext's segments are backed by physical memory.
7255 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7257 if (!verifySegmentMapping(seg
)) {
7258 result
= kOSKextReturnBadData
;
7262 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7266 result
= kOSReturnSuccess
;
7271 /*********************************************************************
7272 *********************************************************************/
7274 OSKext::verifySegmentMapping(kernel_segment_command_t
*seg
)
7276 mach_vm_address_t address
= 0;
7278 if (seg
->vmsize
> UINT32_MAX
) {
7282 if (!segmentShouldBeWired(seg
)) {
7286 for (address
= seg
->vmaddr
;
7287 address
< round_page(seg
->vmaddr
+ seg
->vmsize
);
7288 address
+= PAGE_SIZE
) {
7289 if (!pmap_find_phys(kernel_pmap
, (vm_offset_t
)address
)) {
7291 kOSKextLogErrorLevel
|
7293 "Kext %s - page %p is not backed by physical memory.",
7294 getIdentifierCString(),
7303 /*********************************************************************
7304 *********************************************************************/
7306 OSKextLogKextInfo(OSKext
*aKext
, uint64_t address
, uint64_t size
, firehose_tracepoint_code_t code
)
7309 firehose_tracepoint_id_u trace_id
;
7310 struct firehose_trace_uuid_info_s uuid_info_s
;
7311 firehose_trace_uuid_info_t uuid_info
= &uuid_info_s
;
7312 size_t uuid_info_len
= sizeof(struct firehose_trace_uuid_info_s
);
7313 OSSharedPtr
<OSData
> uuid_data
;
7315 stamp
= firehose_tracepoint_time(firehose_activity_flags_default
);
7316 trace_id
.ftid_value
= FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata
, _firehose_tracepoint_type_metadata_kext
, (firehose_tracepoint_flags_t
)0, code
);
7318 uuid_data
= aKext
->copyTextUUID();
7320 memcpy(uuid_info
->ftui_uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_info
->ftui_uuid
));
7323 uuid_info
->ftui_size
= size
;
7324 if (aKext
->isDriverKit()) {
7325 uuid_info
->ftui_address
= address
;
7327 uuid_info
->ftui_address
= ml_static_unslide(address
);
7329 firehose_trace_metadata(firehose_stream_metadata
, trace_id
, stamp
, uuid_info
, uuid_info_len
);
7334 OSKext::OSKextLogDriverKitInfoLoad(OSKext
*kext
)
7336 OSKextLogKextInfo(kext
, kext
->getLoadTag(), 1, firehose_tracepoint_code_load
);
7339 /*********************************************************************
7340 *********************************************************************/
7342 OSKext::start(bool startDependenciesFlag
)
7344 OSReturn result
= kOSReturnError
;
7345 kern_return_t (* startfunc
)(kmod_info_t
*, void *);
7346 unsigned int i
, count
;
7347 void * kmodStartData
= NULL
;
7349 if (isStarted() || isInterface() || isKernelComponent()) {
7350 result
= kOSReturnSuccess
;
7356 kOSKextLogErrorLevel
|
7358 "Attempt to start nonloaded kext %s.",
7359 getIdentifierCString());
7360 result
= kOSKextReturnInvalidArgument
;
7364 if (!sLoadEnabled
) {
7366 kOSKextLogErrorLevel
|
7368 "Kext loading is disabled (attempt to start kext %s).",
7369 getIdentifierCString());
7370 result
= kOSKextReturnDisabled
;
7374 result
= validateKextMapping(/* start? */ true);
7375 if (result
!= kOSReturnSuccess
) {
7379 startfunc
= kmod_info
->start
;
7381 count
= getNumDependencies();
7382 for (i
= 0; i
< count
; i
++) {
7383 OSKext
* dependency
= OSDynamicCast(OSKext
, dependencies
->getObject(i
));
7384 if (dependency
== NULL
) {
7386 kOSKextLogErrorLevel
|
7388 "Kext %s start - internal error, dependency disappeared.",
7389 getIdentifierCString());
7392 if (!dependency
->isStarted()) {
7393 if (startDependenciesFlag
) {
7394 OSReturn dependencyResult
=
7395 dependency
->start(startDependenciesFlag
);
7396 if (dependencyResult
!= KERN_SUCCESS
) {
7398 kOSKextLogErrorLevel
|
7400 "Kext %s start - dependency %s failed to start (error 0x%x).",
7401 getIdentifierCString(),
7402 dependency
->getIdentifierCString(),
7408 kOSKextLogErrorLevel
|
7410 "Not starting %s - dependency %s not started yet.",
7411 getIdentifierCString(),
7412 dependency
->getIdentifierCString());
7413 result
= kOSKextReturnStartStopError
; // xxx - make new return?
7420 kOSKextLogDetailLevel
|
7422 "Kext %s calling module start function.",
7423 getIdentifierCString());
7427 // Drop a log message so logd can grab the needed information to decode this kext
7428 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_load
);
7429 result
= OSRuntimeInitializeCPP(this);
7430 if (result
== KERN_SUCCESS
) {
7431 result
= startfunc(kmod_info
, kmodStartData
);
7436 /* On success overlap the setting of started/starting. On failure just
7439 if (result
== KERN_SUCCESS
) {
7442 // xxx - log start error from kernel?
7444 kOSKextLogProgressLevel
|
7446 "Kext %s is now started.",
7447 getIdentifierCString());
7449 invokeOrCancelRequestCallbacks(
7450 /* result not actually used */ kOSKextReturnStartStopError
,
7451 /* invokeFlag */ false);
7453 kOSKextLogWarningLevel
|
7455 "Kext %s did not start (return code 0x%x).",
7456 getIdentifierCString(), result
);
7463 /*********************************************************************
7464 *********************************************************************/
7467 OSKext::canUnloadKextWithIdentifier(
7468 OSString
* kextIdentifier
,
7469 bool checkClassesFlag
)
7471 bool result
= false;
7472 OSKext
* aKext
= NULL
; // do not release
7474 IORecursiveLockLock(sKextLock
);
7476 aKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
7479 goto finish
; // can't unload what's not loaded
7482 if (aKext
->isLoaded()) {
7483 if (aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) {
7486 if (checkClassesFlag
&& aKext
->hasOSMetaClassInstances()) {
7494 IORecursiveLockUnlock(sKextLock
);
7498 /*********************************************************************
7499 *********************************************************************/
7503 OSReturn result
= kOSReturnError
;
7504 kern_return_t (*stopfunc
)(kmod_info_t
*, void *);
7506 if (!isStarted() || isInterface()) {
7507 result
= kOSReturnSuccess
;
7513 kOSKextLogErrorLevel
|
7515 "Attempt to stop nonloaded kext %s.",
7516 getIdentifierCString());
7517 result
= kOSKextReturnInvalidArgument
;
7521 /* Refuse to stop if we have clients or instances. It is up to
7522 * the caller to make sure those aren't true.
7524 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7526 kOSKextLogErrorLevel
|
7528 "Kext %s - C++ instances; can't stop.",
7529 getIdentifierCString());
7530 result
= kOSKextReturnInUse
;
7534 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7536 kOSKextLogErrorLevel
|
7538 "Kext %s - has references (linkage or tracking object); "
7540 getIdentifierCString());
7541 result
= kOSKextReturnInUse
;
7545 /* Note: If validateKextMapping fails on the stop & unload path,
7546 * we are in serious trouble and a kernel panic is likely whether
7547 * we stop & unload the kext or not.
7549 result
= validateKextMapping(/* start? */ false);
7550 if (result
!= kOSReturnSuccess
) {
7554 stopfunc
= kmod_info
->stop
;
7557 kOSKextLogDetailLevel
|
7559 "Kext %s calling module stop function.",
7560 getIdentifierCString());
7564 result
= stopfunc(kmod_info
, /* userData */ NULL
);
7565 if (result
== KERN_SUCCESS
) {
7566 result
= OSRuntimeFinalizeCPP(this);
7571 if (result
== KERN_SUCCESS
) {
7575 kOSKextLogDetailLevel
|
7577 "Kext %s is now stopped and ready to unload.",
7578 getIdentifierCString());
7581 kOSKextLogErrorLevel
|
7583 "Kext %s did not stop (return code 0x%x).",
7584 getIdentifierCString(), result
);
7585 result
= kOSKextReturnStartStopError
;
7590 // Drop a log message so logd can update this kext's metadata
7591 OSKextLogKextInfo(this, kmod_info
->address
, kmod_info
->size
, firehose_tracepoint_code_unload
);
7595 /*********************************************************************
7596 *********************************************************************/
7598 OSKext::unload(void)
7600 OSReturn result
= kOSReturnError
;
7602 uint32_t num_kmod_refs
= 0;
7603 OSKextAccount
* freeAccount
;
7604 bool in_fileset
= false;
7606 if (!sUnloadEnabled
) {
7608 kOSKextLogErrorLevel
|
7610 "Kext unloading is disabled (%s).",
7611 this->getIdentifierCString());
7613 result
= kOSKextReturnDisabled
;
7617 // cache this result so we don't need to access the kmod_info after
7618 // it's been potentially free'd
7619 in_fileset
= isInFileset();
7621 /* Refuse to unload if we have clients or instances. It is up to
7622 * the caller to make sure those aren't true.
7624 if (getRetainCount() > kOSKextMinLoadedRetainCount
) {
7625 // xxx - Don't log under errors? this is more of an info thing
7627 kOSKextLogErrorLevel
|
7628 kOSKextLogKextBookkeepingFlag
,
7629 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7630 getIdentifierCString());
7631 result
= kOSKextReturnInUse
;
7635 if (isDriverKit()) {
7636 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7637 if (index
!= (unsigned int)-1) {
7638 sLoadedDriverKitKexts
->removeObject(index
);
7639 OSKextLogKextInfo(this, loadTag
, 1, firehose_tracepoint_code_unload
);
7645 result
= kOSReturnSuccess
;
7649 if (isKernelComponent()) {
7650 result
= kOSKextReturnInvalidArgument
;
7654 if (metaClasses
&& !OSMetaClass::removeClasses(metaClasses
.get())) {
7656 kOSKextLogErrorLevel
|
7657 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
7658 "Can't unload kext %s; classes have instances:",
7659 getIdentifierCString());
7660 reportOSMetaClassInstances(kOSKextLogErrorLevel
|
7661 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
);
7662 result
= kOSKextReturnInUse
;
7666 /* Note that the kext is unloading before running any code that
7667 * might be in the kext (request callbacks, module stop function).
7668 * We will deny certain requests made against a kext in the process
7671 flags
.unloading
= 1;
7673 /* Update the string describing the last kext to unload in case we panic.
7675 savePanicString(/* isLoading */ false);
7679 if (result
!= KERN_SUCCESS
) {
7681 kOSKextLogErrorLevel
|
7683 "Kext %s can't unload - module stop returned 0x%x.",
7684 getIdentifierCString(), (unsigned)result
);
7685 result
= kOSKextReturnStartStopError
;
7691 kOSKextLogProgressLevel
|
7693 "Kext %s unloading.",
7694 getIdentifierCString());
7697 struct list_head
*p
;
7698 struct list_head
*prev
;
7699 struct list_head
*next
;
7700 for (p
= pendingPgoHead
.next
; p
!= &pendingPgoHead
; p
= next
) {
7701 OSKextGrabPgoStruct
*s
= container_of(p
, OSKextGrabPgoStruct
, list_head
);
7702 s
->err
= OSKextGrabPgoDataLocked(this, s
->metadata
, instance_uuid
, s
->pSize
, s
->pBuffer
, s
->bufferSize
);
7709 IORecursiveLockWakeup(sKextLock
, s
, false);
7714 /* Even if we don't call the stop function, we want to be sure we
7715 * have no OSMetaClass references before unloading the kext executable
7716 * from memory. OSMetaClasses may have pointers into the kext executable
7717 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7720 metaClasses
->flushCollection();
7722 (void) OSRuntimeFinalizeCPP(this);
7724 /* Remove the kext from the list of loaded kexts, patch the gap
7725 * in the kmod_info_t linked list, and reset "kmod" to point to the
7726 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7728 index
= sLoadedKexts
->getNextIndexOfObject(this, 0);
7729 if (index
!= (unsigned int)-1) {
7730 sLoadedKexts
->removeObject(index
);
7732 OSKext
* nextKext
= OSDynamicCast(OSKext
,
7733 sLoadedKexts
->getObject(index
));
7737 OSKext
* gapKext
= OSDynamicCast(OSKext
,
7738 sLoadedKexts
->getObject(index
- 1));
7740 nextKext
->kmod_info
->next
= gapKext
->kmod_info
;
7741 } else { /* index == 0 */
7742 nextKext
->kmod_info
->next
= NULL
;
7746 OSKext
* lastKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getLastObject());
7747 if (lastKext
&& !lastKext
->isKernel()) {
7748 kmod
= lastKext
->kmod_info
;
7750 kmod
= NULL
; // clear the global kmod variable
7754 /* Clear out the kmod references that we're keeping for compatibility
7755 * with current panic backtrace code & kgmacros.
7756 * xxx - will want to update those bits sometime and remove this.
7758 num_kmod_refs
= getNumDependencies();
7759 if (num_kmod_refs
&& kmod_info
&& kmod_info
->reference_list
) {
7760 for (uint32_t refIndex
= 0; refIndex
< num_kmod_refs
; refIndex
++) {
7761 kmod_reference_t
* ref
= &(kmod_info
->reference_list
[refIndex
]);
7762 ref
->info
->reference_count
--;
7764 kfree(kmod_info
->reference_list
,
7765 num_kmod_refs
* sizeof(kmod_reference_t
));
7769 unregisterWithDTrace();
7770 #endif /* CONFIG_DTRACE */
7772 notifyKextUnloadObservers(this);
7775 IOSimpleLockLock(sKextAccountsLock
);
7776 account
->kext
= NULL
;
7777 if (account
->site
.tag
) {
7778 account
->site
.flags
|= VM_TAG_UNLOAD
;
7780 freeAccount
= account
;
7782 IOSimpleLockUnlock(sKextAccountsLock
);
7784 IODelete(freeAccount
, OSKextAccount
, 1);
7787 /* Unwire and free the linked executable.
7789 if (linkedExecutable
) {
7791 kasan_unload_kext((vm_offset_t
)linkedExecutable
->getBytesNoCopy(), linkedExecutable
->getLength());
7795 if (!isInterface() && (!in_fileset
|| flags
.resetSegmentsFromVnode
)) {
7796 kernel_segment_command_t
*seg
= NULL
;
7797 vm_map_t kext_map
= kext_get_vm_map(kmod_info
);
7801 kOSKextLogErrorLevel
|
7803 "Failed to free kext %s; couldn't find the kext map.",
7804 getIdentifierCString());
7805 result
= kOSKextReturnInternalError
;
7810 kOSKextLogProgressLevel
|
7812 "Kext %s unwiring and unmapping linked executable.",
7813 getIdentifierCString());
7815 seg
= firstsegfromheader((kernel_mach_header_t
*)kmod_info
->address
);
7817 if (segmentShouldBeWired(seg
)) {
7818 vm_map_offset_t start_wire
= trunc_page(seg
->vmaddr
);
7819 vm_map_offset_t end_wire
= round_page(seg
->vmaddr
+ seg
->vmsize
);
7821 result
= vm_map_unwire(kext_map
, start_wire
,
7823 if (result
!= KERN_SUCCESS
) {
7825 kOSKextLogErrorLevel
|
7827 "Failed to unwire kext %s.",
7828 getIdentifierCString());
7829 result
= kOSKextReturnInternalError
;
7834 seg
= nextsegfromheader((kernel_mach_header_t
*) kmod_info
->address
, seg
);
7836 #if defined(__x86_64__) || defined(__i386__)
7837 if (in_fileset
&& flags
.resetSegmentsFromVnode
) {
7838 IORecursiveLockLock(sKextLock
);
7839 resetKCFileSetSegments();
7840 IORecursiveLockUnlock(sKextLock
);
7842 #endif // (__x86_64__) || defined(__i386__)
7844 #endif /* VM_MAPPED_KEXTS */
7845 if (flags
.resetSegmentsFromImmutableCopy
) {
7846 result
= resetMutableSegments();
7847 if (result
!= kOSReturnSuccess
) {
7849 kOSKextLogErrorLevel
|
7851 "Failed to reset kext %s.",
7852 getIdentifierCString());
7853 result
= kOSKextReturnInternalError
;
7857 if (kc_type
== KCKindUnknown
) {
7858 linkedExecutable
.reset();
7862 /* An interface kext has a fake kmod_info that was allocated,
7863 * so we have to free it.
7865 if (isInterface()) {
7866 kfree(kmod_info
, sizeof(kmod_info_t
));
7874 flags
.loaded
= false;
7875 flushDependencies();
7877 /* save a copy of the bundle ID for us to check when deciding to
7878 * rebuild the kernel cache file. If a kext was already in the kernel
7879 * cache and unloaded then later loaded we do not need to rebuild the
7880 * kernel cache. 9055303
7882 if (isPrelinked()) {
7883 if (!_OSKextInUnloadedPrelinkedKexts(bundleID
.get())) {
7884 IORecursiveLockLock(sKextLock
);
7885 if (sUnloadedPrelinkedKexts
) {
7886 sUnloadedPrelinkedKexts
->setObject(bundleID
.get());
7888 IORecursiveLockUnlock(sKextLock
);
7893 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
7894 "Kext %s unloaded.", getIdentifierCString());
7896 queueKextNotification(kKextRequestPredicateUnloadNotification
,
7897 OSDynamicCast(OSString
, bundleID
.get()));
7900 OSKext::saveLoadedKextPanicList();
7901 OSKext::updateLoadedKextSummaries();
7903 flags
.unloading
= 0;
7907 /*********************************************************************
7908 * Assumes sKextLock is held.
7909 *********************************************************************/
7912 OSKext::queueKextNotification(
7913 const char * notificationName
,
7914 OSString
* kextIdentifier
)
7916 OSReturn result
= kOSReturnError
;
7917 OSSharedPtr
<OSDictionary
> loadRequest
;
7919 if (!kextIdentifier
) {
7920 result
= kOSKextReturnInvalidArgument
;
7924 /* Create a new request unless one is already sitting
7925 * in sKernelRequests for this bundle identifier
7927 result
= _OSKextCreateRequest(notificationName
, loadRequest
);
7928 if (result
!= kOSReturnSuccess
) {
7931 if (!_OSKextSetRequestArgument(loadRequest
.get(),
7932 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
)) {
7933 result
= kOSKextReturnNoMemory
;
7936 if (!sKernelRequests
->setObject(loadRequest
.get())) {
7937 result
= kOSKextReturnNoMemory
;
7941 /* We might want to only queue the notification if the IOKit daemon is active,
7942 * but that wouldn't work for embedded. Note that we don't care if
7943 * the ping immediately succeeds here so don't do anything with the
7944 * result of this call.
7946 OSKext::pingIOKitDaemon();
7948 result
= kOSReturnSuccess
;
7956 /*********************************************************************
7957 *********************************************************************/
7959 _OSKextConsiderDestroyingLinkContext(
7960 __unused thread_call_param_t p0
,
7961 __unused thread_call_param_t p1
)
7963 /* Take multiple locks in the correct order.
7965 IORecursiveLockLock(sKextLock
);
7966 IORecursiveLockLock(sKextInnerLock
);
7968 /* The first time we destroy the kxldContext is in the first
7969 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
7970 * before calling this function. Thereafter any call to this function
7971 * will actually destroy the context.
7973 if (sConsiderUnloadsCalled
&& sKxldContext
) {
7974 kxld_destroy_context(sKxldContext
);
7975 sKxldContext
= NULL
;
7978 /* Free the thread_call that was allocated to execute this function.
7980 if (sDestroyLinkContextThread
) {
7981 if (!thread_call_free(sDestroyLinkContextThread
)) {
7982 OSKextLog(/* kext */ NULL
,
7983 kOSKextLogErrorLevel
|
7984 kOSKextLogGeneralFlag
,
7985 "thread_call_free() failed for kext link context.");
7987 sDestroyLinkContextThread
= NULL
;
7990 IORecursiveLockUnlock(sKextInnerLock
);
7991 IORecursiveLockUnlock(sKextLock
);
7996 /*********************************************************************
7997 * Destroying the kxldContext requires checking variables under both
7998 * sKextInnerLock and sKextLock, so we do it on a separate thread
7999 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8000 * call relationship.
8002 * This function must be invoked with sKextInnerLock held.
8003 * Do not call any function that takes sKextLock here!
8004 *********************************************************************/
8007 OSKext::considerDestroyingLinkContext(void)
8009 IORecursiveLockLock(sKextInnerLock
);
8011 /* If we have already queued a thread to destroy the link context,
8012 * don't bother resetting; that thread will take care of it.
8014 if (sDestroyLinkContextThread
) {
8018 /* The function to be invoked in the thread will deallocate
8019 * this thread_call, so don't share it around.
8021 sDestroyLinkContextThread
= thread_call_allocate(
8022 &_OSKextConsiderDestroyingLinkContext
, NULL
);
8023 if (!sDestroyLinkContextThread
) {
8024 OSKextLog(/* kext */ NULL
,
8025 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
| kOSKextLogLinkFlag
,
8026 "Can't create thread to destroy kext link context.");
8030 thread_call_enter(sDestroyLinkContextThread
);
8033 IORecursiveLockUnlock(sKextInnerLock
);
8037 #else // !CONFIG_KXLD
8041 OSKext::considerDestroyingLinkContext(void)
8046 #endif // CONFIG_KXLD
8049 #pragma mark Autounload
8051 /*********************************************************************
8052 * This is a static method because the kext will be deallocated if it
8054 *********************************************************************/
8057 OSKext::autounloadKext(OSKext
* aKext
)
8059 OSReturn result
= kOSKextReturnInUse
;
8063 * Do not unload prelinked kexts on platforms that do not have an
8064 * IOKit daemon as there is no way to reload the kext or restart
8067 if (aKext
->isPrelinked()) {
8070 #endif /* defined(__x86_64__) */
8072 /* Check for external references to this kext (usu. dependents),
8073 * instances of defined classes (or classes derived from them),
8074 * outstanding requests.
8076 if ((aKext
->getRetainCount() > kOSKextMinLoadedRetainCount
) ||
8077 !aKext
->flags
.autounloadEnabled
||
8078 aKext
->isKernelComponent()) {
8082 /* Skip a delay-autounload kext, once.
8084 if (aKext
->flags
.delayAutounload
) {
8086 kOSKextLogProgressLevel
|
8087 kOSKextLogLoadFlag
| kOSKextLogKextBookkeepingFlag
,
8088 "Kext %s has delayed autounload set; skipping and clearing flag.",
8089 aKext
->getIdentifierCString());
8090 aKext
->flags
.delayAutounload
= 0;
8094 if (aKext
->hasOSMetaClassInstances() ||
8095 aKext
->countRequestCallbacks()) {
8099 result
= OSKext::removeKext(aKext
);
8105 /*********************************************************************
8106 *********************************************************************/
8108 _OSKextConsiderUnloads(
8109 __unused thread_call_param_t p0
,
8110 __unused thread_call_param_t p1
)
8112 bool didUnload
= false;
8113 unsigned int count
, i
;
8115 /* Take multiple locks in the correct order
8116 * (note also sKextSummaries lock further down).
8118 IORecursiveLockLock(sKextLock
);
8119 IORecursiveLockLock(sKextInnerLock
);
8121 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8123 /* If the system is powering down, don't try to unload anything.
8129 OSKextLog(/* kext */ NULL
,
8130 kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
8131 "Checking for unused kexts to autounload.");
8134 * Remove any request callbacks marked as stale,
8135 * and mark as stale any currently in flight.
8137 count
= sRequestCallbackRecords
->getCount();
8141 OSDictionary
* callbackRecord
= OSDynamicCast(OSDictionary
,
8142 sRequestCallbackRecords
->getObject(i
));
8143 OSBoolean
* stale
= OSDynamicCast(OSBoolean
,
8144 callbackRecord
->getObject(kKextRequestStaleKey
));
8146 if (stale
== kOSBooleanTrue
) {
8147 OSKext::invokeRequestCallback(callbackRecord
,
8148 kOSKextReturnTimeout
);
8150 callbackRecord
->setObject(kKextRequestStaleKey
,
8157 * Make multiple passes through the array of loaded kexts until
8158 * we don't unload any. This handles unwinding of dependency
8159 * chains. We have to go *backwards* through the array because
8160 * kexts are removed from it when unloaded, and we cannot make
8161 * a copy or we'll mess up the retain counts we rely on to
8162 * check whether a kext will unload. If only we could have
8163 * nonretaining collections like CF has....
8168 count
= sLoadedKexts
->getCount();
8172 OSKext
* thisKext
= OSDynamicCast(OSKext
,
8173 sLoadedKexts
->getObject(i
));
8174 didUnload
|= (kOSReturnSuccess
== OSKext::autounloadKext(thisKext
));
8177 } while (didUnload
);
8180 sConsiderUnloadsPending
= false;
8181 sConsiderUnloadsExecuted
= true;
8183 (void) OSKext::considerRebuildOfPrelinkedKernel();
8185 IORecursiveLockUnlock(sKextInnerLock
);
8186 IORecursiveLockUnlock(sKextLock
);
8191 /*********************************************************************
8192 * Do not call any function that takes sKextLock here!
8193 *********************************************************************/
8195 OSKext::considerUnloads(Boolean rescheduleOnlyFlag
)
8199 IORecursiveLockLock(sKextInnerLock
);
8201 if (!sUnloadCallout
) {
8202 sUnloadCallout
= thread_call_allocate(&_OSKextConsiderUnloads
, NULL
);
8205 /* we only reset delay value for unloading if we already have something
8206 * pending. rescheduleOnlyFlag should not start the count down.
8208 if (rescheduleOnlyFlag
&& !sConsiderUnloadsPending
) {
8212 thread_call_cancel(sUnloadCallout
);
8213 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8215 && sIOKitDaemonActive
8218 clock_interval_to_deadline(sConsiderUnloadDelay
,
8219 1000 * 1000 * 1000, &when
);
8221 OSKextLog(/* kext */ NULL
,
8222 kOSKextLogProgressLevel
|
8224 "%scheduling %sscan for unused kexts in %lu seconds.",
8225 sConsiderUnloadsPending
? "Res" : "S",
8226 sConsiderUnloadsCalled
? "" : "initial ",
8227 (unsigned long)sConsiderUnloadDelay
);
8229 sConsiderUnloadsPending
= true;
8230 thread_call_enter_delayed(sUnloadCallout
, when
);
8234 /* The kxld context should be reused throughout boot. We mark the end of
8235 * period as the first time considerUnloads() is called, and we destroy
8236 * the first kxld context in that function. Afterwards, it will be
8237 * destroyed in flushNonloadedKexts.
8239 if (!sConsiderUnloadsCalled
) {
8240 sConsiderUnloadsCalled
= true;
8241 OSKext::considerDestroyingLinkContext();
8244 IORecursiveLockUnlock(sKextInnerLock
);
8248 /*********************************************************************
8249 * Do not call any function that takes sKextLock here!
8250 *********************************************************************/
8252 IOReturn
OSKextSystemSleepOrWake(UInt32 messageType
);
8254 OSKextSystemSleepOrWake(UInt32 messageType
)
8256 IORecursiveLockLock(sKextInnerLock
);
8258 /* If the system is going to sleep, cancel the reaper thread timer,
8259 * and note that we're in a sleep state in case it just fired but hasn't
8260 * taken the lock yet. If we are coming back from sleep, just
8261 * clear the sleep flag; IOService's normal operation will cause
8262 * unloads to be considered soon enough.
8264 if (messageType
== kIOMessageSystemWillSleep
) {
8265 if (sUnloadCallout
) {
8266 thread_call_cancel(sUnloadCallout
);
8268 sSystemSleep
= true;
8269 AbsoluteTime_to_scalar(&sLastWakeTime
) = 0;
8270 } else if (messageType
== kIOMessageSystemHasPoweredOn
) {
8271 sSystemSleep
= false;
8272 clock_get_uptime(&sLastWakeTime
);
8274 IORecursiveLockUnlock(sKextInnerLock
);
8276 return kIOReturnSuccess
;
8282 #pragma mark Prelinked Kernel
8286 /*********************************************************************
8287 * Do not access sConsiderUnloads... variables other than
8288 * sConsiderUnloadsExecuted in this function. They are guarded by a
8290 *********************************************************************/
8293 OSKext::considerRebuildOfPrelinkedKernel(void)
8295 static bool requestedPrelink
= false;
8296 OSReturn checkResult
= kOSReturnError
;
8297 OSSharedPtr
<OSDictionary
> prelinkRequest
;
8298 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
8299 const OSSymbol
* thisID
= NULL
; // do not release
8300 bool doRebuild
= false;
8301 AbsoluteTime my_abstime
;
8305 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8306 if (requestedPrelink
|| !sPrelinkBoot
) {
8310 /* no direct return from this point */
8311 IORecursiveLockLock(sKextLock
);
8313 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8314 * and any new startup kexts loaded.
8316 if (!sConsiderUnloadsExecuted
||
8317 !sDeferredLoadSucceeded
) {
8321 /* we really only care about boot / system start up related kexts so bail
8322 * if we're here after REBUILD_MAX_TIME.
8324 if (!_OSKextInPrelinkRebuildWindow()) {
8325 OSKextLog(/* kext */ NULL
,
8326 kOSKextLogArchiveFlag
,
8327 "%s prebuild rebuild has expired",
8329 requestedPrelink
= true;
8333 /* we do not want to trigger a rebuild if we get here too close to waking
8334 * up. (see radar 10233768)
8336 IORecursiveLockLock(sKextInnerLock
);
8338 clock_get_uptime(&my_abstime
);
8339 delta_secs
= MINIMUM_WAKEUP_SECONDS
+ 1;
8340 if (AbsoluteTime_to_scalar(&sLastWakeTime
) != 0) {
8341 SUB_ABSOLUTETIME(&my_abstime
, &sLastWakeTime
);
8342 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
8343 delta_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
8345 IORecursiveLockUnlock(sKextInnerLock
);
8347 if (delta_secs
< MINIMUM_WAKEUP_SECONDS
) {
8348 /* too close to time of last wake from sleep */
8351 requestedPrelink
= true;
8353 /* Now it's time to see if we have a reason to rebuild. We may have done
8354 * some loads and unloads but the kernel cache didn't actually change.
8355 * We will rebuild if any kext is not marked prelinked AND is not in our
8356 * list of prelinked kexts that got unloaded. (see radar 9055303)
8358 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
8359 if (!kextIterator
) {
8363 while ((thisID
= OSDynamicCast(OSSymbol
, kextIterator
->getNextObject()))) {
8364 OSKext
* thisKext
; // do not release
8366 thisKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(thisID
));
8367 if (!thisKext
|| thisKext
->isPrelinked() || thisKext
->isKernel()) {
8371 if (_OSKextInUnloadedPrelinkedKexts(thisKext
->bundleID
.get())) {
8374 /* kext is loaded and was not in current kernel cache so let's rebuild
8377 OSKextLog(/* kext */ NULL
,
8378 kOSKextLogArchiveFlag
,
8379 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8380 thisKext
->bundleID
->getCStringNoCopy());
8383 sUnloadedPrelinkedKexts
->flushCollection();
8389 checkResult
= _OSKextCreateRequest(kKextRequestPredicateRequestPrelink
,
8391 if (checkResult
!= kOSReturnSuccess
) {
8395 if (!sKernelRequests
->setObject(prelinkRequest
.get())) {
8399 OSKext::pingIOKitDaemon();
8402 IORecursiveLockUnlock(sKextLock
);
8407 #else /* !CONFIG_KXLD */
8410 OSKext::considerRebuildOfPrelinkedKernel(void)
8412 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8416 #endif /* CONFIG_KXLD */
8419 #pragma mark Dependencies
8421 /*********************************************************************
8422 *********************************************************************/
8424 OSKext::resolveDependencies(
8425 OSArray
* loopStack
)
8427 bool result
= false;
8428 OSSharedPtr
<OSArray
> localLoopStack
;
8429 bool addedToLoopStack
= false;
8430 OSDictionary
* libraries
= NULL
; // do not release
8431 OSSharedPtr
<OSCollectionIterator
> libraryIterator
;
8432 OSString
* libraryID
= NULL
; // do not release
8433 OSKext
* libraryKext
= NULL
; // do not release
8434 bool hasRawKernelDependency
= false;
8435 bool hasKernelDependency
= false;
8436 bool hasKPIDependency
= false;
8437 bool hasPrivateKPIDependency
= false;
8441 OSString
* infoString
= NULL
; // do not release
8442 OSString
* readableString
= NULL
; // do not release
8443 #endif // CONFIG_KXLD
8445 /* A kernel component will automatically have this flag set,
8446 * and a loaded kext should also have it set (as should all its
8447 * loaded dependencies).
8449 if (flags
.hasAllDependencies
) {
8454 /* Check for loops in the dependency graph.
8457 if (loopStack
->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8459 kOSKextLogErrorLevel
|
8460 kOSKextLogDependenciesFlag
,
8461 "Kext %s has a dependency loop; can't resolve dependencies.",
8462 getIdentifierCString());
8467 kOSKextLogStepLevel
|
8468 kOSKextLogDependenciesFlag
,
8469 "Kext %s resolving dependencies.",
8470 getIdentifierCString());
8472 localLoopStack
= OSArray::withCapacity(6); // any small capacity will do
8473 if (!localLoopStack
) {
8475 kOSKextLogErrorLevel
|
8476 kOSKextLogDependenciesFlag
,
8477 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8478 getIdentifierCString());
8481 loopStack
= localLoopStack
.get();
8483 if (!loopStack
->setObject(this)) {
8485 kOSKextLogErrorLevel
|
8486 kOSKextLogDependenciesFlag
,
8487 "Kext %s - internal error resolving dependencies.",
8488 getIdentifierCString());
8491 addedToLoopStack
= true;
8493 /* Purge any existing kexts in the dependency list and start over.
8495 flushDependencies();
8498 kOSKextLogErrorLevel
|
8499 kOSKextLogDependenciesFlag
,
8500 "Kext %s - internal error resolving dependencies.",
8501 getIdentifierCString());
8504 libraries
= OSDynamicCast(OSDictionary
,
8505 getPropertyForHostArch(kOSBundleLibrariesKey
));
8506 if (libraries
== NULL
|| libraries
->getCount() == 0) {
8508 kOSKextLogErrorLevel
|
8509 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8510 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8511 getIdentifierCString(), kOSBundleLibrariesKey
);
8515 /* Make a new array to hold the dependencies (flush freed the old one).
8517 dependencies
= OSArray::withCapacity(libraries
->getCount());
8518 if (!dependencies
) {
8520 kOSKextLogErrorLevel
|
8521 kOSKextLogDependenciesFlag
,
8522 "Kext %s - can't allocate dependencies array.",
8523 getIdentifierCString());
8527 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8528 // xxx - compat: if none were declared.
8530 libraryIterator
= OSCollectionIterator::withCollection(libraries
);
8531 if (!libraryIterator
) {
8533 kOSKextLogErrorLevel
|
8534 kOSKextLogDependenciesFlag
,
8535 "Kext %s - can't allocate dependencies iterator.",
8536 getIdentifierCString());
8540 while ((libraryID
= OSDynamicCast(OSString
,
8541 libraryIterator
->getNextObject()))) {
8542 const char * library_id
= libraryID
->getCStringNoCopy();
8544 OSString
* libraryVersion
= OSDynamicCast(OSString
,
8545 libraries
->getObject(libraryID
));
8546 if (libraryVersion
== NULL
) {
8548 kOSKextLogErrorLevel
|
8549 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8550 "Kext %s - illegal type in OSBundleLibraries.",
8551 getIdentifierCString());
8555 OSKextVersion libraryVers
=
8556 OSKextParseVersionString(libraryVersion
->getCStringNoCopy());
8557 if (libraryVers
== -1) {
8559 kOSKextLogErrorLevel
|
8560 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8561 "Kext %s - invalid library version %s.",
8562 getIdentifierCString(),
8563 libraryVersion
->getCStringNoCopy());
8567 libraryKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(libraryID
));
8568 if (libraryKext
== NULL
) {
8570 kOSKextLogErrorLevel
|
8571 kOSKextLogDependenciesFlag
,
8572 "Kext %s - library kext %s not found.",
8573 getIdentifierCString(), library_id
);
8577 if (!libraryKext
->isCompatibleWithVersion(libraryVers
)) {
8579 kOSKextLogErrorLevel
|
8580 kOSKextLogDependenciesFlag
,
8581 "Kext %s - library kext %s not compatible "
8582 "with requested version %s.",
8583 getIdentifierCString(), library_id
,
8584 libraryVersion
->getCStringNoCopy());
8588 /* If a nonprelinked library somehow got into the mix for a
8589 * prelinked kext, at any point in the chain, we must fail
8590 * because the prelinked relocs for the library will be all wrong.
8592 if (this->isPrelinked() &&
8593 libraryKext
->declaresExecutable() &&
8594 !libraryKext
->isPrelinked()) {
8596 kOSKextLogErrorLevel
|
8597 kOSKextLogDependenciesFlag
,
8598 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8599 getIdentifierCString(), library_id
,
8600 libraryVersion
->getCStringNoCopy());
8604 if (!libraryKext
->resolveDependencies(loopStack
)) {
8608 /* Add the library directly only if it has an executable to link.
8609 * Otherwise it's just used to collect other dependencies, so put
8610 * *its* dependencies on the list for this kext.
8612 // xxx - We are losing info here; would like to make fake entries or
8613 // xxx - keep these in the dependency graph for loaded kexts.
8614 // xxx - I really want to make kernel components not a special case!
8615 if (libraryKext
->declaresExecutable() ||
8616 libraryKext
->isInterface()) {
8617 if (dependencies
->getNextIndexOfObject(libraryKext
, 0) == (unsigned)-1) {
8618 dependencies
->setObject(libraryKext
);
8621 kOSKextLogDetailLevel
|
8622 kOSKextLogDependenciesFlag
,
8623 "Kext %s added dependency %s.",
8624 getIdentifierCString(),
8625 libraryKext
->getIdentifierCString());
8628 int numLibDependencies
= libraryKext
->getNumDependencies();
8629 OSArray
* libraryDependencies
= libraryKext
->getDependencies();
8632 if (numLibDependencies
) {
8633 // xxx - this msg level should be 1 lower than the per-kext one
8635 kOSKextLogDetailLevel
|
8636 kOSKextLogDependenciesFlag
,
8637 "Kext %s pulling %d dependencies from codeless library %s.",
8638 getIdentifierCString(),
8640 libraryKext
->getIdentifierCString());
8642 for (index
= 0; index
< numLibDependencies
; index
++) {
8643 OSKext
* thisLibDependency
= OSDynamicCast(OSKext
,
8644 libraryDependencies
->getObject(index
));
8645 if (dependencies
->getNextIndexOfObject(thisLibDependency
, 0) == (unsigned)-1) {
8646 dependencies
->setObject(thisLibDependency
);
8648 kOSKextLogDetailLevel
|
8649 kOSKextLogDependenciesFlag
,
8650 "Kext %s added dependency %s from codeless library %s.",
8651 getIdentifierCString(),
8652 thisLibDependency
->getIdentifierCString(),
8653 libraryKext
->getIdentifierCString());
8658 if ((strlen(library_id
) == strlen(KERNEL_LIB
)) &&
8659 0 == strncmp(library_id
, KERNEL_LIB
, sizeof(KERNEL_LIB
) - 1)) {
8660 hasRawKernelDependency
= true;
8661 } else if (STRING_HAS_PREFIX(library_id
, KERNEL_LIB_PREFIX
)) {
8662 hasKernelDependency
= true;
8663 } else if (STRING_HAS_PREFIX(library_id
, KPI_LIB_PREFIX
)) {
8664 hasKPIDependency
= true;
8665 if (!strncmp(library_id
, PRIVATE_KPI
, sizeof(PRIVATE_KPI
) - 1)) {
8666 hasPrivateKPIDependency
= true;
8671 if (hasRawKernelDependency
) {
8673 kOSKextLogErrorLevel
|
8674 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8675 "Error - kext %s declares a dependency on %s, which is not permitted.",
8676 getIdentifierCString(), KERNEL_LIB
);
8680 if (hasKernelDependency
) {
8682 kOSKextLogErrorLevel
|
8683 kOSKextLogValidationFlag
| kOSKextLogDependenciesFlag
,
8684 "Error - kext %s declares %s dependencies. "
8685 "Only %s* dependencies are supported for 64-bit kexts.",
8686 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8689 if (!hasKPIDependency
) {
8691 kOSKextLogWarningLevel
|
8692 kOSKextLogDependenciesFlag
,
8693 "Warning - kext %s declares no %s* dependencies. "
8694 "If it uses any KPIs, the link may fail with undefined symbols.",
8695 getIdentifierCString(), KPI_LIB_PREFIX
);
8697 #else /* __LP64__ */
8698 // xxx - will change to flatly disallow "kernel" dependencies at some point
8699 // xxx - is it invalid to do both "com.apple.kernel" and any
8700 // xxx - "com.apple.kernel.*"?
8702 if (hasKernelDependency
&& hasKPIDependency
) {
8704 kOSKextLogWarningLevel
|
8705 kOSKextLogDependenciesFlag
,
8706 "Warning - kext %s has immediate dependencies on both "
8707 "%s* and %s* components; use only one style.",
8708 getIdentifierCString(), KERNEL_LIB
, KPI_LIB_PREFIX
);
8711 if (!hasKernelDependency
&& !hasKPIDependency
) {
8712 // xxx - do we want to use validation flag for these too?
8714 kOSKextLogWarningLevel
|
8715 kOSKextLogDependenciesFlag
,
8716 "Warning - %s declares no kernel dependencies; using %s.",
8717 getIdentifierCString(), KERNEL6_LIB
);
8718 OSKext
* kernelKext
= OSDynamicCast(OSKext
,
8719 sKextsByID
->getObject(KERNEL6_LIB
));
8721 dependencies
->setObject(kernelKext
);
8724 kOSKextLogErrorLevel
|
8725 kOSKextLogDependenciesFlag
,
8726 "Error - Library %s not found for %s.",
8727 KERNEL6_LIB
, getIdentifierCString());
8731 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8732 * its indirect dependencies to simulate old-style linking. XXX - Should
8733 * check for duplicates.
8735 if (!hasKPIDependency
) {
8738 flags
.hasBleedthrough
= true;
8740 count
= getNumDependencies();
8742 /* We add to the dependencies array in this loop, but do not iterate
8743 * past its original count.
8745 for (i
= 0; i
< count
; i
++) {
8746 OSKext
* dependencyKext
= OSDynamicCast(OSKext
,
8747 dependencies
->getObject(i
));
8748 dependencyKext
->addBleedthroughDependencies(dependencies
.get());
8751 #endif /* __LP64__ */
8755 * If we're not dynamically linking kexts, then we don't need to check
8756 * copyright strings. The linker in user space has already done this.
8758 if (hasPrivateKPIDependency
) {
8759 bool hasApplePrefix
= false;
8760 bool infoCopyrightIsValid
= false;
8761 bool readableCopyrightIsValid
= false;
8763 hasApplePrefix
= STRING_HAS_PREFIX(getIdentifierCString(),
8766 infoString
= OSDynamicCast(OSString
,
8767 getPropertyForHostArch("CFBundleGetInfoString"));
8769 infoCopyrightIsValid
=
8770 kxld_validate_copyright_string(infoString
->getCStringNoCopy());
8773 readableString
= OSDynamicCast(OSString
,
8774 getPropertyForHostArch("NSHumanReadableCopyright"));
8775 if (readableString
) {
8776 readableCopyrightIsValid
=
8777 kxld_validate_copyright_string(readableString
->getCStringNoCopy());
8780 if (!hasApplePrefix
|| (!infoCopyrightIsValid
&& !readableCopyrightIsValid
)) {
8782 kOSKextLogErrorLevel
|
8783 kOSKextLogDependenciesFlag
,
8784 "Error - kext %s declares a dependency on %s. "
8785 "Only Apple kexts may declare a dependency on %s.",
8786 getIdentifierCString(), PRIVATE_KPI
, PRIVATE_KPI
);
8790 #endif // CONFIG_KXLD
8793 flags
.hasAllDependencies
= 1;
8797 if (addedToLoopStack
) {
8798 count
= loopStack
->getCount();
8799 if (count
> 0 && (this == loopStack
->getObject(count
- 1))) {
8800 loopStack
->removeObject(count
- 1);
8803 kOSKextLogErrorLevel
|
8804 kOSKextLogDependenciesFlag
,
8805 "Kext %s - internal error resolving dependencies.",
8806 getIdentifierCString());
8810 if (result
&& localLoopStack
) {
8812 kOSKextLogStepLevel
|
8813 kOSKextLogDependenciesFlag
,
8814 "Kext %s successfully resolved dependencies.",
8815 getIdentifierCString());
8821 /*********************************************************************
8822 *********************************************************************/
8824 OSKext::addBleedthroughDependencies(OSArray
* anArray
)
8826 bool result
= false;
8827 unsigned int dependencyIndex
, dependencyCount
;
8829 dependencyCount
= getNumDependencies();
8831 for (dependencyIndex
= 0;
8832 dependencyIndex
< dependencyCount
;
8833 dependencyIndex
++) {
8834 OSKext
* dependency
= OSDynamicCast(OSKext
,
8835 dependencies
->getObject(dependencyIndex
));
8838 kOSKextLogErrorLevel
|
8839 kOSKextLogDependenciesFlag
,
8840 "Kext %s - internal error propagating compatibility dependencies.",
8841 getIdentifierCString());
8844 if (anArray
->getNextIndexOfObject(dependency
, 0) == (unsigned int)-1) {
8845 anArray
->setObject(dependency
);
8847 dependency
->addBleedthroughDependencies(anArray
);
8856 /*********************************************************************
8857 *********************************************************************/
8859 OSKext::flushDependencies(bool forceFlag
)
8861 bool result
= false;
8863 /* Only clear the dependencies if the kext isn't loaded;
8864 * we need the info for loaded kexts to track references.
8866 if (!isLoaded() || forceFlag
) {
8868 // xxx - check level
8870 kOSKextLogProgressLevel
|
8871 kOSKextLogDependenciesFlag
,
8872 "Kext %s flushing dependencies.",
8873 getIdentifierCString());
8874 dependencies
.reset();
8876 if (!isKernelComponent()) {
8877 flags
.hasAllDependencies
= 0;
8885 /*********************************************************************
8886 *********************************************************************/
8888 OSKext::getNumDependencies(void)
8890 if (!dependencies
) {
8893 return dependencies
->getCount();
8896 /*********************************************************************
8897 *********************************************************************/
8899 OSKext::getDependencies(void)
8901 return dependencies
.get();
8905 OSKext::hasDependency(const OSSymbol
* depID
)
8907 bool result __block
;
8909 if (depID
== getIdentifier()) {
8912 if (!dependencies
) {
8916 dependencies
->iterateObjects(^bool (OSObject
* obj
) {
8918 kext
= OSDynamicCast(OSKext
, obj
);
8922 result
= (depID
== kext
->getIdentifier());
8929 #pragma mark OSMetaClass Support
8931 /*********************************************************************
8932 *********************************************************************/
8935 OSMetaClass
* aClass
,
8936 uint32_t numClasses
)
8938 OSReturn result
= kOSMetaClassNoInsKModSet
;
8941 metaClasses
= OSSet::withCapacity(numClasses
);
8947 if (metaClasses
->containsObject(aClass
)) {
8949 kOSKextLogWarningLevel
|
8951 "Notice - kext %s has already registered class %s.",
8952 getIdentifierCString(),
8953 aClass
->getClassName());
8954 result
= kOSReturnSuccess
;
8958 if (!metaClasses
->setObject(aClass
)) {
8962 kOSKextLogDetailLevel
|
8964 "Kext %s registered class %s.",
8965 getIdentifierCString(),
8966 aClass
->getClassName());
8969 if (!flags
.autounloadEnabled
) {
8970 const OSMetaClass
* metaScan
= NULL
; // do not release
8972 for (metaScan
= aClass
; metaScan
; metaScan
= metaScan
->getSuperClass()) {
8973 if (metaScan
== OSTypeID(IOService
)) {
8975 kOSKextLogProgressLevel
|
8977 "Kext %s has IOService subclass %s; enabling autounload.",
8978 getIdentifierCString(),
8979 aClass
->getClassName());
8981 flags
.autounloadEnabled
= 1;
8987 notifyAddClassObservers(this, aClass
, flags
);
8989 result
= kOSReturnSuccess
;
8992 if (result
!= kOSReturnSuccess
) {
8994 kOSKextLogErrorLevel
|
8996 "Kext %s failed to register class %s.",
8997 getIdentifierCString(),
8998 aClass
->getClassName());
9004 /*********************************************************************
9005 *********************************************************************/
9007 OSKext::removeClass(
9008 OSMetaClass
* aClass
)
9010 OSReturn result
= kOSMetaClassNoKModSet
;
9016 if (!metaClasses
->containsObject(aClass
)) {
9018 kOSKextLogWarningLevel
|
9020 "Notice - kext %s asked to unregister unknown class %s.",
9021 getIdentifierCString(),
9022 aClass
->getClassName());
9023 result
= kOSReturnSuccess
;
9028 kOSKextLogDetailLevel
|
9030 "Kext %s unregistering class %s.",
9031 getIdentifierCString(),
9032 aClass
->getClassName());
9034 metaClasses
->removeObject(aClass
);
9036 notifyRemoveClassObservers(this, aClass
, flags
);
9038 result
= kOSReturnSuccess
;
9041 if (result
!= kOSReturnSuccess
) {
9043 kOSKextLogErrorLevel
|
9045 "Failed to unregister kext %s class %s.",
9046 getIdentifierCString(),
9047 aClass
->getClassName());
9052 /*********************************************************************
9053 *********************************************************************/
9055 OSKext::getMetaClasses(void)
9057 return metaClasses
.get();
9060 /*********************************************************************
9061 *********************************************************************/
9063 OSKext::hasOSMetaClassInstances(void)
9065 bool result
= false;
9066 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9067 OSMetaClass
* checkClass
= NULL
; // do not release
9073 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9074 if (!classIterator
) {
9075 // xxx - log alloc failure?
9078 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9079 if (checkClass
->getInstanceCount()) {
9089 /*********************************************************************
9090 *********************************************************************/
9093 OSKext::reportOSMetaClassInstances(
9094 const char * kextIdentifier
,
9095 OSKextLogSpec msgLogSpec
)
9097 OSSharedPtr
<OSKext
> theKext
;
9099 theKext
= OSKext::lookupKextWithIdentifier(kextIdentifier
);
9104 theKext
->reportOSMetaClassInstances(msgLogSpec
);
9109 /*********************************************************************
9110 *********************************************************************/
9112 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec
)
9114 OSSharedPtr
<OSCollectionIterator
> classIterator
;
9115 OSMetaClass
* checkClass
= NULL
; // do not release
9121 classIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
9122 if (!classIterator
) {
9125 while ((checkClass
= (OSMetaClass
*)classIterator
->getNextObject())) {
9126 if (checkClass
->getInstanceCount()) {
9129 " Kext %s class %s has %d instance%s.",
9130 getIdentifierCString(),
9131 checkClass
->getClassName(),
9132 checkClass
->getInstanceCount(),
9133 checkClass
->getInstanceCount() == 1 ? "" : "s");
9142 #pragma mark User-Space Requests
9145 static kern_return_t
9146 patchDextLaunchRequests(task_t calling_task
, OSArray
*requests
)
9148 OSReturn result
= kOSReturnSuccess
;
9149 for (uint32_t requestIndex
= 0; requestIndex
< requests
->getCount(); requestIndex
++) {
9150 OSDictionary
* request
= NULL
; //do not release
9151 IOUserServerCheckInToken
* token
= NULL
; //do not release
9152 OSString
* requestPredicate
= NULL
; //do not release
9153 OSSharedPtr
<OSNumber
> portNameNumber
;
9154 mach_port_name_t portName
= 0;
9155 request
= OSDynamicCast(OSDictionary
, requests
->getObject(requestIndex
));
9157 OSKextLog(/* kext */ NULL
,
9158 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9159 "Elements of request should be of type OSDictionary");
9160 result
= kOSKextReturnInternalError
;
9163 requestPredicate
= _OSKextGetRequestPredicate(request
);
9164 if (!requestPredicate
) {
9165 OSKextLog(/* kext */ NULL
,
9166 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9167 "Failed to get request predicate");
9168 result
= kOSKextReturnInternalError
;
9171 // is this a dext launch?
9172 if (requestPredicate
->isEqualTo(kKextRequestPredicateRequestDaemonLaunch
)) {
9173 token
= OSDynamicCast(IOUserServerCheckInToken
, _OSKextGetRequestArgument(request
, kKextRequestArgumentCheckInToken
));
9175 OSKextLog(/* kext */ NULL
,
9176 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9177 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9178 result
= kOSKextReturnInternalError
;
9181 portName
= iokit_make_send_right(calling_task
, token
, IKOT_IOKIT_IDENT
);
9182 if (portName
== 0 || portName
== MACH_PORT_DEAD
) {
9183 OSKextLog(/* kext */ NULL
,
9184 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9185 "Could not create send right for object.");
9186 result
= kOSKextReturnInternalError
;
9189 // Store the mach port name as a OSNumber
9190 portNameNumber
= OSNumber::withNumber(portName
, CHAR_BIT
* sizeof(portName
));
9191 if (!portNameNumber
) {
9192 OSKextLog(/* kext */ NULL
,
9193 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9194 "Could not create OSNumber object.");
9195 result
= kOSKextReturnNoMemory
;
9198 if (!_OSKextSetRequestArgument(request
, kKextRequestArgumentCheckInToken
, portNameNumber
.get())) {
9199 OSKextLog(/* kext */ NULL
,
9200 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9201 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken
);
9202 result
= kOSKextReturnNoMemory
;
9207 if (result
!= kOSReturnSuccess
) {
9214 /*********************************************************************
9215 * XXX - this function is a big ugly mess
9216 *********************************************************************/
9219 OSKext::handleRequest(
9220 host_priv_t hostPriv
,
9221 OSKextLogSpec clientLogFilter
,
9222 char * requestBuffer
,
9223 uint32_t requestLength
,
9224 char ** responseOut
,
9225 uint32_t * responseLengthOut
,
9227 uint32_t * logInfoLengthOut
)
9229 OSReturn result
= kOSReturnError
;
9230 kern_return_t kmem_result
= KERN_FAILURE
;
9232 char * response
= NULL
; // returned by reference
9233 uint32_t responseLength
= 0;
9235 bool taskCanManageAllKCs
= false;
9236 bool taskOnlyManagesBootKC
= false;
9238 OSSharedPtr
<OSObject
> parsedXML
;
9239 OSDictionary
* requestDict
= NULL
; // do not release
9240 OSSharedPtr
<OSString
> errorString
;
9242 OSSharedPtr
<OSObject
> responseObject
;
9244 OSSharedPtr
<OSSerialize
> serializer
;
9246 OSSharedPtr
<OSArray
> logInfoArray
;
9248 OSString
* predicate
= NULL
; // do not release
9249 OSString
* kextIdentifier
= NULL
; // do not release
9250 OSArray
* kextIdentifiers
= NULL
; // do not release
9251 OSKext
* theKext
= NULL
; // do not release
9252 OSBoolean
* boolArg
= NULL
; // do not release
9254 IORecursiveLockLock(sKextLock
);
9257 *responseOut
= NULL
;
9258 *responseLengthOut
= 0;
9262 *logInfoLengthOut
= 0;
9265 OSKext::setUserSpaceLogFilter(clientLogFilter
, logInfoOut
? true : false);
9267 /* XML must be nul-terminated.
9269 if (requestBuffer
[requestLength
- 1] != '\0') {
9270 OSKextLog(/* kext */ NULL
,
9271 kOSKextLogErrorLevel
|
9273 "Invalid request from user space (not nul-terminated).");
9274 result
= kOSKextReturnBadData
;
9277 parsedXML
= OSUnserializeXML((const char *)requestBuffer
, errorString
);
9279 requestDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9282 const char * errorCString
= "(unknown error)";
9284 if (errorString
&& errorString
->getCStringNoCopy()) {
9285 errorCString
= errorString
->getCStringNoCopy();
9286 } else if (parsedXML
) {
9287 errorCString
= "not a dictionary";
9289 OSKextLog(/* kext */ NULL
,
9290 kOSKextLogErrorLevel
|
9292 "Error unserializing request from user space: %s.",
9294 result
= kOSKextReturnSerialization
;
9298 predicate
= _OSKextGetRequestPredicate(requestDict
);
9300 OSKextLog(/* kext */ NULL
,
9301 kOSKextLogErrorLevel
|
9303 "Recieved kext request from user space with no predicate.");
9304 result
= kOSKextReturnInvalidArgument
;
9308 OSKextLog(/* kext */ NULL
,
9309 kOSKextLogDebugLevel
|
9311 "Received '%s' request from user space.",
9312 predicate
->getCStringNoCopy());
9315 * All management of file sets requires an entitlement
9317 result
= kOSKextReturnNotPrivileged
;
9318 if (predicate
->isEqualTo(kKextRequestPredicateUnload
) ||
9319 predicate
->isEqualTo(kKextRequestPredicateStart
) ||
9320 predicate
->isEqualTo(kKextRequestPredicateStop
) ||
9321 predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9322 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9323 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9324 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9325 predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
) ||
9326 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9327 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9328 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9329 if (hostPriv
== HOST_PRIV_NULL
) {
9330 OSKextLog(/* kext */ NULL
,
9331 kOSKextLogErrorLevel
|
9333 "Access Failure - must be root user.");
9336 taskCanManageAllKCs
= IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement
) == TRUE
;
9337 taskOnlyManagesBootKC
= IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement
) == TRUE
;
9339 if (!taskCanManageAllKCs
&& !taskOnlyManagesBootKC
) {
9340 OSKextLog(/* kext */ NULL
,
9341 kOSKextLogErrorLevel
|
9343 "Access Failure - client not entitled to manage file sets.");
9348 * The OnlyBootKC entitlement restricts the
9349 * collection-management entitlement to only managing kexts in
9350 * the BootKC. All other predicates that alter global state or
9351 * add new KCs are disallowed.
9353 if (taskOnlyManagesBootKC
&&
9354 (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
) ||
9355 predicate
->isEqualTo(kKextRequestPredicateSendResource
) ||
9356 predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
) ||
9357 predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
) ||
9358 predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
) ||
9359 predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
) ||
9360 predicate
->isEqualTo(kKextRequestPredicateDaemonReady
))) {
9361 OSKextLog(/* kext */ NULL
,
9362 kOSKextLogErrorLevel
|
9364 "Access Failure - client not entitled to manage non-primary KCs");
9369 * If we get here, then the process either has the full KC
9370 * management entitlement, or it has the BootKC-only
9371 * entitlement and the request is about the BootKC.
9375 /* Get common args in anticipation of use.
9377 kextIdentifier
= OSDynamicCast(OSString
, _OSKextGetRequestArgument(
9378 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9379 kextIdentifiers
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
9380 requestDict
, kKextRequestArgumentBundleIdentifierKey
));
9381 if (kextIdentifier
) {
9382 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextIdentifier
));
9384 boolArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
9385 requestDict
, kKextRequestArgumentValueKey
));
9387 if (taskOnlyManagesBootKC
&&
9389 theKext
->isInFileset() &&
9390 theKext
->kc_type
!= KCKindPrimary
) {
9391 OSKextLog(/* kext */ NULL
,
9392 kOSKextLogErrorLevel
|
9394 "Access Failure - client not entitled to manage kext in non-primary KC");
9395 result
= kOSKextReturnNotPrivileged
;
9399 result
= kOSKextReturnInvalidArgument
;
9401 if (predicate
->isEqualTo(kKextRequestPredicateStart
)) {
9402 if (!kextIdentifier
) {
9403 OSKextLog(/* kext */ NULL
,
9404 kOSKextLogErrorLevel
|
9406 "Invalid arguments to kext start request.");
9407 } else if (!theKext
) {
9408 OSKextLog(/* kext */ NULL
,
9409 kOSKextLogErrorLevel
|
9411 "Kext %s not found for start request.",
9412 kextIdentifier
->getCStringNoCopy());
9413 result
= kOSKextReturnNotFound
;
9415 result
= theKext
->start();
9417 } else if (predicate
->isEqualTo(kKextRequestPredicateStop
)) {
9418 if (!kextIdentifier
) {
9419 OSKextLog(/* kext */ NULL
,
9420 kOSKextLogErrorLevel
|
9422 "Invalid arguments to kext stop request.");
9423 } else if (!theKext
) {
9424 OSKextLog(/* kext */ NULL
,
9425 kOSKextLogErrorLevel
|
9427 "Kext %s not found for stop request.",
9428 kextIdentifier
->getCStringNoCopy());
9429 result
= kOSKextReturnNotFound
;
9431 result
= theKext
->stop();
9433 } else if (predicate
->isEqualTo(kKextRequestPredicateMissingAuxKCBundles
)) {
9434 result
= OSKext::setMissingAuxKCBundles(requestDict
);
9435 } else if (predicate
->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable
)) {
9436 if (!kextIdentifier
) {
9437 OSKextLog(/* kext */ NULL
,
9438 kOSKextLogErrorLevel
|
9440 "Invalid arguments to AuxKC Bundle Available request.");
9442 result
= OSKext::setAuxKCBundleAvailable(kextIdentifier
, requestDict
);
9444 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFromKC
)) {
9445 if (!kextIdentifier
) {
9446 OSKextLog(/* kext */ NULL
,
9447 kOSKextLogErrorLevel
|
9449 "Invalid arguments to kext load from KC request.");
9450 } else if (!theKext
) {
9451 OSKextLog(/* kext */ NULL
,
9452 kOSKextLogErrorLevel
|
9454 "Kext %s not found for load from KC request.",
9455 kextIdentifier
->getCStringNoCopy());
9456 result
= kOSKextReturnNotFound
;
9457 } else if (!theKext
->isInFileset()) {
9458 OSKextLog(/* kext */ NULL
,
9459 kOSKextLogErrorLevel
|
9461 "Kext %s does not exist in a KC: refusing to load.",
9462 kextIdentifier
->getCStringNoCopy());
9463 result
= kOSKextReturnNotLoadable
;
9465 result
= OSKext::loadKextFromKC(theKext
, requestDict
);
9467 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadCodeless
)) {
9468 if (!kextIdentifier
) {
9469 OSKextLog(/* kext */ NULL
,
9470 kOSKextLogErrorLevel
|
9472 "Invalid arguments to codeless kext load interface (missing identifier).");
9474 result
= OSKext::loadCodelessKext(kextIdentifier
, requestDict
);
9476 } else if (predicate
->isEqualTo(kKextRequestPredicateUnload
)) {
9477 if (!kextIdentifier
) {
9478 OSKextLog(/* kext */ NULL
,
9479 kOSKextLogErrorLevel
|
9481 "Invalid arguments to kext unload request.");
9482 } else if (!theKext
) {
9483 OSKextLog(/* kext */ NULL
,
9484 kOSKextLogErrorLevel
|
9486 "Kext %s not found for unload request.",
9487 kextIdentifier
->getCStringNoCopy());
9488 result
= kOSKextReturnNotFound
;
9490 OSBoolean
* terminateFlag
= OSDynamicCast(OSBoolean
,
9491 _OSKextGetRequestArgument(requestDict
,
9492 kKextRequestArgumentTerminateIOServicesKey
));
9493 result
= OSKext::removeKext(theKext
, terminateFlag
== kOSBooleanTrue
);
9495 } else if (predicate
->isEqualTo(kKextRequestPredicateSendResource
)) {
9496 result
= OSKext::dispatchResource(requestDict
);
9497 } else if (predicate
->isEqualTo(kKextRequestPredicateGetUUIDByAddress
)) {
9498 OSNumber
*lookupNum
= NULL
;
9499 lookupNum
= OSDynamicCast(OSNumber
,
9500 _OSKextGetRequestArgument(requestDict
,
9501 kKextRequestArgumentLookupAddressKey
));
9503 responseObject
= OSKext::copyKextUUIDForAddress(lookupNum
);
9504 if (responseObject
) {
9505 result
= kOSReturnSuccess
;
9509 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
) ||
9510 predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
) ||
9511 predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9512 OSBoolean
* delayAutounloadBool
= NULL
;
9513 OSObject
* infoKeysRaw
= NULL
;
9514 OSArray
* infoKeys
= NULL
;
9515 uint32_t infoKeysCount
= 0;
9517 delayAutounloadBool
= OSDynamicCast(OSBoolean
,
9518 _OSKextGetRequestArgument(requestDict
,
9519 kKextRequestArgumentDelayAutounloadKey
));
9521 /* If asked to delay autounload, reset the timer if it's currently set.
9522 * (That is, don't schedule an unload if one isn't already pending.
9524 if (delayAutounloadBool
== kOSBooleanTrue
) {
9525 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9528 infoKeysRaw
= _OSKextGetRequestArgument(requestDict
,
9529 kKextRequestArgumentInfoKeysKey
);
9530 infoKeys
= OSDynamicCast(OSArray
, infoKeysRaw
);
9531 if (infoKeysRaw
&& !infoKeys
) {
9532 OSKextLog(/* kext */ NULL
,
9533 kOSKextLogErrorLevel
|
9535 "Invalid arguments to kext info request.");
9540 infoKeysCount
= infoKeys
->getCount();
9541 for (uint32_t i
= 0; i
< infoKeysCount
; i
++) {
9542 if (!OSDynamicCast(OSString
, infoKeys
->getObject(i
))) {
9543 OSKextLog(/* kext */ NULL
,
9544 kOSKextLogErrorLevel
|
9546 "Invalid arguments to kext info request.");
9552 if (predicate
->isEqualTo(kKextRequestPredicateGetLoaded
)) {
9553 responseObject
= OSKext::copyLoadedKextInfo(kextIdentifiers
, infoKeys
);
9554 } else if (predicate
->isEqualTo(kKextRequestPredicateGetLoadedByUUID
)) {
9555 responseObject
= OSKext::copyLoadedKextInfoByUUID(kextIdentifiers
, infoKeys
);
9556 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKextsInCollection
)) {
9557 responseObject
= OSKext::copyKextCollectionInfo(requestDict
, infoKeys
);
9560 if (!responseObject
) {
9561 result
= kOSKextReturnInternalError
;
9563 OSKextLog(/* kext */ NULL
,
9564 kOSKextLogDebugLevel
|
9566 "Returning loaded kext info.");
9567 result
= kOSReturnSuccess
;
9569 } else if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9570 /* Hand the current sKernelRequests array to the caller
9571 * (who must release it), and make a new one.
9573 responseObject
= os::move(sKernelRequests
);
9574 sKernelRequests
= OSArray::withCapacity(0);
9575 sPostedKextLoadIdentifiers
->flushCollection();
9576 OSKextLog(/* kext */ NULL
,
9577 kOSKextLogDebugLevel
|
9579 "Returning kernel requests.");
9580 result
= kOSReturnSuccess
;
9581 } else if (predicate
->isEqualTo(kKextRequestPredicateGetAllLoadRequests
)) {
9582 /* Return the set of all requested bundle identifiers */
9583 responseObject
= sAllKextLoadIdentifiers
;
9584 OSKextLog(/* kext */ NULL
,
9585 kOSKextLogDebugLevel
|
9587 "Returning load requests.");
9588 result
= kOSReturnSuccess
;
9589 } else if (predicate
->isEqualTo(kKextRequestPredicateLoadFileSetKC
)) {
9590 printf("KextLog: Loading FileSet KC(s)\n");
9591 result
= OSKext::loadFileSetKexts(requestDict
);
9592 } else if (predicate
->isEqualTo(kKextRequestPredicateDaemonReady
)) {
9593 printf("KextLog: " kIOKitDaemonName
" is %s\n", sIOKitDaemonActive
? "active" : "not active");
9594 result
= (sIOKitDaemonActive
&& !sOSKextWasResetAfterUserspaceReboot
) ? kOSReturnSuccess
: kIOReturnNotReady
;
9596 OSKextLog(/* kext */ NULL
,
9597 kOSKextLogDebugLevel
|
9599 "Received '%s' invalid request from user space.",
9600 predicate
->getCStringNoCopy());
9605 * Now we have handle the request, or not. Gather up the response & logging
9606 * info to ship to user space.
9609 /* Note: Nothing in OSKext is supposed to retain requestDict,
9610 * but you never know....
9612 if (requestDict
->getRetainCount() > 1) {
9613 OSKextLog(/* kext */ NULL
,
9614 kOSKextLogWarningLevel
|
9616 "Request from user space still retained by a kext; "
9617 "probable memory leak.");
9620 if (responseOut
&& responseObject
) {
9621 serializer
= OSSerialize::withCapacity(0);
9623 result
= kOSKextReturnNoMemory
;
9627 * Before serializing the kernel requests, patch the dext launch requests so
9628 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9629 * IOUserServerCheckInToken kernel object.
9631 if (predicate
->isEqualTo(kKextRequestPredicateGetKernelRequests
)) {
9632 OSArray
* requests
= OSDynamicCast(OSArray
, responseObject
.get());
9633 task_t calling_task
= current_task();
9635 OSKextLog(/* kext */ NULL
,
9636 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9637 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests
);
9638 result
= kOSKextReturnInternalError
;
9641 result
= patchDextLaunchRequests(calling_task
, requests
);
9642 if (result
!= kOSReturnSuccess
) {
9643 OSKextLog(/* kext */ NULL
,
9644 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9645 "Failed to patch dext launch requests.");
9650 if (!responseObject
->serialize(serializer
.get())) {
9651 OSKextLog(/* kext */ NULL
,
9652 kOSKextLogGeneralFlag
| kOSKextLogErrorLevel
,
9653 "Failed to serialize response to request from user space.");
9654 result
= kOSKextReturnSerialization
;
9658 response
= (char *)serializer
->text();
9659 responseLength
= serializer
->getLength();
9662 if (responseOut
&& response
) {
9665 /* This kmem_alloc sets the return value of the function.
9667 kmem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&buffer
,
9668 round_page(responseLength
), VM_KERN_MEMORY_OSKEXT
);
9669 if (kmem_result
!= KERN_SUCCESS
) {
9670 OSKextLog(/* kext */ NULL
,
9671 kOSKextLogErrorLevel
|
9673 "Failed to copy response to request from user space.");
9674 result
= kmem_result
;
9677 /* 11981737 - clear uninitialized data in last page */
9678 bzero((void *)(buffer
+ responseLength
),
9679 (round_page(responseLength
) - responseLength
));
9680 memcpy(buffer
, response
, responseLength
);
9681 *responseOut
= buffer
;
9682 *responseLengthOut
= responseLength
;
9688 /* Gather up the collected log messages for user space. Any messages
9689 * messages past this call will not make it up as log messages but
9690 * will be in the system log. Note that we ignore the return of the
9691 * serialize; it has no bearing on the operation at hand even if we
9692 * fail to get the log messages.
9694 logInfoArray
= OSKext::clearUserSpaceLogFilter();
9696 if (logInfoArray
&& logInfoOut
&& logInfoLengthOut
) {
9697 (void)OSKext::serializeLogInfo(logInfoArray
.get(),
9698 logInfoOut
, logInfoLengthOut
);
9701 IORecursiveLockUnlock(sKextLock
);
9707 #pragma mark Linked Kext Collection Support
9711 __whereIsAddr(vm_offset_t theAddr
, unsigned long *segSizes
, vm_offset_t
*segAddrs
, int segCount
)
9713 for (int i
= 0; i
< segCount
; i
++) {
9714 vm_offset_t segStart
= segAddrs
[i
];
9715 vm_offset_t segEnd
= segStart
+ (vm_offset_t
)segSizes
[i
];
9717 if (theAddr
>= segStart
&& theAddr
< segEnd
) {
9725 __slideOldKaslrOffsets(kernel_mach_header_t
*mh
,
9726 kernel_segment_command_t
*kextTextSeg
,
9727 OSData
*kaslrOffsets
)
9729 static const char *plk_segNames
[] = {
9743 static const size_t num_plk_seg
= (size_t)(sizeof(plk_segNames
) / sizeof(plk_segNames
[0]));
9745 unsigned long plk_segSizes
[num_plk_seg
];
9746 vm_offset_t plk_segAddrs
[num_plk_seg
];
9748 for (size_t i
= 0; i
< num_plk_seg
; i
++) {
9749 plk_segSizes
[i
] = 0;
9750 plk_segAddrs
[i
] = (vm_offset_t
)getsegdatafromheader(mh
, plk_segNames
[i
], &plk_segSizes
[i
]);
9753 uint64_t kextTextStart
= (uint64_t)kextTextSeg
->vmaddr
;
9755 int slidKextAddrCount
= 0;
9756 int badSlideAddr
= 0;
9757 int badSlideTarget
= 0;
9759 struct kaslrPackedOffsets
{
9760 uint32_t count
; /* number of offsets */
9761 uint32_t offsetsArray
[]; /* offsets to slide */
9763 const struct kaslrPackedOffsets
*myOffsets
= NULL
;
9764 myOffsets
= (const struct kaslrPackedOffsets
*)kaslrOffsets
->getBytesNoCopy();
9766 for (uint32_t j
= 0; j
< myOffsets
->count
; j
++) {
9767 uint64_t slideOffset
= (uint64_t)myOffsets
->offsetsArray
[j
];
9768 vm_offset_t
*slideAddr
= (vm_offset_t
*)((uint64_t)kextTextStart
+ slideOffset
);
9769 int slideAddrSegIndex
= -1;
9770 int addrToSlideSegIndex
= -1;
9772 slideAddrSegIndex
= __whereIsAddr((vm_offset_t
)slideAddr
, &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9773 if (slideAddrSegIndex
>= 0) {
9774 addrToSlideSegIndex
= __whereIsAddr(ml_static_slide(*slideAddr
), &plk_segSizes
[0], &plk_segAddrs
[0], num_plk_seg
);
9775 if (addrToSlideSegIndex
< 0) {
9784 slidKextAddrCount
++;
9785 *slideAddr
= ml_static_slide(*slideAddr
);
9791 /********************************************************************
9792 * addKextsFromKextCollection
9794 * Input: MachO header of kext collection. The MachO is assumed to
9795 * have a section named 'info_seg_name,info_sect_name' that
9796 * contains a serialized XML info dictionary. This dictionary
9797 * contains a UUID, possibly a set of relocations (for older
9798 * kxld-built binaries), and an array of kext personalities.
9800 ********************************************************************/
9802 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9803 OSDictionary
*infoDict
, const char *text_seg_name
,
9804 OSData
**kcUUID
, kc_kind_t type
)
9806 bool result
= false;
9808 OSArray
*kextArray
= NULL
; // do not release
9809 OSData
*infoDictKCUUID
= NULL
; // do not release
9810 OSData
*kaslrOffsets
= NULL
; // do not release
9812 IORegistryEntry
*registryRoot
= NULL
; // do not release
9813 OSSharedPtr
<OSNumber
> kcKextCount
;
9815 /* extract the KC UUID from the dictionary */
9816 infoDictKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
9817 if (infoDictKCUUID
) {
9818 if (infoDictKCUUID
->getLength() != sizeof(uuid_t
)) {
9819 panic("kcUUID length is %d, expected %lu",
9820 infoDictKCUUID
->getLength(), sizeof(uuid_t
));
9824 /* locate the array of kext dictionaries */
9825 kextArray
= OSDynamicCast(OSArray
, infoDict
->getObject(kPrelinkInfoDictionaryKey
));
9827 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9828 "The given KC has no kext info dictionaries");
9833 * old-style KASLR offsets may be present in the info dictionary. If
9834 * we find them, use them and eventually slide them.
9836 kaslrOffsets
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkLinkKASLROffsetsKey
));
9839 * Before processing any kexts, locate the special kext bundle which
9840 * contains a list of kexts that we are to prevent from loading.
9842 createExcludeListFromPrelinkInfo(kextArray
);
9845 * Create OSKext objects for each kext we find in the array of kext
9846 * info plist dictionaries.
9848 for (int i
= 0; i
< (int)kextArray
->getCount(); ++i
) {
9849 OSDictionary
*kextDict
= NULL
;
9850 kextDict
= OSDynamicCast(OSDictionary
, kextArray
->getObject(i
));
9852 OSKextLog(/* kext */ NULL
,
9853 kOSKextLogErrorLevel
|
9854 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9855 "Kext info dictionary for kext #%d isn't a dictionary?", i
);
9860 * Create the kext for the entry, then release it, because the
9861 * kext system keeps a reference around until the kext is
9862 * explicitly removed. Any creation/registration failures are
9863 * already logged for us.
9865 withPrelinkedInfoDict(kextDict
, (kaslrOffsets
? TRUE
: FALSE
), type
);
9869 * slide old-style kxld relocations
9870 * NOTE: this is still used on embedded KCs built with kcgen
9871 * TODO: Remove this once we use the new kext linker everywhere!
9873 if (kaslrOffsets
&& vm_kernel_slide
> 0) {
9874 kernel_segment_command_t
*text_segment
= NULL
;
9875 text_segment
= getsegbynamefromheader(mh
, text_seg_name
);
9876 if (!text_segment
) {
9877 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9878 "Can't find a TEXT segment named '%s' in macho header", text_seg_name
);
9882 __slideOldKaslrOffsets(mh
, text_segment
, kaslrOffsets
);
9883 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9884 setAllVMAttributes();
9887 /* Store the number of prelinked kexts in the registry so we can tell
9888 * when the system has been started from a prelinked kernel.
9890 registryRoot
= IORegistryEntry::getRegistryRoot();
9891 assert(registryRoot
);
9893 kcKextCount
= OSNumber::withNumber((unsigned long long)infoDict
->getCount(), 8 * sizeof(uint32_t));
9894 assert(kcKextCount
);
9896 OSSharedPtr
<OSObject
> prop
= registryRoot
->copyProperty(kOSPrelinkKextCountKey
);
9898 num
= OSDynamicCast(OSNumber
, prop
.get());
9900 kcKextCount
->addValue(num
->unsigned64BitValue());
9902 registryRoot
->setProperty(kOSPrelinkKextCountKey
, kcKextCount
.get());
9905 OSKextLog(/* kext */ NULL
,
9906 kOSKextLogProgressLevel
|
9907 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
9908 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
9909 "%u prelinked kexts", infoDict
->getCount());
9912 if (kcUUID
&& infoDictKCUUID
) {
9913 *kcUUID
= OSData::withData(infoDictKCUUID
).detach();
9923 OSKext::addKextsFromKextCollection(kernel_mach_header_t
*mh
,
9924 OSDictionary
*infoDict
, const char *text_seg_name
,
9925 OSSharedPtr
<OSData
> &kcUUID
, kc_kind_t type
)
9927 OSData
*result
= NULL
;
9928 bool success
= addKextsFromKextCollection(mh
,
9934 kcUUID
.reset(result
, OSNoRetain
);
9939 static OSSharedPtr
<OSObject
> deferredAuxKCXML
;
9941 OSKext::registerDeferredKextCollection(kernel_mach_header_t
*mh
,
9942 OSSharedPtr
<OSObject
> &parsedXML
, kc_kind_t type
)
9944 if (type
!= KCKindAuxiliary
) {
9948 kernel_mach_header_t
*_mh
;
9949 _mh
= (kernel_mach_header_t
*)PE_get_kc_header(type
);
9950 if (!_mh
|| _mh
!= mh
) {
9954 if (deferredAuxKCXML
) {
9955 /* only allow this to be called once */
9956 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9957 "An Aux KC has already been registered for deferred processing.");
9961 OSDictionary
*infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
9963 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9964 "The Aux KC has info dictionary");
9968 OSData
*kcUUID
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
9969 if (!kcUUID
|| kcUUID
->getLength() != sizeof(uuid_t
)) {
9970 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
9971 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey
);
9976 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
9977 * sysctl can return the UUID to user space which will check this
9980 memcpy((void *)&auxkc_uuid
, (const void *)kcUUID
->getBytesNoCopy(),
9981 kcUUID
->getLength());
9982 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
9983 auxkc_uuid_valid
= TRUE
;
9985 deferredAuxKCXML
= parsedXML
;
9990 OSSharedPtr
<OSObject
>
9991 OSKext::consumeDeferredKextCollection(kc_kind_t type
)
9993 if (type
!= KCKindAuxiliary
|| !deferredAuxKCXML
) {
9997 return os::move(deferredAuxKCXML
);
10001 #pragma mark Profile-Guided-Optimization Support
10004 // #include <InstrProfiling.h>
10006 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin
,
10007 const char *DataEnd
,
10008 const char *CountersBegin
,
10009 const char *CountersEnd
,
10010 const char *NamesBegin
,
10011 const char *NamesEnd
);
10012 int __llvm_profile_write_buffer_internal(char *Buffer
,
10013 const char *DataBegin
,
10014 const char *DataEnd
,
10015 const char *CountersBegin
,
10016 const char *CountersEnd
,
10017 const char *NamesBegin
,
10018 const char *NamesEnd
);
10024 OSKextPgoMetadataPut(char *pBuffer
,
10027 uint32_t *num_pairs
,
10031 size_t strlen_key
= strlen(key
);
10032 size_t strlen_value
= strlen(value
);
10033 size_t len
= strlen(key
) + 1 + strlen(value
) + 1;
10034 char *pos
= pBuffer
+ *position
;
10036 if (pBuffer
&& bufferSize
&& *position
<= bufferSize
) {
10037 memcpy(pos
, key
, strlen_key
); pos
+= strlen_key
;
10039 memcpy(pos
, value
, strlen_value
); pos
+= strlen_value
;
10050 OSKextPgoMetadataPutMax(size_t *position
, const char *key
, size_t value_max
)
10052 *position
+= strlen(key
) + 1 + value_max
+ 1;
10058 OSKextPgoMetadataPutAll(OSKext
*kext
,
10059 uuid_t instance_uuid
,
10063 uint32_t *num_pairs
)
10065 _static_assert_1_arg(sizeof(clock_sec_t
) % 2 == 0);
10066 //log_10 2^16 ≈ 4.82
10067 const size_t max_secs_string_size
= 5 * sizeof(clock_sec_t
) / 2;
10068 const size_t max_timestamp_string_size
= max_secs_string_size
+ 1 + 6;
10071 OSKextPgoMetadataPutMax(position
, "INSTANCE", 36);
10072 OSKextPgoMetadataPutMax(position
, "UUID", 36);
10073 OSKextPgoMetadataPutMax(position
, "TIMESTAMP", max_timestamp_string_size
);
10075 uuid_string_t instance_uuid_string
;
10076 uuid_unparse(instance_uuid
, instance_uuid_string
);
10077 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10078 "INSTANCE", instance_uuid_string
);
10080 OSSharedPtr
<OSData
> uuid_data
;
10082 uuid_string_t uuid_string
;
10083 uuid_data
= kext
->copyUUID();
10085 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid
));
10086 uuid_unparse(uuid
, uuid_string
);
10087 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10088 "UUID", uuid_string
);
10092 clock_usec_t usecs
;
10093 clock_get_calendar_microtime(&secs
, &usecs
);
10094 assert(usecs
< 1000000);
10095 char timestamp
[max_timestamp_string_size
+ 1];
10096 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t
));
10097 snprintf(timestamp
, sizeof(timestamp
), "%lu.%06d", (unsigned long)secs
, (int)usecs
);
10098 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10099 "TIMESTAMP", timestamp
);
10102 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10103 "NAME", kext
->getIdentifierCString());
10105 char versionCString
[kOSKextVersionMaxLength
];
10106 OSKextVersionGetString(kext
->getVersion(), versionCString
, kOSKextVersionMaxLength
);
10107 OSKextPgoMetadataPut(pBuffer
, position
, bufferSize
, num_pairs
,
10108 "VERSION", versionCString
);
10113 OSKextPgoMetadataSize(OSKext
*kext
)
10115 size_t position
= 0;
10116 uuid_t fakeuuid
= {};
10117 OSKextPgoMetadataPutAll(kext
, fakeuuid
, NULL
, &position
, 0, NULL
);
10122 OSKextGrabPgoDataLocked(OSKext
*kext
,
10124 uuid_t instance_uuid
,
10127 uint64_t bufferSize
)
10131 kernel_section_t
*sect_prf_data
= NULL
;
10132 kernel_section_t
*sect_prf_name
= NULL
;
10133 kernel_section_t
*sect_prf_cnts
= NULL
;
10135 size_t metadata_size
= 0;
10136 size_t offset_to_pairs
= 0;
10138 sect_prf_data
= kext
->lookupSection("__DATA", "__llvm_prf_data");
10139 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_names");
10140 if (!sect_prf_name
) {
10141 // kextcache sometimes truncates the section name to 15 chars
10142 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10143 sect_prf_name
= kext
->lookupSection("__DATA", "__llvm_prf_name");
10145 sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10147 if (!sect_prf_data
|| !sect_prf_name
|| !sect_prf_cnts
) {
10152 size
= __llvm_profile_get_size_for_buffer_internal(
10153 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10154 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10155 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10158 metadata_size
= OSKextPgoMetadataSize(kext
);
10159 size
+= metadata_size
;
10160 size
+= sizeof(pgo_metadata_footer
);
10168 if (pBuffer
&& bufferSize
) {
10169 if (bufferSize
< size
) {
10174 err
= __llvm_profile_write_buffer_internal(
10176 (const char*) sect_prf_data
->addr
, (const char*) sect_prf_data
->addr
+ sect_prf_data
->size
,
10177 (const char*) sect_prf_cnts
->addr
, (const char*) sect_prf_cnts
->addr
+ sect_prf_cnts
->size
,
10178 (const char*) sect_prf_name
->addr
, (const char*) sect_prf_name
->addr
+ sect_prf_name
->size
);
10186 offset_to_pairs
= sizeof(struct pgo_metadata_footer
) + metadata_size
;
10187 if (offset_to_pairs
> UINT32_MAX
) {
10192 char *end_of_buffer
= pBuffer
+ size
;
10193 struct pgo_metadata_footer
*footerp
= (struct pgo_metadata_footer
*) (end_of_buffer
- sizeof(struct pgo_metadata_footer
));
10194 char *metadata_buffer
= end_of_buffer
- (sizeof(struct pgo_metadata_footer
) + metadata_size
);
10196 size_t metadata_position
= 0;
10197 uint32_t num_pairs
= 0;
10198 OSKextPgoMetadataPutAll(kext
, instance_uuid
, metadata_buffer
, &metadata_position
, metadata_size
, &num_pairs
);
10199 while (metadata_position
< metadata_size
) {
10200 metadata_buffer
[metadata_position
++] = 0;
10203 struct pgo_metadata_footer footer
;
10204 footer
.magic
= htonl(0x6d657461);
10205 footer
.number_of_pairs
= htonl( num_pairs
);
10206 footer
.offset_to_pairs
= htonl((uint32_t)offset_to_pairs
);
10207 memcpy(footerp
, &footer
, sizeof(footer
));
10217 OSKextGrabPgoData(uuid_t uuid
,
10220 uint64_t bufferSize
,
10221 int wait_for_unload
,
10225 OSSharedPtr
<OSKext
> kext
;
10228 IORecursiveLockLock(sKextLock
);
10230 kext
= OSKext::lookupKextWithUUID(uuid
);
10236 if (wait_for_unload
) {
10237 OSKextGrabPgoStruct s
;
10239 s
.metadata
= metadata
;
10241 s
.pBuffer
= pBuffer
;
10242 s
.bufferSize
= bufferSize
;
10245 struct list_head
*prev
= &kext
->pendingPgoHead
;
10246 struct list_head
*next
= kext
->pendingPgoHead
.next
;
10248 s
.list_head
.prev
= prev
;
10249 s
.list_head
.next
= next
;
10251 prev
->next
= &s
.list_head
;
10252 next
->prev
= &s
.list_head
;
10256 IORecursiveLockSleep(sKextLock
, &s
, THREAD_ABORTSAFE
);
10258 prev
= s
.list_head
.prev
;
10259 next
= s
.list_head
.next
;
10266 err
= OSKextGrabPgoDataLocked(kext
.get(), metadata
, kext
->instance_uuid
, pSize
, pBuffer
, bufferSize
);
10271 IORecursiveLockUnlock(sKextLock
);
10277 OSKextResetPgoCountersLock()
10279 IORecursiveLockLock(sKextLock
);
10283 OSKextResetPgoCountersUnlock()
10285 IORecursiveLockUnlock(sKextLock
);
10289 extern unsigned int not_in_kdp
;
10292 OSKextResetPgoCounters()
10294 assert(!not_in_kdp
);
10295 uint32_t count
= sLoadedKexts
->getCount();
10296 for (uint32_t i
= 0; i
< count
; i
++) {
10297 OSKext
*kext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
10298 kernel_section_t
*sect_prf_cnts
= kext
->lookupSection("__DATA", "__llvm_prf_cnts");
10299 if (!sect_prf_cnts
) {
10302 memset((void*)sect_prf_cnts
->addr
, 0, sect_prf_cnts
->size
);
10306 OSSharedPtr
<OSDictionary
>
10307 OSKext::copyLoadedKextInfoByUUID(
10308 OSArray
* kextIdentifiers
,
10309 OSArray
* infoKeys
)
10311 OSSharedPtr
<OSDictionary
> result
;
10312 OSSharedPtr
<OSDictionary
> kextInfo
;
10313 uint32_t max_count
, i
, j
;
10314 uint32_t idCount
= 0;
10315 uint32_t idIndex
= 0;
10316 IORecursiveLockLock(sKextLock
);
10317 OSArray
*list
[2] = {sLoadedKexts
.get(), sLoadedDriverKitKexts
.get()};
10318 uint32_t count
[2] = {sLoadedKexts
->getCount(), sLoadedDriverKitKexts
->getCount()};
10321 /* Is the calling process allowed to query kext info? */
10322 if (current_task() != kernel_task
) {
10323 int macCheckResult
= 0;
10324 kauth_cred_t cred
= NULL
;
10326 cred
= kauth_cred_get_with_ref();
10327 macCheckResult
= mac_kext_check_query(cred
);
10328 kauth_cred_unref(&cred
);
10330 if (macCheckResult
!= 0) {
10331 OSKextLog(/* kext */ NULL
,
10332 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10333 "Failed to query kext info (MAC policy error 0x%x).",
10340 /* Empty list of UUIDs is equivalent to no list (get all).
10342 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10343 kextIdentifiers
= NULL
;
10344 } else if (kextIdentifiers
) {
10345 idCount
= kextIdentifiers
->getCount();
10350 if (infoKeys
&& !infoKeys
->getCount()) {
10354 max_count
= count
[0] + count
[1];
10355 result
= OSDictionary::withCapacity(max_count
);
10360 for (j
= 0; j
< (sizeof(list
) / sizeof(list
[0])); j
++) {
10361 for (i
= 0; i
< count
[j
]; i
++) {
10362 OSKext
*thisKext
= NULL
; // do not release
10363 Boolean includeThis
= true;
10364 uuid_t thisKextUUID
;
10365 uuid_t thisKextTextUUID
;
10366 OSSharedPtr
<OSData
> uuid_data
;
10367 uuid_string_t uuid_key
;
10369 thisKext
= OSDynamicCast(OSKext
, list
[j
]->getObject(i
));
10374 uuid_data
= thisKext
->copyUUID();
10379 memcpy(&thisKextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextUUID
));
10381 uuid_unparse(thisKextUUID
, uuid_key
);
10383 uuid_data
= thisKext
->copyTextUUID();
10387 memcpy(&thisKextTextUUID
, uuid_data
->getBytesNoCopy(), sizeof(thisKextTextUUID
));
10389 /* Skip current kext if we have a list of UUIDs and
10390 * it isn't in the list.
10392 if (kextIdentifiers
) {
10393 includeThis
= false;
10395 for (idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10396 const OSString
* wantedUUID
= OSDynamicCast(OSString
,
10397 kextIdentifiers
->getObject(idIndex
));
10400 uuid_parse(wantedUUID
->getCStringNoCopy(), uuid
);
10402 if ((0 == uuid_compare(uuid
, thisKextUUID
))
10403 || (0 == uuid_compare(uuid
, thisKextTextUUID
))) {
10404 includeThis
= true;
10405 /* Only need to find the first kext if multiple match,
10406 * ie. asking for the kernel uuid does not need to find
10407 * interface kexts or builtin static kexts.
10409 kextIdentifiers
->removeObject(idIndex
);
10410 uuid_unparse(uuid
, uuid_key
);
10416 if (!includeThis
) {
10420 kextInfo
= thisKext
->copyInfo(infoKeys
);
10422 result
->setObject(uuid_key
, kextInfo
.get());
10425 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10432 IORecursiveLockUnlock(sKextLock
);
10437 /*********************************************************************
10438 *********************************************************************/
10440 OSSharedPtr
<OSDictionary
>
10441 OSKext::copyKextCollectionInfo(
10442 OSDictionary
*requestDict
,
10445 OSSharedPtr
<OSDictionary
> result
;
10446 OSString
*collectionType
= NULL
;
10447 OSObject
*rawLoadedState
= NULL
;
10448 OSString
*loadedState
= NULL
;
10450 kc_kind_t kc_request_kind
= KCKindUnknown
;
10451 bool onlyLoaded
= false;
10452 bool onlyUnloaded
= false;
10455 /* Is the calling process allowed to query kext info? */
10456 if (current_task() != kernel_task
) {
10457 int macCheckResult
= 0;
10458 kauth_cred_t cred
= NULL
;
10460 cred
= kauth_cred_get_with_ref();
10461 macCheckResult
= mac_kext_check_query(cred
);
10462 kauth_cred_unref(&cred
);
10464 if (macCheckResult
!= 0) {
10465 OSKextLog(/* kext */ NULL
,
10466 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10467 "Failed to query kext info (MAC policy error 0x%x).",
10474 if (infoKeys
&& !infoKeys
->getCount()) {
10478 collectionType
= OSDynamicCast(OSString
,
10479 _OSKextGetRequestArgument(requestDict
,
10480 kKextRequestArgumentCollectionTypeKey
));
10481 if (!collectionType
) {
10482 OSKextLog(/* kext */ NULL
,
10483 kOSKextLogErrorLevel
|
10485 "Invalid '%s' argument to kext collection info request.",
10486 kKextRequestArgumentCollectionTypeKey
);
10489 if (collectionType
->isEqualTo(kKCTypePrimary
)) {
10490 kc_request_kind
= KCKindPrimary
;
10491 } else if (collectionType
->isEqualTo(kKCTypeSystem
)) {
10492 kc_request_kind
= KCKindPageable
;
10493 } else if (collectionType
->isEqualTo(kKCTypeAuxiliary
)) {
10494 kc_request_kind
= KCKindAuxiliary
;
10495 } else if (collectionType
->isEqualTo(kKCTypeCodeless
)) {
10496 kc_request_kind
= KCKindNone
;
10497 } else if (!collectionType
->isEqualTo(kKCTypeAny
)) {
10498 OSKextLog(/* kext */ NULL
,
10499 kOSKextLogErrorLevel
|
10501 "Invalid '%s' argument value '%s' to kext collection info request.",
10502 kKextRequestArgumentCollectionTypeKey
,
10503 collectionType
->getCStringNoCopy());
10507 rawLoadedState
= _OSKextGetRequestArgument(requestDict
,
10508 kKextRequestArgumentLoadedStateKey
);
10509 if (rawLoadedState
) {
10510 loadedState
= OSDynamicCast(OSString
, rawLoadedState
);
10511 if (!loadedState
) {
10512 OSKextLog(/* kext */ NULL
,
10513 kOSKextLogErrorLevel
|
10515 "Invalid '%s' argument to kext collection info request.",
10516 kKextRequestArgumentLoadedStateKey
);
10521 if (loadedState
->isEqualTo("Loaded")) {
10523 } else if (loadedState
->isEqualTo("Unloaded")) {
10524 onlyUnloaded
= true;
10525 } else if (!loadedState
->isEqualTo("Any")) {
10526 OSKextLog(/* kext */ NULL
,
10527 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10528 "Invalid '%s' argument value '%s' for '%s' collection info",
10529 kKextRequestArgumentLoadedStateKey
,
10530 loadedState
->getCStringNoCopy(),
10531 collectionType
->getCStringNoCopy());
10536 result
= OSDictionary::withCapacity(sKextsByID
->getCount());
10541 IORecursiveLockLock(sKextLock
);
10542 { // start block scope
10543 sKextsByID
->iterateObjects(^bool (const OSSymbol
*thisKextID
, OSObject
*obj
)
10545 OSKext
*thisKext
= NULL
; // do not release
10546 OSSharedPtr
<OSDictionary
> kextInfo
;
10550 thisKext
= OSDynamicCast(OSKext
, obj
);
10556 * skip the kext if it came from the wrong collection type
10557 * (and the caller requested a specific type)
10559 if ((kc_request_kind
!= KCKindUnknown
) && (thisKext
->kc_type
!= kc_request_kind
)) {
10564 * respect the caller's desire to find only loaded or
10567 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10570 if (onlyUnloaded
&& (-1U != sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10574 kextInfo
= thisKext
->copyInfo(infoKeys
);
10576 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10580 } // end block scope
10581 IORecursiveLockUnlock(sKextLock
);
10587 /*********************************************************************
10588 *********************************************************************/
10590 OSSharedPtr
<OSDictionary
>
10591 OSKext::copyLoadedKextInfo(
10592 OSArray
* kextIdentifiers
,
10593 OSArray
* infoKeys
)
10595 OSSharedPtr
<OSDictionary
> result
;
10596 uint32_t idCount
= 0;
10599 IORecursiveLockLock(sKextLock
);
10602 /* Is the calling process allowed to query kext info? */
10603 if (current_task() != kernel_task
) {
10604 int macCheckResult
= 0;
10605 kauth_cred_t cred
= NULL
;
10607 cred
= kauth_cred_get_with_ref();
10608 macCheckResult
= mac_kext_check_query(cred
);
10609 kauth_cred_unref(&cred
);
10611 if (macCheckResult
!= 0) {
10612 OSKextLog(/* kext */ NULL
,
10613 kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
10614 "Failed to query kext info (MAC policy error 0x%x).",
10621 /* Empty list of bundle ids is equivalent to no list (get all).
10623 if (kextIdentifiers
&& !kextIdentifiers
->getCount()) {
10624 kextIdentifiers
= NULL
;
10625 } else if (kextIdentifiers
) {
10626 idCount
= kextIdentifiers
->getCount();
10631 if (infoKeys
&& !infoKeys
->getCount()) {
10635 onlyLoaded
= (!infoKeys
|| !_OSArrayContainsCString(infoKeys
, kOSBundleAllPrelinkedKey
));
10637 result
= OSDictionary::withCapacity(128);
10643 OSKextLog(/* kext */ NULL
,
10644 kOSKextLogErrorLevel
|
10645 kOSKextLogGeneralFlag
,
10646 "kaslr: vm_kernel_slide 0x%lx \n",
10648 OSKextLog(/* kext */ NULL
,
10649 kOSKextLogErrorLevel
|
10650 kOSKextLogGeneralFlag
,
10651 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10652 vm_kernel_stext
, vm_kernel_etext
);
10653 OSKextLog(/* kext */ NULL
,
10654 kOSKextLogErrorLevel
|
10655 kOSKextLogGeneralFlag
,
10656 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10657 vm_kernel_base
, vm_kernel_top
);
10658 OSKextLog(/* kext */ NULL
,
10659 kOSKextLogErrorLevel
|
10660 kOSKextLogGeneralFlag
,
10661 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10662 vm_kext_base
, vm_kext_top
);
10663 OSKextLog(/* kext */ NULL
,
10664 kOSKextLogErrorLevel
|
10665 kOSKextLogGeneralFlag
,
10666 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10667 vm_prelink_stext
, vm_prelink_etext
);
10668 OSKextLog(/* kext */ NULL
,
10669 kOSKextLogErrorLevel
|
10670 kOSKextLogGeneralFlag
,
10671 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10672 vm_prelink_sinfo
, vm_prelink_einfo
);
10673 OSKextLog(/* kext */ NULL
,
10674 kOSKextLogErrorLevel
|
10675 kOSKextLogGeneralFlag
,
10676 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10677 vm_slinkedit
, vm_elinkedit
);
10679 { // start block scope
10680 sKextsByID
->iterateObjects(^bool (const OSSymbol
* thisKextID
, OSObject
* obj
)
10682 OSKext
* thisKext
= NULL
; // do not release
10683 Boolean includeThis
= true;
10684 OSSharedPtr
<OSDictionary
> kextInfo
;
10686 thisKext
= OSDynamicCast(OSKext
, obj
);
10691 /* Skip current kext if not yet started and caller didn't request all.
10693 if (onlyLoaded
&& (-1U == sLoadedKexts
->getNextIndexOfObject(thisKext
, 0))) {
10697 /* Skip current kext if we have a list of bundle IDs and
10698 * it isn't in the list.
10700 if (kextIdentifiers
) {
10701 includeThis
= false;
10703 for (uint32_t idIndex
= 0; idIndex
< idCount
; idIndex
++) {
10704 const OSString
* thisRequestID
= OSDynamicCast(OSString
,
10705 kextIdentifiers
->getObject(idIndex
));
10706 if (thisKextID
->isEqualTo(thisRequestID
)) {
10707 includeThis
= true;
10713 if (!includeThis
) {
10717 kextInfo
= thisKext
->copyInfo(infoKeys
);
10719 result
->setObject(thisKext
->getIdentifier(), kextInfo
.get());
10723 } // end block scope
10726 IORecursiveLockUnlock(sKextLock
);
10731 /*********************************************************************
10732 * Any info that needs to do allocations must goto finish on alloc
10733 * failure. Info that is just a lookup should just not set the object
10734 * if the info does not exist.
10735 *********************************************************************/
10736 #define _OSKextLoadInfoDictCapacity (12)
10738 OSSharedPtr
<OSDictionary
>
10739 OSKext::copyInfo(OSArray
* infoKeys
)
10741 OSSharedPtr
<OSDictionary
> result
;
10742 bool success
= false;
10743 OSSharedPtr
<OSData
> headerData
;
10744 OSSharedPtr
<OSData
> logData
;
10745 OSSharedPtr
<OSNumber
> cpuTypeNumber
;
10746 OSSharedPtr
<OSNumber
> cpuSubtypeNumber
;
10747 OSString
* versionString
= NULL
; // do not release
10748 OSString
* bundleType
= NULL
; // do not release
10749 uint32_t executablePathCStringSize
= 0;
10750 char * executablePathCString
= NULL
; // must kfree
10751 OSSharedPtr
<OSString
> executablePathString
;
10752 OSSharedPtr
<OSData
> uuid
;
10753 OSSharedPtr
<OSArray
> dependencyLoadTags
;
10754 OSSharedPtr
<OSCollectionIterator
> metaClassIterator
;
10755 OSSharedPtr
<OSArray
> metaClassInfo
;
10756 OSSharedPtr
<OSDictionary
> metaClassDict
;
10757 OSMetaClass
* thisMetaClass
= NULL
; // do not release
10758 OSSharedPtr
<OSString
> metaClassName
;
10759 OSSharedPtr
<OSString
> superclassName
;
10760 kc_format_t kcformat
;
10763 result
= OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity
);
10769 /* Empty keys means no keys, but NULL is quicker to check.
10771 if (infoKeys
&& !infoKeys
->getCount()) {
10775 if (!PE_get_primary_kc_format(&kcformat
)) {
10779 /* Headers, CPU type, and CPU subtype.
10782 _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
) ||
10783 _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
) ||
10784 _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
) ||
10785 _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10786 if (linkedExecutable
&& !isInterface()) {
10787 kernel_mach_header_t
*kext_mach_hdr
= (kernel_mach_header_t
*)
10788 linkedExecutable
->getBytesNoCopy();
10790 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10791 // do not return macho header info on shipping embedded - 19095897
10792 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleMachOHeadersKey
)) {
10793 kernel_mach_header_t
* temp_kext_mach_hdr
;
10794 struct load_command
* lcp
;
10796 headerData
= OSData::withBytes(kext_mach_hdr
,
10797 (u_int
) (sizeof(*kext_mach_hdr
) + kext_mach_hdr
->sizeofcmds
));
10802 // unslide any vmaddrs we return to userspace - 10726716
10803 temp_kext_mach_hdr
= (kernel_mach_header_t
*)
10804 headerData
->getBytesNoCopy();
10805 if (temp_kext_mach_hdr
== NULL
) {
10809 lcp
= (struct load_command
*) (temp_kext_mach_hdr
+ 1);
10810 for (i
= 0; i
< temp_kext_mach_hdr
->ncmds
; i
++) {
10811 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
10812 kernel_segment_command_t
* segp
;
10813 kernel_section_t
* secp
;
10815 segp
= (kernel_segment_command_t
*) lcp
;
10816 // 10543468 - if we jettisoned __LINKEDIT clear size info
10817 if (flags
.jettisonLinkeditSeg
) {
10818 if (strncmp(segp
->segname
, SEG_LINKEDIT
, sizeof(segp
->segname
)) == 0) {
10821 segp
->filesize
= 0;
10825 #if __arm__ || __arm64__
10826 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10827 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10828 if (segp
->vmsize
== 0 && segp
->vmaddr
< gVirtBase
) {
10829 segp
->vmaddr
= gVirtBase
;
10830 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10831 secp
->size
= 0; // paranoia :)
10832 secp
->addr
= gVirtBase
;
10838 OSKextLog(/* kext */ NULL
,
10839 kOSKextLogErrorLevel
|
10840 kOSKextLogGeneralFlag
,
10841 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10842 __FUNCTION__
, segp
->segname
, segp
->vmaddr
,
10843 VM_KERNEL_UNSLIDE(segp
->vmaddr
),
10844 segp
->vmsize
, segp
->nsects
);
10845 if ((VM_KERNEL_IS_SLID(segp
->vmaddr
) == false) &&
10846 (VM_KERNEL_IS_KEXT(segp
->vmaddr
) == false) &&
10847 (VM_KERNEL_IS_PRELINKTEXT(segp
->vmaddr
) == false) &&
10848 (VM_KERNEL_IS_PRELINKINFO(segp
->vmaddr
) == false) &&
10849 (VM_KERNEL_IS_KEXT_LINKEDIT(segp
->vmaddr
) == false)) {
10850 OSKextLog(/* kext */ NULL
,
10851 kOSKextLogErrorLevel
|
10852 kOSKextLogGeneralFlag
,
10853 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10854 __FUNCTION__
, segp
->vmaddr
, vm_kext_base
, vm_kext_top
);
10857 segp
->vmaddr
= ml_static_unslide(segp
->vmaddr
);
10859 for (secp
= firstsect(segp
); secp
!= NULL
; secp
= nextsect(segp
, secp
)) {
10860 secp
->addr
= ml_static_unslide(secp
->addr
);
10863 lcp
= (struct load_command
*)((caddr_t
)lcp
+ lcp
->cmdsize
);
10865 result
->setObject(kOSBundleMachOHeadersKey
, headerData
.get());
10867 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10869 if (_OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10870 osLogDataHeaderRef
*header
;
10871 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10873 void *os_log_data
= NULL
;
10874 void *cstring_data
= NULL
;
10875 unsigned long os_log_size
= 0;
10876 unsigned long cstring_size
= 0;
10877 uint32_t os_log_offset
= 0;
10878 uint32_t cstring_offset
= 0;
10881 os_log_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__os_log", &os_log_size
);
10882 os_log_offset
= (uintptr_t)os_log_data
- (uintptr_t)kext_mach_hdr
;
10883 cstring_data
= getsectdatafromheader(kext_mach_hdr
, "__TEXT", "__cstring", &cstring_size
);
10884 cstring_offset
= (uintptr_t)cstring_data
- (uintptr_t)kext_mach_hdr
;
10886 header
= (osLogDataHeaderRef
*) headerBytes
;
10887 header
->version
= OS_LOG_HDR_VERSION
;
10888 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10889 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= os_log_offset
;
10890 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) os_log_size
;
10891 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= cstring_offset
;
10892 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) cstring_size
;
10895 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10899 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10904 res
= logData
->appendBytes(os_log_data
, (u_int
)header
->sections
[OS_LOG_SECT_IDX
].sect_size
);
10909 if (cstring_data
) {
10910 res
= logData
->appendBytes(cstring_data
, (u_int
)header
->sections
[CSTRING_SECT_IDX
].sect_size
);
10915 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10918 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUTypeKey
)) {
10919 cpuTypeNumber
= OSNumber::withNumber(
10920 (uint64_t) kext_mach_hdr
->cputype
,
10921 8 * sizeof(kext_mach_hdr
->cputype
));
10922 if (!cpuTypeNumber
) {
10925 result
->setObject(kOSBundleCPUTypeKey
, cpuTypeNumber
.get());
10928 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCPUSubtypeKey
)) {
10929 cpuSubtypeNumber
= OSNumber::withNumber(
10930 (uint64_t) kext_mach_hdr
->cpusubtype
,
10931 8 * sizeof(kext_mach_hdr
->cpusubtype
));
10932 if (!cpuSubtypeNumber
) {
10935 result
->setObject(kOSBundleCPUSubtypeKey
, cpuSubtypeNumber
.get());
10938 if (isDriverKit() && _OSArrayContainsCString(infoKeys
, kOSBundleLogStringsKey
)) {
10939 osLogDataHeaderRef
*header
;
10940 char headerBytes
[offsetof(osLogDataHeaderRef
, sections
) + NUM_OS_LOG_SECTIONS
* sizeof(header
->sections
[0])];
10943 header
= (osLogDataHeaderRef
*) headerBytes
;
10944 header
->version
= OS_LOG_HDR_VERSION
;
10945 header
->sect_count
= NUM_OS_LOG_SECTIONS
;
10946 header
->sections
[OS_LOG_SECT_IDX
].sect_offset
= 0;
10947 header
->sections
[OS_LOG_SECT_IDX
].sect_size
= (uint32_t) 0;
10948 header
->sections
[CSTRING_SECT_IDX
].sect_offset
= 0;
10949 header
->sections
[CSTRING_SECT_IDX
].sect_size
= (uint32_t) 0;
10951 logData
= OSData::withBytes(header
, (u_int
) (sizeof(osLogDataHeaderRef
)));
10955 res
= logData
->appendBytes(&(header
->sections
[0]), (u_int
)(header
->sect_count
* sizeof(header
->sections
[0])));
10959 result
->setObject(kOSBundleLogStringsKey
, logData
.get());
10964 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10966 result
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
10968 /* CFBundlePackageType
10970 bundleType
= infoDict
? OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
)): NULL
;
10972 result
->setObject(kCFBundlePackageTypeKey
, bundleType
);
10975 /* CFBundleVersion.
10977 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kCFBundleVersionKey
)) {
10978 versionString
= OSDynamicCast(OSString
,
10979 getPropertyForHostArch(kCFBundleVersionKey
));
10980 if (versionString
) {
10981 result
->setObject(kCFBundleVersionKey
, versionString
);
10985 /* OSBundleCompatibleVersion.
10987 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCompatibleVersionKey
)) {
10988 versionString
= OSDynamicCast(OSString
,
10989 getPropertyForHostArch(kOSBundleCompatibleVersionKey
));
10990 if (versionString
) {
10991 result
->setObject(kOSBundleCompatibleVersionKey
, versionString
);
10997 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePathKey
)) {
10999 result
->setObject(kOSBundlePathKey
, path
.get());
11004 /* OSBundleExecutablePath.
11006 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecutablePathKey
)) {
11007 if (path
&& executableRelPath
) {
11008 uint32_t pathLength
= path
->getLength(); // gets incremented below
11010 // +1 for slash, +1 for \0
11011 executablePathCStringSize
= pathLength
+ executableRelPath
->getLength() + 2;
11013 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11014 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
); // +1 for \0
11015 if (!executablePathCString
) {
11018 strlcpy(executablePathCString
, path
->getCStringNoCopy(),
11019 executablePathCStringSize
);
11020 executablePathCString
[pathLength
++] = '/';
11021 executablePathCString
[pathLength
++] = '\0';
11022 strlcat(executablePathCString
, executableRelPath
->getCStringNoCopy(),
11023 executablePathCStringSize
);
11025 executablePathString
= OSString::withCString(executablePathCString
);
11027 if (!executablePathString
) {
11031 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11032 } else if (flags
.builtin
) {
11033 result
->setObject(kOSBundleExecutablePathKey
, bundleID
.get());
11034 } else if (isDriverKit()) {
11036 // +1 for slash, +1 for \0
11037 uint32_t pathLength
= path
->getLength();
11038 executablePathCStringSize
= pathLength
+ 2;
11040 executablePathCString
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
11041 executablePathCStringSize
, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
11042 if (!executablePathCString
) {
11045 strlcpy(executablePathCString
, path
->getCStringNoCopy(), executablePathCStringSize
);
11046 executablePathCString
[pathLength
++] = '/';
11047 executablePathCString
[pathLength
++] = '\0';
11049 executablePathString
= OSString::withCString(executablePathCString
);
11051 if (!executablePathString
) {
11055 result
->setObject(kOSBundleExecutablePathKey
, executablePathString
.get());
11060 /* UUID, if the kext has one.
11062 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleUUIDKey
)) {
11065 result
->setObject(kOSBundleUUIDKey
, uuid
.get());
11068 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleTextUUIDKey
)) {
11069 uuid
= copyTextUUID();
11071 result
->setObject(kOSBundleTextUUIDKey
, uuid
.get());
11076 * Info.plist digest
11078 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextInfoPlistDigestKey
)) {
11080 digest
= infoDict
? OSDynamicCast(OSData
, infoDict
->getObject(kOSKextInfoPlistDigestKey
)) : NULL
;
11082 result
->setObject(kOSKextInfoPlistDigestKey
, digest
);
11089 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextBundleCollectionTypeKey
)) {
11090 result
->setObject(kOSKextBundleCollectionTypeKey
, OSString::withCString(getKCTypeString()));
11094 * Collection availability
11096 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKextAuxKCAvailabilityKey
)) {
11097 result
->setObject(kOSKextAuxKCAvailabilityKey
,
11098 isLoadable() ? kOSBooleanTrue
: kOSBooleanFalse
);
11104 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleAllowUserLoadKey
)) {
11105 OSBoolean
*allowUserLoad
= OSDynamicCast(OSBoolean
, getPropertyForHostArch(kOSBundleAllowUserLoadKey
));
11106 if (allowUserLoad
) {
11107 result
->setObject(kOSBundleAllowUserLoadKey
, allowUserLoad
);
11112 * Bundle Dependencies (OSBundleLibraries)
11114 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLibrariesKey
)) {
11115 OSDictionary
*libraries
= OSDynamicCast(OSDictionary
, getPropertyForHostArch(kOSBundleLibrariesKey
));
11117 result
->setObject(kOSBundleLibrariesKey
, libraries
);
11122 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11124 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSKernelResourceKey
)) {
11125 result
->setObject(kOSKernelResourceKey
,
11126 isKernelComponent() ? kOSBooleanTrue
: kOSBooleanFalse
);
11129 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleIsInterfaceKey
)) {
11130 result
->setObject(kOSBundleIsInterfaceKey
,
11131 isInterface() ? kOSBooleanTrue
: kOSBooleanFalse
);
11134 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundlePrelinkedKey
)) {
11135 result
->setObject(kOSBundlePrelinkedKey
,
11136 isPrelinked() ? kOSBooleanTrue
: kOSBooleanFalse
);
11139 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleStartedKey
)) {
11140 result
->setObject(kOSBundleStartedKey
,
11141 isStarted() ? kOSBooleanTrue
: kOSBooleanFalse
);
11144 /* LoadTag (Index).
11146 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadTagKey
)) {
11147 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber((unsigned long long)loadTag
,
11148 /* numBits */ 8 * sizeof(loadTag
));
11149 if (!scratchNumber
) {
11152 result
->setObject(kOSBundleLoadTagKey
, scratchNumber
.get());
11155 /* LoadAddress, LoadSize.
11158 _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
) ||
11159 _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
) ||
11160 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
) ||
11161 _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
) ||
11162 _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11163 bool is_dext
= isDriverKit();
11164 if (isInterface() || flags
.builtin
|| linkedExecutable
|| is_dext
) {
11165 /* These go to userspace via serialization, so we don't want any doubts
11166 * about their size.
11168 uint64_t loadAddress
= 0;
11169 uint32_t loadSize
= 0;
11170 uint32_t wiredSize
= 0;
11171 uint64_t execLoadAddress
= 0;
11172 uint32_t execLoadSize
= 0;
11174 /* Interfaces always report 0 load address & size.
11175 * Just the way they roll.
11177 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11178 * xxx - shouldn't have one!
11181 if (flags
.builtin
|| linkedExecutable
) {
11182 kernel_mach_header_t
*mh
= NULL
;
11183 kernel_segment_command_t
*seg
= NULL
;
11185 if (flags
.builtin
) {
11186 loadAddress
= kmod_info
->address
;
11187 loadSize
= (uint32_t)kmod_info
->size
;
11189 loadAddress
= (uint64_t)linkedExecutable
->getBytesNoCopy();
11190 loadSize
= linkedExecutable
->getLength();
11192 mh
= (kernel_mach_header_t
*)loadAddress
;
11193 loadAddress
= ml_static_unslide(loadAddress
);
11195 /* Walk through the kext, looking for the first executable
11196 * segment in case we were asked for its size/address.
11198 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
11199 if (seg
->initprot
& VM_PROT_EXECUTE
) {
11200 execLoadAddress
= ml_static_unslide(seg
->vmaddr
);
11201 execLoadSize
= (uint32_t)seg
->vmsize
;
11206 /* If we have a kmod_info struct, calculated the wired size
11207 * from that. Otherwise it's the full load size.
11210 wiredSize
= loadSize
- (uint32_t)kmod_info
->hdr_size
;
11212 wiredSize
= loadSize
;
11214 } else if (is_dext
) {
11216 * DriverKit userspace executables do not have a kernel linkedExecutable,
11217 * so we "fake" their address range with the LoadTag.
11220 loadAddress
= execLoadAddress
= loadTag
;
11221 loadSize
= execLoadSize
= 1;
11225 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadAddressKey
)) {
11226 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11227 (unsigned long long)(loadAddress
),
11228 /* numBits */ 8 * sizeof(loadAddress
));
11229 if (!scratchNumber
) {
11232 result
->setObject(kOSBundleLoadAddressKey
, scratchNumber
.get());
11234 if (kcformat
== KCFormatStatic
|| kcformat
== KCFormatKCGEN
) {
11235 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleCacheLoadAddressKey
))
11236 && loadAddress
&& loadSize
) {
11237 void *baseAddress
= PE_get_kc_baseaddress(KCKindPrimary
);
11238 if (!baseAddress
) {
11242 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11243 (unsigned long long)ml_static_unslide((vm_offset_t
)baseAddress
),
11244 /* numBits */ 8 * sizeof(loadAddress
));
11245 if (!scratchNumber
) {
11248 result
->setObject(kOSBundleCacheLoadAddressKey
, scratchNumber
.get());
11250 if ((!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleKextsInKernelTextKey
))
11251 && (this == sKernelKext
) && gBuiltinKmodsCount
) {
11252 result
->setObject(kOSBundleKextsInKernelTextKey
, kOSBooleanTrue
);
11256 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadAddressKey
)) {
11257 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11258 (unsigned long long)(execLoadAddress
),
11259 /* numBits */ 8 * sizeof(execLoadAddress
));
11260 if (!scratchNumber
) {
11263 result
->setObject(kOSBundleExecLoadAddressKey
, scratchNumber
.get());
11265 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleLoadSizeKey
)) {
11266 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11267 (unsigned long long)(loadSize
),
11268 /* numBits */ 8 * sizeof(loadSize
));
11269 if (!scratchNumber
) {
11272 result
->setObject(kOSBundleLoadSizeKey
, scratchNumber
.get());
11274 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleExecLoadSizeKey
)) {
11275 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11276 (unsigned long long)(execLoadSize
),
11277 /* numBits */ 8 * sizeof(execLoadSize
));
11278 if (!scratchNumber
) {
11281 result
->setObject(kOSBundleExecLoadSizeKey
, scratchNumber
.get());
11283 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleWiredSizeKey
)) {
11284 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11285 (unsigned long long)(wiredSize
),
11286 /* numBits */ 8 * sizeof(wiredSize
));
11287 if (!scratchNumber
) {
11290 result
->setObject(kOSBundleWiredSizeKey
, scratchNumber
.get());
11295 /* OSBundleDependencies. In descending order for
11296 * easy compatibility with kextstat(8).
11298 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleDependenciesKey
)) {
11299 if ((count
= getNumDependencies())) {
11300 dependencyLoadTags
= OSArray::withCapacity(count
);
11301 result
->setObject(kOSBundleDependenciesKey
, dependencyLoadTags
.get());
11305 OSKext
* dependency
= OSDynamicCast(OSKext
,
11306 dependencies
->getObject(i
));
11311 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11312 (unsigned long long)dependency
->getLoadTag(),
11313 /* numBits*/ 8 * sizeof(loadTag
));
11314 if (!scratchNumber
) {
11317 dependencyLoadTags
->setObject(scratchNumber
.get());
11322 /* OSBundleMetaClasses.
11324 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleClassesKey
)) {
11325 if (metaClasses
&& metaClasses
->getCount()) {
11326 metaClassIterator
= OSCollectionIterator::withCollection(metaClasses
.get());
11327 metaClassInfo
= OSArray::withCapacity(metaClasses
->getCount());
11328 if (!metaClassIterator
|| !metaClassInfo
) {
11331 result
->setObject(kOSBundleClassesKey
, metaClassInfo
.get());
11333 while ((thisMetaClass
= OSDynamicCast(OSMetaClass
,
11334 metaClassIterator
->getNextObject()))) {
11335 metaClassDict
= OSDictionary::withCapacity(3);
11336 if (!metaClassDict
) {
11340 metaClassName
= OSString::withCString(thisMetaClass
->getClassName());
11341 if (thisMetaClass
->getSuperClass()) {
11342 superclassName
= OSString::withCString(
11343 thisMetaClass
->getSuperClass()->getClassName());
11345 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(thisMetaClass
->getInstanceCount(),
11346 8 * sizeof(unsigned int));
11348 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11351 if (!metaClassDict
|| !metaClassName
|| !scratchNumber
) {
11355 metaClassInfo
->setObject(metaClassDict
.get());
11356 metaClassDict
->setObject(kOSMetaClassNameKey
, metaClassName
.get());
11357 if (superclassName
) {
11358 metaClassDict
->setObject(kOSMetaClassSuperclassNameKey
, superclassName
.get());
11360 metaClassDict
->setObject(kOSMetaClassTrackingCountKey
, scratchNumber
.get());
11365 /* OSBundleRetainCount.
11367 if (!infoKeys
|| _OSArrayContainsCString(infoKeys
, kOSBundleRetainCountKey
)) {
11369 int kextRetainCount
= getRetainCount() - 1;
11373 OSSharedPtr
<OSNumber
> scratchNumber
= OSNumber::withNumber(
11374 (int)kextRetainCount
,
11375 /* numBits*/ 8 * sizeof(int));
11376 if (scratchNumber
) {
11377 result
->setObject(kOSBundleRetainCountKey
, scratchNumber
.get());
11385 if (executablePathCString
) {
11386 kheap_free(KHEAP_TEMP
, executablePathCString
, executablePathCStringSize
);
11394 /*********************************************************************
11395 *********************************************************************/
11398 OSKext::copyUserExecutablePath(const OSSymbol
* bundleID
, char * pathResult
, size_t pathSize
)
11401 OSSharedPtr
<OSKext
> kext
;
11403 IORecursiveLockLock(sKextLock
);
11404 kext
.reset(OSDynamicCast(OSKext
, sKextsByID
->getObject(bundleID
)), OSRetain
);
11405 IORecursiveLockUnlock(sKextLock
);
11407 if (!kext
|| !kext
->path
|| !kext
->userExecutableRelPath
) {
11410 snprintf(pathResult
, pathSize
, "%s/Contents/MacOS/%s",
11411 kext
->path
->getCStringNoCopy(),
11412 kext
->userExecutableRelPath
->getCStringNoCopy());
11418 /*********************************************************************
11419 *********************************************************************/
11422 OSKext::requestResource(
11423 const char * kextIdentifierCString
,
11424 const char * resourceNameCString
,
11425 OSKextRequestResourceCallback callback
,
11427 OSKextRequestTag
* requestTagOut
)
11429 OSReturn result
= kOSReturnError
;
11430 OSSharedPtr
<OSKext
> callbackKext
; // looked up
11432 OSKextRequestTag requestTag
= -1;
11433 OSSharedPtr
<OSNumber
> requestTagNum
;
11434 OSSharedPtr
<OSDictionary
> requestDict
;
11435 OSSharedPtr
<OSString
> kextIdentifier
;
11436 OSSharedPtr
<OSString
> resourceName
;
11438 OSSharedPtr
<OSDictionary
> callbackRecord
;
11439 OSSharedPtr
<OSData
> callbackWrapper
;
11441 OSSharedPtr
<OSData
> contextWrapper
;
11443 IORecursiveLockLock(sKextLock
);
11445 if (requestTagOut
) {
11446 *requestTagOut
= kOSKextRequestTagInvalid
;
11449 /* If requests to user space are disabled, don't go any further */
11450 if (!sKernelRequestsEnabled
) {
11451 OSKextLog(/* kext */ NULL
,
11452 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11453 "Can't request resource %s for %s - requests to user space are disabled.",
11454 resourceNameCString
,
11455 kextIdentifierCString
);
11456 result
= kOSKextReturnDisabled
;
11460 if (!kextIdentifierCString
|| !resourceNameCString
|| !callback
) {
11461 result
= kOSKextReturnInvalidArgument
;
11465 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
11466 if (!callbackKext
) {
11467 OSKextLog(/* kext */ NULL
,
11468 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11469 "Resource request has bad callback address.");
11470 result
= kOSKextReturnInvalidArgument
;
11473 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
11474 OSKextLog(/* kext */ NULL
,
11475 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11476 "Resource request callback is in a kext that is not started.");
11477 result
= kOSKextReturnInvalidArgument
;
11481 /* Do not allow any new requests to be made on a kext that is unloading.
11483 if (callbackKext
->flags
.stopping
) {
11484 result
= kOSKextReturnStopping
;
11488 /* If we're wrapped the next available request tag around to the negative
11489 * numbers, we can't service any more requests.
11491 if (sNextRequestTag
== kOSKextRequestTagInvalid
) {
11492 OSKextLog(/* kext */ NULL
,
11493 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11494 "No more request tags available; restart required.");
11495 result
= kOSKextReturnNoResources
;
11498 requestTag
= sNextRequestTag
++;
11500 result
= _OSKextCreateRequest(kKextRequestPredicateRequestResource
,
11502 if (result
!= kOSReturnSuccess
) {
11506 kextIdentifier
= OSString::withCString(kextIdentifierCString
);
11507 resourceName
= OSString::withCString(resourceNameCString
);
11508 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11509 8 * sizeof(requestTag
));
11510 if (!kextIdentifier
||
11513 !_OSKextSetRequestArgument(requestDict
.get(),
11514 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
.get()) ||
11515 !_OSKextSetRequestArgument(requestDict
.get(),
11516 kKextRequestArgumentNameKey
, resourceName
.get()) ||
11517 !_OSKextSetRequestArgument(requestDict
.get(),
11518 kKextRequestArgumentRequestTagKey
, requestTagNum
.get())) {
11519 result
= kOSKextReturnNoMemory
;
11523 callbackRecord
= OSDynamicPtrCast
<OSDictionary
>(requestDict
->copyCollection());
11524 if (!callbackRecord
) {
11525 result
= kOSKextReturnNoMemory
;
11528 // we validate callback address at call time
11529 callbackWrapper
= OSData::withBytes((void *)&callback
, sizeof(void *));
11531 contextWrapper
= OSData::withBytes((void *)&context
, sizeof(void *));
11533 if (!callbackWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11534 kKextRequestArgumentCallbackKey
, callbackWrapper
.get())) {
11535 result
= kOSKextReturnNoMemory
;
11540 if (!contextWrapper
|| !_OSKextSetRequestArgument(callbackRecord
.get(),
11541 kKextRequestArgumentContextKey
, contextWrapper
.get())) {
11542 result
= kOSKextReturnNoMemory
;
11547 /* Only post the requests after all the other potential failure points
11548 * have been passed.
11550 if (!sKernelRequests
->setObject(requestDict
.get()) ||
11551 !sRequestCallbackRecords
->setObject(callbackRecord
.get())) {
11552 result
= kOSKextReturnNoMemory
;
11556 OSKext::pingIOKitDaemon();
11558 result
= kOSReturnSuccess
;
11559 if (requestTagOut
) {
11560 *requestTagOut
= requestTag
;
11565 /* If we didn't succeed, yank the request & callback
11566 * from their holding arrays.
11568 if (result
!= kOSReturnSuccess
) {
11569 unsigned int index
;
11571 index
= sKernelRequests
->getNextIndexOfObject(requestDict
.get(), 0);
11572 if (index
!= (unsigned int)-1) {
11573 sKernelRequests
->removeObject(index
);
11575 index
= sRequestCallbackRecords
->getNextIndexOfObject(callbackRecord
.get(), 0);
11576 if (index
!= (unsigned int)-1) {
11577 sRequestCallbackRecords
->removeObject(index
);
11581 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11583 IORecursiveLockUnlock(sKextLock
);
11589 OSKext::requestDaemonLaunch(
11590 OSString
*kextIdentifier
,
11591 OSString
*serverName
,
11592 OSNumber
*serverTag
,
11593 OSSharedPtr
<IOUserServerCheckInToken
> &checkInToken
)
11596 IOUserServerCheckInToken
* checkInTokenRaw
= NULL
;
11598 result
= requestDaemonLaunch(kextIdentifier
, serverName
,
11599 serverTag
, &checkInTokenRaw
);
11601 if (kOSReturnSuccess
== result
) {
11602 checkInToken
.reset(checkInTokenRaw
, OSNoRetain
);
11609 OSKext::requestDaemonLaunch(
11610 OSString
*kextIdentifier
,
11611 OSString
*serverName
,
11612 OSNumber
*serverTag
,
11613 IOUserServerCheckInToken
** checkInToken
)
11615 OSReturn result
= kOSReturnError
;
11616 OSSharedPtr
<OSDictionary
> requestDict
;
11617 OSSharedPtr
<IOUserServerCheckInToken
> token
;
11619 if (!kextIdentifier
|| !serverName
|| !serverTag
) {
11620 result
= kOSKextReturnInvalidArgument
;
11624 IORecursiveLockLock(sKextLock
);
11626 OSKextLog(/* kext */ NULL
,
11627 kOSKextLogDebugLevel
|
11628 kOSKextLogGeneralFlag
,
11629 "Requesting daemon launch for %s with serverName %s and tag %llu",
11630 kextIdentifier
->getCStringNoCopy(),
11631 serverName
->getCStringNoCopy(),
11632 serverTag
->unsigned64BitValue()
11635 result
= _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch
, requestDict
);
11636 if (result
!= kOSReturnSuccess
) {
11640 token
.reset(IOUserServerCheckInToken::create(), OSNoRetain
);
11642 result
= kOSKextReturnNoMemory
;
11646 if (!_OSKextSetRequestArgument(requestDict
.get(),
11647 kKextRequestArgumentBundleIdentifierKey
, kextIdentifier
) ||
11648 !_OSKextSetRequestArgument(requestDict
.get(),
11649 kKextRequestArgumentDriverExtensionServerName
, serverName
) ||
11650 !_OSKextSetRequestArgument(requestDict
.get(),
11651 kKextRequestArgumentDriverExtensionServerTag
, serverTag
) ||
11652 !_OSKextSetRequestArgument(requestDict
.get(),
11653 kKextRequestArgumentCheckInToken
, token
.get())) {
11654 result
= kOSKextReturnNoMemory
;
11658 /* Only post the requests after all the other potential failure points
11659 * have been passed.
11661 if (!sKernelRequests
->setObject(requestDict
.get())) {
11662 result
= kOSKextReturnNoMemory
;
11665 *checkInToken
= token
.detach();
11666 OSKext::pingIOKitDaemon();
11668 result
= kOSReturnSuccess
;
11670 IORecursiveLockUnlock(sKextLock
);
11674 /*********************************************************************
11675 * Assumes sKextLock is held.
11676 *********************************************************************/
11679 OSKext::dequeueCallbackForRequestTag(
11680 OSKextRequestTag requestTag
,
11681 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11683 OSDictionary
* callbackRecordOutRaw
= NULL
;
11686 result
= dequeueCallbackForRequestTag(requestTag
,
11687 &callbackRecordOutRaw
);
11689 if (kOSReturnSuccess
== result
) {
11690 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11696 OSKext::dequeueCallbackForRequestTag(
11697 OSKextRequestTag requestTag
,
11698 OSDictionary
** callbackRecordOut
)
11700 OSReturn result
= kOSReturnError
;
11701 OSSharedPtr
<OSNumber
> requestTagNum
;
11703 requestTagNum
= OSNumber::withNumber((long long unsigned int)requestTag
,
11704 8 * sizeof(requestTag
));
11705 if (!requestTagNum
) {
11709 result
= OSKext::dequeueCallbackForRequestTag(requestTagNum
.get(),
11710 callbackRecordOut
);
11716 /*********************************************************************
11717 * Assumes sKextLock is held.
11718 *********************************************************************/
11721 OSKext::dequeueCallbackForRequestTag(
11722 OSNumber
* requestTagNum
,
11723 OSSharedPtr
<OSDictionary
> &callbackRecordOut
)
11725 OSDictionary
* callbackRecordOutRaw
= NULL
;
11728 result
= dequeueCallbackForRequestTag(requestTagNum
,
11729 &callbackRecordOutRaw
);
11731 if (kOSReturnSuccess
== result
) {
11732 callbackRecordOut
.reset(callbackRecordOutRaw
, OSNoRetain
);
11738 OSKext::dequeueCallbackForRequestTag(
11739 OSNumber
* requestTagNum
,
11740 OSDictionary
** callbackRecordOut
)
11742 OSReturn result
= kOSKextReturnInvalidArgument
;
11743 OSDictionary
* callbackRecord
= NULL
; // retain if matched!
11744 OSNumber
* callbackTagNum
= NULL
; // do not release
11745 unsigned int count
, i
;
11747 result
= kOSReturnError
;
11748 count
= sRequestCallbackRecords
->getCount();
11749 for (i
= 0; i
< count
; i
++) {
11750 callbackRecord
= OSDynamicCast(OSDictionary
,
11751 sRequestCallbackRecords
->getObject(i
));
11752 if (!callbackRecord
) {
11756 /* If we don't find a tag, we basically have a leak here. Maybe
11757 * we should just remove it.
11759 callbackTagNum
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(
11760 callbackRecord
, kKextRequestArgumentRequestTagKey
));
11761 if (!callbackTagNum
) {
11765 /* We could be even more paranoid and check that all the incoming
11766 * args match what's in the callback record.
11768 if (callbackTagNum
->isEqualTo(requestTagNum
)) {
11769 if (callbackRecordOut
) {
11770 *callbackRecordOut
= callbackRecord
;
11771 callbackRecord
->retain();
11773 sRequestCallbackRecords
->removeObject(i
);
11774 result
= kOSReturnSuccess
;
11778 result
= kOSKextReturnNotFound
;
11785 /*********************************************************************
11786 * Busy timeout triage
11787 *********************************************************************/
11790 OSKext::pendingIOKitDaemonRequests(void)
11792 return sRequestCallbackRecords
&& sRequestCallbackRecords
->getCount();
11795 /*********************************************************************
11796 * Acquires and releases sKextLock
11798 * This function is designed to be called exactly once on boot by
11799 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11800 * kext and dext personalities, and then attempts to map a System
11801 * (pageable) KC and an Auxiliary (aux) KC.
11803 * Even if the pageable or aux KC fail to load - this function will
11804 * not allow a second call. This avoids security issues where
11805 * kernelmanagerd has been compromised or the pageable kc has been
11806 * tampered with and the attacker attempts to re-load a malicious
11809 * Return: if a KC fails to load the return value will contain:
11810 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11811 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11812 * Similarly, if the aux kc load fails, the return value will
11813 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11814 * compose with each other and with kOSKextReturnKCLoadFailure.
11815 *********************************************************************/
11818 OSKext::loadFileSetKexts(OSDictionary
* requestDict __unused
)
11820 static bool daemon_ready
= false;
11822 OSReturn ret
= kOSKextReturnInvalidArgument
;
11823 OSReturn kcerr
= 0;
11824 bool start_matching
= false;
11826 bool allow_fileset_load
= !daemon_ready
;
11827 #if !(defined(__x86_64__) || defined(__i386__))
11828 /* never allow KCs full of kexts on non-x86 machines */
11829 allow_fileset_load
= false;
11833 * Get the args from the request. Right now we need the file
11834 * name for the pageable and the aux kext collection file sets.
11836 OSDictionary
* requestArgs
= NULL
; // do not release
11837 OSString
* pageable_filepath
= NULL
; // do not release
11838 OSString
* aux_filepath
= NULL
; // do not release
11839 OSArray
* codeless_kexts
= NULL
; // do not release
11841 kernel_mach_header_t
*akc_mh
= NULL
;
11843 requestArgs
= OSDynamicCast(OSDictionary
,
11844 requestDict
->getObject(kKextRequestArgumentsKey
));
11846 if (requestArgs
== NULL
) {
11847 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11848 "KextLog: No arguments in plist for loading fileset kext\n");
11849 printf("KextLog: No arguments in plist for loading fileset kext\n");
11853 ret
= kOSKextReturnDisabled
;
11855 IORecursiveLockLock(sKextLock
);
11857 if (!sLoadEnabled
) {
11858 OSKextLog(NULL
, kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11859 "KextLog: Kext loading is disabled (attempt to load KCs).");
11860 IORecursiveLockUnlock(sKextLock
);
11864 pageable_filepath
= OSDynamicCast(OSString
,
11865 requestArgs
->getObject(kKextRequestArgumentPageableKCFilename
));
11867 if (allow_fileset_load
&& pageable_filepath
!= NULL
) {
11868 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath
->getCStringNoCopy());
11870 ret
= OSKext::loadKCFileSet(pageable_filepath
->getCStringNoCopy(), KCKindPageable
);
11872 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11873 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11875 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret
);
11876 ret
= kOSKextReturnKCLoadFailure
;
11877 kcerr
|= kOSKextReturnKCLoadFailureSystemKC
;
11881 * Even if the AuxKC fails to load, we still want to send
11882 * the System KC personalities to the catalog for matching
11884 start_matching
= true;
11885 } else if (pageable_filepath
!= NULL
) {
11886 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11887 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath
->getCStringNoCopy());
11888 ret
= kOSKextReturnUnsupported
;
11892 akc_mh
= (kernel_mach_header_t
*)PE_get_kc_header(KCKindAuxiliary
);
11895 * If we try to load a deferred AuxKC, then don't ever attempt
11896 * a filesystem map of a file
11898 allow_fileset_load
= false;
11901 * This function is only called once per boot, so we haven't
11902 * yet loaded an AuxKC. If we have registered the AuxKC mach
11903 * header, that means that the kext collection has been placed
11904 * in memory for us by the booter, and is waiting for us to
11905 * process it. Grab the deferred XML plist of info
11906 * dictionaries and add all the kexts.
11908 OSSharedPtr
<OSObject
> parsedXML
;
11909 OSSharedPtr
<OSData
> loaded_kcUUID
;
11910 OSDictionary
*infoDict
;
11911 parsedXML
= consumeDeferredKextCollection(KCKindAuxiliary
);
11912 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
11915 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11916 added
= OSKext::addKextsFromKextCollection(akc_mh
, infoDict
,
11917 kPrelinkTextSegment
, loaded_kcUUID
, KCKindAuxiliary
);
11918 if (!loaded_kcUUID
) {
11919 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11920 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11921 } else if (!added
) {
11922 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
11923 "KextLog: WARNING: Failed to load AuxKC from memory.");
11925 /* only return success if the pageable load (above) was successful */
11926 if (ret
!= kOSKextReturnKCLoadFailure
) {
11927 ret
= kOSReturnSuccess
;
11929 /* the registration of the AuxKC parsed out the KC's UUID already */
11931 if (daemon_ready
) {
11933 * Complain, but don't return an error if this isn't the first time the
11934 * IOKit daemon is checking in. If the daemon ever restarts, we will
11935 * hit this case because we've already consumed the deferred personalities.
11936 * We return success here so that a call to this function from a restarted
11937 * daemon with no codeless kexts will succeed.
11939 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11940 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
11941 if (ret
!= kOSKextReturnKCLoadFailure
) {
11942 ret
= kOSReturnSuccess
;
11945 /* this is a real error case */
11946 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
11947 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
11948 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
11949 ret
= kOSKextReturnKCLoadFailure
;
11950 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
11955 aux_filepath
= OSDynamicCast(OSString
,
11956 requestArgs
->getObject(kKextRequestArgumentAuxKCFilename
));
11957 if (allow_fileset_load
&& aux_filepath
!= NULL
) {
11958 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath
->getCStringNoCopy());
11960 ret
= OSKext::loadKCFileSet(aux_filepath
->getCStringNoCopy(), KCKindAuxiliary
);
11962 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11963 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
11965 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret
);
11966 ret
= kOSKextReturnKCLoadFailure
;
11967 kcerr
|= kOSKextReturnKCLoadFailureAuxKC
;
11970 start_matching
= true;
11971 } else if (aux_filepath
!= NULL
) {
11972 OSKextLog(/* kext */ NULL
, kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
11973 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath
->getCStringNoCopy());
11974 if (ret
!= kOSKextReturnKCLoadFailure
) {
11975 ret
= kOSKextReturnUnsupported
;
11981 * Load codeless kexts last so that there is no possibilty of a
11982 * codeless kext bundle ID preventing a kext in the system KC from
11985 codeless_kexts
= OSDynamicCast(OSArray
,
11986 requestArgs
->getObject(kKextRequestArgumentCodelessPersonalities
));
11987 if (codeless_kexts
!= NULL
) {
11988 uint32_t count
= codeless_kexts
->getCount();
11989 OSKextLog(NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
11990 "KextLog: loading %d codeless kexts/dexts", count
);
11991 for (uint32_t i
= 0; i
< count
; i
++) {
11992 OSDictionary
*infoDict
;
11993 infoDict
= OSDynamicCast(OSDictionary
,
11994 codeless_kexts
->getObject(i
));
11998 // instantiate a new kext, and don't hold a reference
11999 // (the kext subsystem will hold one implicitly)
12000 OSKext::withCodelessInfo(infoDict
);
12002 /* ignore errors that are not KC load failures */
12003 if (ret
!= kOSKextReturnKCLoadFailure
) {
12004 ret
= kOSReturnSuccess
;
12006 start_matching
= true;
12009 /* send personalities to the IOCatalog once */
12010 if (ret
== kOSReturnSuccess
|| start_matching
|| sOSKextWasResetAfterUserspaceReboot
) {
12011 OSKext::sendAllKextPersonalitiesToCatalog(true);
12013 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12014 * things as active and start all the delayed matching: the
12015 * dext and codeless kext personalities should have all been
12016 * delivered via this one call.
12018 if (!daemon_ready
) {
12019 OSKext::setIOKitDaemonActive();
12020 OSKext::setDeferredLoadSucceeded(TRUE
);
12021 IOService::iokitDaemonLaunched();
12023 if (sOSKextWasResetAfterUserspaceReboot
) {
12024 sOSKextWasResetAfterUserspaceReboot
= false;
12025 OSKext::setIOKitDaemonActive();
12026 IOService::startDeferredMatches();
12030 if (ret
== kOSKextReturnKCLoadFailure
) {
12035 * Only allow this function to attempt to load the pageable and
12036 * aux KCs once per boot.
12038 daemon_ready
= true;
12040 IORecursiveLockUnlock(sKextLock
);
12046 OSKext::resetMutableSegments(void)
12048 kernel_segment_command_t
*seg
= NULL
;
12049 kernel_mach_header_t
*k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12051 OSKextSavedMutableSegment
*savedSegment
= NULL
;
12052 uintptr_t kext_slide
= PE_get_kc_slide(kc_type
);
12055 if (!savedMutableSegments
) {
12056 OSKextLog(this, kOSKextLogErrorLevel
| kOSKextLogLoadFlag
,
12057 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12058 err
= kOSKextReturnInternalError
;
12062 for (seg
= firstsegfromheader(k_mh
), index
= 0; seg
; seg
= nextsegfromheader(k_mh
, seg
)) {
12063 if (!segmentIsMutable(seg
)) {
12066 uint64_t unslid_vmaddr
= seg
->vmaddr
- kext_slide
;
12067 uint64_t vmsize
= seg
->vmsize
;
12068 err
= kOSKextReturnInternalError
;
12069 for (index
= 0; index
< savedMutableSegments
->getCount(); index
++) {
12070 savedSegment
= OSDynamicCast(OSKextSavedMutableSegment
, savedMutableSegments
->getObject(index
));
12071 assert(savedSegment
);
12072 if (savedSegment
->getVMAddr() == seg
->vmaddr
&& savedSegment
->getVMSize() == seg
->vmsize
) {
12073 OSKextLog(this, kOSKextLogDebugLevel
| kOSKextLogLoadFlag
,
12074 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg
->segname
, sizeof(seg
->segname
)), seg
->segname
, unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12075 err
= savedSegment
->restoreContents(seg
);
12076 if (err
!= kOSReturnSuccess
) {
12077 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12081 if (err
!= kOSReturnSuccess
) {
12082 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr
, unslid_vmaddr
+ vmsize
- 1);
12085 err
= kOSReturnSuccess
;
12091 /*********************************************************************
12092 * Assumes sKextLock is held.
12093 *********************************************************************/
12096 OSKext::loadKCFileSet(
12097 const char *filepath
,
12100 #if VM_MAPPED_KEXTS
12101 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12103 struct vnode
*vp
= NULL
;
12104 void *fileset_control
;
12106 bool pageable
= (type
== KCKindPageable
);
12108 if ((pageable
&& pageableKCloaded
) ||
12109 (!pageable
&& auxKCloaded
)) {
12110 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12111 "KC FileSet of type %s is already loaded", (pageable
? "Pageable" : "Aux"));
12113 return kOSKextReturnInvalidArgument
;
12116 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12117 if (!pageable
&& !pageableKCloaded
) {
12118 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12119 "Trying to load the Aux KC without loading the Pageable KC");
12120 return kOSKextReturnInvalidArgument
;
12123 fileset_control
= ubc_getobject_from_filename(filepath
, &vp
, &fsize
);
12125 if (fileset_control
== NULL
) {
12126 printf("Could not get memory control object for file %s", filepath
);
12128 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12129 "Could not get memory control object for file %s", filepath
);
12130 return kOSKextReturnInvalidArgument
;
12133 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12134 "Could not find vnode for file %s", filepath
);
12135 return kOSKextReturnInvalidArgument
;
12138 kernel_mach_header_t
*mh
= NULL
;
12139 uintptr_t slide
= 0;
12143 * When SIP is enabled, the KC we map must be SIP-protected
12145 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS
) != 0) {
12146 struct vnode_attr va
;
12149 VATTR_WANTED(&va
, va_flags
);
12150 error
= vnode_getattr(vp
, &va
, vfs_context_current());
12152 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12153 "vnode_getattr(%s) failed (error=%d)", filepath
, error
);
12154 err
= kOSKextReturnInternalError
;
12157 if (!(va
.va_flags
& SF_RESTRICTED
)) {
12158 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12159 "Path to KC '%s' is not SIP-protected", filepath
);
12160 err
= kOSKextReturnInvalidArgument
;
12166 err
= OSKext::mapKCFileSet(fileset_control
, (vm_size_t
)fsize
, &mh
, 0, &slide
, pageable
, NULL
);
12168 printf("KextLog: mapKCFileSet returned %d\n", err
);
12170 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12171 "mapKCFileSet returned %d\n", err
);
12173 err
= kOSKextReturnInvalidArgument
;
12179 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12180 assert(vp
!= NULL
);
12181 if (err
== kOSReturnSuccess
) {
12182 PE_set_kc_vp(type
, vp
);
12184 pageableKCloaded
= true;
12186 auxKCloaded
= true;
12196 return kOSKextReturnUnsupported
;
12197 #endif // VM_MAPPED_KEXTS
12200 #if defined(__x86_64__) || defined(__i386__)
12201 /*********************************************************************
12202 * Assumes sKextLock is held.
12203 *********************************************************************/
12206 OSKext::mapKCFileSet(
12209 kernel_mach_header_t
**mhp
,
12213 void *map_entry_list
)
12215 bool fileset_load
= false;
12218 kernel_section_t
*infoPlistSection
= NULL
;
12219 OSDictionary
*infoDict
= NULL
;
12221 OSSharedPtr
<OSObject
> parsedXML
;
12222 OSSharedPtr
<OSString
> errorString
;
12223 OSSharedPtr
<OSData
> loaded_kcUUID
;
12225 /* Check if initial load for file set */
12226 if (*mhp
== NULL
) {
12227 fileset_load
= true;
12229 /* Get a page aligned address from kext map to map the file */
12230 vm_map_offset_t pagealigned_addr
= get_address_from_kext_map(fsize
);
12231 if (pagealigned_addr
== 0) {
12232 return kOSKextReturnNoMemory
;
12235 *mhp
= (kernel_mach_header_t
*)pagealigned_addr
;
12237 /* Allocate memory for bailout mechanism */
12238 map_entry_list
= allocate_kcfileset_map_entry_list();
12239 if (map_entry_list
== NULL
) {
12240 return kOSKextReturnNoMemory
;
12244 uintptr_t *slideptr
= fileset_load
? slidep
: NULL
;
12245 err
= mapKCTextSegment(control
, mhp
, file_offset
, slideptr
, map_entry_list
);
12246 /* mhp and slideptr are updated by mapKCTextSegment */
12248 if (fileset_load
) {
12249 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12254 /* Initialize the kc header globals */
12255 if (fileset_load
) {
12257 PE_set_kc_header(KCKindPageable
, *mhp
, *slidep
);
12259 PE_set_kc_header(KCKindAuxiliary
, *mhp
, *slidep
);
12263 /* Iterate through all the segments and map necessary segments */
12264 struct load_command
*lcp
= (struct load_command
*) (*mhp
+ 1);
12265 for (unsigned int i
= 0; i
< (*mhp
)->ncmds
; i
++, lcp
= (struct load_command
*)((uintptr_t)lcp
+ lcp
->cmdsize
)) {
12266 vm_map_offset_t start
;
12267 kernel_mach_header_t
*k_mh
= NULL
;
12268 kernel_segment_command_t
* seg
= NULL
;
12269 struct fileset_entry_command
*fse
= NULL
;
12271 if (lcp
->cmd
== LC_SEGMENT_KERNEL
) {
12272 seg
= (kernel_segment_command_t
*)lcp
;
12273 start
= ((uintptr_t)(seg
->vmaddr
)) + *slidep
;
12274 } else if (lcp
->cmd
== LC_FILESET_ENTRY
) {
12275 fse
= (struct fileset_entry_command
*)lcp
;
12276 k_mh
= (kernel_mach_header_t
*)(((uintptr_t)(fse
->vmaddr
)) + *slidep
);
12278 /* Map the segments of the mach-o binary */
12279 err
= OSKext::mapKCFileSet(control
, 0, &k_mh
, fse
->fileoff
, slidep
, pageable
, map_entry_list
);
12281 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12282 return kOSKextReturnInvalidArgument
;
12285 } else if (lcp
->cmd
== LC_DYLD_CHAINED_FIXUPS
) {
12286 /* Check if the Aux KC is built pageable style */
12287 if (!pageable
&& !fileset_load
&& !auxKCloaded
) {
12288 resetAuxKCSegmentOnUnload
= true;
12295 if (fileset_load
) {
12296 if (seg
->vmsize
== 0) {
12300 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12301 if (strncmp(seg
->segname
, kPrelinkInfoSegment
, sizeof(seg
->segname
)) != 0 &&
12302 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) != 0 &&
12303 strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) != 0 &&
12304 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) != 0) {
12308 if (seg
->vmsize
== 0) {
12312 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12313 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12314 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12315 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12320 ret
= vm_map_kcfileset_segment(
12321 &start
, seg
->vmsize
,
12322 (memory_object_control_t
)control
, seg
->fileoff
, seg
->maxprot
);
12324 if (ret
!= KERN_SUCCESS
) {
12325 if (fileset_load
) {
12326 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12328 return kOSKextReturnInvalidArgument
;
12330 add_kcfileset_map_entry(map_entry_list
, start
, seg
->vmsize
);
12333 /* Return if regular mach-o */
12334 if (!fileset_load
) {
12339 * Fixup for the Pageable KC and the Aux KC is done by
12340 * i386_slide_kext_collection_mh_addrs, but it differs in
12343 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12344 * The fixup of kext segments and kext load commands are done at kext
12345 * load time by calling i386_slide_individual_kext.
12347 * AuxKC old style: Fixup all the segments and all the load commands.
12349 * AuxKC pageable style: Same as the Pageable KC.
12351 bool adjust_mach_header
= (pageable
? true : ((resetAuxKCSegmentOnUnload
) ? true : false));
12352 ret
= i386_slide_kext_collection_mh_addrs(*mhp
, *slidep
, adjust_mach_header
);
12353 if (ret
!= KERN_SUCCESS
) {
12354 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12355 return kOSKextReturnInvalidArgument
;
12358 /* Get the prelink info dictionary */
12359 infoPlistSection
= getsectbynamefromheader(*mhp
, kPrelinkInfoSegment
, kPrelinkInfoSection
);
12360 parsedXML
= OSUnserializeXML((const char *)infoPlistSection
->addr
, errorString
);
12362 infoDict
= OSDynamicCast(OSDictionary
, parsedXML
.get());
12366 const char *errorCString
= "(unknown error)";
12368 if (errorString
&& errorString
->getCStringNoCopy()) {
12369 errorCString
= errorString
->getCStringNoCopy();
12370 } else if (parsedXML
) {
12371 errorCString
= "not a dictionary";
12373 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12374 "Error unserializing kext info plist section: %s.", errorCString
);
12375 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12376 return kOSKextReturnInvalidArgument
;
12379 /* Validate that the Kext Collection is prelinked to the loaded KC */
12380 err
= OSKext::validateKCFileSetUUID(infoDict
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12382 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, TRUE
, pageable
);
12383 return kOSKextReturnInvalidArgument
;
12386 /* Set Protection of Segments */
12387 OSKext::protectKCFileSet(*mhp
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12389 OSKext::addKextsFromKextCollection(*mhp
,
12390 infoDict
, kPrelinkTextSegment
,
12391 loaded_kcUUID
, pageable
? KCKindPageable
: KCKindAuxiliary
);
12393 /* Copy in the KC UUID */
12394 if (!loaded_kcUUID
) {
12395 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12396 "WARNING: did not find UUID in prelinked %s KC!", pageable
? "Pageable" : "Aux");
12397 } else if (pageable
) {
12398 pageablekc_uuid_valid
= TRUE
;
12399 memcpy((void *)&pageablekc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12400 uuid_unparse_upper(pageablekc_uuid
, pageablekc_uuid_string
);
12402 auxkc_uuid_valid
= TRUE
;
12403 memcpy((void *)&auxkc_uuid
, (const void *)loaded_kcUUID
->getBytesNoCopy(), loaded_kcUUID
->getLength());
12404 uuid_unparse_upper(auxkc_uuid
, auxkc_uuid_string
);
12407 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list
, FALSE
, pageable
);
12412 /*********************************************************************
12413 * Assumes sKextLock is held.
12414 *********************************************************************/
12417 OSKext::mapKCTextSegment(
12419 kernel_mach_header_t
**mhp
,
12422 void *map_entry_list
)
12425 vm_map_offset_t mach_header_map_size
= vm_map_round_page(sizeof(kernel_mach_header_t
),
12427 vm_map_offset_t load_command_map_size
= 0;
12428 kernel_mach_header_t
*base_mh
= *mhp
;
12430 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12431 ret
= vm_map_kcfileset_segment(
12432 (vm_map_offset_t
*)&base_mh
, mach_header_map_size
,
12433 (memory_object_control_t
)control
, file_offset
, (VM_PROT_READ
| VM_PROT_WRITE
));
12435 if (ret
!= KERN_SUCCESS
) {
12436 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret
);
12438 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12439 "Failed to map mach header of kc fileset with error %d", ret
);
12440 return kOSKextReturnInvalidArgument
;
12444 /* Verify that it's an MH_FILESET */
12445 if (base_mh
->filetype
!= MH_FILESET
) {
12446 printf("Kext Log: mapKCTextSegment mach header filetype"
12447 " is not an MH_FILESET, it is %x", base_mh
->filetype
);
12449 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12450 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh
->filetype
);
12452 /* Unmap the mach header */
12453 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12454 return kOSKextReturnInvalidArgument
;
12458 /* Map the remaining pages of load commands */
12459 if (base_mh
->sizeofcmds
> mach_header_map_size
) {
12460 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12461 load_command_map_size
= base_mh
->sizeofcmds
- mach_header_map_size
;
12463 /* Map the load commands */
12464 ret
= vm_map_kcfileset_segment(
12465 &load_command_addr
, load_command_map_size
,
12466 (memory_object_control_t
)control
, file_offset
+ mach_header_map_size
,
12467 (VM_PROT_READ
| VM_PROT_WRITE
));
12469 if (ret
!= KERN_SUCCESS
) {
12470 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret
);
12471 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12472 "Failed to map load commands of kc fileset with error %d", ret
);
12474 /* Unmap the mach header */
12475 vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12476 return kOSKextReturnInvalidArgument
;
12480 kernel_segment_command_t
*text_seg
;
12481 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)base_mh
, SEG_TEXT
);
12483 /* Calculate the slide and vm addr of mach header */
12485 *mhp
= (kernel_mach_header_t
*)((uintptr_t)base_mh
+ text_seg
->vmaddr
);
12486 *slidep
= ((uintptr_t)*mhp
) - text_seg
->vmaddr
;
12489 /* Cache the text segment size and file offset before unmapping */
12490 vm_map_offset_t text_segment_size
= text_seg
->vmsize
;
12491 vm_object_offset_t text_segment_fileoff
= text_seg
->fileoff
;
12492 vm_prot_t text_maxprot
= text_seg
->maxprot
;
12494 /* Unmap the first page and loadcommands and map the text segment */
12495 ret
= vm_unmap_kcfileset_segment((vm_map_offset_t
*)&base_mh
, mach_header_map_size
);
12496 assert(ret
== KERN_SUCCESS
);
12498 if (load_command_map_size
) {
12499 vm_map_offset_t load_command_addr
= ((vm_map_offset_t
)base_mh
) + mach_header_map_size
;
12500 ret
= vm_unmap_kcfileset_segment(&load_command_addr
, load_command_map_size
);
12501 assert(ret
== KERN_SUCCESS
);
12504 /* Map the text segment at actual vm addr specified in fileset */
12505 ret
= vm_map_kcfileset_segment((vm_map_offset_t
*)mhp
, text_segment_size
,
12506 (memory_object_control_t
)control
, text_segment_fileoff
, text_maxprot
);
12507 if (ret
!= KERN_SUCCESS
) {
12508 OSKextLog(/* kext */ NULL
, kOSKextLogDebugLevel
| kOSKextLogIPCFlag
,
12509 "Failed to map Text segment of kc fileset with error %d", ret
);
12510 return kOSKextReturnInvalidArgument
;
12513 add_kcfileset_map_entry(map_entry_list
, (vm_map_offset_t
)*mhp
, text_segment_size
);
12517 /*********************************************************************
12518 * Assumes sKextLock is held.
12519 *********************************************************************/
12522 OSKext::protectKCFileSet(
12523 kernel_mach_header_t
*mh
,
12526 vm_map_t kext_map
= g_kext_map
;
12527 kernel_segment_command_t
* seg
= NULL
;
12528 vm_map_offset_t start
= 0;
12529 vm_map_offset_t end
= 0;
12532 /* Set VM permissions */
12533 seg
= firstsegfromheader((kernel_mach_header_t
*)mh
);
12535 start
= round_page(seg
->vmaddr
);
12536 end
= trunc_page(seg
->vmaddr
+ seg
->vmsize
);
12539 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12540 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12541 * for the Aux KC as well.
12543 if (strncmp(seg
->segname
, kKCBranchGots
, sizeof(seg
->segname
)) == 0 ||
12544 strncmp(seg
->segname
, kKCBranchStubs
, sizeof(seg
->segname
)) == 0 ||
12545 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0 ||
12546 (type
== KCKindAuxiliary
&& !resetAuxKCSegmentOnUnload
&&
12547 strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0)) {
12548 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12549 kext_map
, start
, end
, seg
->maxprot
, TRUE
, type
);
12550 if (ret
!= KERN_SUCCESS
) {
12551 printf("OSKext protect failed with error %d", ret
);
12552 return kOSKextReturnInvalidArgument
;
12555 ret
= OSKext_protect((kernel_mach_header_t
*)mh
,
12556 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12557 if (ret
!= KERN_SUCCESS
) {
12558 printf("OSKext protect failed with error %d", ret
);
12559 return kOSKextReturnInvalidArgument
;
12562 ret
= OSKext_wire((kernel_mach_header_t
*)mh
,
12563 kext_map
, start
, end
, seg
->initprot
, FALSE
, type
);
12564 if (ret
!= KERN_SUCCESS
) {
12565 printf("OSKext wire failed with error %d", ret
);
12566 return kOSKextReturnInvalidArgument
;
12570 seg
= nextsegfromheader((kernel_mach_header_t
*) mh
, seg
);
12576 /*********************************************************************
12577 * Assumes sKextLock is held.
12578 *********************************************************************/
12581 OSKext::freeKCFileSetcontrol(void)
12583 PE_reset_all_kc_vp();
12586 /*********************************************************************
12587 * Assumes sKextLock is held.
12589 * resetKCFileSetSegments: Kext start function expects data segment to
12590 * be pristine on every load, unmap the dirty segments on unload and
12591 * remap them from FileSet on disk. Remap all segments of kext since
12592 * fixups are done per kext and not per segment.
12593 *********************************************************************/
12595 OSKext::resetKCFileSetSegments(void)
12597 kernel_segment_command_t
*seg
= NULL
;
12598 kernel_segment_command_t
*text_seg
;
12599 uint32_t text_fileoff
;
12600 kernel_mach_header_t
*k_mh
= NULL
;
12602 struct vnode
*vp
= NULL
;
12603 void *fileset_control
= NULL
;
12604 bool pageable
= (kc_type
== KCKindPageable
);
12608 /* Check the vnode reference is still available */
12609 vp
= (struct vnode
*)PE_get_kc_vp(kc_type
);
12611 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12612 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12613 return kOSKextReturnInternalError
;
12616 fileset_control
= ubc_getobject(vp
, 0);
12617 assert(fileset_control
!= NULL
);
12619 OSKextLog(this, kOSKextLogProgressLevel
| kOSKextLogLoadFlag
,
12620 "Kext %s resetting all segments", getIdentifierCString());
12622 k_mh
= (kernel_mach_header_t
*)kmod_info
->address
;
12623 text_seg
= getsegbynamefromheader((kernel_mach_header_t
*)kmod_info
->address
, SEG_TEXT
);
12624 text_fileoff
= text_seg
->fileoff
;
12625 slide
= PE_get_kc_slide(kc_type
);
12627 seg
= firstsegfromheader((kernel_mach_header_t
*)k_mh
);
12629 if (seg
->vmsize
== 0) {
12630 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12634 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12635 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0 ||
12636 strncmp(seg
->segname
, SEG_LINKINFO
, sizeof(seg
->segname
)) == 0 ||
12637 strncmp(seg
->segname
, SEG_TEXT
, sizeof(seg
->segname
)) == 0) {
12638 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12642 kr
= vm_unmap_kcfileset_segment(&seg
->vmaddr
, seg
->vmsize
);
12643 assert(kr
== KERN_SUCCESS
);
12644 seg
= nextsegfromheader((kernel_mach_header_t
*) k_mh
, seg
);
12647 /* Unmap the text segment */
12648 kr
= vm_unmap_kcfileset_segment(&text_seg
->vmaddr
, text_seg
->vmsize
);
12649 assert(kr
== KERN_SUCCESS
);
12651 /* Map all the segments of the kext */
12652 err
= OSKext::mapKCFileSet(fileset_control
, 0, &k_mh
, text_fileoff
, &slide
, pageable
, NULL
);
12654 panic("Could not reset segments of a mapped kext, error %x", err
);
12657 /* Update address in kmod_info, since it has been reset */
12658 if (kmod_info
->address
) {
12659 kmod_info
->address
= (((uintptr_t)(kmod_info
->address
)) + slide
);
12665 /*********************************************************************
12666 * Mechanism to track all segment mapping while mapping KC fileset.
12667 *********************************************************************/
12669 struct kcfileset_map_entry
{
12670 vm_map_offset_t me_start
;
12671 vm_map_offset_t me_size
;
12674 struct kcfileset_map_entry_list
{
12675 int kme_list_count
;
12676 int kme_list_index
;
12677 struct kcfileset_map_entry kme_list
[];
12680 #define KCFILESET_MAP_ENTRY_MAX (16380)
12683 allocate_kcfileset_map_entry_list(void)
12685 struct kcfileset_map_entry_list
*entry_list
;
12687 entry_list
= (struct kcfileset_map_entry_list
*)kalloc(sizeof(struct kcfileset_map_entry_list
) +
12688 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12690 entry_list
->kme_list_count
= KCFILESET_MAP_ENTRY_MAX
;
12691 entry_list
->kme_list_index
= 0;
12696 add_kcfileset_map_entry(
12697 void *map_entry_list
,
12698 vm_map_offset_t start
,
12699 vm_map_offset_t size
)
12701 if (map_entry_list
== NULL
) {
12705 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12707 if (entry_list
->kme_list_index
>= entry_list
->kme_list_count
) {
12708 panic("Ran out of map kc fileset list\n");
12711 entry_list
->kme_list
[entry_list
->kme_list_index
].me_start
= start
;
12712 entry_list
->kme_list
[entry_list
->kme_list_index
].me_size
= size
;
12714 entry_list
->kme_list_index
++;
12718 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12719 void *map_entry_list
,
12720 boolean_t unmap_entries
,
12723 struct kcfileset_map_entry_list
*entry_list
= (struct kcfileset_map_entry_list
*)map_entry_list
;
12725 if (unmap_entries
) {
12726 for (int i
= 0; i
< entry_list
->kme_list_index
; i
++) {
12728 ret
= vm_unmap_kcfileset_segment(
12729 &(entry_list
->kme_list
[i
].me_start
),
12730 entry_list
->kme_list
[i
].me_size
);
12731 assert(ret
== KERN_SUCCESS
);
12734 PE_reset_kc_header(pageable
? KCKindPageable
: KCKindAuxiliary
);
12737 kfree(entry_list
, sizeof(struct kcfileset_map_entry_list
) +
12738 (sizeof(struct kcfileset_map_entry
) * KCFILESET_MAP_ENTRY_MAX
));
12741 /*********************************************************************
12742 * Mechanism to map kext segment.
12743 *********************************************************************/
12746 vm_map_kcfileset_segment(
12747 vm_map_offset_t
*start
,
12748 vm_map_offset_t size
,
12750 vm_object_offset_t fileoffset
,
12751 vm_prot_t max_prot
)
12753 vm_map_kernel_flags_t vmk_flags
;
12754 vmk_flags
.vmkf_no_copy_on_read
= 1;
12755 vmk_flags
.vmkf_cs_enforcement
= 0;
12756 vmk_flags
.vmkf_cs_enforcement_override
= 1;
12759 /* Add Write to max prot to allow fixups */
12760 max_prot
= max_prot
| VM_PROT_WRITE
;
12763 * Map the segments from file as COPY mappings to
12764 * make sure changes on disk to the file does not affect
12767 ret
= vm_map_enter_mem_object_control(
12771 (mach_vm_offset_t
)0,
12774 VM_KERN_MEMORY_OSKEXT
,
12775 (memory_object_control_t
)control
,
12778 (VM_PROT_READ
| VM_PROT_WRITE
), max_prot
,
12785 vm_unmap_kcfileset_segment(
12786 vm_map_offset_t
*start
,
12787 vm_map_offset_t size
)
12789 return mach_vm_deallocate(g_kext_map
, *start
, size
);
12792 #endif //(__x86_64__) || defined(__i386__)
12794 /*********************************************************************
12795 * Assumes sKextLock is held.
12796 *********************************************************************/
12799 OSKext::validateKCFileSetUUID(
12800 OSDictionary
*infoDict
,
12803 OSReturn ret
= kOSReturnSuccess
;
12805 if (!kernelcache_uuid_valid
) {
12806 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12807 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12808 ret
= kOSKextReturnInvalidArgument
;
12811 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid
, type
, infoDict
, kPrelinkInfoBootKCIDKey
);
12816 #if defined(__x86_64__) || defined(__i386__)
12817 /* Check if the Aux KC is prelinked to correct Pageable KC */
12818 if (type
== KCKindAuxiliary
) {
12819 if (!pageablekc_uuid_valid
) {
12820 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12821 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12822 ret
= kOSKextReturnInvalidArgument
;
12825 ret
= OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid
, type
, infoDict
, kPrelinkInfoPageableKCIDKey
);
12830 #endif //(__x86_64__) || defined(__i386__)
12832 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12837 /*********************************************************************
12838 * Assumes sKextLock is held.
12839 *********************************************************************/
12842 OSKext::validateKCUUIDfromPrelinkInfo(
12843 uuid_t
*loaded_kcuuid
,
12845 OSDictionary
*infoDict
,
12846 const char *uuid_key
)
12848 /* extract the UUID from the dictionary */
12849 OSData
*prelinkinfoKCUUID
= OSDynamicCast(OSData
, infoDict
->getObject(uuid_key
));
12850 if (!prelinkinfoKCUUID
) {
12851 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12852 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key
);
12853 return kOSKextReturnInvalidArgument
;
12856 if (prelinkinfoKCUUID
->getLength() != sizeof(uuid_t
)) {
12857 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12858 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key
, prelinkinfoKCUUID
->getLength());
12859 return kOSKextReturnInvalidArgument
;
12862 if (memcmp((void *)loaded_kcuuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(),
12863 prelinkinfoKCUUID
->getLength())) {
12864 OSData
*info_dict_uuid
;
12865 uuid_string_t info_dict_uuid_str
= {};
12866 uuid_string_t expected_uuid_str
= {};
12867 uuid_string_t given_uuid_str
= {};
12870 /* extract the KC UUID from the dictionary */
12871 info_dict_uuid
= OSDynamicCast(OSData
, infoDict
->getObject(kPrelinkInfoKCIDKey
));
12872 if (info_dict_uuid
&& info_dict_uuid
->getLength() == sizeof(uuid_t
)) {
12874 memcpy(tmp_uuid
, (const void *)info_dict_uuid
->getBytesNoCopy(), sizeof(tmp_uuid
));
12875 uuid_unparse(tmp_uuid
, info_dict_uuid_str
);
12878 uuid_unparse(*loaded_kcuuid
, expected_uuid_str
);
12879 memcpy(given_uuid
, (const void *)prelinkinfoKCUUID
->getBytesNoCopy(), sizeof(given_uuid
));
12880 uuid_unparse(given_uuid
, given_uuid_str
);
12882 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12883 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12884 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
12885 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key
,
12886 given_uuid_str
, expected_uuid_str
, info_dict_uuid_str
);
12887 if (type
== KCKindPageable
&& sPanicOnKCMismatch
) {
12888 panic("System KC UUID %s linked against %s, but %s is loaded",
12889 info_dict_uuid_str
, given_uuid_str
, expected_uuid_str
);
12891 return kOSKextReturnInvalidArgument
;
12897 /*********************************************************************
12898 * Assumes sKextLock is held.
12899 *********************************************************************/
12902 OSKext::dispatchResource(OSDictionary
* requestDict
)
12904 OSReturn result
= kOSReturnError
;
12905 OSSharedPtr
<OSDictionary
> callbackRecord
;
12906 OSNumber
* requestTag
= NULL
; // do not release
12907 OSNumber
* requestResult
= NULL
; // do not release
12908 OSData
* dataObj
= NULL
; // do not release
12909 uint32_t dataLength
= 0;
12910 const void * dataPtr
= NULL
; // do not free
12911 OSData
* callbackWrapper
= NULL
; // do not release
12912 OSKextRequestResourceCallback callback
= NULL
;
12913 OSData
* contextWrapper
= NULL
; // do not release
12914 void * context
= NULL
; // do not free
12915 OSSharedPtr
<OSKext
> callbackKext
;
12917 /* Get the args from the request. Right now we need the tag
12918 * to look up the callback record, and the result for invoking the callback.
12920 requestTag
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12921 kKextRequestArgumentRequestTagKey
));
12922 requestResult
= OSDynamicCast(OSNumber
, _OSKextGetRequestArgument(requestDict
,
12923 kKextRequestArgumentResultKey
));
12924 if (!requestTag
|| !requestResult
) {
12925 result
= kOSKextReturnInvalidArgument
;
12929 /* Look for a callback record matching this request's tag.
12931 result
= dequeueCallbackForRequestTag(requestTag
, callbackRecord
);
12932 if (result
!= kOSReturnSuccess
) {
12937 * Get the context pointer of the callback record (if there is one).
12939 contextWrapper
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(callbackRecord
.get(),
12940 kKextRequestArgumentContextKey
));
12941 context
= _OSKextExtractPointer(contextWrapper
);
12942 if (contextWrapper
&& !context
) {
12946 callbackWrapper
= OSDynamicCast(OSData
,
12947 _OSKextGetRequestArgument(callbackRecord
.get(),
12948 kKextRequestArgumentCallbackKey
));
12949 callback
= _OSKextExtractCallbackPointer(callbackWrapper
);
12954 /* Check for a data obj. We might not have one and that's ok, that means
12955 * we didn't find the requested resource, and we still have to tell the
12956 * caller that via the callback.
12958 dataObj
= OSDynamicCast(OSData
, _OSKextGetRequestArgument(requestDict
,
12959 kKextRequestArgumentValueKey
));
12961 dataPtr
= dataObj
->getBytesNoCopy();
12962 dataLength
= dataObj
->getLength();
12965 callbackKext
= OSKext::lookupKextWithAddress((vm_address_t
)callback
);
12966 if (!callbackKext
) {
12967 OSKextLog(/* kext */ NULL
,
12968 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
12969 "Can't invoke callback for resource request; ");
12972 if (!callbackKext
->flags
.starting
&& !callbackKext
->flags
.started
) {
12973 OSKextLog(/* kext */ NULL
,
12974 kOSKextLogErrorLevel
| kOSKextLogIPCFlag
,
12975 "Can't invoke kext resource callback; ");
12979 (void)callback(requestTag
->unsigned32BitValue(),
12980 (OSReturn
)requestResult
->unsigned32BitValue(),
12981 dataPtr
, dataLength
, context
);
12983 result
= kOSReturnSuccess
;
12989 /*********************************************************************
12990 * Assumes sKextLock is held.
12991 *********************************************************************/
12994 OSKext::setMissingAuxKCBundles(OSDictionary
* requestDict
)
12996 OSSharedPtr
<OSDictionary
> missingIDs
;
12997 OSArray
*bundleIDList
= NULL
; // do not release
12999 bundleIDList
= OSDynamicCast(OSArray
, _OSKextGetRequestArgument(
13000 requestDict
, kKextRequestArgumentMissingBundleIDs
));
13001 if (!bundleIDList
) {
13002 return kOSKextReturnInvalidArgument
;
13005 missingIDs
= OSDictionary::withCapacity(bundleIDList
->getCount());
13007 return kOSKextReturnNoMemory
;
13011 count
= bundleIDList
->getCount();
13012 for (i
= 0; i
< count
; i
++) {
13013 OSString
*thisID
= OSDynamicCast(OSString
, bundleIDList
->getObject(i
));
13015 missingIDs
->setObject(thisID
, kOSBooleanFalse
);
13019 sNonLoadableKextsByID
.reset(missingIDs
.get(), OSRetain
);
13021 return kOSReturnSuccess
;
13024 /*********************************************************************
13025 * Assumes sKextLock is held.
13026 *********************************************************************/
13029 OSKext::setAuxKCBundleAvailable(OSString
*kextIdentifier
, OSDictionary
*requestDict
)
13031 bool loadable
= true;
13032 if (!kextIdentifier
) {
13033 return kOSKextReturnInvalidArgument
;
13037 OSBoolean
*loadableArg
;
13038 loadableArg
= OSDynamicCast(OSBoolean
, _OSKextGetRequestArgument(
13039 requestDict
, kKextRequestArgumentBundleAvailability
));
13040 /* If we find the "Bundle Available" arg, and it's false, then
13041 * mark the bundle ID as _not_ loadable
13043 if (loadableArg
&& !loadableArg
->getValue()) {
13048 if (!sNonLoadableKextsByID
) {
13049 sNonLoadableKextsByID
= OSDictionary::withCapacity(1);
13052 sNonLoadableKextsByID
->setObject(kextIdentifier
, OSBoolean::withBoolean(loadable
));
13054 OSKextLog(/* kext */ NULL
,
13055 kOSKextLogBasicLevel
| kOSKextLogIPCFlag
,
13056 "KextLog: AuxKC bundle %s marked as %s",
13057 kextIdentifier
->getCStringNoCopy(),
13058 (loadable
? "loadable" : "NOT loadable"));
13060 return kOSReturnSuccess
;
13063 /*********************************************************************
13064 *********************************************************************/
13067 OSKext::invokeRequestCallback(
13068 OSDictionary
* callbackRecord
,
13069 OSReturn callbackResult
)
13071 OSString
* predicate
= _OSKextGetRequestPredicate(callbackRecord
);
13072 OSSharedPtr
<OSNumber
> resultNum
;
13078 resultNum
= OSNumber::withNumber((long long unsigned int)callbackResult
,
13079 8 * sizeof(callbackResult
));
13084 /* Insert the result into the callback record and dispatch it as if it
13085 * were the reply coming down from user space.
13087 _OSKextSetRequestArgument(callbackRecord
, kKextRequestArgumentResultKey
,
13090 if (predicate
->isEqualTo(kKextRequestPredicateRequestResource
)) {
13091 /* This removes the pending callback record.
13093 OSKext::dispatchResource(callbackRecord
);
13100 /*********************************************************************
13101 * Assumes sKextLock is held.
13102 *********************************************************************/
13105 OSKext::cancelRequest(
13106 OSKextRequestTag requestTag
,
13107 void ** contextOut
)
13109 OSReturn result
= kOSKextReturnNoMemory
;
13110 OSSharedPtr
<OSDictionary
> callbackRecord
;
13111 OSData
* contextWrapper
= NULL
; // do not release
13113 IORecursiveLockLock(sKextLock
);
13114 result
= OSKext::dequeueCallbackForRequestTag(requestTag
,
13116 IORecursiveLockUnlock(sKextLock
);
13118 if (result
== kOSReturnSuccess
&& contextOut
) {
13119 contextWrapper
= OSDynamicCast(OSData
,
13120 _OSKextGetRequestArgument(callbackRecord
.get(),
13121 kKextRequestArgumentContextKey
));
13122 *contextOut
= _OSKextExtractPointer(contextWrapper
);
13128 /*********************************************************************
13129 * Assumes sKextLock is held.
13130 *********************************************************************/
13132 OSKext::invokeOrCancelRequestCallbacks(
13133 OSReturn callbackResult
,
13136 unsigned int count
, i
;
13138 count
= sRequestCallbackRecords
->getCount();
13145 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13146 sRequestCallbackRecords
->getObject(i
));
13151 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13152 _OSKextGetRequestArgument(request
,
13153 kKextRequestArgumentCallbackKey
));
13155 if (!callbackWrapper
) {
13156 sRequestCallbackRecords
->removeObject(i
);
13160 vm_address_t callbackAddress
= (vm_address_t
)
13161 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13163 if ((kmod_info
->address
<= callbackAddress
) &&
13164 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13166 /* This removes the callback record.
13168 invokeRequestCallback(request
, callbackResult
);
13170 sRequestCallbackRecords
->removeObject(i
);
13179 /*********************************************************************
13180 * Assumes sKextLock is held.
13181 *********************************************************************/
13183 OSKext::countRequestCallbacks(void)
13185 uint32_t result
= 0;
13186 unsigned int count
, i
;
13188 count
= sRequestCallbackRecords
->getCount();
13195 OSDictionary
* request
= OSDynamicCast(OSDictionary
,
13196 sRequestCallbackRecords
->getObject(i
));
13201 OSData
* callbackWrapper
= OSDynamicCast(OSData
,
13202 _OSKextGetRequestArgument(request
,
13203 kKextRequestArgumentCallbackKey
));
13205 if (!callbackWrapper
) {
13209 vm_address_t callbackAddress
= (vm_address_t
)
13210 ptrauth_strip(_OSKextExtractPointer(callbackWrapper
), ptrauth_key_function_pointer
);
13212 if ((kmod_info
->address
<= callbackAddress
) &&
13213 (callbackAddress
< (kmod_info
->address
+ kmod_info
->size
))) {
13222 /*********************************************************************
13223 *********************************************************************/
13225 _OSKextCreateRequest(
13226 const char * predicate
,
13227 OSSharedPtr
<OSDictionary
> & requestR
)
13229 OSReturn result
= kOSKextReturnNoMemory
;
13230 OSSharedPtr
<OSDictionary
> request
;
13232 request
= OSDictionary::withCapacity(2);
13236 result
= _OSDictionarySetCStringValue(request
.get(),
13237 kKextRequestPredicateKey
, predicate
);
13238 if (result
!= kOSReturnSuccess
) {
13241 result
= kOSReturnSuccess
;
13244 if (result
== kOSReturnSuccess
) {
13245 requestR
= os::move(request
);
13251 /*********************************************************************
13252 *********************************************************************/
13254 _OSKextGetRequestPredicate(OSDictionary
* requestDict
)
13256 return OSDynamicCast(OSString
,
13257 requestDict
->getObject(kKextRequestPredicateKey
));
13260 /*********************************************************************
13261 *********************************************************************/
13263 _OSKextGetRequestArgument(
13264 OSDictionary
* requestDict
,
13265 const char * argName
)
13267 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13268 requestDict
->getObject(kKextRequestArgumentsKey
));
13270 return args
->getObject(argName
);
13275 /*********************************************************************
13276 *********************************************************************/
13278 _OSKextSetRequestArgument(
13279 OSDictionary
* requestDict
,
13280 const char * argName
,
13283 OSDictionary
* args
= OSDynamicCast(OSDictionary
,
13284 requestDict
->getObject(kKextRequestArgumentsKey
));
13285 OSSharedPtr
<OSDictionary
> newArgs
;
13287 newArgs
= OSDictionary::withCapacity(2);
13288 args
= newArgs
.get();
13292 requestDict
->setObject(kKextRequestArgumentsKey
, args
);
13295 return args
->setObject(argName
, value
);
13301 /*********************************************************************
13302 *********************************************************************/
13304 _OSKextExtractPointer(OSData
* wrapper
)
13306 void * result
= NULL
;
13307 const void * resultPtr
= NULL
;
13312 resultPtr
= wrapper
->getBytesNoCopy();
13313 result
= *(void **)resultPtr
;
13318 /*********************************************************************
13319 *********************************************************************/
13320 static OSKextRequestResourceCallback
13321 _OSKextExtractCallbackPointer(OSData
* wrapper
)
13323 OSKextRequestResourceCallback result
= NULL
;
13324 const void * resultPtr
= NULL
;
13329 resultPtr
= wrapper
->getBytesNoCopy();
13330 result
= *(OSKextRequestResourceCallback
*)resultPtr
;
13336 /*********************************************************************
13337 *********************************************************************/
13339 _OSDictionarySetCStringValue(
13340 OSDictionary
* dict
,
13342 const char * cValue
)
13344 OSReturn result
= kOSKextReturnNoMemory
;
13345 OSSharedPtr
<const OSSymbol
> key
;
13346 OSSharedPtr
<OSString
> value
;
13348 key
= OSSymbol::withCString(cKey
);
13349 value
= OSString::withCString(cValue
);
13350 if (!key
|| !value
) {
13353 if (dict
->setObject(key
.get(), value
.get())) {
13354 result
= kOSReturnSuccess
;
13361 /*********************************************************************
13362 *********************************************************************/
13364 _OSArrayContainsCString(
13366 const char * cString
)
13368 bool result
= false;
13369 OSSharedPtr
<const OSSymbol
> symbol
;
13372 if (!array
|| !cString
) {
13376 symbol
= OSSymbol::withCStringNoCopy(cString
);
13381 count
= array
->getCount();
13382 for (i
= 0; i
< count
; i
++) {
13383 OSObject
* thisObject
= array
->getObject(i
);
13384 if (symbol
->isEqualTo(thisObject
)) {
13395 /*********************************************************************
13396 * We really only care about boot / system start up related kexts.
13397 * We return true if we're less than REBUILD_MAX_TIME since start up,
13398 * otherwise return false.
13399 *********************************************************************/
13401 _OSKextInPrelinkRebuildWindow(void)
13403 static bool outside_the_window
= false;
13404 AbsoluteTime my_abstime
;
13408 if (outside_the_window
) {
13411 clock_get_uptime(&my_abstime
);
13412 absolutetime_to_nanoseconds(my_abstime
, &my_ns
);
13413 my_secs
= (SInt32
)(my_ns
/ NSEC_PER_SEC
);
13414 if (my_secs
> REBUILD_MAX_TIME
) {
13415 outside_the_window
= true;
13420 #endif /* CONFIG_KXLD */
13422 /*********************************************************************
13423 *********************************************************************/
13425 _OSKextInUnloadedPrelinkedKexts( const OSSymbol
* theBundleID
)
13427 int unLoadedCount
, i
;
13428 bool result
= false;
13430 IORecursiveLockLock(sKextLock
);
13432 if (sUnloadedPrelinkedKexts
== NULL
) {
13435 unLoadedCount
= sUnloadedPrelinkedKexts
->getCount();
13436 if (unLoadedCount
== 0) {
13440 for (i
= 0; i
< unLoadedCount
; i
++) {
13441 const OSSymbol
* myBundleID
; // do not release
13443 myBundleID
= OSDynamicCast(OSSymbol
, sUnloadedPrelinkedKexts
->getObject(i
));
13447 if (theBundleID
->isEqualTo(myBundleID
->getCStringNoCopy())) {
13453 IORecursiveLockUnlock(sKextLock
);
13458 #pragma mark Personalities (IOKit Drivers)
13460 /*********************************************************************
13461 *********************************************************************/
13463 OSSharedPtr
<OSArray
>
13464 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag
)
13466 OSSharedPtr
<OSArray
> result
;
13467 OSSharedPtr
<OSCollectionIterator
> kextIterator
;
13468 OSSharedPtr
<OSArray
> personalities
;
13470 OSString
* kextID
= NULL
; // do not release
13471 OSKext
* theKext
= NULL
; // do not release
13473 IORecursiveLockLock(sKextLock
);
13475 /* Let's conservatively guess that any given kext has around 3
13476 * personalities for now.
13478 result
= OSArray::withCapacity(sKextsByID
->getCount() * 3);
13483 kextIterator
= OSCollectionIterator::withCollection(sKextsByID
.get());
13484 if (!kextIterator
) {
13488 while ((kextID
= OSDynamicCast(OSString
, kextIterator
->getNextObject()))) {
13489 theKext
= OSDynamicCast(OSKext
, sKextsByID
->getObject(kextID
));
13490 if (theKext
->flags
.requireExplicitLoad
) {
13492 kOSKextLogDebugLevel
|
13493 kOSKextLogLoadFlag
,
13494 "Kext %s requires an explicit kextload; "
13495 "omitting its personalities.",
13496 theKext
->getIdentifierCString());
13497 } else if (!sSafeBoot
|| !filterSafeBootFlag
|| theKext
->isLoadableInSafeBoot()) {
13498 personalities
= theKext
->copyPersonalitiesArray();
13499 if (!personalities
) {
13502 result
->merge(personalities
.get());
13504 // xxx - check for better place to put this log msg
13506 kOSKextLogWarningLevel
|
13507 kOSKextLogLoadFlag
,
13508 "Kext %s is not loadable during safe boot; "
13509 "omitting its personalities.",
13510 theKext
->getIdentifierCString());
13515 IORecursiveLockUnlock(sKextLock
);
13520 /*********************************************************************
13521 *********************************************************************/
13524 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching
)
13526 int numPersonalities
= 0;
13528 OSKextLog(/* kext */ NULL
,
13529 kOSKextLogStepLevel
|
13530 kOSKextLogLoadFlag
,
13531 "Sending all eligible registered kexts' personalities "
13532 "to the IOCatalogue %s.",
13533 startMatching
? "and starting matching" : "but not starting matching");
13535 OSSharedPtr
<OSArray
> personalities
= OSKext::copyAllKextPersonalities(
13536 /* filterSafeBootFlag */ true);
13538 if (personalities
) {
13539 gIOCatalogue
->addDrivers(personalities
.get(), startMatching
);
13540 numPersonalities
= personalities
->getCount();
13543 OSKextLog(/* kext */ NULL
,
13544 kOSKextLogStepLevel
|
13545 kOSKextLogLoadFlag
,
13546 "%d kext personalit%s sent to the IOCatalogue; %s.",
13547 numPersonalities
, numPersonalities
> 0 ? "ies" : "y",
13548 startMatching
? "matching started" : "matching not started");
13552 /*********************************************************************
13553 * Do not make a deep copy, just convert the IOKitPersonalities dict
13554 * to an array for sending to the IOCatalogue.
13555 *********************************************************************/
13556 OSSharedPtr
<OSArray
>
13557 OSKext::copyPersonalitiesArray(void)
13559 OSSharedPtr
<OSArray
> result
;
13560 OSDictionary
* personalities
= NULL
; // do not release
13561 OSSharedPtr
<OSCollectionIterator
> personalitiesIterator
;
13563 OSString
* personalityName
= NULL
; // do not release
13564 OSString
* personalityBundleIdentifier
= NULL
; // do not release
13566 personalities
= OSDynamicCast(OSDictionary
,
13567 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13568 if (!personalities
) {
13572 result
= OSArray::withCapacity(personalities
->getCount());
13577 personalitiesIterator
=
13578 OSCollectionIterator::withCollection(personalities
);
13579 if (!personalitiesIterator
) {
13582 while ((personalityName
= OSDynamicCast(OSString
,
13583 personalitiesIterator
->getNextObject()))) {
13584 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13585 personalities
->getObject(personalityName
));
13588 * If the personality doesn't have a CFBundleIdentifier, or if it
13589 * differs from the kext's, insert the kext's ID so we can find it.
13590 * The publisher ID is used to remove personalities from bundles
13593 personalityBundleIdentifier
= OSDynamicCast(OSString
,
13594 personality
->getObject(kCFBundleIdentifierKey
));
13596 if (!personalityBundleIdentifier
) {
13597 personality
->setObject(kCFBundleIdentifierKey
, bundleID
.get());
13598 } else if (!personalityBundleIdentifier
->isEqualTo(bundleID
.get())) {
13599 personality
->setObject(kIOPersonalityPublisherKey
, bundleID
.get());
13602 result
->setObject(personality
);
13609 /*********************************************************************
13610 * Might want to change this to a bool return?
13611 *********************************************************************/
13613 OSKext::sendPersonalitiesToCatalog(
13614 bool startMatching
,
13615 OSArray
* personalityNames
)
13617 OSReturn result
= kOSReturnSuccess
;
13618 OSSharedPtr
<OSArray
> personalitiesToSend
;
13619 OSDictionary
* kextPersonalities
= NULL
; // do not release
13622 if (!sLoadEnabled
) {
13624 kOSKextLogErrorLevel
|
13625 kOSKextLogLoadFlag
,
13626 "Kext loading is disabled (attempt to start matching for kext %s).",
13627 getIdentifierCString());
13628 result
= kOSKextReturnDisabled
;
13632 if (sSafeBoot
&& !isLoadableInSafeBoot()) {
13634 kOSKextLogErrorLevel
|
13635 kOSKextLogLoadFlag
,
13636 "Kext %s is not loadable during safe boot; "
13637 "not sending personalities to the IOCatalogue.",
13638 getIdentifierCString());
13639 result
= kOSKextReturnNotLoadable
;
13643 if (!personalityNames
|| !personalityNames
->getCount()) {
13644 personalitiesToSend
= copyPersonalitiesArray();
13646 kextPersonalities
= OSDynamicCast(OSDictionary
,
13647 getPropertyForHostArch(kIOKitPersonalitiesKey
));
13648 if (!kextPersonalities
|| !kextPersonalities
->getCount()) {
13652 personalitiesToSend
= OSArray::withCapacity(0);
13653 if (!personalitiesToSend
) {
13654 result
= kOSKextReturnNoMemory
;
13657 count
= personalityNames
->getCount();
13658 for (i
= 0; i
< count
; i
++) {
13659 OSString
* name
= OSDynamicCast(OSString
,
13660 personalityNames
->getObject(i
));
13664 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
13665 kextPersonalities
->getObject(name
));
13667 personalitiesToSend
->setObject(personality
);
13671 if (personalitiesToSend
) {
13672 unsigned numPersonalities
= personalitiesToSend
->getCount();
13674 kOSKextLogStepLevel
|
13675 kOSKextLogLoadFlag
,
13676 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13677 getIdentifierCString(),
13679 numPersonalities
> 1 ? "ies" : "y",
13680 startMatching
? " and starting matching" : " but not starting matching");
13681 gIOCatalogue
->addDrivers(personalitiesToSend
.get(), startMatching
);
13687 /*********************************************************************
13688 * xxx - We should allow removing the kext's declared personalities,
13689 * xxx - even with other bundle identifiers.
13690 *********************************************************************/
13692 OSKext::removePersonalitiesFromCatalog(void)
13694 OSSharedPtr
<OSDictionary
> personality
;
13696 personality
= OSDictionary::withCapacity(1);
13697 if (!personality
) {
13700 personality
->setObject(kCFBundleIdentifierKey
, getIdentifier());
13703 kOSKextLogStepLevel
|
13704 kOSKextLogLoadFlag
,
13705 "Kext %s removing all personalities naming it from the IOCatalogue.",
13706 getIdentifierCString());
13708 /* Have the IOCatalog remove all personalities matching this kext's
13709 * bundle ID and trigger matching anew.
13711 gIOCatalogue
->removeDrivers(personality
.get(), /* startMatching */ true);
13719 #pragma mark Logging
13721 /*********************************************************************
13722 * Do not call any function that takes sKextLock here!
13723 *********************************************************************/
13726 OSKext::setUserSpaceLogFilter(
13727 OSKextLogSpec newUserLogFilter
,
13730 OSKextLogSpec result
;
13731 bool allocError
= false;
13733 /* Do not call any function that takes sKextLoggingLock during
13734 * this critical block. That means do logging after.
13736 IOLockLock(sKextLoggingLock
);
13738 result
= sUserSpaceKextLogFilter
;
13739 sUserSpaceKextLogFilter
= newUserLogFilter
;
13741 if (newUserLogFilter
&& captureFlag
&&
13742 !sUserSpaceLogSpecArray
&& !sUserSpaceLogMessageArray
) {
13743 // xxx - do some measurements for a good initial capacity?
13744 sUserSpaceLogSpecArray
= OSArray::withCapacity(0);
13745 sUserSpaceLogMessageArray
= OSArray::withCapacity(0);
13747 if (!sUserSpaceLogSpecArray
|| !sUserSpaceLogMessageArray
) {
13752 IOLockUnlock(sKextLoggingLock
);
13754 /* If the config flag itself is changing, log the state change
13755 * going both ways, before setting up the user-space log arrays,
13756 * so that this is only logged in the kernel.
13758 if (result
!= newUserLogFilter
) {
13759 OSKextLog(/* kext */ NULL
,
13760 kOSKextLogDebugLevel
|
13761 kOSKextLogGeneralFlag
,
13762 "User-space log flags changed from 0x%x to 0x%x.",
13763 result
, newUserLogFilter
);
13766 OSKextLog(/* kext */ NULL
,
13767 kOSKextLogErrorLevel
|
13768 kOSKextLogGeneralFlag
,
13769 "Failed to allocate user-space log message arrays.");
13775 /*********************************************************************
13776 * Do not call any function that takes sKextLock here!
13777 *********************************************************************/
13779 OSSharedPtr
<OSArray
>
13780 OSKext::clearUserSpaceLogFilter(void)
13782 OSSharedPtr
<OSArray
> result
;
13783 OSKextLogSpec oldLogFilter
;
13784 OSKextLogSpec newLogFilter
= kOSKextLogSilentFilter
;
13786 /* Do not call any function that takes sKextLoggingLock during
13787 * this critical block. That means do logging after.
13789 IOLockLock(sKextLoggingLock
);
13791 result
= OSArray::withCapacity(2);
13793 result
->setObject(sUserSpaceLogSpecArray
.get());
13794 result
->setObject(sUserSpaceLogMessageArray
.get());
13796 sUserSpaceLogSpecArray
.reset();
13797 sUserSpaceLogMessageArray
.reset();
13799 oldLogFilter
= sUserSpaceKextLogFilter
;
13800 sUserSpaceKextLogFilter
= newLogFilter
;
13802 IOLockUnlock(sKextLoggingLock
);
13804 /* If the config flag itself is changing, log the state change
13805 * going both ways, after tearing down the user-space log
13806 * arrays, so this is only logged within the kernel.
13808 if (oldLogFilter
!= newLogFilter
) {
13809 OSKextLog(/* kext */ NULL
,
13810 kOSKextLogDebugLevel
|
13811 kOSKextLogGeneralFlag
,
13812 "User-space log flags changed from 0x%x to 0x%x.",
13813 oldLogFilter
, newLogFilter
);
13820 /*********************************************************************
13821 * Do not call any function that takes sKextLock here!
13822 *********************************************************************/
13825 OSKext::getUserSpaceLogFilter(void)
13827 OSKextLogSpec result
;
13829 IOLockLock(sKextLoggingLock
);
13830 result
= sUserSpaceKextLogFilter
;
13831 IOLockUnlock(sKextLoggingLock
);
13836 /*********************************************************************
13837 * This function is called by OSMetaClass during kernel C++ setup.
13838 * Be careful what you access here; assume only OSKext::initialize()
13841 * Do not call any function that takes sKextLock here!
13842 *********************************************************************/
13843 #define VTRESET "\033[0m"
13845 #define VTBOLD "\033[1m"
13846 #define VTUNDER "\033[4m"
13848 #define VTRED "\033[31m"
13849 #define VTGREEN "\033[32m"
13850 #define VTYELLOW "\033[33m"
13851 #define VTBLUE "\033[34m"
13852 #define VTMAGENTA "\033[35m"
13853 #define VTCYAN "\033[36m"
13855 inline const char *
13856 colorForFlags(OSKextLogSpec flags
)
13858 OSKextLogSpec logLevel
= flags
& kOSKextLogLevelMask
;
13860 switch (logLevel
) {
13861 case kOSKextLogErrorLevel
:
13862 return VTRED VTBOLD
;
13863 case kOSKextLogWarningLevel
:
13865 case kOSKextLogBasicLevel
:
13866 return VTYELLOW VTUNDER
;
13867 case kOSKextLogProgressLevel
:
13869 case kOSKextLogStepLevel
:
13871 case kOSKextLogDetailLevel
:
13873 case kOSKextLogDebugLevel
:
13876 return ""; // white
13882 OSKextLogSpec msgLogSpec
,
13883 OSKextLogSpec logFilter
)
13885 OSKextLogSpec filterKextGlobal
= logFilter
& kOSKextLogKextOrGlobalMask
;
13886 OSKextLogSpec filterLevel
= logFilter
& kOSKextLogLevelMask
;
13887 OSKextLogSpec filterFlags
= logFilter
& kOSKextLogFlagsMask
;
13889 OSKextLogSpec msgKextGlobal
= msgLogSpec
& kOSKextLogKextOrGlobalMask
;
13890 OSKextLogSpec msgLevel
= msgLogSpec
& kOSKextLogLevelMask
;
13891 OSKextLogSpec msgFlags
= msgLogSpec
& kOSKextLogFlagsMask
;
13893 /* Explicit messages always get logged.
13895 if (msgLevel
== kOSKextLogExplicitLevel
) {
13899 /* Warnings and errors are logged regardless of the flags.
13901 if (msgLevel
<= kOSKextLogBasicLevel
&& (msgLevel
<= filterLevel
)) {
13905 /* A verbose message that isn't for a logging-enabled kext and isn't global
13906 * does *not* get logged.
13908 if (!msgKextGlobal
&& !filterKextGlobal
) {
13912 /* Warnings and errors are logged regardless of the flags.
13913 * All other messages must fit the flags and
13914 * have a level at or below the filter.
13917 if ((msgFlags
& filterFlags
) && (msgLevel
<= filterLevel
)) {
13927 OSKextLogSpec msgLogSpec
,
13928 const char * format
, ...)
13932 va_start(argList
, format
);
13933 OSKextVLog(aKext
, msgLogSpec
, format
, argList
);
13940 OSKextLogSpec msgLogSpec
,
13941 const char * format
,
13942 va_list srcArgList
)
13944 extern int disableConsoleOutput
;
13946 bool logForKernel
= false;
13947 bool logForUser
= false;
13949 char stackBuffer
[120];
13950 uint32_t length
= 0;
13951 char * allocBuffer
= NULL
; // must kfree
13952 OSSharedPtr
<OSNumber
> logSpecNum
;
13953 OSSharedPtr
<OSString
> logString
;
13954 char * buffer
= stackBuffer
; // do not free
13956 IOLockLock(sKextLoggingLock
);
13958 /* Set the kext/global bit in the message spec if we have no
13959 * kext or if the kext requests logging.
13961 if (!aKext
|| aKext
->flags
.loggingEnabled
) {
13962 msgLogSpec
= msgLogSpec
| kOSKextLogKextOrGlobalMask
;
13965 logForKernel
= logSpecMatch(msgLogSpec
, sKernelLogFilter
);
13966 if (sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
13967 logForUser
= logSpecMatch(msgLogSpec
, sUserSpaceKextLogFilter
);
13970 if (!(logForKernel
|| logForUser
)) {
13974 /* No goto from here until past va_end()!
13976 va_copy(argList
, srcArgList
);
13977 length
= vsnprintf(stackBuffer
, sizeof(stackBuffer
), format
, argList
);
13980 if (length
+ 1 >= sizeof(stackBuffer
)) {
13981 allocBuffer
= (char *)kheap_alloc_tag(KHEAP_TEMP
,
13982 length
+ 1, Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
13983 if (!allocBuffer
) {
13987 /* No goto from here until past va_end()!
13989 va_copy(argList
, srcArgList
);
13990 vsnprintf(allocBuffer
, length
+ 1, format
, argList
);
13993 buffer
= allocBuffer
;
13996 /* If user space wants the log message, queue it up.
13998 if (logForUser
&& sUserSpaceLogSpecArray
&& sUserSpaceLogMessageArray
) {
13999 logSpecNum
= OSNumber::withNumber(msgLogSpec
, 8 * sizeof(msgLogSpec
));
14000 logString
= OSString::withCString(buffer
);
14001 if (logSpecNum
&& logString
) {
14002 sUserSpaceLogSpecArray
->setObject(logSpecNum
.get());
14003 sUserSpaceLogMessageArray
->setObject(logString
.get());
14007 /* Always log messages from the kernel according to the kernel's
14010 if (logForKernel
) {
14011 /* If we are in console mode and have a custom log filter,
14012 * colorize the log message.
14014 if (!disableConsoleOutput
&& sBootArgLogFilterFound
) {
14015 const char * color
= ""; // do not free
14016 color
= colorForFlags(msgLogSpec
);
14017 printf("%s%s%s\n", colorForFlags(msgLogSpec
),
14018 buffer
, color
[0] ? VTRESET
: "");
14020 printf("%s\n", buffer
);
14025 IOLockUnlock(sKextLoggingLock
);
14028 kheap_free(KHEAP_TEMP
, allocBuffer
, (length
+ 1) * sizeof(char));
14033 #if KASLR_IOREG_DEBUG
14035 #define IOLOG_INDENT( the_indention ) \
14038 for ( i = 0; i < (the_indention); i++ ) { \
14043 extern vm_offset_t vm_kernel_stext
;
14044 extern vm_offset_t vm_kernel_etext
;
14045 extern mach_vm_offset_t kext_alloc_base
;
14046 extern mach_vm_offset_t kext_alloc_max
;
14048 bool ScanForAddrInObject(OSObject
* theObject
,
14052 ScanForAddrInObject(OSObject
* theObject
,
14055 const OSMetaClass
* myTypeID
;
14056 OSSharedPtr
<OSCollectionIterator
> myIter
;
14058 OSObject
* myValue
;
14059 bool myResult
= false;
14061 if (theObject
== NULL
) {
14062 IOLog("%s: theObject is NULL \n",
14067 myTypeID
= OSTypeIDInst(theObject
);
14069 if (myTypeID
== OSTypeID(OSDictionary
)) {
14070 OSDictionary
* myDictionary
;
14072 myDictionary
= OSDynamicCast(OSDictionary
, theObject
);
14073 myIter
= OSCollectionIterator::withCollection( myDictionary
);
14074 if (myIter
== NULL
) {
14078 // !! reset the iterator
14081 while ((myKey
= OSDynamicCast(OSSymbol
, myIter
->getNextObject()))) {
14084 myValue
= myDictionary
->getObject(myKey
);
14085 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14086 if (myTempResult
) {
14087 // if we ever get a true result return true
14089 IOLOG_INDENT(indent
);
14090 IOLog("OSDictionary key \"%s\" \n", myKey
->getCStringNoCopy());
14094 // !! release the iterator
14096 } else if (myTypeID
== OSTypeID(OSArray
)) {
14099 myArray
= OSDynamicCast(OSArray
, theObject
);
14100 myIter
= OSCollectionIterator::withCollection(myArray
);
14101 if (myIter
== NULL
) {
14104 // !! reset the iterator
14107 while ((myValue
= myIter
->getNextObject())) {
14109 myTempResult
= ScanForAddrInObject(myValue
, (indent
+ 4));
14110 if (myTempResult
) {
14111 // if we ever get a true result return true
14113 IOLOG_INDENT(indent
);
14114 IOLog("OSArray: \n");
14117 // !! release the iterator
14119 } else if (myTypeID
== OSTypeID(OSString
) || myTypeID
== OSTypeID(OSSymbol
)) {
14120 // should we look for addresses in strings?
14121 } else if (myTypeID
== OSTypeID(OSData
)) {
14123 unsigned int myLen
;
14124 OSData
* myDataObj
;
14126 myDataObj
= OSDynamicCast(OSData
, theObject
);
14127 myPtrPtr
= (void * *) myDataObj
->getBytesNoCopy();
14128 myLen
= myDataObj
->getLength();
14130 if (myPtrPtr
&& myLen
&& myLen
> 7) {
14132 int myPtrCount
= (myLen
/ sizeof(void *));
14134 for (i
= 0; i
< myPtrCount
; i
++) {
14135 UInt64 numberValue
= (UInt64
) * (myPtrPtr
);
14137 if (kext_alloc_max
!= 0 &&
14138 numberValue
>= kext_alloc_base
&&
14139 numberValue
< kext_alloc_max
) {
14140 OSSharedPtr
<OSKext
> myKext
;
14141 // IOLog("found OSData %p in kext map %p to %p \n",
14143 // (void *) kext_alloc_base,
14144 // (void *) kext_alloc_max);
14146 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) *(myPtrPtr
));
14148 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14150 myKext
->getIdentifierCString());
14154 if (vm_kernel_etext
!= 0 &&
14155 numberValue
>= vm_kernel_stext
&&
14156 numberValue
< vm_kernel_etext
) {
14157 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14159 (void *) vm_kernel_stext
,
14160 (void *) vm_kernel_etext
);
14166 } else if (myTypeID
== OSTypeID(OSBoolean
)) {
14167 // do nothing here...
14168 } else if (myTypeID
== OSTypeID(OSNumber
)) {
14169 OSNumber
* number
= OSDynamicCast(OSNumber
, theObject
);
14171 UInt64 numberValue
= number
->unsigned64BitValue();
14173 if (kext_alloc_max
!= 0 &&
14174 numberValue
>= kext_alloc_base
&&
14175 numberValue
< kext_alloc_max
) {
14176 OSSharedPtr
<OSKext
> myKext
;
14177 IOLog("found OSNumber in kext map %p to %p \n",
14178 (void *) kext_alloc_base
,
14179 (void *) kext_alloc_max
);
14180 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14182 myKext
= OSKext::lookupKextWithAddress((vm_address_t
) numberValue
);
14184 IOLog("found in kext \"%s\" \n",
14185 myKext
->getIdentifierCString());
14190 if (vm_kernel_etext
!= 0 &&
14191 numberValue
>= vm_kernel_stext
&&
14192 numberValue
< vm_kernel_etext
) {
14193 IOLog("found OSNumber in kernel text segment %p to %p \n",
14194 (void *) vm_kernel_stext
,
14195 (void *) vm_kernel_etext
);
14196 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue
, numberValue
);
14202 const OSMetaClass
* myMetaClass
= NULL
;
14204 myMetaClass
= theObject
->getMetaClass();
14206 IOLog("class %s \n", myMetaClass
->getClassName());
14208 IOLog("Unknown object \n" );
14215 #endif // KASLR_KEXT_DEBUG
14216 }; /* extern "C" */
14219 #pragma mark Backtrace Dump & kmod_get_info() support
14221 /*********************************************************************
14222 * This function must be safe to call in panic context.
14223 *********************************************************************/
14226 OSKext::printKextsInBacktrace(
14227 vm_offset_t
* addr __unused
,
14228 unsigned int cnt __unused
,
14229 int (* printf_func
)(const char *fmt
, ...) __unused
,
14230 uint32_t flags __unused
)
14232 addr64_t summary_page
= 0;
14233 addr64_t last_summary_page
= 0;
14234 bool found_kmod
= false;
14237 if (kPrintKextsLock
& flags
) {
14238 if (!sKextSummariesLock
) {
14241 IOLockLock(sKextSummariesLock
);
14244 if (!gLoadedKextSummaries
) {
14245 (*printf_func
)(" can't perform kext scan: no kext summary");
14249 summary_page
= trunc_page((addr64_t
)(uintptr_t)gLoadedKextSummaries
);
14250 last_summary_page
= round_page(summary_page
+ sLoadedKextSummariesAllocSize
);
14251 for (; summary_page
< last_summary_page
; summary_page
+= PAGE_SIZE
) {
14252 if (pmap_find_phys(kernel_pmap
, summary_page
) == 0) {
14253 (*printf_func
)(" can't perform kext scan: "
14254 "missing kext summary page %p", summary_page
);
14259 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14260 OSKextLoadedKextSummary
* summary
;
14262 summary
= gLoadedKextSummaries
->summaries
+ i
;
14263 if (!summary
->address
) {
14267 if (!summaryIsInBacktrace(summary
, addr
, cnt
)) {
14272 if (!(kPrintKextsTerse
& flags
)) {
14273 (*printf_func
)(" Kernel Extensions in backtrace:\n");
14278 printSummary(summary
, printf_func
, flags
);
14282 if (kPrintKextsLock
& flags
) {
14283 IOLockUnlock(sKextSummariesLock
);
14289 /*********************************************************************
14290 * This function must be safe to call in panic context.
14291 *********************************************************************/
14294 OSKext::summaryIsInBacktrace(
14295 OSKextLoadedKextSummary
* summary
,
14296 vm_offset_t
* addr
,
14301 for (i
= 0; i
< cnt
; i
++) {
14302 vm_offset_t kscan_addr
= addr
[i
];
14303 #if __has_feature(ptrauth_calls)
14304 kscan_addr
= (vm_offset_t
)VM_KERNEL_STRIP_PTR(kscan_addr
);
14305 #endif /* __has_feature(ptrauth_calls) */
14306 if ((kscan_addr
>= summary
->text_exec_address
) &&
14307 (kscan_addr
< (summary
->text_exec_address
+ summary
->text_exec_size
))) {
14316 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14317 * sKextSummariesLock held.
14319 OSKextLoadedKextSummary
*
14320 OSKext::summaryForAddress(uintptr_t addr
)
14322 #if __has_feature(ptrauth_calls)
14323 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14324 #endif /* __has_feature(ptrauth_calls) */
14325 for (unsigned i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14326 OSKextLoadedKextSummary
*summary
= &gLoadedKextSummaries
->summaries
[i
];
14327 if (!summary
->address
) {
14331 #if VM_MAPPED_KEXTS
14332 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14333 * support split kexts, but we also may unmap the kexts, which can
14334 * race with the above codepath (see OSKext::unload). As such,
14335 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14337 if ((addr
>= summary
->address
) && (addr
< (summary
->address
+ summary
->size
))) {
14341 kernel_mach_header_t
*mh
= (kernel_mach_header_t
*)summary
->address
;
14342 kernel_segment_command_t
*seg
;
14344 for (seg
= firstsegfromheader(mh
); seg
!= NULL
; seg
= nextsegfromheader(mh
, seg
)) {
14345 if ((addr
>= seg
->vmaddr
) && (addr
< (seg
->vmaddr
+ seg
->vmsize
))) {
14352 /* addr did not map to any kext */
14358 OSKext::kextForAddress(const void *address
)
14360 void * image
= NULL
;
14361 OSKextActiveAccount
* active
;
14362 OSKext
* kext
= NULL
;
14365 uintptr_t addr
= (uintptr_t) address
;
14371 #if __has_feature(ptrauth_calls)
14372 addr
= (uintptr_t)VM_KERNEL_STRIP_PTR(addr
);
14373 #endif /* __has_feature(ptrauth_calls) */
14375 if (sKextAccountsCount
) {
14376 IOSimpleLockLock(sKextAccountsLock
);
14377 // bsearch sKextAccounts list
14378 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
14379 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
14380 if ((addr
>= active
->address
) && (addr
< active
->address_end
)) {
14381 kext
= active
->account
->kext
;
14382 if (kext
&& kext
->kmod_info
) {
14383 image
= (void *) kext
->kmod_info
->address
;
14386 } else if (addr
> active
->address
) {
14388 baseIdx
+= (lim
>> 1) + 1;
14393 IOSimpleLockUnlock(sKextAccountsLock
);
14395 if (!image
&& (addr
>= vm_kernel_stext
) && (addr
< vm_kernel_etext
)) {
14396 image
= (void *) &_mh_execute_header
;
14398 if (!image
&& gLoadedKextSummaries
) {
14399 IOLockLock(sKextSummariesLock
);
14400 for (i
= 0; i
< gLoadedKextSummaries
->numSummaries
; i
++) {
14401 OSKextLoadedKextSummary
*summary
= gLoadedKextSummaries
->summaries
+ i
;
14402 if (addr
>= summary
->address
&& addr
< summary
->address
+ summary
->size
) {
14403 image
= (void *)summary
->address
;
14406 IOLockUnlock(sKextSummariesLock
);
14413 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14414 * Safe to call in panic context.
14416 static OSKextLoadedKextSummary
*
14417 findSummary(uint32_t tagID
)
14419 OSKextLoadedKextSummary
* summary
;
14420 for (size_t i
= 0; i
< gLoadedKextSummaries
->numSummaries
; ++i
) {
14421 summary
= gLoadedKextSummaries
->summaries
+ i
;
14422 if (summary
->loadTag
== tagID
) {
14429 /*********************************************************************
14430 * This function must be safe to call in panic context.
14431 *********************************************************************/
14433 OSKext::printSummary(
14434 OSKextLoadedKextSummary
* summary
,
14435 int (* printf_func
)(const char *fmt
, ...),
14438 kmod_reference_t
* kmod_ref
= NULL
;
14439 uuid_string_t uuid
;
14440 char version
[kOSKextVersionMaxLength
];
14443 OSKextLoadedKextSummary
*dependencySummary
;
14445 if (!OSKextVersionGetString(summary
->version
, version
, sizeof(version
))) {
14446 strlcpy(version
, "unknown version", sizeof(version
));
14448 (void) uuid_unparse(summary
->uuid
, uuid
);
14450 #if defined(__arm__) || defined(__arm64__)
14451 tmpAddr
= summary
->text_exec_address
;
14452 tmpSize
= summary
->text_exec_size
;
14454 tmpAddr
= summary
->address
;
14455 tmpSize
= summary
->size
;
14457 if (kPrintKextsUnslide
& flags
) {
14458 tmpAddr
= ml_static_unslide(tmpAddr
);
14460 (*printf_func
)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14461 (kPrintKextsTerse
& flags
) ? "" : " ",
14462 summary
->name
, version
, uuid
,
14463 tmpAddr
, tmpAddr
+ tmpSize
- 1);
14465 if (kPrintKextsTerse
& flags
) {
14469 /* print dependency info */
14470 for (kmod_ref
= (kmod_reference_t
*) summary
->reference_list
;
14472 kmod_ref
= kmod_ref
->next
) {
14473 kmod_info_t
* rinfo
;
14475 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_ref
)) == 0) {
14476 (*printf_func
)(" kmod dependency scan stopped "
14477 "due to missing dependency page: %p\n",
14478 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)kmod_ref
) : kmod_ref
);
14481 rinfo
= kmod_ref
->info
;
14483 if (pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)rinfo
)) == 0) {
14484 (*printf_func
)(" kmod dependency scan stopped "
14485 "due to missing kmod page: %p\n",
14486 (kPrintKextsUnslide
& flags
) ? (void *)ml_static_unslide((vm_offset_t
)rinfo
) : rinfo
);
14490 if (!rinfo
->address
) {
14491 continue; // skip fake entries for built-ins
14494 dependencySummary
= findSummary(rinfo
->id
);
14496 tmpAddr
= rinfo
->address
;
14497 tmpSize
= rinfo
->size
;
14498 if (dependencySummary
) {
14499 (void) uuid_unparse(dependencySummary
->uuid
, uuid
);
14500 #if defined(__arm__) || defined(__arm64__)
14501 tmpAddr
= dependencySummary
->text_exec_address
;
14502 tmpSize
= dependencySummary
->text_exec_size
;
14506 if (kPrintKextsUnslide
& flags
) {
14507 tmpAddr
= ml_static_unslide(tmpAddr
);
14509 (*printf_func
)(" dependency: %s(%s)[%s]@%p->%p\n",
14510 rinfo
->name
, rinfo
->version
, uuid
, tmpAddr
, tmpAddr
+ tmpSize
- 1);
14516 #if !defined(__arm__) && !defined(__arm64__)
14517 /*******************************************************************************
14518 * substitute() looks at an input string (a pointer within a larger buffer)
14519 * for a match to a substring, and on match it writes the marker & substitution
14520 * character to an output string, updating the scan (from) and
14521 * output (to) indexes as appropriate.
14522 *******************************************************************************/
14523 static int substitute(
14524 const char * scan_string
,
14526 uint32_t * to_index
,
14527 uint32_t * from_index
,
14528 const char * substring
,
14530 char substitution
);
14532 /* string_out must be at least KMOD_MAX_NAME bytes.
14536 const char * scan_string
,
14538 uint32_t * to_index
,
14539 uint32_t * from_index
,
14540 const char * substring
,
14544 size_t substring_length
= strnlen(substring
, KMOD_MAX_NAME
- 1);
14546 /* On a substring match, append the marker (if there is one) and then
14547 * the substitution character, updating the output (to) index accordingly.
14548 * Then update the input (from) length by the length of the substring
14549 * that got replaced.
14551 if (!strncmp(scan_string
, substring
, substring_length
)) {
14553 string_out
[(*to_index
)++] = marker
;
14555 string_out
[(*to_index
)++] = substitution
;
14556 (*from_index
) += substring_length
;
14562 /*******************************************************************************
14563 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14564 * KMOD_MAX_NAME characters and performs various substitutions of common
14565 * prefixes & substrings as defined by tables in kext_panic_report.h.
14566 *******************************************************************************/
14567 static void compactIdentifier(
14568 const char * identifier
,
14569 char * identifier_out
,
14570 char ** identifier_out_end
);
14574 const char * identifier
,
14575 char * identifier_out
,
14576 char ** identifier_out_end
)
14578 uint32_t from_index
, to_index
;
14579 uint32_t scan_from_index
= 0;
14580 uint32_t scan_to_index
= 0;
14581 subs_entry_t
* subs_entry
= NULL
;
14584 from_index
= to_index
= 0;
14585 identifier_out
[0] = '\0';
14587 /* Replace certain identifier prefixes with shorter @+character sequences.
14588 * Check the return value of substitute() so we only replace the prefix.
14590 for (subs_entry
= &kext_identifier_prefix_subs
[0];
14591 subs_entry
->substring
&& !did_sub
;
14593 did_sub
= substitute(identifier
, identifier_out
,
14594 &scan_to_index
, &scan_from_index
,
14595 subs_entry
->substring
, /* marker */ '\0', subs_entry
->substitute
);
14599 /* Now scan through the identifier looking for the common substrings
14600 * and replacing them with shorter !+character sequences via substitute().
14602 for (/* see above */;
14603 scan_from_index
< KMOD_MAX_NAME
- 1 && identifier
[scan_from_index
];
14605 const char * scan_string
= &identifier
[scan_from_index
];
14609 if (scan_from_index
) {
14610 for (subs_entry
= &kext_identifier_substring_subs
[0];
14611 subs_entry
->substring
&& !did_sub
;
14613 did_sub
= substitute(scan_string
, identifier_out
,
14614 &scan_to_index
, &scan_from_index
,
14615 subs_entry
->substring
, '!', subs_entry
->substitute
);
14619 /* If we didn't substitute, copy the input character to the output.
14622 identifier_out
[scan_to_index
++] = identifier
[scan_from_index
++];
14626 identifier_out
[scan_to_index
] = '\0';
14627 if (identifier_out_end
) {
14628 *identifier_out_end
= &identifier_out
[scan_to_index
];
14633 #endif /* !defined(__arm__) && !defined(__arm64__) */
14635 /*******************************************************************************
14636 * assemble_identifier_and_version() adds to a string buffer a compacted
14637 * bundle identifier followed by a version string.
14638 *******************************************************************************/
14640 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14642 static size_t assemble_identifier_and_version(
14643 kmod_info_t
* kmod_info
,
14644 char * identPlusVers
,
14648 assemble_identifier_and_version(
14649 kmod_info_t
* kmod_info
,
14650 char * identPlusVers
,
14655 #if defined(__arm__) || defined(__arm64__)
14656 result
= strlcpy(identPlusVers
, kmod_info
->name
, KMOD_MAX_NAME
);
14658 compactIdentifier(kmod_info
->name
, identPlusVers
, NULL
);
14659 result
= strnlen(identPlusVers
, KMOD_MAX_NAME
- 1);
14661 identPlusVers
[result
++] = '\t'; // increment for real char
14662 identPlusVers
[result
] = '\0'; // don't increment for nul char
14663 result
= strlcat(identPlusVers
, kmod_info
->version
, bufSize
);
14664 if (result
>= bufSize
) {
14665 identPlusVers
[bufSize
- 1] = '\0';
14666 result
= bufSize
- 1;
14672 /*******************************************************************************
14673 * Assumes sKextLock is held.
14674 *******************************************************************************/
14677 OSKext::saveLoadedKextPanicListTyped(
14678 const char * prefix
,
14682 uint32_t list_size
)
14685 unsigned int count
, i
;
14687 count
= sLoadedKexts
->getCount();
14694 OSObject
* rawKext
= sLoadedKexts
->getObject(i
);
14695 OSKext
* theKext
= OSDynamicCast(OSKext
, rawKext
);
14697 size_t identPlusVersLength
;
14699 char identPlusVers
[2 * KMOD_MAX_NAME
];
14702 printf("OSKext::saveLoadedKextPanicListTyped - "
14703 "NULL kext in loaded kext list; continuing\n");
14708 printf("OSKext::saveLoadedKextPanicListTyped - "
14709 "Kext type cast failed in loaded kext list; continuing\n");
14713 /* Skip all built-in kexts.
14715 if (theKext
->isKernelComponent()) {
14719 kmod_info_t
* kmod_info
= theKext
->kmod_info
;
14721 /* Filter for kmod name (bundle identifier).
14723 match
= !strncmp(kmod_info
->name
, prefix
, strnlen(prefix
, KMOD_MAX_NAME
));
14724 if ((match
&& invertFlag
) || (!match
&& !invertFlag
)) {
14728 /* Filter for libraries (kexts that have a compatible version).
14730 if ((libsFlag
== 0 && theKext
->getCompatibleVersion() > 1) ||
14731 (libsFlag
== 1 && theKext
->getCompatibleVersion() < 1)) {
14736 !pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)kmod_info
))) {
14737 printf("kext scan stopped due to missing kmod_info page: %p\n",
14742 identPlusVersLength
= assemble_identifier_and_version(kmod_info
,
14744 sizeof(identPlusVers
));
14745 if (!identPlusVersLength
) {
14746 printf("error saving loaded kext info\n");
14750 /* make sure everything fits and we null terminate.
14752 tempLen
= strlcat(paniclist
, identPlusVers
, list_size
);
14753 if (tempLen
>= list_size
) {
14754 // panic list is full, keep it and null terminate
14755 paniclist
[list_size
- 1] = 0x00;
14759 tempLen
= strlcat(paniclist
, "\n", list_size
);
14760 if (tempLen
>= list_size
) {
14761 // panic list is full, keep it and null terminate
14762 paniclist
[list_size
- 1] = 0x00;
14774 /*********************************************************************
14775 *********************************************************************/
14778 OSKext::saveLoadedKextPanicList(void)
14780 char * newlist
= NULL
;
14781 uint32_t newlist_size
= 0;
14783 newlist_size
= KEXT_PANICLIST_SIZE
;
14784 newlist
= (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS
, newlist_size
,
14785 Z_WAITOK
, VM_KERN_MEMORY_OSKEXT
);
14788 OSKextLog(/* kext */ NULL
,
14789 kOSKextLogErrorLevel
| kOSKextLogGeneralFlag
,
14790 "Couldn't allocate kext panic log buffer.");
14796 // non-"com.apple." kexts
14797 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14798 /* libs? */ -1, newlist
, newlist_size
) != 0) {
14801 // "com.apple." nonlibrary kexts
14802 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14803 /* libs? */ 0, newlist
, newlist_size
) != 0) {
14806 // "com.apple." library kexts
14807 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14808 /* libs? */ 1, newlist
, newlist_size
) != 0) {
14812 if (loaded_kext_paniclist
) {
14813 kheap_free(KHEAP_DATA_BUFFERS
, loaded_kext_paniclist
,
14814 loaded_kext_paniclist_size
);
14816 loaded_kext_paniclist
= newlist
;
14818 loaded_kext_paniclist_size
= newlist_size
;
14822 kheap_free(KHEAP_TEMP
, newlist
, newlist_size
);
14827 /*********************************************************************
14828 * Assumes sKextLock is held.
14829 *********************************************************************/
14831 OSKext::savePanicString(bool isLoading
)
14836 return; // do not goto finish here b/c of lock
14839 len
= assemble_identifier_and_version( kmod_info
,
14840 (isLoading
) ? last_loaded_str_buf
: last_unloaded_str_buf
,
14841 (isLoading
) ? sizeof(last_loaded_str_buf
) : sizeof(last_unloaded_str_buf
));
14843 printf("error saving unloaded kext info\n");
14848 last_loaded_strlen
= len
;
14849 last_loaded_address
= (void *)kmod_info
->address
;
14850 last_loaded_size
= kmod_info
->size
;
14851 clock_get_uptime(&last_loaded_timestamp
);
14853 last_unloaded_strlen
= len
;
14854 last_unloaded_address
= (void *)kmod_info
->address
;
14855 last_unloaded_size
= kmod_info
->size
;
14856 clock_get_uptime(&last_unloaded_timestamp
);
14863 /*********************************************************************
14864 *********************************************************************/
14867 OSKext::printKextPanicLists(int (*printf_func
)(const char *fmt
, ...))
14869 if (last_loaded_strlen
) {
14870 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14871 AbsoluteTime_to_scalar(&last_loaded_timestamp
),
14872 last_loaded_strlen
, last_loaded_str_buf
,
14873 last_loaded_address
, last_loaded_size
);
14876 if (last_unloaded_strlen
) {
14877 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14878 AbsoluteTime_to_scalar(&last_unloaded_timestamp
),
14879 last_unloaded_strlen
, last_unloaded_str_buf
,
14880 last_unloaded_address
, last_unloaded_size
);
14883 printf_func("loaded kexts:\n");
14884 if (loaded_kext_paniclist
&&
14885 pmap_find_phys(kernel_pmap
, (addr64_t
) (uintptr_t) loaded_kext_paniclist
) &&
14886 loaded_kext_paniclist
[0]) {
14887 printf_func("%.*s",
14888 strnlen(loaded_kext_paniclist
, loaded_kext_paniclist_size
),
14889 loaded_kext_paniclist
);
14891 printf_func("(none)\n");
14896 /*********************************************************************
14897 * Assumes sKextLock is held.
14898 *********************************************************************/
14901 OSKext::updateLoadedKextSummaries(void)
14903 kern_return_t result
= KERN_FAILURE
;
14904 OSKextLoadedKextSummaryHeader
*summaryHeader
= NULL
;
14905 OSKextLoadedKextSummaryHeader
*summaryHeaderAlloc
= NULL
;
14907 vm_map_offset_t start
, end
;
14908 size_t summarySize
= 0;
14913 OSKextActiveAccount
* accountingList
;
14914 OSKextActiveAccount
* prevAccountingList
;
14915 uint32_t idx
, accountingListAlloc
, accountingListCount
, prevAccountingListCount
;
14917 prevAccountingList
= NULL
;
14918 prevAccountingListCount
= 0;
14920 #if DEVELOPMENT || DEBUG
14921 if (IORecursiveLockHaveLock(sKextLock
) == false) {
14922 panic("sKextLock must be held");
14926 IOLockLock(sKextSummariesLock
);
14928 count
= sLoadedKexts
->getCount();
14929 for (i
= 0, maxKexts
= 0; i
< count
; ++i
) {
14930 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14931 maxKexts
+= (aKext
&& aKext
->isExecutable());
14937 if (maxKexts
< kOSKextTypicalLoadCount
) {
14938 maxKexts
= kOSKextTypicalLoadCount
;
14941 /* Calculate the size needed for the new summary headers.
14944 size
= sizeof(*gLoadedKextSummaries
);
14945 size
+= maxKexts
* sizeof(*gLoadedKextSummaries
->summaries
);
14946 size
= round_page(size
);
14948 if (gLoadedKextSummaries
== NULL
|| sLoadedKextSummariesAllocSize
< size
) {
14949 if (gLoadedKextSummaries
) {
14950 kmem_free(kernel_map
, (vm_offset_t
)gLoadedKextSummaries
, sLoadedKextSummariesAllocSize
);
14951 gLoadedKextSummaries
= NULL
;
14952 gLoadedKextSummariesTimestamp
= mach_absolute_time();
14953 sLoadedKextSummariesAllocSize
= 0;
14955 result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&summaryHeaderAlloc
, size
, VM_KERN_MEMORY_OSKEXT
);
14956 if (result
!= KERN_SUCCESS
) {
14959 summaryHeader
= summaryHeaderAlloc
;
14960 summarySize
= size
;
14962 summaryHeader
= gLoadedKextSummaries
;
14963 summarySize
= sLoadedKextSummariesAllocSize
;
14965 start
= (vm_map_offset_t
) summaryHeader
;
14966 end
= start
+ summarySize
;
14967 result
= vm_map_protect(kernel_map
,
14972 if (result
!= KERN_SUCCESS
) {
14977 /* Populate the summary header.
14980 bzero(summaryHeader
, summarySize
);
14981 summaryHeader
->version
= kOSKextLoadedKextSummaryVersion
;
14982 summaryHeader
->entry_size
= sizeof(OSKextLoadedKextSummary
);
14984 /* Populate each kext summary.
14987 count
= sLoadedKexts
->getCount();
14988 accountingListAlloc
= 0;
14989 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
14990 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
14991 if (!aKext
|| !aKext
->isExecutable()) {
14995 aKext
->updateLoadedKextSummary(&summaryHeader
->summaries
[j
++]);
14996 summaryHeader
->numSummaries
++;
14997 accountingListAlloc
++;
15000 accountingList
= IONew(typeof(accountingList
[0]), accountingListAlloc
);
15001 accountingListCount
= 0;
15002 for (i
= 0, j
= 0; i
< count
&& j
< maxKexts
; ++i
) {
15003 aKext
= OSDynamicCast(OSKext
, sLoadedKexts
->getObject(i
));
15004 if (!aKext
|| !aKext
->isExecutable()) {
15008 OSKextActiveAccount activeAccount
;
15009 aKext
->updateActiveAccount(&activeAccount
);
15010 // order by address
15011 for (idx
= 0; idx
< accountingListCount
; idx
++) {
15012 if (activeAccount
.address
< accountingList
[idx
].address
) {
15016 bcopy(&accountingList
[idx
], &accountingList
[idx
+ 1], (accountingListCount
- idx
) * sizeof(accountingList
[0]));
15017 accountingList
[idx
] = activeAccount
;
15018 accountingListCount
++;
15020 assert(accountingListCount
== accountingListAlloc
);
15021 /* Write protect the buffer and move it into place.
15024 start
= (vm_map_offset_t
) summaryHeader
;
15025 end
= start
+ summarySize
;
15027 result
= vm_map_protect(kernel_map
, start
, end
, VM_PROT_READ
, FALSE
);
15028 if (result
!= KERN_SUCCESS
) {
15032 gLoadedKextSummaries
= summaryHeader
;
15033 gLoadedKextSummariesTimestamp
= mach_absolute_time();
15034 sLoadedKextSummariesAllocSize
= summarySize
;
15035 summaryHeaderAlloc
= NULL
;
15037 /* Call the magic breakpoint function through a static function pointer so
15038 * the compiler can't optimize the function away.
15040 if (sLoadedKextSummariesUpdated
) {
15041 (*sLoadedKextSummariesUpdated
)();
15044 IOSimpleLockLock(sKextAccountsLock
);
15045 prevAccountingList
= sKextAccounts
;
15046 prevAccountingListCount
= sKextAccountsCount
;
15047 sKextAccounts
= accountingList
;
15048 sKextAccountsCount
= accountingListCount
;
15049 IOSimpleLockUnlock(sKextAccountsLock
);
15052 IOLockUnlock(sKextSummariesLock
);
15054 /* If we had to allocate a new buffer but failed to generate the summaries,
15057 if (summaryHeaderAlloc
) {
15058 kmem_free(kernel_map
, (vm_offset_t
)summaryHeaderAlloc
, summarySize
);
15060 if (prevAccountingList
) {
15061 IODelete(prevAccountingList
, typeof(accountingList
[0]), prevAccountingListCount
);
15067 /*********************************************************************
15068 *********************************************************************/
15070 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary
*summary
)
15072 OSSharedPtr
<OSData
> uuid
;
15074 strlcpy(summary
->name
, getIdentifierCString(),
15075 sizeof(summary
->name
));
15079 memcpy(summary
->uuid
, uuid
->getBytesNoCopy(), sizeof(summary
->uuid
));
15082 if (flags
.builtin
) {
15083 // this value will stop lldb from parsing the mach-o header
15084 // summary->address = UINT64_MAX;
15085 // summary->size = 0;
15086 summary
->address
= kmod_info
->address
;
15087 summary
->size
= kmod_info
->size
;
15089 summary
->address
= kmod_info
->address
;
15090 summary
->size
= kmod_info
->size
;
15092 summary
->version
= getVersion();
15093 summary
->loadTag
= kmod_info
->id
;
15094 summary
->flags
= 0;
15095 summary
->reference_list
= (uint64_t) kmod_info
->reference_list
;
15097 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT_EXEC", &summary
->text_exec_size
);
15098 if (summary
->text_exec_address
== 0) {
15099 // Fallback to __TEXT
15100 summary
->text_exec_address
= (uint64_t) getsegdatafromheader((kernel_mach_header_t
*)summary
->address
, "__TEXT", &summary
->text_exec_size
);
15105 /*********************************************************************
15106 *********************************************************************/
15109 OSKext::updateActiveAccount(OSKextActiveAccount
*accountp
)
15111 kernel_mach_header_t
*hdr
= NULL
;
15112 kernel_segment_command_t
*seg
= NULL
;
15114 bzero(accountp
, sizeof(*accountp
));
15116 hdr
= (kernel_mach_header_t
*)kmod_info
->address
;
15117 if (getcommandfromheader(hdr
, LC_SEGMENT_SPLIT_INFO
) || isInFileset()) {
15119 * If this kext supports split segments (or is in a new
15120 * MH_FILESET kext collection), use the first
15121 * executable segment as the range for instructions
15122 * (and thus for backtracing.
15124 for (seg
= firstsegfromheader(hdr
); seg
!= NULL
; seg
= nextsegfromheader(hdr
, seg
)) {
15125 if (seg
->initprot
& VM_PROT_EXECUTE
) {
15131 accountp
->address
= seg
->vmaddr
;
15132 if (accountp
->address
) {
15133 accountp
->address_end
= seg
->vmaddr
+ seg
->vmsize
;
15136 /* For non-split kexts and for kexts without executable
15137 * segments, just use the kmod_info range (as the kext
15138 * is either all in one range or should not show up in
15139 * instruction backtraces).
15141 accountp
->address
= kmod_info
->address
;
15142 if (accountp
->address
) {
15143 accountp
->address_end
= kmod_info
->address
+ kmod_info
->size
;
15147 accountp
->account
= this->account
;
15151 OSKext::isDriverKit(void)
15153 OSString
*bundleType
;
15156 bundleType
= OSDynamicCast(OSString
, infoDict
->getObject(kCFBundlePackageTypeKey
));
15157 if (bundleType
&& bundleType
->isEqualTo(kOSKextBundlePackageTypeDriverKit
)) {
15165 OSKext::isInFileset(void)
15168 goto check_prelinked
;
15171 if (kmod_info
->address
&& kernel_mach_header_is_in_fileset((kernel_mach_header_t
*)kmod_info
->address
)) {
15176 if (isPrelinked()) {
15178 * If we haven't setup kmod_info yet, but we know
15179 * we're loading a prelinked kext in an MH_FILESET KC,
15182 kc_format_t kc_format
;
15183 if (PE_get_primary_kc_format(&kc_format
) && kc_format
== KCFormatFileset
) {
15191 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t
*seg
)
15193 kern_return_t result
;
15194 if (!super::init()) {
15197 if (seg
== nullptr) {
15200 result
= kmem_alloc_pageable(kernel_map
, (vm_offset_t
*)&data
, seg
->vmsize
, VM_KERN_MEMORY_KEXT
);
15201 if (result
!= KERN_SUCCESS
) {
15204 memcpy((void *)data
, (const void *)seg
->vmaddr
, seg
->vmsize
);
15205 savedSegment
= seg
;
15206 vmsize
= seg
->vmsize
;
15207 vmaddr
= seg
->vmaddr
;
15211 OSSharedPtr
<OSKextSavedMutableSegment
>
15212 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t
*seg
)
15214 OSSharedPtr
<OSKextSavedMutableSegment
> me
= OSMakeShared
<OSKextSavedMutableSegment
>();
15215 if (me
&& !me
->initWithSegment(seg
)) {
15222 OSKextSavedMutableSegment::free(void)
15225 kmem_free(kernel_map
, (vm_offset_t
)data
, vmsize
);
15230 OSKextSavedMutableSegment::getVMAddr() const
15236 OSKextSavedMutableSegment::getVMSize() const
15242 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t
*seg
)
15244 if (seg
!= savedSegment
) {
15245 return kOSKextReturnInvalidArgument
;
15247 if (seg
->vmaddr
!= vmaddr
|| seg
->vmsize
!= vmsize
) {
15248 return kOSKextReturnInvalidArgument
;
15250 memcpy((void *)seg
->vmaddr
, data
, vmsize
);
15251 return kOSReturnSuccess
;
15254 extern "C" const vm_allocation_site_t
*
15255 OSKextGetAllocationSiteForCaller(uintptr_t address
)
15257 OSKextActiveAccount
* active
;
15258 vm_allocation_site_t
* site
;
15259 vm_allocation_site_t
* releasesite
;
15263 #if __has_feature(ptrauth_calls)
15264 address
= (uintptr_t)VM_KERNEL_STRIP_PTR(address
);
15265 #endif /* __has_feature(ptrauth_calls) */
15267 IOSimpleLockLock(sKextAccountsLock
);
15268 site
= releasesite
= NULL
;
15270 // bsearch sKextAccounts list
15271 for (baseIdx
= 0, lim
= sKextAccountsCount
; lim
; lim
>>= 1) {
15272 active
= &sKextAccounts
[baseIdx
+ (lim
>> 1)];
15273 if ((address
>= active
->address
) && (address
< active
->address_end
)) {
15274 site
= &active
->account
->site
;
15276 vm_tag_alloc_locked(site
, &releasesite
);
15279 } else if (address
> active
->address
) {
15281 baseIdx
+= (lim
>> 1) + 1;
15286 IOSimpleLockUnlock(sKextAccountsLock
);
15288 kern_allocation_name_release(releasesite
);
15294 extern "C" uint32_t
15295 OSKextGetKmodIDForSite(const vm_allocation_site_t
* site
, char * name
, vm_size_t namelen
)
15297 OSKextAccount
* account
= (typeof(account
))site
;
15298 const char * kname
;
15301 if (account
->kext
) {
15302 kname
= account
->kext
->getIdentifierCString();
15306 strlcpy(name
, kname
, namelen
);
15309 return account
->loadTag
;
15313 OSKextFreeSite(vm_allocation_site_t
* site
)
15315 OSKextAccount
* freeAccount
= (typeof(freeAccount
))site
;
15316 IODelete(freeAccount
, OSKextAccount
, 1);
15319 /*********************************************************************
15320 *********************************************************************/
15322 #if CONFIG_IMAGEBOOT
15324 OSKextGetUUIDForName(const char *name
, uuid_t uuid
)
15326 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithIdentifier(name
);
15331 OSSharedPtr
<OSData
> uuid_data
= kext
->copyUUID();
15333 memcpy(uuid
, uuid_data
->getBytesNoCopy(), sizeof(uuid_t
));
15342 sysctl_willuserspacereboot
15343 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
15345 int new_value
= 0, old_value
= 0, changed
= 0;
15346 int error
= sysctl_io_number(req
, old_value
, sizeof(int), &new_value
, &changed
);
15351 OSKext::willUserspaceReboot();
15356 static SYSCTL_PROC(_kern
, OID_AUTO
, willuserspacereboot
,
15357 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
,
15358 NULL
, 0, sysctl_willuserspacereboot
, "I", "");