1/*
2 * Copyright (c) 2008-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#define IOKIT_ENABLE_SHARED_PTR
30
31extern "C" {
32#include <string.h>
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_map.h>
40#include <kextd/kextd_mach.h>
41#include <libkern/kernel_mach_header.h>
42#include <libkern/kext_panic_report.h>
43#include <libkern/kext_request_keys.h>
44#include <libkern/mkext.h>
45#include <libkern/prelink.h>
46#include <libkern/version.h>
47#include <libkern/zlib.h>
48#include <mach/host_special_ports.h>
49#include <mach/mach_vm.h>
50#include <mach/mach_time.h>
51#include <uuid/uuid.h>
52#include <sys/random.h>
53#include <pexpert/pexpert.h>
54
55#include <sys/pgo.h>
56
57#if CONFIG_CSR
58#include <sys/csr.h>
59#include <sys/stat.h>
60#include <sys/vnode.h>
61#endif /* CONFIG_CSR */
62};
63
64#if CONFIG_MACF
65#include <sys/kauth.h>
66#include <security/mac_framework.h>
67#endif
68
69#include <vm/vm_kern.h>
70#include <sys/sysctl.h>
71#include <kern/task.h>
72#include <os/cpp_util.h>
73
74#include <libkern/OSKextLibPrivate.h>
75#include <libkern/c++/OSKext.h>
76#include <libkern/c++/OSLib.h>
77
78#include <IOKit/IOLib.h>
79#include <IOKit/IOCatalogue.h>
80#include <IOKit/IORegistryEntry.h>
81#include <IOKit/IOService.h>
82#include <IOKit/IOUserServer.h>
83
84#include <IOKit/IOStatisticsPrivate.h>
85#include <IOKit/IOBSD.h>
86#include <IOKit/IOPlatformExpert.h>
87
88#include <san/kasan.h>
89
90#if CONFIG_SPTM
91#include <arm64/sptm/sptm.h>
92#endif
93
94#if PRAGMA_MARK
95#pragma mark External & Internal Function Protos
96#endif
97/*********************************************************************
98*********************************************************************/
99extern "C" {
100extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
101extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
102
103extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
104extern int dtrace_keep_kernel_symbols(void);
105
106#if defined(__x86_64__) || defined(__i386__)
107extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
108extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
109extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
110static void *allocate_kcfileset_map_entry_list(void);
111static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
112static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
113int vnode_put(struct vnode *vp);
114kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
115 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
116kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
117void * ubc_getobject(struct vnode *vp, __unused int flags);
118#endif //(__x86_64__) || defined(__i386__)
119}
120
121extern unsigned long gVirtBase;
122extern unsigned long gPhysBase;
123extern vm_map_t g_kext_map;
124
125bool pageableKCloaded = false;
126bool auxKCloaded = false;
127bool resetAuxKCSegmentOnUnload = false;
128
129extern boolean_t pageablekc_uuid_valid;
130extern uuid_t pageablekc_uuid;
131extern uuid_string_t pageablekc_uuid_string;
132
133extern boolean_t auxkc_uuid_valid;
134extern uuid_t auxkc_uuid;
135extern uuid_string_t auxkc_uuid_string;
136
137static OSReturn _OSKextCreateRequest(
138 const char * predicate,
139 OSSharedPtr<OSDictionary> & requestP);
140static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
141static OSObject * _OSKextGetRequestArgument(
142 OSDictionary * requestDict,
143 const char * argName);
144static bool _OSKextSetRequestArgument(
145 OSDictionary * requestDict,
146 const char * argName,
147 OSMetaClassBase * value);
148template <typename T>
149static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
150static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
151static OSReturn _OSDictionarySetCStringValue(
152 OSDictionary * dict,
153 const char * key,
154 const char * value);
155static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
156#if CONFIG_KXLD
157static bool _OSKextInPrelinkRebuildWindow(void);
158#endif
159
160// We really should add containsObject() & containsCString to OSCollection & subclasses.
161// So few pad slots, though....
162static bool _OSArrayContainsCString(OSArray * array, const char * cString);
163static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
164
165static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
166
167/* Prelinked arm kexts do not have VM entries because the method we use to
168 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
169 * not work on ARM. To get around that, we must free prelinked kext
170 * executables with ml_static_mfree() instead of kext_free().
171 */
172#if __i386__ || __x86_64__
173#define VM_MAPPED_KEXTS 1
174#define KASLR_KEXT_DEBUG 0
175#define KASLR_IOREG_DEBUG 0
176#elif __arm__ || __arm64__
177#define VM_MAPPED_KEXTS 0
178#define KASLR_KEXT_DEBUG 0
179#else
180#error Unsupported architecture
181#endif
182
183#if PRAGMA_MARK
184#pragma mark Constants & Macros
185#endif
186/*********************************************************************
187* Constants & Macros
188*********************************************************************/
189
190/* Use this number to create containers.
191 */
192#define kOSKextTypicalLoadCount (150)
193#define kOSKextTypicalUpgradeCount (5)
194
195/* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
196 * A loaded kext will no dependents or external retains will have 2 retains.
197 */
198#define kOSKextMinRetainCount (1)
199#define kOSKextMinLoadedRetainCount (2)
200
201#define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
202#define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
203
204/**********
205 * Strings and substrings used in dependency resolution.
206 */
207#define APPLE_KEXT_PREFIX "com.apple."
208#define KERNEL_LIB "com.apple.kernel"
209
210#define PRIVATE_KPI "com.apple.kpi.private"
211
212/* Version for compatbility pseudokexts (com.apple.kernel.*),
213 * compatible back to v6.0.
214 */
215#define KERNEL6_LIB "com.apple.kernel.6.0"
216#define KERNEL6_VERSION "7.9.9"
217
218#define KERNEL_LIB_PREFIX "com.apple.kernel."
219#define KPI_LIB_PREFIX "com.apple.kpi."
220
221#define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
222
223#define REBUILD_MAX_TIME (60 * 5) // 5 minutes
224#define MINIMUM_WAKEUP_SECONDS (30)
225
226/*********************************************************************
227* infoDict keys for internally-stored data. Saves on ivar slots for
228* objects we don't keep around past boot time or during active load.
229*********************************************************************/
230
231/* A usable, uncompressed file is stored under this key.
232 */
233#define _kOSKextExecutableKey "_OSKextExecutable"
234
235/* An indirect reference to the executable file from an mkext
236 * is stored under this key.
237 */
238#define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
239
240/* If the file is contained in a larger buffer laid down by the booter or
241 * sent from user space, the OSKext stores that OSData under this key so that
242 * references are properly tracked. This is always an mkext, right now.
243 */
244#define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
245
246#define OS_LOG_HDR_VERSION 1
247#define NUM_OS_LOG_SECTIONS 3
248
249#define OS_LOG_SECT_IDX 0
250#define CSTRING_SECT_IDX 1
251#define ASAN_CSTRING_SECT_IDX 2
252
253#if PRAGMA_MARK
254#pragma mark Typedefs
255#endif
256/*********************************************************************
257* Typedefs
258*********************************************************************/
259
260/*********************************************************************
261* osLogDataHeaderRef describes the header information of an OSData
262* object that is returned when querying for kOSBundleLogStringsKey.
263* We currently return information regarding 2 sections - os_log and
264* cstring. In the case that the os_log section doesn't exist, we just
265* return an offset and length of 0 for that section.
266*********************************************************************/
267typedef struct osLogDataHeader {
268 uint32_t version;
269 uint32_t sect_count;
270 struct {
271 uint32_t sect_offset;
272 uint32_t sect_size;
273 } sections[0];
274} osLogDataHeaderRef;
275
276/*********************************************************************
277* MkextEntryRef describes the contents of an OSData object
278* referencing a file entry from an mkext so that we can uncompress
279* (if necessary) and extract it on demand.
280*
281* It contains the mkextVersion in case we ever wind up supporting
282* multiple mkext formats. Mkext format 1 is officially retired as of
283* Snow Leopard.
284*********************************************************************/
285typedef struct MkextEntryRef {
286 mkext_basic_header * mkext; // beginning of whole mkext file
287 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
288} MkextEntryRef;
289
290#if PRAGMA_MARK
291#pragma mark Global and static Module Variables
292#endif
293/*********************************************************************
294* Global & static variables, used to keep track of kexts.
295*********************************************************************/
296
297static bool sPrelinkBoot = false;
298static bool sSafeBoot = false;
299static bool sKeepSymbols = false;
300static bool sPanicOnKCMismatch = false;
301static bool sOSKextWasResetAfterUserspaceReboot = false;
302
303/*********************************************************************
304 * sKextLock is the principal lock for OSKext, and guards all static
305 * and global variables not owned by other locks (declared further
306 * below). It must be taken by any entry-point method or function,
307 * including internal functions called on scheduled threads.
308 *
309 * sKextLock and sKextInnerLock are recursive due to multiple functions
310 * that are called both externally and internally. The other locks are
311 * nonrecursive.
312 *
313 * Which locks are taken depends on what they protect, but if more than
314 * one must be taken, they must always be locked in this order
315 * (and unlocked in reverse order) to prevent deadlocks:
316 *
317 * 1. sKextLock
318 * 2. sKextInnerLock
319 * 3. sKextSummariesLock
320 * 4. sKextLoggingLock
321 */
322static IORecursiveLock * sKextLock = NULL;
323
324static OSSharedPtr<OSDictionary> sKextsByID;
325static OSSharedPtr<OSDictionary> sExcludeListByID;
326static OSKextVersion sExcludeListVersion = 0;
327static OSSharedPtr<OSArray> sLoadedKexts;
328static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
329static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
330static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
331static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
332
333// Requests to the IOKit daemon waiting to be picked up.
334static OSSharedPtr<OSArray> sKernelRequests;
335// Identifier of kext load requests in sKernelRequests
336static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
337static OSSharedPtr<OSArray> sRequestCallbackRecords;
338
339// Identifiers of all kexts ever requested in kernel; used for prelinked kernel
340static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
341#if CONFIG_KXLD
342static KXLDContext * sKxldContext = NULL;
343#endif
344static uint32_t sNextLoadTag = 0;
345static uint32_t sNextRequestTag = 0;
346
347static bool sUserLoadsActive = false;
348static bool sIOKitDaemonActive = false;
349static bool sDeferredLoadSucceeded = false;
350static bool sConsiderUnloadsExecuted = false;
351
352#if NO_KEXTD
353static bool sKernelRequestsEnabled = false;
354#else
355static bool sKernelRequestsEnabled = true;
356#endif
357static bool sLoadEnabled = true;
358static bool sUnloadEnabled = true;
359
360/*********************************************************************
361 * Stuff for the OSKext representing the kernel itself.
362 **********/
363static OSKext * sKernelKext = NULL;
364
365/* Load Tag IDs used by statically loaded binaries (e.g, the kernel itself). */
366enum : uint32_t {
367 kOSKextKernelLoadTag = 0,
368#if CONFIG_SPTM
369 kOSKextSPTMLoadTag = 1,
370 kOSKextTXMLoadTag = 2,
371#endif /* CONFIG_SPTM */
372 kOSKextLoadTagCount
373};
374
375/* Set up a fake kmod_info struct for the kernel.
376 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
377 * before OSKext is initialized; that call only needs the name
378 * and address to be set correctly.
379 *
380 * We don't do much else with the kerne's kmod_info; we never
381 * put it into the kmod list, never adjust the reference count,
382 * and never have kernel components reference it.
383 * For that matter, we don't do much with kmod_info structs
384 * at all anymore! We just keep them filled in for gdb and
385 * binary compability.
386 */
387kmod_info_t g_kernel_kmod_info = {
388 .next = NULL,
389 .info_version = KMOD_INFO_VERSION,
390 .id = kOSKextKernelLoadTag, // loadTag: kernel is always 0
391 .name = kOSKextKernelIdentifier,// bundle identifier
392 .version = "0", // filled in in OSKext::initialize()
393 .reference_count = -1, // never adjusted; kernel never unloads
394 .reference_list = NULL,
395 .address = 0,
396 .size = 0, // filled in in OSKext::initialize()
397 .hdr_size = 0,
398 .start = NULL,
399 .stop = NULL
400};
401
402#if CONFIG_SPTM
403/* The SPTM and TXM need fake kmod structures just like the kernel. */
404kmod_info_t g_sptm_kmod_info = {
405 .next = NULL,
406 .info_version = KMOD_INFO_VERSION,
407 .id = kOSKextSPTMLoadTag, // Always one after the kernel
408 .name = kOSKextSPTMIdentifier,// bundle identifier
409 .version = "0", // filled in by OSKext::initialize()
410 .reference_count = -1, // never adjusted; SPTM never unloads
411 .reference_list = NULL,
412 .address = 0,
413 .size = 0, // filled in by OSKext::initialize()
414 .hdr_size = 0,
415 .start = NULL,
416 .stop = NULL
417};
418
419kmod_info_t g_txm_kmod_info = {
420 .next = NULL,
421 .info_version = KMOD_INFO_VERSION,
422 .id = kOSKextTXMLoadTag, // Always one after the SPTM
423 .name = kOSKextTXMIdentifier,// bundle identifier
424 .version = "0", // filled in by OSKext::initialize()
425 .reference_count = -1, // never adjusted; TXM never unloads
426 .reference_list = NULL,
427 .address = 0,
428 .size = 0, // filled in by OSKext::initialize()
429 .hdr_size = 0,
430 .start = NULL,
431 .stop = NULL
432};
433#endif /* CONFIG_SPTM */
434
435/* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
436
437kmod_info_t invalid_kmod_info = {
438 .next = NULL,
439 .info_version = KMOD_INFO_VERSION,
440 .id = UINT32_MAX,
441 .name = "invalid",
442 .version = "0",
443 .reference_count = -1,
444 .reference_list = NULL,
445 .address = 0,
446 .size = 0,
447 .hdr_size = 0,
448 .start = NULL,
449 .stop = NULL
450};
451
452extern "C" {
453// symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
454// dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
455// misc_protos.h, db_low_trace.c, kgmacros
456// 'kmod' is a holdover from the old kmod system, we can't rename it.
457kmod_info_t * kmod = NULL;
458
459#define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
460
461
462static char * loaded_kext_paniclist = NULL;
463static uint32_t loaded_kext_paniclist_size = 0;
464
465AbsoluteTime last_loaded_timestamp;
466static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
467static u_long last_loaded_strlen = 0;
468static void * last_loaded_address = NULL;
469static u_long last_loaded_size = 0;
470
471AbsoluteTime last_unloaded_timestamp;
472static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
473static u_long last_unloaded_strlen = 0;
474static void * last_unloaded_address = NULL;
475static u_long last_unloaded_size = 0;
476
477// Statically linked kmods described by several mach-o sections:
478//
479// kPrelinkInfoSegment:kBuiltinInfoSection
480// Array of pointers to kmod_info_t structs.
481//
482// kPrelinkInfoSegment:kBuiltinInfoSection
483// Array of pointers to an embedded mach-o header.
484//
485// __DATA:kBuiltinInitSection, kBuiltinTermSection
486// Structors for all kmods. Has to be filtered by proc address.
487//
488
489static uint32_t gBuiltinKmodsCount;
490static kernel_section_t * gBuiltinKmodsSectionInfo;
491static kernel_section_t * gBuiltinKmodsSectionStart;
492
493const OSSymbol * gIOSurfaceIdentifier;
494vm_tag_t gIOSurfaceTag;
495
496/*********************************************************************
497 * sKextInnerLock protects against cross-calls with IOService and
498 * IOCatalogue, and owns the variables declared immediately below.
499 *
500 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
501 *
502 * When both sKextLock and sKextInnerLock need to be taken,
503 * always lock sKextLock first and unlock it second. Never take both
504 * locks in an entry point to OSKext; if you need to do so, you must
505 * spawn an independent thread to avoid potential deadlocks for threads
506 * calling into OSKext.
507 **********/
508static IORecursiveLock * sKextInnerLock = NULL;
509
510#if XNU_TARGET_OS_OSX
511static bool sAutounloadEnabled = true;
512#endif
513static bool sConsiderUnloadsCalled = false;
514static bool sConsiderUnloadsPending = false;
515
516static unsigned int sConsiderUnloadDelay = 60; // seconds
517static thread_call_t sUnloadCallout = NULL;
518#if CONFIG_KXLD
519static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
520#endif // CONFIG_KXLD
521static bool sSystemSleep = false; // true when system going to sleep
522static AbsoluteTime sLastWakeTime; // last time we woke up
523
524/*********************************************************************
525 * Backtraces can be printed at various times so we need a tight lock
526 * on data used for that. sKextSummariesLock protects the variables
527 * declared immediately below.
528 *
529 * gLoadedKextSummaries is accessed by other modules, but only during
530 * a panic so the lock isn't needed then.
531 *
532 * gLoadedKextSummaries has the "used" attribute in order to ensure
533 * that it remains visible even when we are performing extremely
534 * aggressive optimizations, as it is needed to allow the debugger
535 * to automatically parse the list of loaded kexts.
536 **********/
537static IOLock * sKextSummariesLock = NULL;
538extern "C" lck_ticket_t vm_allocation_sites_lock;
539extern "C" lck_grp_t vm_page_lck_grp_bucket;
540static lck_ticket_t * sKextAccountsLock = &vm_allocation_sites_lock;
541static lck_grp_t * sKextAccountsLockGrp = &vm_page_lck_grp_bucket;
542
543void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
544OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
545uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
546static size_t sLoadedKextSummariesAllocSize = 0;
547
548static OSKextActiveAccount * sKextAccounts;
549static uint32_t sKextAccountsCount;
550};
551
552/*********************************************************************
553 * sKextLoggingLock protects the logging variables declared immediately below.
554 **********/
555static IOLock * sKextLoggingLock = NULL;
556
557static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
558 kOSKextLogVerboseFlagsMask;
559static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
560static bool sBootArgLogFilterFound = false;
561SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
562 0, "kernel kext logging");
563
564static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
565static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
566static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
567
568/*********
569 * End scope for sKextInnerLock-protected variables.
570 *********************************************************************/
571
572/*********************************************************************
573 * OSValueObject concrete type instantiations
574 **********/
575OSDefineValueObjectForDependentType(void*)
576OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
577
578
579/**********************************************************************/
580
581TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
582
583/*********************************************************************
584 * helper function used for collecting PGO data upon unload of a kext
585 */
586
587static int OSKextGrabPgoDataLocked(OSKext *kext,
588 bool metadata,
589 uuid_t instance_uuid,
590 uint64_t *pSize,
591 char *pBuffer,
592 uint64_t bufferSize);
593
594/**********************************************************************/
595
596
597
598#if PRAGMA_MARK
599#pragma mark OSData callbacks (need to move to OSData)
600#endif
601/*********************************************************************
602* C functions used for callbacks.
603*********************************************************************/
604extern "C" {
605void
606osdata_kmem_free(void * ptr, unsigned int length)
607{
608 kmem_free(map: kernel_map, addr: (vm_address_t)ptr, size: length);
609 return;
610}
611
612void
613osdata_phys_free(void * ptr, unsigned int length)
614{
615 ml_static_mfree((vm_offset_t)ptr, length);
616 return;
617}
618
619void
620osdata_vm_deallocate(void * ptr, unsigned int length)
621{
622 (void)vm_deallocate(target_task: kernel_map, address: (vm_offset_t)ptr, size: length);
623 return;
624}
625
626void
627osdata_kext_free(void * ptr, unsigned int length)
628{
629 (void)kext_free(addr: (vm_offset_t)ptr, size: length);
630}
631};
632
633#if PRAGMA_MARK
634#pragma mark KXLD Allocation Callback
635#endif
636#if CONFIG_KXLD
637/*********************************************************************
638* KXLD Allocation Callback
639*********************************************************************/
640kxld_addr_t
641kern_allocate(
642 u_long size,
643 KXLDAllocateFlags * flags,
644 void * user_data)
645{
646 vm_address_t result = 0; // returned
647 kern_return_t mach_result = KERN_FAILURE;
648 bool success = false;
649 OSKext * theKext = (OSKext *)user_data;
650 unsigned int roundSize = 0;
651 OSSharedPtr<OSData> linkBuffer;
652
653 if (round_page(size) > UINT_MAX) {
654 OSKextLog(theKext,
655 kOSKextLogErrorLevel |
656 kOSKextLogGeneralFlag,
657 "%s: Requested memory size is greater than UINT_MAX.",
658 theKext->getIdentifierCString());
659 goto finish;
660 }
661
662 roundSize = (unsigned int)round_page(size);
663
664 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
665 if (mach_result != KERN_SUCCESS) {
666 OSKextLog(theKext,
667 kOSKextLogErrorLevel |
668 kOSKextLogGeneralFlag,
669 "Can't allocate kernel memory to link %s.",
670 theKext->getIdentifierCString());
671 goto finish;
672 }
673
674 /* Create an OSData wrapper for the allocated buffer.
675 */
676 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
677 if (!linkBuffer) {
678 OSKextLog(theKext,
679 kOSKextLogErrorLevel |
680 kOSKextLogGeneralFlag,
681 "Can't allocate linked executable wrapper for %s.",
682 theKext->getIdentifierCString());
683 goto finish;
684 }
685 linkBuffer->setDeallocFunction(osdata_kext_free);
686 OSKextLog(theKext,
687 kOSKextLogProgressLevel |
688 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
689 "Allocated link buffer for kext %s at %p (%lu bytes).",
690 theKext->getIdentifierCString(),
691 (void *)result, (unsigned long)roundSize);
692
693 theKext->setLinkedExecutable(linkBuffer.get());
694
695 *flags = kKxldAllocateWritable;
696 success = true;
697
698finish:
699 if (!success && result) {
700 kext_free(result, roundSize);
701 result = 0;
702 }
703
704 return (kxld_addr_t)result;
705}
706
707/*********************************************************************
708*********************************************************************/
709void
710kxld_log_callback(
711 KXLDLogSubsystem subsystem,
712 KXLDLogLevel level,
713 const char * format,
714 va_list argList,
715 void * user_data)
716{
717 OSKext *theKext = (OSKext *) user_data;
718 OSKextLogSpec logSpec = 0;
719
720 switch (subsystem) {
721 case kKxldLogLinking:
722 logSpec |= kOSKextLogLinkFlag;
723 break;
724 case kKxldLogPatching:
725 logSpec |= kOSKextLogPatchFlag;
726 break;
727 }
728
729 switch (level) {
730 case kKxldLogExplicit:
731 logSpec |= kOSKextLogExplicitLevel;
732 break;
733 case kKxldLogErr:
734 logSpec |= kOSKextLogErrorLevel;
735 break;
736 case kKxldLogWarn:
737 logSpec |= kOSKextLogWarningLevel;
738 break;
739 case kKxldLogBasic:
740 logSpec |= kOSKextLogProgressLevel;
741 break;
742 case kKxldLogDetail:
743 logSpec |= kOSKextLogDetailLevel;
744 break;
745 case kKxldLogDebug:
746 logSpec |= kOSKextLogDebugLevel;
747 break;
748 }
749
750 OSKextVLog(theKext, logSpec, format, argList);
751}
752#endif // CONFIG_KXLD
753
754#if PRAGMA_MARK
755#pragma mark IOStatistics defines
756#endif
757
758#if IOKITSTATS
759
760#define notifyKextLoadObservers(kext, kmod_info) \
761do { \
762 IOStatistics::onKextLoad(kext, kmod_info); \
763} while (0)
764
765#define notifyKextUnloadObservers(kext) \
766do { \
767 IOStatistics::onKextUnload(kext); \
768} while (0)
769
770#define notifyAddClassObservers(kext, addedClass, flags) \
771do { \
772 IOStatistics::onClassAdded(kext, addedClass); \
773} while (0)
774
775#define notifyRemoveClassObservers(kext, removedClass, flags) \
776do { \
777 IOStatistics::onClassRemoved(kext, removedClass); \
778} while (0)
779
780#else
781
782#define notifyKextLoadObservers(kext, kmod_info)
783#define notifyKextUnloadObservers(kext)
784#define notifyAddClassObservers(kext, addedClass, flags)
785#define notifyRemoveClassObservers(kext, removedClass, flags)
786
787#endif /* IOKITSTATS */
788
789#if PRAGMA_MARK
790#pragma mark Module Config (Startup & Shutdown)
791#endif
792/*********************************************************************
793* Module Config (Class Definition & Class Methods)
794*********************************************************************/
795#define super OSObject
796OSDefineMetaClassAndStructors(OSKext, OSObject)
797
798OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
799
800OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
801
802/*********************************************************************
803*********************************************************************/
804/**
805 * Allocate and intialize a fake/representative OSKext object for a statically
806 * loaded (by iBoot) binary (e.g., the XNU kernel itself).
807 *
808 * @param kmod_info Pointer to the kmod_info structure for the binary being
809 * setup. At least the "name" and "id" fields needs to already
810 * be set correctly.
811 *
812 * @return The allocated and initialized OSKext object.
813 */
814/* static */
815OSKext *
816OSKext::allocAndInitFakeKext(kmod_info_t *kmod_info)
817{
818 vm_offset_t load_address = 0;
819 const char *bundle_name = NULL;
820 bool macho_is_unslid = false;
821 bool set_custom_path = false;
822 const char *executable_fallback_name = NULL;
823
824 if (kmod_info->id == kOSKextKernelLoadTag) {
825 load_address = (vm_offset_t)&_mh_execute_header;
826 bundle_name = "mach_kernel";
827
828 /* The kernel Mach-O header is fixed up to slide all of its addresses. */
829 macho_is_unslid = false;
830
831 /**
832 * No path to the binary is set for the kernel in its OSKext object. The
833 * kernel binary is located in fixed directories depending on the OS.
834 */
835 set_custom_path = false;
836 executable_fallback_name = NULL;
837#if CONFIG_SPTM
838 } else if (kmod_info->id == kOSKextSPTMLoadTag) {
839 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_SPTM];
840 bundle_name = "sptm";
841
842 /* The addresses in the SPTM Mach-O header are all unslid. */
843 macho_is_unslid = true;
844
845 set_custom_path = true;
846 executable_fallback_name = "sptm.no.binname.in.macho";
847 } else if (kmod_info->id == kOSKextTXMLoadTag) {
848 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_TXM];
849 bundle_name = "txm";
850
851 /* The addresses in the TXM Mach-O header are all unslid. */
852 macho_is_unslid = true;
853
854 set_custom_path = true;
855 executable_fallback_name = "txm.no.binname.in.macho";
856#endif /* CONFIG_SPTM */
857 } else {
858 panic("%s: Unsupported kmod_info->id (%d)", __func__, kmod_info->id);
859 }
860
861 /* Set up an OSKext instance to represent the statically loaded binary. */
862 OSKext *fakeKext = new OSKext;
863 assert(fakeKext);
864 assert(load_address != 0);
865
866 /*
867 * The start address is always a slid address whereas the last VA returned
868 * by getlastaddr() might be unslid depending on the Mach-O. If the address
869 * coming from the Mach-O is unslid, then unslide the start address before
870 * computing the length of the executable.
871 */
872 size_t binaryLength = getlastaddr(header: (kernel_mach_header_t*)load_address);
873 binaryLength -= (macho_is_unslid) ? ml_static_unslide(vaddr: load_address) : load_address;
874 assert(binaryLength <= UINT_MAX);
875
876 /**
877 * The load address is always slid. That value will be unslid before being
878 * exposed to userspace.
879 */
880 OSSharedPtr<OSData> executable = OSData::withBytesNoCopy(
881 bytes: (void*)load_address, numBytes: (unsigned int)binaryLength);
882 assert(executable);
883
884 fakeKext->loadTag = sNextLoadTag++;
885 fakeKext->bundleID = OSSymbol::withCString(cString: kmod_info->name);
886
887 fakeKext->version = OSKextParseVersionString(versionString: osrelease);
888 fakeKext->compatibleVersion = fakeKext->version;
889 fakeKext->linkedExecutable = os::move(t&: executable);
890 fakeKext->interfaceUUID = fakeKext->copyUUID();
891
892 fakeKext->flags.hasAllDependencies = 1;
893 fakeKext->flags.kernelComponent = 1;
894 fakeKext->flags.prelinked = 0;
895 fakeKext->flags.loaded = 1;
896 fakeKext->flags.started = 1;
897 fakeKext->flags.CPPInitialized = 0;
898 fakeKext->flags.jettisonLinkeditSeg = 0;
899 fakeKext->flags.unslidMachO = macho_is_unslid;
900
901#if CONFIG_SPTM
902 if (set_custom_path) {
903 /* Only SPTM/TXM should have custom paths to their executables set. */
904 assert((kmod_info->id == kOSKextSPTMLoadTag) ||
905 (kmod_info->id == kOSKextTXMLoadTag));
906
907 /* All SPTM/TXM binaries are placed into the same path on internal systems. */
908 fakeKext->path = OSString::withCStringNoCopy("/usr/appleinternal/standalone/platform");
909
910 /**
911 * Each SPTM/TXM Mach-O should contain a __TEXT,__binname section which contains
912 * a character array representing the name of the Mach-O executable.
913 */
914 kernel_section_t *binname_sect =
915 getsectbynamefromheader((kernel_mach_header_t*)load_address, "__TEXT", "__binname");
916
917 if (binname_sect != NULL) {
918 const char *binname = (const char *)ml_static_slide(binname_sect->addr);
919 fakeKext->executableRelPath = OSString::withCStringNoCopy(binname);
920 } else {
921 fakeKext->executableRelPath = OSString::withCStringNoCopy(executable_fallback_name);
922 }
923 }
924#endif /* CONFIG_SPTM */
925
926 fakeKext->kmod_info = kmod_info;
927 strlcpy(dst: kmod_info->version, src: osrelease,
928 n: sizeof(kmod_info->version));
929 kmod_info->size = binaryLength;
930 assert(kmod_info->id == fakeKext->loadTag);
931
932 /*
933 * Con up an info dict, so we don't have to have special-case checking all
934 * over.
935 */
936 fakeKext->infoDict = OSDictionary::withCapacity(capacity: 5);
937 assert(fakeKext->infoDict);
938 bool setResult = fakeKext->infoDict->setObject(kCFBundleIdentifierKey,
939 anObject: fakeKext->bundleID.get());
940 assert(setResult);
941 setResult = fakeKext->infoDict->setObject(kOSKernelResourceKey,
942 anObject: kOSBooleanTrue);
943 assert(setResult);
944
945 {
946 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(cString: osrelease));
947 assert(scratchString);
948 setResult = fakeKext->infoDict->setObject(kCFBundleVersionKey,
949 anObject: scratchString.get());
950 assert(setResult);
951 }
952
953 {
954 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(cString: bundle_name));
955 assert(scratchString);
956 setResult = fakeKext->infoDict->setObject(kCFBundleNameKey,
957 anObject: scratchString.get());
958 assert(setResult);
959 }
960
961 return fakeKext;
962}
963
964/* static */
965void
966OSKext::initialize(void)
967{
968 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
969 IORegistryEntry * registryRoot = NULL;// do not release
970 OSSharedPtr<OSNumber> kernelCPUType;
971 OSSharedPtr<OSNumber> kernelCPUSubtype;
972 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
973 bool setResult = false;
974 uint64_t * timestamp = NULL;
975 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
976
977 /* This must be the first thing allocated. Everything else grabs this lock.
978 */
979 sKextLock = IORecursiveLockAlloc();
980 sKextInnerLock = IORecursiveLockAlloc();
981 sKextSummariesLock = IOLockAlloc();
982 sKextLoggingLock = IOLockAlloc();
983 assert(sKextLock);
984 assert(sKextInnerLock);
985 assert(sKextSummariesLock);
986 assert(sKextLoggingLock);
987
988 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
989 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
990 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
991 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
992 sKernelRequests = OSArray::withCapacity(capacity: 0);
993 sPostedKextLoadIdentifiers = OSSet::withCapacity(capacity: 0);
994 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
995 sRequestCallbackRecords = OSArray::withCapacity(capacity: 0);
996 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
997
998 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
999 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
1000 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
1001
1002 /* Read the log flag boot-args and set the log flags.
1003 */
1004 if (PE_parse_boot_argn(arg_string: "kextlog", arg_ptr: &bootLogFilter, max_arg: sizeof(bootLogFilter))) {
1005 sBootArgLogFilterFound = true;
1006 sKernelLogFilter = bootLogFilter;
1007 // log this if any flags are set
1008 OSKextLog(/* kext */ NULL,
1009 kOSKextLogBasicLevel |
1010 kOSKextLogFlagsMask,
1011 format: "Kernel kext log filter 0x%x per kextlog boot arg.",
1012 (unsigned)sKernelLogFilter);
1013 }
1014
1015#if !defined(__arm__) && !defined(__arm64__)
1016 /*
1017 * On our ARM targets, the kernelcache/boot kernel collection contains
1018 * the set of kexts required to boot, as specified by KCB. Safeboot is
1019 * either unsupported, or is supported by the bootloader only loading
1020 * the boot kernel collection; as a result OSKext has no role to play
1021 * in safeboot policy on ARM.
1022 */
1023 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
1024 sizeof(bootArgBuffer)) ? true : false;
1025#endif /* defined(__arm__) && defined(__arm64__) */
1026
1027 if (sSafeBoot) {
1028 OSKextLog(/* kext */ NULL,
1029 kOSKextLogWarningLevel |
1030 kOSKextLogGeneralFlag,
1031 format: "SAFE BOOT DETECTED - "
1032 "only valid OSBundleRequired kexts will be loaded.");
1033 }
1034
1035 PE_parse_boot_argn(arg_string: "keepsyms", arg_ptr: &sKeepSymbols, max_arg: sizeof(sKeepSymbols));
1036#if CONFIG_DTRACE
1037 if (dtrace_keep_kernel_symbols()) {
1038 sKeepSymbols = true;
1039 }
1040#endif /* CONFIG_DTRACE */
1041#if KASAN_DYNAMIC_BLACKLIST
1042 /* needed for function lookup */
1043 sKeepSymbols = true;
1044#endif
1045
1046 /*
1047 * Should we panic when the SystemKC is not linked against the
1048 * BootKC that was loaded by the booter? By default: yes, if the
1049 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
1050 * on mis-match and instead just print an error and continue.
1051 */
1052 sPanicOnKCMismatch = PE_parse_boot_argn(arg_string: "-nokcmismatchpanic", arg_ptr: bootArgBuffer,
1053 max_arg: sizeof(bootArgBuffer)) ? false : true;
1054
1055 /* Set up an OSKext instance to represent the kernel itself. */
1056 sKernelKext = allocAndInitFakeKext(kmod_info: &g_kernel_kmod_info);
1057 assert(sKernelKext);
1058
1059#if CONFIG_SPTM
1060 /* Set up OSKext instances to represent the SPTM/TXM. */
1061 OSKext *SPTMKext = allocAndInitFakeKext(&g_sptm_kmod_info);
1062 OSKext *TXMKext = allocAndInitFakeKext(&g_txm_kmod_info);
1063#endif
1064
1065 /* Add the kernel kext to the bookkeeping dictionaries. Note that
1066 * the kernel kext doesn't have a kmod_info struct. copyInfo()
1067 * gathers info from other places anyhow.
1068 */
1069 setResult = sKextsByID->setObject(aKey: sKernelKext->bundleID.get(), anObject: sKernelKext);
1070 assert(setResult);
1071 setResult = sLoadedKexts->setObject(sKernelKext);
1072 assert(setResult);
1073
1074#if CONFIG_SPTM
1075 setResult = sKextsByID->setObject(SPTMKext->bundleID.get(), SPTMKext);
1076 assert(setResult);
1077 setResult = sLoadedKexts->setObject(SPTMKext);
1078 assert(setResult);
1079
1080 setResult = sKextsByID->setObject(TXMKext->bundleID.get(), TXMKext);
1081 assert(setResult);
1082 setResult = sLoadedKexts->setObject(TXMKext);
1083 assert(setResult);
1084#endif /* CONFIG_SPTM */
1085
1086 // XXX: better way with OSSharedPtr?
1087 // sKernelKext remains a valid pointer even after the decref
1088 sKernelKext->release();
1089#if CONFIG_SPTM
1090 SPTMKext->release();
1091 TXMKext->release();
1092#endif /* CONFIG_SPTM */
1093
1094 registryRoot = IORegistryEntry::getRegistryRoot();
1095 kernelCPUType = OSNumber::withNumber(
1096 value: (long long unsigned int)_mh_execute_header.cputype,
1097 numberOfBits: 8 * sizeof(_mh_execute_header.cputype));
1098 kernelCPUSubtype = OSNumber::withNumber(
1099 value: (long long unsigned int)_mh_execute_header.cpusubtype,
1100 numberOfBits: 8 * sizeof(_mh_execute_header.cpusubtype));
1101 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
1102
1103 registryRoot->setProperty(kOSKernelCPUTypeKey, anObject: kernelCPUType.get());
1104 registryRoot->setProperty(kOSKernelCPUSubtypeKey, anObject: kernelCPUSubtype.get());
1105
1106 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
1107 if (gBuiltinKmodsSectionInfo) {
1108 uint32_t count;
1109
1110 assert(gBuiltinKmodsSectionInfo->addr);
1111 assert(gBuiltinKmodsSectionInfo->size);
1112 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
1113 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
1114
1115 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
1116 assert(gBuiltinKmodsSectionStart);
1117 assert(gBuiltinKmodsSectionStart->addr);
1118 assert(gBuiltinKmodsSectionStart->size);
1119 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
1120 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
1121 // one extra pointer for the end of last kmod
1122 assert(count == (gBuiltinKmodsCount + 1));
1123
1124 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
1125 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
1126 }
1127
1128 // Don't track this object -- it's never released
1129 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy(cString: "com.apple.iokit.IOSurface").detach();
1130
1131 timestamp = __OSAbsoluteTimePtr(abstime: &last_loaded_timestamp);
1132 *timestamp = 0;
1133 timestamp = __OSAbsoluteTimePtr(abstime: &last_unloaded_timestamp);
1134 *timestamp = 0;
1135 timestamp = __OSAbsoluteTimePtr(abstime: &sLastWakeTime);
1136 *timestamp = 0;
1137
1138 OSKextLog(/* kext */ NULL,
1139 kOSKextLogProgressLevel |
1140 kOSKextLogGeneralFlag,
1141 format: "Kext system initialized.");
1142
1143 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
1144#if CONFIG_SPTM
1145 notifyKextLoadObservers(SPTMKext, SPTMKext->kmod_info);
1146 notifyKextLoadObservers(TXMKext, TXMKext->kmod_info);
1147#endif
1148
1149 return;
1150}
1151
1152/*********************************************************************
1153* This is expected to be called exactly once, from exactly one thread
1154* context, during kernel bootstrap.
1155*********************************************************************/
1156/* static */
1157OSReturn
1158OSKext::removeKextBootstrap(void)
1159{
1160 OSReturn result = kOSReturnError;
1161
1162 const char * dt_kernel_header_name = "Kernel-__HEADER";
1163 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
1164 kernel_mach_header_t * dt_mach_header = NULL;
1165 int dt_mach_header_size = 0;
1166 struct symtab_command * dt_symtab = NULL;
1167 int dt_symtab_size = 0;
1168 int dt_result = 0;
1169
1170 kernel_segment_command_t * seg_kld = NULL;
1171 kernel_segment_command_t * seg_klddata = NULL;
1172 kernel_segment_command_t * seg_linkedit = NULL;
1173
1174 const char __unused * dt_segment_name = NULL;
1175 void __unused * segment_paddress = NULL;
1176 int __unused segment_size = 0;
1177
1178 OSKextLog(/* kext */ NULL,
1179 kOSKextLogProgressLevel |
1180 kOSKextLogGeneralFlag,
1181 format: "Jettisoning kext bootstrap segments.");
1182
1183 /*
1184 * keep the linkedit segment around when booted from a new MH_FILESET
1185 * KC because all the kexts shared a linkedit segment.
1186 */
1187 kc_format_t kc_format;
1188 if (!PE_get_primary_kc_format(type: &kc_format)) {
1189 OSKextLog(/* kext */ NULL,
1190 kOSKextLogErrorLevel |
1191 kOSKextLogGeneralFlag,
1192 format: "Unable to determine primary KC format");
1193 }
1194
1195 /*****
1196 * Dispose of unnecessary stuff that the booter didn't need to load.
1197 */
1198 dt_result = IODTGetLoaderInfo(key: dt_kernel_header_name,
1199 infoAddr: (void **)&dt_mach_header, infoSize: &dt_mach_header_size);
1200 if (dt_result == 0 && dt_mach_header) {
1201 IODTFreeLoaderInfo(key: dt_kernel_header_name, infoAddr: (void *)dt_mach_header,
1202 infoSize: round_page_32(x: dt_mach_header_size));
1203 }
1204 dt_result = IODTGetLoaderInfo(key: dt_kernel_symtab_name,
1205 infoAddr: (void **)&dt_symtab, infoSize: &dt_symtab_size);
1206 if (dt_result == 0 && dt_symtab) {
1207 IODTFreeLoaderInfo(key: dt_kernel_symtab_name, infoAddr: (void *)dt_symtab,
1208 infoSize: round_page_32(x: dt_symtab_size));
1209 }
1210
1211 /*****
1212 * KLD & KLDDATA bootstrap segments.
1213 */
1214 // xxx - should rename KLD segment
1215 seg_kld = getsegbyname(seg_name: "__KLD");
1216 seg_klddata = getsegbyname(seg_name: "__KLDDATA");
1217 if (seg_klddata) {
1218 // __mod_term_func is part of __KLDDATA
1219 OSRuntimeUnloadCPPForSegment(segment: seg_klddata);
1220 }
1221
1222#if __arm__ || __arm64__
1223 /* Free the memory that was set up by iBoot.
1224 */
1225#if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1226 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1227 * is covered by the contiguous rorgn.
1228 */
1229 dt_segment_name = "Kernel-__KLD";
1230 if (0 == IODTGetLoaderInfo(key: dt_segment_name, infoAddr: &segment_paddress, infoSize: &segment_size)) {
1231 IODTFreeLoaderInfo(key: dt_segment_name, infoAddr: (void *)segment_paddress,
1232 infoSize: (int)segment_size); // calls ml_static_mfree
1233 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1234 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1235#if !CONFIG_SPTM
1236 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1237 seg_kld->vmsize);
1238#else
1239 ml_static_mfree(seg_kld->vmaddr), seg_kld->vmsize);
1240#endif
1241 }
1242#endif
1243 dt_segment_name = "Kernel-__KLDDATA";
1244 if (0 == IODTGetLoaderInfo(key: dt_segment_name, infoAddr: &segment_paddress, infoSize: &segment_size)) {
1245 IODTFreeLoaderInfo(key: dt_segment_name, infoAddr: (void *)segment_paddress,
1246 infoSize: (int)segment_size); // calls ml_static_mfree
1247 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1248 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1249#if !CONFIG_SPTM
1250 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1251 seg_klddata->vmsize);
1252#else
1253 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1254#endif
1255 }
1256#elif __i386__ || __x86_64__
1257 /* On x86, use the mapping data from the segment load command to
1258 * unload KLD & KLDDATA directly.
1259 * This may invalidate any assumptions about "avail_start"
1260 * defining the lower bound for valid physical addresses.
1261 */
1262 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1263 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1264 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1265 }
1266 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1267 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1268 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1269 }
1270#else
1271#error arch
1272#endif
1273
1274 /*****
1275 * Prelinked kernel's symtab (if there is one).
1276 */
1277 if (kc_format != KCFormatFileset) {
1278 kernel_section_t * sect;
1279 sect = getsectbyname(seg_name: "__PRELINK", sect_name: "__symtab");
1280 if (sect && sect->addr && sect->size) {
1281 ml_static_mfree(sect->addr, sect->size);
1282 }
1283 }
1284
1285 seg_linkedit = (kernel_segment_command_t *)getsegbyname(seg_name: "__LINKEDIT");
1286
1287 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1288 * pageable, unless keepsyms is set. To do that, we have to copy it from
1289 * its booter-allocated memory, free the booter memory, reallocate proper
1290 * managed memory, then copy the segment back in.
1291 *
1292 * NOTE: This optimization is not valid for fileset KCs because each
1293 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1294 * that points to one fileset-global LINKEDIT segment. This
1295 * optimization is also only valid for platforms that support vm
1296 * mapped kexts or mapped kext collections (pageable KCs)
1297 */
1298#if VM_MAPPED_KEXTS
1299 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1300 kern_return_t mem_result;
1301 void *seg_copy = NULL;
1302 void *seg_data = NULL;
1303 vm_map_offset_t seg_offset = 0;
1304 vm_map_offset_t seg_copy_offset = 0;
1305 vm_map_size_t seg_length = 0;
1306
1307 seg_data = (void *) seg_linkedit->vmaddr;
1308 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1309 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1310
1311 /* Allocate space for the LINKEDIT copy.
1312 */
1313 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1314 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1315 if (mem_result != KERN_SUCCESS) {
1316 OSKextLog(/* kext */ NULL,
1317 kOSKextLogErrorLevel |
1318 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1319 "Can't copy __LINKEDIT segment for VM reassign.");
1320 return result;
1321 }
1322 seg_copy_offset = (vm_map_offset_t) seg_copy;
1323
1324 /* Copy it out.
1325 */
1326 memcpy(seg_copy, seg_data, seg_length);
1327
1328 /* Dump the booter memory.
1329 */
1330 ml_static_mfree(seg_offset, seg_length);
1331
1332 /* Set up the VM region.
1333 */
1334 mem_result = vm_map_enter_mem_object(
1335 kernel_map,
1336 &seg_offset,
1337 seg_length, /* mask */ 0,
1338 VM_MAP_KERNEL_FLAGS_FIXED(.vmf_overwrite = true),
1339 (ipc_port_t)NULL,
1340 (vm_object_offset_t) 0,
1341 /* copy */ FALSE,
1342 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1343 /* max_protection */ VM_PROT_ALL,
1344 /* inheritance */ VM_INHERIT_DEFAULT);
1345 if ((mem_result != KERN_SUCCESS) ||
1346 (seg_offset != (vm_map_offset_t) seg_data)) {
1347 OSKextLog(/* kext */ NULL,
1348 kOSKextLogErrorLevel |
1349 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1350 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1351 seg_data, seg_length, mem_result);
1352 return result;
1353 }
1354
1355 /* And copy it back.
1356 */
1357 memcpy(seg_data, seg_copy, seg_length);
1358
1359 /* Free the copy.
1360 */
1361 kmem_free(kernel_map, seg_copy_offset, seg_length);
1362 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1363 /* Remove the linkedit segment of the Boot KC */
1364 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1365 OSKext::jettisonFileSetLinkeditSegment(mh);
1366 }
1367#else // !VM_MAPPED_KEXTS
1368 /*****
1369 * Dump the LINKEDIT segment, unless keepsyms is set.
1370 */
1371 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1372 dt_segment_name = "Kernel-__LINKEDIT";
1373 if (0 == IODTGetLoaderInfo(key: dt_segment_name,
1374 infoAddr: &segment_paddress, infoSize: &segment_size)) {
1375#ifdef SECURE_KERNEL
1376 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1377 bzero((void*)vmaddr, segment_size);
1378#endif
1379 IODTFreeLoaderInfo(key: dt_segment_name, infoAddr: (void *)segment_paddress,
1380 infoSize: (int)segment_size);
1381 }
1382 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1383 /* Remove the linkedit segment of the Boot KC */
1384 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(type: KCKindPrimary);
1385 OSKext::jettisonFileSetLinkeditSegment(mh);
1386 } else {
1387 OSKextLog(/* kext */ NULL,
1388 kOSKextLogBasicLevel |
1389 kOSKextLogGeneralFlag,
1390 format: "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1391 }
1392#endif // VM_MAPPED_KEXTS
1393
1394 result = kOSReturnSuccess;
1395
1396 return result;
1397}
1398
1399#if CONFIG_KXLD
1400/*********************************************************************
1401*********************************************************************/
1402void
1403OSKext::flushNonloadedKexts(
1404 Boolean flushPrelinkedKexts)
1405{
1406 OSSharedPtr<OSSet> keepKexts;
1407
1408 /* TODO: make this more efficient with MH_FILESET kexts */
1409
1410 // Do not unload prelinked kexts on arm because the kernelcache is not
1411 // structured in a way that allows them to be unmapped
1412#if !defined(__x86_64__)
1413 flushPrelinkedKexts = false;
1414#endif /* defined(__x86_64__) */
1415
1416 IORecursiveLockLock(sKextLock);
1417
1418 OSKextLog(/* kext */ NULL,
1419 kOSKextLogProgressLevel |
1420 kOSKextLogKextBookkeepingFlag,
1421 "Flushing nonloaded kexts and other unused data.");
1422
1423 OSKext::considerDestroyingLinkContext();
1424
1425 /* If we aren't flushing unused prelinked kexts, we have to put them
1426 * aside while we flush everything else so make a container for them.
1427 */
1428 keepKexts = OSSet::withCapacity(16);
1429 if (!keepKexts) {
1430 goto finish;
1431 }
1432
1433 /* Set aside prelinked kexts (in-use or not) and break
1434 * any lingering inter-kext references for nonloaded kexts
1435 * so they have min. retain counts.
1436 */
1437 {
1438 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1439 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1440 if (!thisKext) {
1441 return false;
1442 }
1443 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1444 keepKexts->setObject(thisKext);
1445 } else if (!thisKext->declaresExecutable()) {
1446 /*
1447 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1448 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1449 * flushNonloadedKexts().
1450 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1451 */
1452 keepKexts->setObject(thisKext);
1453 } else if (thisKext->isInFileset()) {
1454 /* keep all kexts in the new MH_FILESET KC */
1455 keepKexts->setObject(thisKext);
1456 }
1457
1458 thisKext->flushDependencies(/* forceIfLoaded */ false);
1459 return false;
1460 });
1461 }
1462 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1463 */
1464 sKextsByID->flushCollection();
1465
1466 /* Now put the loaded kexts back into the ID dictionary.
1467 */
1468 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1469 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1470 if (!thisKext) {
1471 return false;
1472 }
1473 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1474 return false;
1475 });
1476
1477 /* Finally, put back the kept kexts if we saved any.
1478 */
1479 keepKexts->iterateObjects(^bool (OSObject * obj) {
1480 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1481 if (!thisKext) {
1482 return false;
1483 }
1484 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1485 return false;
1486 });
1487
1488finish:
1489 IORecursiveLockUnlock(sKextLock);
1490 return;
1491}
1492#else /* !CONFIG_KXLD */
1493
1494void
1495OSKext::flushNonloadedKexts(
1496 Boolean flushPrelinkedKexts __unused)
1497{
1498 IORecursiveLockLock(lock: sKextLock);
1499
1500 OSKextLog(/* kext */ NULL,
1501 kOSKextLogProgressLevel |
1502 kOSKextLogKextBookkeepingFlag,
1503 format: "Flushing dependency info for non-loaded kexts.");
1504
1505 /*
1506 * In a world where we don't dynamically link kexts, they all come
1507 * from a kext collection that's either in wired memory, or
1508 * wire-on-demand. We don't need to mess around with moving kexts in
1509 * and out of the sKextsByID array - they can all just stay there.
1510 * Here we just flush the dependency list for kexts that are not
1511 * loaded.
1512 */
1513 sKextsByID->iterateObjects(block: ^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1514 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1515 if (!thisKext) {
1516 return false;
1517 }
1518 thisKext->flushDependencies(/* forceIfLoaded */ forceFlag: false);
1519 return false;
1520 });
1521
1522 IORecursiveLockUnlock(lock: sKextLock);
1523 return;
1524}
1525
1526#endif /* CONFIG_KXLD */
1527
1528/*********************************************************************
1529*********************************************************************/
1530/* static */
1531void
1532OSKext::setIOKitDaemonActive(bool active)
1533{
1534 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1535 IORecursiveLockLock(lock: sKextLock);
1536 sIOKitDaemonActive = active;
1537 if (sKernelRequests->getCount()) {
1538 OSKext::pingIOKitDaemon();
1539 }
1540 IORecursiveLockUnlock(lock: sKextLock);
1541
1542 return;
1543}
1544
1545/*********************************************************************
1546* OSKextLib.cpp might need access to this someday but for now it's
1547* private.
1548*********************************************************************/
1549extern "C" {
1550extern void ipc_port_release_send(ipc_port_t);
1551};
1552
1553/* static */
1554OSReturn
1555OSKext::pingIOKitDaemon(void)
1556{
1557 OSReturn result = kOSReturnError;
1558#if !NO_KEXTD
1559 mach_port_t kextd_port = IPC_PORT_NULL;
1560
1561 if (!sIOKitDaemonActive) {
1562 result = kOSKextReturnDisabled; // basically unavailable
1563 goto finish;
1564 }
1565
1566 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1567 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1568 OSKextLog(/* kext */ NULL,
1569 kOSKextLogErrorLevel |
1570 kOSKextLogIPCFlag,
1571 format: "Can't get " kIOKitDaemonName " port.");
1572 goto finish;
1573 }
1574
1575 result = kextd_ping(server: kextd_port);
1576 if (result != KERN_SUCCESS) {
1577 OSKextLog(/* kext */ NULL,
1578 kOSKextLogErrorLevel |
1579 kOSKextLogIPCFlag,
1580 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1581 goto finish;
1582 }
1583
1584finish:
1585 if (IPC_PORT_VALID(kextd_port)) {
1586 ipc_port_release_send(kextd_port);
1587 }
1588#endif
1589
1590 return result;
1591}
1592
1593/*********************************************************************
1594*********************************************************************/
1595/* static */
1596bool
1597OSKext::driverkitEnabled(void)
1598{
1599#if XNU_TARGET_OS_WATCH
1600 return false;
1601#else //!XNU_TARGET_OS_WATCH
1602 return true;
1603#endif //XNU_TARGET_OS_WATCH
1604}
1605
1606/*********************************************************************
1607*********************************************************************/
1608/* static */
1609bool
1610OSKext::iokitDaemonAvailable(void)
1611{
1612 int notused;
1613 if (PE_parse_boot_argn(arg_string: "-restore", arg_ptr: &notused, max_arg: sizeof(notused))) {
1614 return false;
1615 }
1616 return driverkitEnabled();
1617}
1618
1619/*********************************************************************
1620*********************************************************************/
1621/* static */
1622void
1623OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1624{
1625 IORecursiveLockLock(lock: sKextLock);
1626 sDeferredLoadSucceeded = succeeded;
1627 IORecursiveLockUnlock(lock: sKextLock);
1628
1629 return;
1630}
1631
1632/*********************************************************************
1633* Called from IOSystemShutdownNotification.
1634*********************************************************************/
1635/* static */
1636void
1637OSKext::willShutdown(void)
1638{
1639#if !NO_KEXTD
1640 OSReturn checkResult = kOSReturnError;
1641#endif
1642 OSSharedPtr<OSDictionary> exitRequest;
1643
1644 IORecursiveLockLock(lock: sKextLock);
1645
1646 OSKext::setLoadEnabled(false);
1647 OSKext::setUnloadEnabled(false);
1648 OSKext::setAutounloadsEnabled(false);
1649 OSKext::setKernelRequestsEnabled(false);
1650
1651#if defined(__x86_64__) || defined(__i386__)
1652 if (IOPMRootDomainGetWillShutdown()) {
1653 OSKext::freeKCFileSetcontrol();
1654 }
1655#endif // (__x86_64__) || defined(__i386__)
1656
1657#if !NO_KEXTD
1658 OSKextLog(/* kext */ NULL,
1659 kOSKextLogProgressLevel |
1660 kOSKextLogGeneralFlag,
1661 format: "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1662
1663 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1664 requestP&: exitRequest);
1665 if (checkResult != kOSReturnSuccess) {
1666 goto finish;
1667 }
1668 if (!sKernelRequests->setObject(exitRequest.get())) {
1669 goto finish;
1670 }
1671
1672 OSKext::pingIOKitDaemon();
1673
1674finish:
1675#endif
1676
1677 IORecursiveLockUnlock(lock: sKextLock);
1678 return;
1679}
1680
1681void
1682OSKext::willUserspaceReboot(void)
1683{
1684 OSKext::willShutdown();
1685 IOService::userSpaceWillReboot();
1686 gIOCatalogue->terminateDriversForUserspaceReboot();
1687}
1688
1689void
1690OSKext::resetAfterUserspaceReboot(void)
1691{
1692 OSSharedPtr<OSArray> arr = OSArray::withCapacity(capacity: 1);
1693 IOService::updateConsoleUsers(consoleUsers: arr.get(), systemMessage: 0, afterUserspaceReboot: true /* after_userspace_reboot */);
1694
1695 IORecursiveLockLock(lock: sKextLock);
1696 gIOCatalogue->resetAfterUserspaceReboot();
1697 IOService::userSpaceDidReboot();
1698 OSKext::removeDaemonExitRequests();
1699 OSKext::setLoadEnabled(true);
1700 OSKext::setUnloadEnabled(true);
1701 OSKext::setAutounloadsEnabled(true);
1702 OSKext::setKernelRequestsEnabled(true);
1703 sOSKextWasResetAfterUserspaceReboot = true;
1704 IORecursiveLockUnlock(lock: sKextLock);
1705}
1706
1707extern "C" void
1708OSKextResetAfterUserspaceReboot(void)
1709{
1710 OSKext::resetAfterUserspaceReboot();
1711}
1712
1713/*
1714 * Remove daemon exit requests from sKernelRequests
1715 *
1716 * If we sent a daemon exit request during a userspace reboot and launchd
1717 * killed the IOKit daemon before it was able to dequeue the exit request, the
1718 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1719 *
1720 * This removes exit requests so that this does not happen.
1721 */
1722void
1723OSKext::removeDaemonExitRequests(void)
1724{
1725 OSDictionary * current = NULL;
1726 OSString * predicate = NULL;
1727 size_t index = 0;
1728 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1729
1730 while (index < sKernelRequests->getCount()) {
1731 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1732 if (current) {
1733 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1734 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1735 sKernelRequests->removeObject(index);
1736 continue;
1737 }
1738 }
1739 index++;
1740 }
1741}
1742
1743/*********************************************************************
1744*********************************************************************/
1745/* static */
1746bool
1747OSKext::getLoadEnabled(void)
1748{
1749 bool result;
1750
1751 IORecursiveLockLock(lock: sKextLock);
1752 result = sLoadEnabled;
1753 IORecursiveLockUnlock(lock: sKextLock);
1754 return result;
1755}
1756
1757/*********************************************************************
1758*********************************************************************/
1759/* static */
1760bool
1761OSKext::setLoadEnabled(bool flag)
1762{
1763 bool result;
1764
1765 IORecursiveLockLock(lock: sKextLock);
1766 result = sLoadEnabled;
1767 sLoadEnabled = (flag ? true : false);
1768
1769 if (sLoadEnabled != result) {
1770 OSKextLog(/* kext */ NULL,
1771 kOSKextLogBasicLevel |
1772 kOSKextLogLoadFlag,
1773 format: "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1774 }
1775
1776 IORecursiveLockUnlock(lock: sKextLock);
1777
1778 return result;
1779}
1780
1781/*********************************************************************
1782*********************************************************************/
1783/* static */
1784bool
1785OSKext::getUnloadEnabled(void)
1786{
1787 bool result;
1788
1789 IORecursiveLockLock(lock: sKextLock);
1790 result = sUnloadEnabled;
1791 IORecursiveLockUnlock(lock: sKextLock);
1792 return result;
1793}
1794
1795/*********************************************************************
1796*********************************************************************/
1797/* static */
1798bool
1799OSKext::setUnloadEnabled(bool flag)
1800{
1801 bool result;
1802
1803 IORecursiveLockLock(lock: sKextLock);
1804 result = sUnloadEnabled;
1805 sUnloadEnabled = (flag ? true : false);
1806 IORecursiveLockUnlock(lock: sKextLock);
1807
1808 if (sUnloadEnabled != result) {
1809 OSKextLog(/* kext */ NULL,
1810 kOSKextLogBasicLevel |
1811 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1812 format: "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1813 }
1814
1815 return result;
1816}
1817
1818/*********************************************************************
1819* Do not call any function that takes sKextLock here!
1820*********************************************************************/
1821/* static */
1822bool
1823OSKext::getAutounloadEnabled(void)
1824{
1825#if XNU_TARGET_OS_OSX
1826 bool result;
1827
1828 IORecursiveLockLock(lock: sKextInnerLock);
1829 result = sAutounloadEnabled ? true : false;
1830 IORecursiveLockUnlock(lock: sKextInnerLock);
1831 return result;
1832#else
1833 return false;
1834#endif /* XNU_TARGET_OS_OSX */
1835}
1836
1837/*********************************************************************
1838* Do not call any function that takes sKextLock here!
1839*********************************************************************/
1840/* static */
1841bool
1842OSKext::setAutounloadsEnabled(bool flag)
1843{
1844#if XNU_TARGET_OS_OSX
1845 bool result;
1846
1847 IORecursiveLockLock(lock: sKextInnerLock);
1848
1849 result = sAutounloadEnabled;
1850 sAutounloadEnabled = (flag ? true : false);
1851 if (!sAutounloadEnabled && sUnloadCallout) {
1852 thread_call_cancel(call: sUnloadCallout);
1853 }
1854
1855 if (sAutounloadEnabled != result) {
1856 OSKextLog(/* kext */ NULL,
1857 kOSKextLogBasicLevel |
1858 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1859 format: "Kext autounloading now %sabled.",
1860 sAutounloadEnabled ? "en" : "dis");
1861 }
1862
1863 IORecursiveLockUnlock(lock: sKextInnerLock);
1864
1865 return result;
1866#else
1867 (void)flag;
1868 return false;
1869#endif /* XNU_TARGET_OS_OSX */
1870}
1871
1872/*********************************************************************
1873*********************************************************************/
1874/* instance method operating on OSKext field */
1875bool
1876OSKext::setAutounloadEnabled(bool flag)
1877{
1878 bool result = flags.autounloadEnabled ? true : false;
1879 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1880
1881 if (result != (flag ? true : false)) {
1882 OSKextLog(aKext: this,
1883 kOSKextLogProgressLevel |
1884 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1885 format: "Autounloading for kext %s now %sabled.",
1886 getIdentifierCString(),
1887 flags.autounloadEnabled ? "en" : "dis");
1888 }
1889 return result;
1890}
1891
1892/*********************************************************************
1893*********************************************************************/
1894/* static */
1895bool
1896OSKext::setKernelRequestsEnabled(bool flag)
1897{
1898 bool result;
1899
1900 IORecursiveLockLock(lock: sKextLock);
1901 result = sKernelRequestsEnabled;
1902 sKernelRequestsEnabled = flag ? true : false;
1903
1904 if (sKernelRequestsEnabled != result) {
1905 OSKextLog(/* kext */ NULL,
1906 kOSKextLogBasicLevel |
1907 kOSKextLogGeneralFlag,
1908 format: "Kernel requests now %sabled.",
1909 sKernelRequestsEnabled ? "en" : "dis");
1910 }
1911 IORecursiveLockUnlock(lock: sKextLock);
1912 return result;
1913}
1914
1915/*********************************************************************
1916*********************************************************************/
1917/* static */
1918bool
1919OSKext::getKernelRequestsEnabled(void)
1920{
1921 bool result;
1922
1923 IORecursiveLockLock(lock: sKextLock);
1924 result = sKernelRequestsEnabled;
1925 IORecursiveLockUnlock(lock: sKextLock);
1926 return result;
1927}
1928
1929static bool
1930segmentIsMutable(kernel_segment_command_t *seg)
1931{
1932 /* Mutable segments have to have VM_PROT_WRITE */
1933 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1934 return false;
1935 }
1936 /* Exclude the __DATA_CONST segment */
1937 if (strncmp(s1: seg->segname, s2: "__DATA_CONST", n: sizeof(seg->segname)) == 0) {
1938 return false;
1939 }
1940 /* Exclude __LINKEDIT */
1941 if (strncmp(s1: seg->segname, s2: "__LINKEDIT", n: sizeof(seg->segname)) == 0) {
1942 return false;
1943 }
1944 return true;
1945}
1946
1947#if PRAGMA_MARK
1948#pragma mark Kext Life Cycle
1949#endif
1950/*********************************************************************
1951*********************************************************************/
1952OSSharedPtr<OSKext>
1953OSKext::withPrelinkedInfoDict(
1954 OSDictionary * anInfoDict,
1955 bool doCoalescedSlides,
1956 kc_kind_t type)
1957{
1958 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1959
1960 if (newKext && !newKext->initWithPrelinkedInfoDict(infoDict: anInfoDict, doCoalesedSlides: doCoalescedSlides, type)) {
1961 return NULL;
1962 }
1963
1964 return newKext;
1965}
1966
1967OSData *
1968OSKext::parseDextUniqueID(
1969 OSDictionary * anInfoDict,
1970 const char *dextIDCS)
1971{
1972 OSData *ret = NULL;
1973 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1974 if (data_duid != NULL) {
1975 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1976 OSKextLog(NULL,
1977 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1978 format: "Dext %s DextUniqueIdentifier too long.",
1979 dextIDCS);
1980 } else {
1981 /*
1982 * If the DextUniqueID exists it should be
1983 * present also into the personalities.
1984 */
1985 setDextUniqueIDInPersonalities(anInfoDict, dextUniqueID: data_duid);
1986 ret = data_duid;
1987 }
1988 } else {
1989 OSKextLog(NULL,
1990 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1991 format: "Dext %s does not have a DextUniqueIdentifier",
1992 dextIDCS);
1993 }
1994 return ret;
1995}
1996
1997void
1998OSKext::setDextUniqueIDInPersonalities(
1999 OSDictionary * anInfoDict,
2000 OSData * dextUniqueID)
2001{
2002 OSDictionary * dextPersonalities = NULL;
2003 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
2004 OSString * personalityName = NULL;
2005
2006 dextPersonalities = OSDynamicCast(OSDictionary,
2007 anInfoDict->getObject(kIOKitPersonalitiesKey));
2008 if (!dextPersonalities || !dextPersonalities->getCount()) {
2009 return;
2010 }
2011
2012 personalitiesIterator =
2013 OSCollectionIterator::withCollection(inColl: dextPersonalities);
2014 if (!personalitiesIterator) {
2015 return;
2016 }
2017 while ((personalityName = OSDynamicCast(OSString,
2018 personalitiesIterator->getNextObject()))) {
2019 OSDictionary * personality = OSDynamicCast(OSDictionary,
2020 dextPersonalities->getObject(personalityName));
2021 if (personality) {
2022 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
2023 if (duid == NULL) {
2024 personality->setObject(kOSBundleDextUniqueIdentifierKey, anObject: dextUniqueID);
2025 }
2026 }
2027 }
2028}
2029/*********************************************************************
2030*********************************************************************/
2031bool
2032OSKext::initWithPrelinkedInfoDict(
2033 OSDictionary * anInfoDict,
2034 bool doCoalescedSlides,
2035 kc_kind_t type)
2036{
2037 bool result = false;
2038 OSString * kextPath = NULL; // do not release
2039 OSNumber * addressNum = NULL; // reused; do not release
2040 OSNumber * lengthNum = NULL; // reused; do not release
2041 OSBoolean * scratchBool = NULL; // do not release
2042 void * data = NULL; // do not free
2043 void * srcData = NULL; // do not free
2044 OSSharedPtr<OSData> prelinkedExecutable;
2045 uint32_t length = 0; // reused
2046 uintptr_t kext_slide = PE_get_kc_slide(type);
2047 bool shouldSaveSegments = false;
2048 kc_format format = KCFormatUnknown;
2049
2050 if (!super::init()) {
2051 goto finish;
2052 }
2053
2054 /* Get the path. Don't look for an arch-specific path property.
2055 */
2056 kextPath = OSDynamicCast(OSString,
2057 anInfoDict->getObject(kPrelinkBundlePathKey));
2058
2059 if (!setInfoDictionaryAndPath(aDictionary: anInfoDict, aPath: kextPath)) {
2060 goto finish;
2061 }
2062
2063#if KASLR_KEXT_DEBUG
2064 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
2065#endif
2066
2067 /* Also get the executable's bundle-relative path if present.
2068 * Don't look for an arch-specific path property.
2069 */
2070 executableRelPath.reset(OSDynamicCast(OSString,
2071 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
2072 userExecutableRelPath.reset(OSDynamicCast(OSString,
2073 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2074
2075 /* Don't need the paths to be in the info dictionary any more.
2076 */
2077 anInfoDict->removeObject(kPrelinkBundlePathKey);
2078 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
2079
2080 scratchBool = OSDynamicCast(OSBoolean,
2081 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2082 if (scratchBool == kOSBooleanTrue) {
2083 flags.requireExplicitLoad = 1;
2084 }
2085
2086 /* Create an OSData wrapper around the linked executable.
2087 */
2088 addressNum = OSDynamicCast(OSNumber,
2089 anInfoDict->getObject(kPrelinkExecutableLoadKey));
2090 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
2091 lengthNum = OSDynamicCast(OSNumber,
2092 anInfoDict->getObject(kPrelinkExecutableSizeKey));
2093 if (!lengthNum) {
2094 OSKextLog(aKext: this,
2095 kOSKextLogErrorLevel |
2096 kOSKextLogArchiveFlag,
2097 format: "Kext %s can't find prelinked kext executable size.",
2098 getIdentifierCString());
2099 return result;
2100 }
2101
2102 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2103 length = (uint32_t) (lengthNum->unsigned32BitValue());
2104
2105#if KASLR_KEXT_DEBUG
2106 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
2107 (unsigned long)ml_static_unslide((vm_offset_t)data),
2108 (unsigned long)data,
2109 length);
2110#endif
2111
2112 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
2113 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
2114
2115 /* If the kext's load address differs from its source address, allocate
2116 * space in the kext map at the load address and copy the kext over.
2117 */
2118 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
2119 if (addressNum) {
2120 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2121
2122#if KASLR_KEXT_DEBUG
2123 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
2124 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
2125 (unsigned long)srcData);
2126#endif
2127
2128 if (data != srcData) {
2129#if __LP64__
2130 kern_return_t alloc_result;
2131
2132 alloc_result = kext_alloc(addr: (vm_offset_t *)&data, size: length, /* fixed */ TRUE);
2133 if (alloc_result != KERN_SUCCESS) {
2134 OSKextLog(aKext: this,
2135 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2136 format: "Failed to allocate space for prelinked kext %s.",
2137 getIdentifierCString());
2138 goto finish;
2139 }
2140 memcpy(dst: data, src: srcData, n: length);
2141#else
2142 OSKextLog(this,
2143 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2144 "Error: prelinked kext %s - source and load addresses "
2145 "differ on ILP32 architecture.",
2146 getIdentifierCString());
2147 goto finish;
2148#endif /* __LP64__ */
2149 }
2150
2151 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
2152 }
2153
2154 prelinkedExecutable = OSData::withBytesNoCopy(bytes: data, numBytes: length);
2155 if (!prelinkedExecutable) {
2156 OSKextLog(aKext: this,
2157 kOSKextLogErrorLevel |
2158 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
2159 format: "Kext %s failed to create executable wrapper.",
2160 getIdentifierCString());
2161 goto finish;
2162 }
2163
2164 /*
2165 * Fileset KCs are mapped as a whole by iBoot.
2166 * Individual kext executables should not be unmapped
2167 * by xnu.
2168 * Doing so may result in panics like rdar://85419651
2169 */
2170 if (PE_get_kc_format(type: kc_type, format: &format) && (format == KCFormatFileset)) {
2171 prelinkedExecutable->setDeallocFunction(NULL);
2172 } else { // Not from a Fileset KC
2173#if VM_MAPPED_KEXTS
2174 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
2175#else
2176 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
2177#endif
2178 }
2179 setLinkedExecutable(prelinkedExecutable.get());
2180 addressNum = OSDynamicCast(OSNumber,
2181 anInfoDict->getObject(kPrelinkKmodInfoKey));
2182 if (!addressNum) {
2183 OSKextLog(aKext: this,
2184 kOSKextLogErrorLevel |
2185 kOSKextLogArchiveFlag,
2186 format: "Kext %s can't find prelinked kext kmod_info address.",
2187 getIdentifierCString());
2188 goto finish;
2189 }
2190
2191 if (addressNum->unsigned64BitValue() != 0) {
2192 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2193 if (kmod_info->address) {
2194 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2195 } else {
2196 kmod_info->address = (uintptr_t)data;
2197 kmod_info->size = length;
2198 }
2199#if KASLR_KEXT_DEBUG
2200 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2201 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2202 (unsigned long)kmod_info);
2203 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2204 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2205 (unsigned long)kmod_info->address);
2206 #endif
2207 }
2208
2209 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2210 }
2211
2212 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2213 uintptr_t builtinTextStart;
2214 uintptr_t builtinTextEnd;
2215
2216 flags.builtin = true;
2217 builtinKmodIdx = addressNum->unsigned32BitValue();
2218 assert(builtinKmodIdx < gBuiltinKmodsCount);
2219
2220 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2221 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2222
2223 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2224 kmod_info->address = builtinTextStart;
2225 kmod_info->size = builtinTextEnd - builtinTextStart;
2226 }
2227
2228 /* If the plist has a UUID for an interface, save that off.
2229 */
2230 if (isInterface()) {
2231 interfaceUUID.reset(OSDynamicCast(OSData,
2232 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2233 if (interfaceUUID) {
2234 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2235 }
2236 }
2237
2238 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalesedSlides: doCoalescedSlides));
2239 if (!result) {
2240 goto finish;
2241 }
2242
2243 kc_type = type;
2244 /* Exclude builtin and codeless kexts */
2245 if (prelinkedExecutable && kmod_info) {
2246 switch (kc_type) {
2247 case KCKindPrimary:
2248 shouldSaveSegments = (
2249 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2250 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2251 if (shouldSaveSegments) {
2252 flags.resetSegmentsFromImmutableCopy = 1;
2253 } else {
2254 flags.unloadUnsupported = 1;
2255 }
2256 break;
2257 case KCKindPageable:
2258 flags.resetSegmentsFromVnode = 1;
2259 break;
2260 case KCKindAuxiliary:
2261 if (!pageableKCloaded) {
2262 flags.resetSegmentsFromImmutableCopy = 1;
2263 } else if (resetAuxKCSegmentOnUnload) {
2264 flags.resetSegmentsFromVnode = 1;
2265 } else {
2266 flags.unloadUnsupported = 1;
2267 }
2268 break;
2269 default:
2270 break;
2271 }
2272 }
2273
2274 if (flags.resetSegmentsFromImmutableCopy) {
2275 /* Save a pristine copy of the mutable segments */
2276 kernel_segment_command_t *seg = NULL;
2277 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2278
2279 savedMutableSegments = OSArray::withCapacity(capacity: 0);
2280
2281 for (seg = firstsegfromheader(header: k_mh); seg; seg = nextsegfromheader(header: k_mh, seg)) {
2282 if (!segmentIsMutable(seg)) {
2283 continue;
2284 }
2285 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2286 uint64_t vmsize = seg->vmsize;
2287 OSKextLog(aKext: this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2288 format: "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(s: seg->segname, n: sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2289 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2290 if (!savedSegment) {
2291 OSKextLog(aKext: this,
2292 kOSKextLogErrorLevel |
2293 kOSKextLogGeneralFlag,
2294 format: "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2295 result = false;
2296 goto finish;
2297 }
2298 savedMutableSegments->setObject(savedSegment);
2299 }
2300 }
2301
2302 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2303 /*
2304 * set VM protections now, wire pages for the old style Aux KC now,
2305 * wire pages for the rest of the KC types at load time.
2306 */
2307 result = (kOSReturnSuccess == setVMAttributes(protect: true, wire: (type == KCKindAuxiliary) ? true : false));
2308 if (!result) {
2309 goto finish;
2310 }
2311 }
2312
2313 flags.prelinked = true;
2314
2315 if (isDriverKit()) {
2316 dextStatistics = OSDextStatistics::create();
2317 dextUniqueID.reset(p: parseDextUniqueID(anInfoDict, dextIDCS: getIdentifierCString()), OSRetain);
2318 dextLaunchedCount = 0;
2319 }
2320
2321 /* If we created a kext from prelink info,
2322 * we must be booting from a prelinked kernel.
2323 */
2324 sPrelinkBoot = true;
2325
2326 result = (registerIdentifier() == kOSKextInitialized);
2327finish:
2328 return result;
2329}
2330
2331/*********************************************************************
2332*********************************************************************/
2333/* static */
2334OSSharedPtr<OSKext>
2335OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2336{
2337 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2338 if (!newKext) {
2339 return NULL;
2340 }
2341
2342 OSKextInitResult ret = newKext->initWithCodelessInfo(infoDict: anInfoDict);
2343 if (result != NULL) {
2344 *result = ret;
2345 }
2346 if (ret != kOSKextInitialized) {
2347 return NULL;
2348 }
2349
2350 return newKext;
2351}
2352
2353/*********************************************************************
2354*********************************************************************/
2355OSKextInitResult
2356OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2357{
2358 OSKextInitResult result = kOSKextInitFailure;
2359 OSString * kextPath = NULL; // do not release
2360 OSBoolean * scratchBool = NULL; // do not release
2361
2362 if (anInfoDict == NULL || !super::init()) {
2363 goto finish;
2364 }
2365
2366 /*
2367 * Get the path. Don't look for an arch-specific path property.
2368 */
2369 kextPath = OSDynamicCast(OSString,
2370 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2371 if (!kextPath) {
2372 OSKextLog(NULL,
2373 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2374 format: "Requested codeless kext dictionary does not contain the '%s' key",
2375 kKextRequestArgumentCodelessInfoBundlePathKey);
2376 goto finish;
2377 }
2378
2379 uniquePersonalityProperties(personalityDict: anInfoDict);
2380
2381 if (!setInfoDictionaryAndPath(aDictionary: anInfoDict, aPath: kextPath)) {
2382 goto finish;
2383 }
2384
2385 /*
2386 * This path is meant to initialize codeless kexts only. Refuse
2387 * anything that looks like it has an executable and/or declares
2388 * itself as a kernel component.
2389 */
2390 if (declaresExecutable() || isKernelComponent()) {
2391 OSKextLog(NULL,
2392 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2393 format: "Refusing to register codeless kext that declares an executable/kernel component: %s",
2394 getIdentifierCString());
2395 goto finish;
2396 }
2397
2398 if (strcmp(s1: getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2399 boolean_t updated = updateExcludeList(infoDict: infoDict.get());
2400 if (updated) {
2401 OSKextLog(aKext: this,
2402 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2403 format: "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2404 }
2405 }
2406
2407 kc_type = KCKindNone;
2408
2409 scratchBool = OSDynamicCast(OSBoolean,
2410 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2411 if (scratchBool == kOSBooleanTrue) {
2412 flags.requireExplicitLoad = 1;
2413 }
2414
2415 /* Also get the executable's bundle-relative path if present.
2416 * Don't look for an arch-specific path property.
2417 */
2418 userExecutableRelPath.reset(OSDynamicCast(OSString,
2419 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2420
2421 /* remove unnecessary paths from the info dict */
2422 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2423
2424 if (isDriverKit()) {
2425 dextStatistics = OSDextStatistics::create();
2426 dextUniqueID.reset(p: parseDextUniqueID(anInfoDict, dextIDCS: getIdentifierCString()), OSRetain);
2427 dextLaunchedCount = 0;
2428 }
2429
2430 result = registerIdentifier();
2431
2432finish:
2433 return result;
2434}
2435
2436/*********************************************************************
2437*********************************************************************/
2438/* static */
2439void
2440OSKext::setAllVMAttributes(void)
2441{
2442 OSSharedPtr<OSCollectionIterator> kextIterator;
2443 const OSSymbol * thisID = NULL; // do not release
2444
2445 IORecursiveLockLock(lock: sKextLock);
2446
2447 kextIterator = OSCollectionIterator::withCollection(inColl: sKextsByID.get());
2448 if (!kextIterator) {
2449 goto finish;
2450 }
2451
2452 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2453 OSKext * thisKext; // do not release
2454
2455 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2456 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2457 continue;
2458 }
2459
2460 if (!thisKext->flags.resetSegmentsFromVnode) {
2461 /*
2462 * set VM protections now, wire pages for the old style Aux KC now,
2463 * wire pages for the rest of the KC types at load time.
2464 */
2465 thisKext->setVMAttributes(protect: true, wire: (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2466 }
2467 }
2468
2469finish:
2470 IORecursiveLockUnlock(lock: sKextLock);
2471
2472 return;
2473}
2474
2475/*********************************************************************
2476*********************************************************************/
2477OSSharedPtr<OSKext>
2478OSKext::withBooterData(
2479 OSString * deviceTreeName,
2480 OSData * booterData)
2481{
2482 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2483
2484 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2485 return NULL;
2486 }
2487
2488 return newKext;
2489}
2490
2491/*********************************************************************
2492*********************************************************************/
2493typedef struct _BooterKextFileInfo {
2494 uint32_t infoDictPhysAddr;
2495 uint32_t infoDictLength;
2496 uint32_t executablePhysAddr;
2497 uint32_t executableLength;
2498 uint32_t bundlePathPhysAddr;
2499 uint32_t bundlePathLength;
2500} _BooterKextFileInfo;
2501
2502bool
2503OSKext::initWithBooterData(
2504 OSString * deviceTreeName,
2505 OSData * booterData)
2506{
2507 bool result = false;
2508 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2509 char * infoDictAddr = NULL; // do not free
2510 void * executableAddr = NULL; // do not free
2511 char * bundlePathAddr = NULL; // do not free
2512
2513 OSDictionary * theInfoDict = NULL; // do not release
2514 OSSharedPtr<OSObject> parsedXML;
2515 OSSharedPtr<OSString> kextPath;
2516
2517 OSSharedPtr<OSString> errorString;
2518 OSSharedPtr<OSData> executable;
2519
2520 if (!super::init()) {
2521 goto finish;
2522 }
2523
2524 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2525 if (!kextFileInfo) {
2526 OSKextLog(aKext: this,
2527 kOSKextLogErrorLevel |
2528 kOSKextLogGeneralFlag,
2529 format: "No booter-provided data for kext device tree entry %s.",
2530 deviceTreeName->getCStringNoCopy());
2531 goto finish;
2532 }
2533
2534 /* The info plist must exist or we can't read the kext.
2535 */
2536 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2537 OSKextLog(aKext: this,
2538 kOSKextLogErrorLevel |
2539 kOSKextLogGeneralFlag,
2540 format: "No kext info dictionary for booter device tree entry %s.",
2541 deviceTreeName->getCStringNoCopy());
2542 goto finish;
2543 }
2544
2545 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2546 if (!infoDictAddr) {
2547 OSKextLog(aKext: this,
2548 kOSKextLogErrorLevel |
2549 kOSKextLogGeneralFlag,
2550 format: "Can't translate physical address 0x%x of kext info dictionary "
2551 "for device tree entry %s.",
2552 (int)kextFileInfo->infoDictPhysAddr,
2553 deviceTreeName->getCStringNoCopy());
2554 goto finish;
2555 }
2556
2557 parsedXML = OSUnserializeXML(buffer: infoDictAddr, errorString);
2558 if (parsedXML) {
2559 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2560 }
2561 if (!theInfoDict) {
2562 const char * errorCString = "(unknown error)";
2563
2564 if (errorString && errorString->getCStringNoCopy()) {
2565 errorCString = errorString->getCStringNoCopy();
2566 } else if (parsedXML) {
2567 errorCString = "not a dictionary";
2568 }
2569 OSKextLog(aKext: this,
2570 kOSKextLogErrorLevel |
2571 kOSKextLogGeneralFlag,
2572 format: "Error unserializing info dictionary for device tree entry %s: %s.",
2573 deviceTreeName->getCStringNoCopy(), errorCString);
2574 goto finish;
2575 }
2576
2577 /* A bundle path is not mandatory.
2578 */
2579 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2580 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2581 if (!bundlePathAddr) {
2582 OSKextLog(aKext: this,
2583 kOSKextLogErrorLevel |
2584 kOSKextLogGeneralFlag,
2585 format: "Can't translate physical address 0x%x of kext bundle path "
2586 "for device tree entry %s.",
2587 (int)kextFileInfo->bundlePathPhysAddr,
2588 deviceTreeName->getCStringNoCopy());
2589 goto finish;
2590 }
2591 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2592
2593 kextPath = OSString::withCString(cString: bundlePathAddr);
2594 if (!kextPath) {
2595 OSKextLog(aKext: this,
2596 kOSKextLogErrorLevel |
2597 kOSKextLogGeneralFlag,
2598 format: "Failed to create wrapper for device tree entry %s kext path %s.",
2599 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2600 goto finish;
2601 }
2602 }
2603
2604 if (!setInfoDictionaryAndPath(aDictionary: theInfoDict, aPath: kextPath.get())) {
2605 goto finish;
2606 }
2607
2608 /* An executable is not mandatory.
2609 */
2610 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2611 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2612 if (!executableAddr) {
2613 OSKextLog(aKext: this,
2614 kOSKextLogErrorLevel |
2615 kOSKextLogGeneralFlag,
2616 format: "Can't translate physical address 0x%x of kext executable "
2617 "for device tree entry %s.",
2618 (int)kextFileInfo->executablePhysAddr,
2619 deviceTreeName->getCStringNoCopy());
2620 goto finish;
2621 }
2622
2623 executable = OSData::withBytesNoCopy(bytes: executableAddr,
2624 numBytes: kextFileInfo->executableLength);
2625 if (!executable) {
2626 OSKextLog(aKext: this,
2627 kOSKextLogErrorLevel |
2628 kOSKextLogGeneralFlag,
2629 format: "Failed to create executable wrapper for device tree entry %s.",
2630 deviceTreeName->getCStringNoCopy());
2631 goto finish;
2632 }
2633
2634 /* A kext with an executable needs to retain the whole booterData
2635 * object to keep the executable in memory.
2636 */
2637 if (!setExecutable(anExecutable: executable.get(), externalData: booterData)) {
2638 OSKextLog(aKext: this,
2639 kOSKextLogErrorLevel |
2640 kOSKextLogGeneralFlag,
2641 format: "Failed to set kext executable for device tree entry %s.",
2642 deviceTreeName->getCStringNoCopy());
2643 goto finish;
2644 }
2645 }
2646
2647 if (isDriverKit()) {
2648 dextStatistics = OSDextStatistics::create();
2649 dextUniqueID.reset(p: parseDextUniqueID(anInfoDict: theInfoDict, dextIDCS: getIdentifierCString()), OSRetain);
2650 dextLaunchedCount = 0;
2651 }
2652
2653 result = (registerIdentifier() == kOSKextInitialized);
2654
2655finish:
2656 return result;
2657}
2658
2659/*********************************************************************
2660*********************************************************************/
2661OSKextInitResult
2662OSKext::registerIdentifier(void)
2663{
2664 OSKextInitResult result = kOSKextInitFailure;
2665 OSKext * existingKext = NULL; // do not release
2666 bool existingIsLoaded = false;
2667 bool existingIsPrelinked = false;
2668 bool existingIsCodeless = false;
2669 bool existingIsDext = false;
2670 OSKextVersion newVersion = -1;
2671 OSKextVersion existingVersion = -1;
2672 char newVersionCString[kOSKextVersionMaxLength];
2673 char existingVersionCString[kOSKextVersionMaxLength];
2674 OSSharedPtr<OSData> newUUID;
2675 OSSharedPtr<OSData> existingUUID;
2676 const char *newDextUniqueIDCString = NULL;
2677 const char *existingDextUniqueIDCString = NULL;
2678 unsigned int newDextUniqueIDCStringSize = 0;
2679 unsigned int existingDextUniqueIDCStringSize = 0;
2680
2681 IORecursiveLockLock(lock: sKextLock);
2682
2683 /* Get the new kext's version for checks & log messages.
2684 */
2685 newVersion = getVersion();
2686 OSKextVersionGetString(aVersion: newVersion, buffer: newVersionCString,
2687 kOSKextVersionMaxLength);
2688
2689 /* If we don't have an existing kext with this identifier,
2690 * just record the new kext and we're done!
2691 */
2692 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2693 if (!existingKext) {
2694 sKextsByID->setObject(aKey: bundleID.get(), anObject: this);
2695 result = kOSKextInitialized;
2696 goto finish;
2697 }
2698
2699 /* Get the existing kext's version for checks & log messages.
2700 */
2701 existingVersion = existingKext->getVersion();
2702 OSKextVersionGetString(aVersion: existingVersion,
2703 buffer: existingVersionCString, kOSKextVersionMaxLength);
2704
2705 existingIsLoaded = existingKext->isLoaded();
2706 existingIsPrelinked = existingKext->isPrelinked();
2707 existingIsDext = existingKext->isDriverKit();
2708 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2709
2710 /*
2711 * Check if we are trying to upgrade a dext
2712 * with another dext.
2713 */
2714 if (isDriverKit() && existingIsDext) {
2715 OSData *newDextUID = getDextUniqueID();
2716 if (!newDextUID) {
2717 OSKextLog(aKext: this,
2718 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2719 format: "New dext %s, v%s requested does not have a unique dext identifier\n",
2720 getIdentifierCString(), newVersionCString);
2721 goto finish;
2722 }
2723 newDextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: newDextUID, size: &newDextUniqueIDCStringSize);
2724 assert(newDextUniqueIDCString != NULL);
2725
2726 OSData *existingDextUID = existingKext->getDextUniqueID();
2727 if (!existingDextUID) {
2728 OSKextLog(aKext: this,
2729 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2730 format: "Found a dext %s, v%s: with no unique dext identifier\n",
2731 existingKext->getIdentifierCString(), existingVersionCString);
2732 goto finish;
2733 }
2734 existingDextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: existingDextUID, size: &existingDextUniqueIDCStringSize);
2735 assert(existingDextUniqueIDCString != NULL);
2736
2737 /*
2738 * We might get multiple requests to save the same dext.
2739 * Check if we already have saved it or if this is an upgrade
2740 * for a dext with the same BundleID.
2741 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2742 * is requested for a BundleID we are going to upgrade to the newest
2743 * received irrespective from the dext version.
2744 */
2745 if (newDextUID->isEqualTo(aDataObj: existingDextUID) && existingKext->flags.dextToReplace == 0) {
2746 OSKextLog(aKext: this,
2747 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2748 format: "Refusing new dext %s, v%s:"
2749 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2750 getIdentifierCString(), newVersionCString,
2751 existingVersionCString, newDextUniqueIDCString);
2752 result = kOSKextAlreadyExist;
2753 goto finish;
2754 }
2755
2756 bool upgraded = upgradeDext(olddext: existingKext, newdext: this);
2757 if (upgraded) {
2758 /* If the dext was upgraded existingKext might have been deallocated */
2759 existingKext = NULL;
2760 OSKextLog(aKext: this,
2761 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2762 format: "Dext %s, v%s , unique dext identifier %s "
2763 "Upgraded to v%s, unique dext identifier %s \n",
2764 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2765 newVersionCString, newDextUniqueIDCString);
2766 result = kOSKextInitialized;
2767 } else {
2768 OSKextLog(aKext: this,
2769 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2770 format: "Upgrade delayed for %s v%s, unique dext identifier %s "
2771 "with v%s, unique dext identifier %s.\n",
2772 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2773 newVersionCString, newDextUniqueIDCString);
2774 result = kOSKextAlreadyExist;
2775 }
2776
2777 goto finish;
2778 }
2779
2780 /* If we have a non-codeless kext with this identifier that's already
2781 * loaded/prelinked, we can't use the new one, but let's be really
2782 * thorough and check how the two are related for a precise diagnostic
2783 * log message.
2784 *
2785 * This check is valid for kexts that declare an executable and for
2786 * dexts, but not for codeless kexts - we can just replace those.
2787 */
2788 if ((!existingIsCodeless || existingIsDext) &&
2789 (existingIsLoaded || existingIsPrelinked)) {
2790 bool sameVersion = (newVersion == existingVersion);
2791 bool sameExecutable = true; // assume true unless we have UUIDs
2792
2793 /* Only get the UUID if the existing kext is loaded. Doing so
2794 * might have to uncompress an mkext executable and we shouldn't
2795 * take that hit when neither kext is loaded.
2796 *
2797 * Note: there is no decompression that happens when all kexts
2798 * are loaded from kext collecitons.
2799 */
2800 newUUID = copyUUID();
2801 existingUUID = existingKext->copyUUID();
2802
2803 if (existingIsDext && !isDriverKit()) {
2804 OSKextLog(aKext: this,
2805 kOSKextLogWarningLevel |
2806 kOSKextLogKextBookkeepingFlag,
2807 format: "Notice - new kext %s, v%s matches a %s dext"
2808 "with the same bundle ID, v%s.",
2809 getIdentifierCString(), newVersionCString,
2810 (existingIsLoaded ? "loaded" : "prelinked"),
2811 existingVersionCString);
2812 goto finish;
2813 }
2814
2815 /* I'm entirely too paranoid about checking equivalence of executables,
2816 * but I remember nasty problems with it in the past.
2817 *
2818 * - If we have UUIDs for both kexts, compare them.
2819 * - If only one kext has a UUID, they're definitely different.
2820 */
2821 if (newUUID && existingUUID) {
2822 sameExecutable = newUUID->isEqualTo(aDataObj: existingUUID.get());
2823 } else if (newUUID || existingUUID) {
2824 sameExecutable = false;
2825 }
2826
2827 if (!newUUID && !existingUUID) {
2828 /* If there are no UUIDs, we can't really tell that the executables
2829 * are *different* without a lot of work; the loaded kext's
2830 * unrelocated executable is no longer around (and we never had it
2831 * in-kernel for a prelinked kext). We certainly don't want to do
2832 * a whole fake link for the new kext just to compare, either.
2833 */
2834 OSKextLog(aKext: this,
2835 kOSKextLogWarningLevel |
2836 kOSKextLogKextBookkeepingFlag,
2837 format: "Notice - new kext %s, v%s matches %s kext "
2838 "but can't determine if executables are the same (no UUIDs).",
2839 getIdentifierCString(),
2840 newVersionCString,
2841 (existingIsLoaded ? "loaded" : "prelinked"));
2842 }
2843
2844 if (sameVersion && sameExecutable) {
2845 OSKextLog(aKext: this,
2846 msgLogSpec: (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2847 kOSKextLogKextBookkeepingFlag,
2848 format: "Refusing new kext %s, v%s: a %s copy is already present "
2849 "(same version and executable).",
2850 getIdentifierCString(), newVersionCString,
2851 (existingIsLoaded ? "loaded" : "prelinked"));
2852 } else {
2853 if (!sameVersion) {
2854 /* This condition is significant so log it under warnings.
2855 */
2856 OSKextLog(aKext: this,
2857 kOSKextLogWarningLevel |
2858 kOSKextLogKextBookkeepingFlag,
2859 format: "Refusing new kext %s, v%s: already have %s v%s.",
2860 getIdentifierCString(),
2861 newVersionCString,
2862 (existingIsLoaded ? "loaded" : "prelinked"),
2863 existingVersionCString);
2864 } else {
2865 /* This condition is significant so log it under warnings.
2866 */
2867 OSKextLog(aKext: this,
2868 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2869 format: "Refusing new kext %s, v%s: a %s copy with a different "
2870 "executable UUID is already present.",
2871 getIdentifierCString(), newVersionCString,
2872 (existingIsLoaded ? "loaded" : "prelinked"));
2873 }
2874 }
2875 goto finish;
2876 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2877
2878 /* Refuse to allow an existing loaded codeless kext be replaced by a
2879 * normal kext with the same bundle ID.
2880 */
2881 if (existingIsCodeless && declaresExecutable()) {
2882 OSKextLog(aKext: this,
2883 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2884 format: "Refusing new kext %s, v%s: a codeless copy is already %s",
2885 getIdentifierCString(), newVersionCString,
2886 (existingIsLoaded ? "loaded" : "prelinked"));
2887 goto finish;
2888 }
2889
2890 /* Dexts packaged in the BootKC will be protected against replacement
2891 * by non-dexts by the logic above which checks if they are prelinked.
2892 * Dexts which are prelinked into the System KC will be registered
2893 * before any other kexts in the AuxKC are registered, and we never
2894 * put dexts in the AuxKC. Therefore, there is no need to check if an
2895 * existing object is a dext and is being replaced by a non-dext.
2896 * The scenario cannot happen by construction.
2897 *
2898 * See: OSKext::loadFileSetKexts()
2899 */
2900
2901
2902 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2903 * user loads are happening or if we're still in early boot. User agents are
2904 * supposed to resolve dependencies topside and include only the exact
2905 * kexts needed; so we always accept the new kext (in fact we should never
2906 * see an older unloaded copy hanging around).
2907 */
2908 if (sUserLoadsActive) {
2909 sKextsByID->setObject(aKey: bundleID.get(), anObject: this);
2910 result = kOSKextInitialized;
2911
2912 OSKextLog(aKext: this,
2913 kOSKextLogStepLevel |
2914 kOSKextLogKextBookkeepingFlag,
2915 format: "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2916 getIdentifierCString(),
2917 existingVersionCString,
2918 newVersionCString);
2919
2920 goto finish;
2921 }
2922
2923 /* During early boot, the kext with the highest version always wins out.
2924 * Prelinked kernels will never hit this, but mkexts and booter-read
2925 * kexts might have duplicates.
2926 */
2927 if (newVersion > existingVersion) {
2928 sKextsByID->setObject(aKey: bundleID.get(), anObject: this);
2929 result = kOSKextInitialized;
2930
2931 OSKextLog(aKext: this,
2932 kOSKextLogStepLevel |
2933 kOSKextLogKextBookkeepingFlag,
2934 format: "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2935 existingVersionCString,
2936 getIdentifierCString(),
2937 newVersionCString);
2938 } else {
2939 OSKextLog(aKext: this,
2940 kOSKextLogStepLevel |
2941 kOSKextLogKextBookkeepingFlag,
2942 format: "Kext %s is already registered with a higher/same version (v%s); "
2943 "dropping newly-added (v%s).",
2944 getIdentifierCString(),
2945 existingVersionCString,
2946 newVersionCString);
2947 }
2948
2949 /* result has been set appropriately by now. */
2950
2951finish:
2952
2953 IORecursiveLockUnlock(lock: sKextLock);
2954
2955 if (newDextUniqueIDCString != NULL) {
2956 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2957 }
2958 if (existingDextUniqueIDCString != NULL) {
2959 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2960 }
2961
2962 if (result == kOSKextInitialized) {
2963 OSKextLog(aKext: this,
2964 kOSKextLogStepLevel |
2965 kOSKextLogKextBookkeepingFlag,
2966 format: "Kext %s, v%s registered and available for loading.",
2967 getIdentifierCString(), newVersionCString);
2968 }
2969
2970 return result;
2971}
2972
2973/*********************************************************************
2974 * Does the bare minimum validation to look up a kext.
2975 * All other validation is done on the spot as needed.
2976 **********************************************************************/
2977bool
2978OSKext::setInfoDictionaryAndPath(
2979 OSDictionary * aDictionary,
2980 OSString * aPath)
2981{
2982 bool result = false;
2983 OSString * bundleIDString = NULL; // do not release
2984 OSString * versionString = NULL; // do not release
2985 OSString * compatibleVersionString = NULL; // do not release
2986 const char * versionCString = NULL; // do not free
2987 const char * compatibleVersionCString = NULL; // do not free
2988 OSBoolean * scratchBool = NULL; // do not release
2989 OSDictionary * scratchDict = NULL; // do not release
2990
2991 if (infoDict) {
2992 panic("Attempt to set info dictionary on a kext "
2993 "that already has one (%s).",
2994 getIdentifierCString());
2995 }
2996
2997 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2998 goto finish;
2999 }
3000
3001 infoDict.reset(p: aDictionary, OSRetain);
3002
3003 /* Check right away if the info dictionary has any log flags.
3004 */
3005 scratchBool = OSDynamicCast(OSBoolean,
3006 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
3007 if (scratchBool == kOSBooleanTrue) {
3008 flags.loggingEnabled = 1;
3009 }
3010
3011 /* The very next thing to get is the bundle identifier. Unlike
3012 * in user space, a kext with no bundle identifier gets axed
3013 * immediately.
3014 */
3015 bundleIDString = OSDynamicCast(OSString,
3016 getPropertyForHostArch(kCFBundleIdentifierKey));
3017 if (!bundleIDString) {
3018 OSKextLog(aKext: this,
3019 kOSKextLogErrorLevel |
3020 kOSKextLogValidationFlag,
3021 format: "CFBundleIdentifier missing/invalid type in kext %s.",
3022 aPath ? aPath->getCStringNoCopy() : "(unknown)");
3023 goto finish;
3024 }
3025 bundleID = OSSymbol::withString(aString: bundleIDString);
3026 if (!bundleID) {
3027 OSKextLog(aKext: this,
3028 kOSKextLogErrorLevel |
3029 kOSKextLogValidationFlag,
3030 format: "Can't copy bundle identifier as symbol for kext %s.",
3031 bundleIDString->getCStringNoCopy());
3032 goto finish;
3033 }
3034
3035 /* Save the path if we got one (it should always be available but it's
3036 * just something nice to have for bookkeeping).
3037 */
3038 if (aPath) {
3039 path.reset(p: aPath, OSRetain);
3040 }
3041
3042 /*****
3043 * Minimal validation to initialize. We'll do other validation on the spot.
3044 */
3045 if (bundleID->getLength() >= KMOD_MAX_NAME) {
3046 OSKextLog(aKext: this,
3047 kOSKextLogErrorLevel |
3048 kOSKextLogValidationFlag,
3049 format: "Kext %s error - CFBundleIdentifier over max length %d.",
3050 getIdentifierCString(), KMOD_MAX_NAME - 1);
3051 goto finish;
3052 }
3053
3054 version = compatibleVersion = -1;
3055
3056 versionString = OSDynamicCast(OSString,
3057 getPropertyForHostArch(kCFBundleVersionKey));
3058 if (!versionString) {
3059 OSKextLog(aKext: this,
3060 kOSKextLogErrorLevel |
3061 kOSKextLogValidationFlag,
3062 format: "Kext %s error - CFBundleVersion missing/invalid type.",
3063 getIdentifierCString());
3064 goto finish;
3065 }
3066 versionCString = versionString->getCStringNoCopy();
3067 version = OSKextParseVersionString(versionString: versionCString);
3068 if (version < 0) {
3069 OSKextLog(aKext: this,
3070 kOSKextLogErrorLevel |
3071 kOSKextLogValidationFlag,
3072 format: "Kext %s error - CFBundleVersion bad value '%s'.",
3073 getIdentifierCString(), versionCString);
3074 goto finish;
3075 }
3076
3077 compatibleVersion = -1; // set to illegal value for kexts that don't have
3078
3079 compatibleVersionString = OSDynamicCast(OSString,
3080 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
3081 if (compatibleVersionString) {
3082 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
3083 compatibleVersion = OSKextParseVersionString(versionString: compatibleVersionCString);
3084 if (compatibleVersion < 0) {
3085 OSKextLog(aKext: this,
3086 kOSKextLogErrorLevel |
3087 kOSKextLogValidationFlag,
3088 format: "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
3089 getIdentifierCString(), compatibleVersionCString);
3090 goto finish;
3091 }
3092
3093 if (compatibleVersion > version) {
3094 OSKextLog(aKext: this,
3095 kOSKextLogErrorLevel |
3096 kOSKextLogValidationFlag,
3097 format: "Kext %s error - %s %s > %s %s (must be <=).",
3098 getIdentifierCString(),
3099 kOSBundleCompatibleVersionKey, compatibleVersionCString,
3100 kCFBundleVersionKey, versionCString);
3101 goto finish;
3102 }
3103 }
3104
3105 /* Check to see if this kext is in exclude list */
3106 if (isInExcludeList()) {
3107 OSKextLog(aKext: this,
3108 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3109 format: "Kext %s is in exclude list, not loadable",
3110 getIdentifierCString());
3111 goto finish;
3112 }
3113
3114 /* Set flags for later use if the infoDict gets flushed. We only
3115 * check for true values, not false ones(!)
3116 */
3117 scratchBool = OSDynamicCast(OSBoolean,
3118 getPropertyForHostArch(kOSBundleIsInterfaceKey));
3119 if (scratchBool == kOSBooleanTrue) {
3120 flags.interface = 1;
3121 }
3122
3123 scratchBool = OSDynamicCast(OSBoolean,
3124 getPropertyForHostArch(kOSKernelResourceKey));
3125 if (scratchBool == kOSBooleanTrue) {
3126 flags.kernelComponent = 1;
3127 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
3128 flags.started = 1;
3129
3130 /* A kernel component has one implicit dependency on the kernel.
3131 */
3132 flags.hasAllDependencies = 1;
3133 }
3134
3135 /* Make sure common string values in personalities are uniqued to OSSymbols.
3136 */
3137 scratchDict = OSDynamicCast(OSDictionary,
3138 getPropertyForHostArch(kIOKitPersonalitiesKey));
3139 if (scratchDict) {
3140 uniquePersonalityProperties(personalityDict: scratchDict);
3141 }
3142
3143 result = true;
3144
3145finish:
3146
3147 return result;
3148}
3149
3150/*********************************************************************
3151* Not used for prelinked kernel boot as there is no unrelocated
3152* executable.
3153*********************************************************************/
3154bool
3155OSKext::setExecutable(
3156 OSData * anExecutable,
3157 OSData * externalData,
3158 bool externalDataIsMkext)
3159{
3160 bool result = false;
3161 const char * executableKey = NULL; // do not free
3162
3163 if (!anExecutable) {
3164 infoDict->removeObject(_kOSKextExecutableKey);
3165 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3166 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3167 result = true;
3168 goto finish;
3169 }
3170
3171 if (infoDict->getObject(_kOSKextExecutableKey) ||
3172 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
3173 panic("Attempt to set an executable on a kext "
3174 "that already has one (%s).",
3175 getIdentifierCString());
3176 goto finish;
3177 }
3178
3179 if (externalDataIsMkext) {
3180 executableKey = _kOSKextMkextExecutableReferenceKey;
3181 } else {
3182 executableKey = _kOSKextExecutableKey;
3183 }
3184
3185 if (anExecutable) {
3186 infoDict->setObject(aKey: executableKey, anObject: anExecutable);
3187 if (externalData) {
3188 infoDict->setObject(_kOSKextExecutableExternalDataKey, anObject: externalData);
3189 }
3190 }
3191
3192 result = true;
3193
3194finish:
3195 return result;
3196}
3197
3198/*********************************************************************
3199*********************************************************************/
3200static void
3201uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3202{
3203 OSObject * value = NULL; // do not release
3204 OSString * stringValue = NULL; // do not release
3205 OSSharedPtr<const OSSymbol> symbolValue;
3206
3207 value = dict->getObject(aKey: key);
3208 if (!value) {
3209 goto finish;
3210 }
3211 if (OSDynamicCast(OSSymbol, value)) {
3212 /* this is already an OSSymbol: we're good */
3213 goto finish;
3214 }
3215
3216 stringValue = OSDynamicCast(OSString, value);
3217 if (!stringValue) {
3218 goto finish;
3219 }
3220
3221 symbolValue = OSSymbol::withString(aString: stringValue);
3222 if (!symbolValue) {
3223 goto finish;
3224 }
3225
3226 dict->setObject(aKey: key, anObject: symbolValue.get());
3227
3228finish:
3229 return;
3230}
3231
3232/*********************************************************************
3233*********************************************************************/
3234static void
3235uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3236{
3237 OSObject * value = NULL; // do not release
3238 OSString * stringValue = NULL; // do not release
3239 OSSharedPtr<const OSSymbol> symbolValue;
3240
3241 value = dict->getObject(aKey: key);
3242 if (!value) {
3243 goto finish;
3244 }
3245 if (OSDynamicCast(OSSymbol, value)) {
3246 /* this is already an OSSymbol: we're good */
3247 goto finish;
3248 }
3249
3250 stringValue = OSDynamicCast(OSString, value);
3251 if (!stringValue) {
3252 goto finish;
3253 }
3254
3255 symbolValue = OSSymbol::withString(aString: stringValue);
3256 if (!symbolValue) {
3257 goto finish;
3258 }
3259
3260 dict->setObject(aKey: key, anObject: symbolValue.get());
3261
3262finish:
3263 return;
3264}
3265
3266void
3267OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3268{
3269 OSKext::uniquePersonalityProperties(personalityDict, defaultAddKernelBundleIdentifier: true);
3270}
3271
3272/*********************************************************************
3273* Replace common personality property values with uniqued instances
3274* to save on wired memory.
3275*********************************************************************/
3276/* static */
3277void
3278OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3279{
3280 /* Properties every personality has.
3281 */
3282 uniqueStringPlistProperty(dict: personalityDict, kCFBundleIdentifierKey);
3283 uniqueStringPlistProperty(dict: personalityDict, kIOProviderClassKey);
3284 uniqueStringPlistProperty(dict: personalityDict, key: gIOClassKey.get());
3285 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3286 uniqueStringPlistProperty(dict: personalityDict, kCFBundleIdentifierKernelKey);
3287 } else if (defaultAddKernelBundleIdentifier) {
3288 personalityDict->setObject(kCFBundleIdentifierKernelKey, anObject: personalityDict->getObject(kCFBundleIdentifierKey));
3289 }
3290
3291 /* Other commonly used properties.
3292 */
3293 uniqueStringPlistProperty(dict: personalityDict, key: gIOMatchCategoryKey);
3294 uniqueStringPlistProperty(dict: personalityDict, key: gIOResourceMatchKey);
3295 uniqueStringPlistProperty(dict: personalityDict, key: gIOUserClientClassKey);
3296
3297 uniqueStringPlistProperty(dict: personalityDict, key: "HIDDefaultBehavior");
3298 uniqueStringPlistProperty(dict: personalityDict, key: "HIDPointerAccelerationType");
3299 uniqueStringPlistProperty(dict: personalityDict, key: "HIDRemoteControlType");
3300 uniqueStringPlistProperty(dict: personalityDict, key: "HIDScrollAccelerationType");
3301 uniqueStringPlistProperty(dict: personalityDict, key: "IOPersonalityPublisher");
3302 uniqueStringPlistProperty(dict: personalityDict, key: "Physical Interconnect");
3303 uniqueStringPlistProperty(dict: personalityDict, key: "Physical Interconnect Location");
3304 uniqueStringPlistProperty(dict: personalityDict, key: "Vendor");
3305 uniqueStringPlistProperty(dict: personalityDict, key: "Vendor Identification");
3306 uniqueStringPlistProperty(dict: personalityDict, key: "Vendor Name");
3307 uniqueStringPlistProperty(dict: personalityDict, key: "bConfigurationValue");
3308 uniqueStringPlistProperty(dict: personalityDict, key: "bInterfaceNumber");
3309 uniqueStringPlistProperty(dict: personalityDict, key: "idProduct");
3310
3311 return;
3312}
3313
3314/*********************************************************************
3315*********************************************************************/
3316void
3317OSKext::free(void)
3318{
3319 if (isLoaded()) {
3320 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3321 }
3322
3323 if (isDriverKit()) {
3324 if (dextLaunchedCount > 0) {
3325 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3326 }
3327 }
3328
3329 infoDict.reset();
3330 bundleID.reset();
3331 path.reset();
3332 executableRelPath.reset();
3333 userExecutableRelPath.reset();
3334 dependencies.reset();
3335 linkedExecutable.reset();
3336 metaClasses.reset();
3337 interfaceUUID.reset();
3338 driverKitUUID.reset();
3339 dextStatistics.reset();
3340 dextUniqueID.reset();
3341
3342 if (isInterface() && kmod_info) {
3343 kfree_type(kmod_info_t, kmod_info);
3344 }
3345
3346 super::free();
3347 return;
3348}
3349
3350#if PRAGMA_MARK
3351#pragma mark Mkext files
3352#endif
3353
3354#if CONFIG_KXLD
3355/*
3356 * mkext archives are really only relevant on kxld-enabled kernels.
3357 * Without a dynamic kernel linker, we don't need to support any mkexts.
3358 */
3359
3360/*********************************************************************
3361*********************************************************************/
3362OSReturn
3363OSKext::readMkextArchive(OSData * mkextData,
3364 uint32_t * checksumPtr)
3365{
3366 OSReturn result = kOSKextReturnBadData;
3367 uint32_t mkextLength = 0;
3368 mkext_header * mkextHeader = NULL; // do not free
3369 uint32_t mkextVersion = 0;
3370
3371 /* Note default return of kOSKextReturnBadData above.
3372 */
3373 mkextLength = mkextData->getLength();
3374 if (mkextLength < sizeof(mkext_basic_header)) {
3375 OSKextLog(/* kext */ NULL,
3376 kOSKextLogErrorLevel |
3377 kOSKextLogArchiveFlag,
3378 "Mkext archive too small to be valid.");
3379 goto finish;
3380 }
3381
3382 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3383
3384 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3385 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3386 OSKextLog(/* kext */ NULL,
3387 kOSKextLogErrorLevel |
3388 kOSKextLogArchiveFlag,
3389 "Mkext archive has invalid magic or signature.");
3390 goto finish;
3391 }
3392
3393 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3394 OSKextLog(/* kext */ NULL,
3395 kOSKextLogErrorLevel |
3396 kOSKextLogArchiveFlag,
3397 "Mkext archive recorded length doesn't match actual file length.");
3398 goto finish;
3399 }
3400
3401 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3402
3403 if (mkextVersion == MKEXT_VERS_2) {
3404 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3405 } else {
3406 OSKextLog(/* kext */ NULL,
3407 kOSKextLogErrorLevel |
3408 kOSKextLogArchiveFlag,
3409 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3410 result = kOSKextReturnUnsupported;
3411 }
3412
3413finish:
3414 return result;
3415}
3416
3417/*********************************************************************
3418* Assumes magic, signature, version, length have been checked.
3419* xxx - need to add further bounds checking for each file entry
3420*
3421* Should keep track of all kexts created so far, and if we hit a
3422* fatal error halfway through, remove those kexts. If we've dropped
3423* an older version that had already been read, whoops! Might want to
3424* add a level of buffering?
3425*********************************************************************/
3426/* static */
3427OSReturn
3428OSKext::readMkext2Archive(
3429 OSData * mkextData,
3430 OSDictionary ** mkextPlistOut,
3431 uint32_t * checksumPtr)
3432{
3433 OSReturn result = kOSReturnError;
3434 uint32_t mkextLength;
3435 mkext2_header * mkextHeader = NULL; // do not free
3436 void * mkextEnd = NULL; // do not free
3437 uint32_t mkextVersion;
3438 uint8_t * crc_address = NULL;
3439 size_t crc_buffer_size = 0;
3440 uint32_t checksum;
3441 uint32_t mkextPlistOffset;
3442 uint32_t mkextPlistCompressedSize;
3443 char * mkextPlistEnd = NULL; // do not free
3444 uint32_t mkextPlistFullSize;
3445 OSSharedPtr<OSString> errorString;
3446 OSSharedPtr<OSData> mkextPlistUncompressedData;
3447 const char * mkextPlistDataBuffer = NULL; // do not free
3448 OSSharedPtr<OSObject> parsedXML;
3449 OSDictionary * mkextPlist = NULL; // do not release
3450 OSArray * mkextInfoDictArray = NULL; // do not release
3451 uint32_t count, i;
3452 kc_format_t kc_format;
3453
3454 if (!PE_get_primary_kc_format(&kc_format)) {
3455 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3456 "Unable to determine primary KC format");
3457 goto finish;
3458 }
3459
3460 mkextLength = mkextData->getLength();
3461 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3462 mkextEnd = (char *)mkextHeader + mkextLength;
3463 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3464
3465 crc_address = (u_int8_t *)&mkextHeader->version;
3466 crc_buffer_size = (uintptr_t)mkextHeader +
3467 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3468 if (crc_buffer_size > INT32_MAX) {
3469 OSKextLog(/* kext */ NULL,
3470 kOSKextLogErrorLevel |
3471 kOSKextLogArchiveFlag,
3472 "Mkext archive size is too large (%lu > INT32_MAX).",
3473 crc_buffer_size);
3474 result = kOSKextReturnBadData;
3475 goto finish;
3476 }
3477 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3478
3479 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3480 OSKextLog(/* kext */ NULL,
3481 kOSKextLogErrorLevel |
3482 kOSKextLogArchiveFlag,
3483 "Mkext archive has bad checksum.");
3484 result = kOSKextReturnBadData;
3485 goto finish;
3486 }
3487
3488 if (checksumPtr) {
3489 *checksumPtr = checksum;
3490 }
3491
3492 /* Check that the CPU type & subtype match that of the running kernel. */
3493 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3494 OSKextLog(/* kext */ NULL,
3495 kOSKextLogErrorLevel |
3496 kOSKextLogArchiveFlag,
3497 "Mkext archive must have a specific CPU type.");
3498 result = kOSKextReturnBadData;
3499 goto finish;
3500 } else {
3501 if ((UInt32)_mh_execute_header.cputype !=
3502 MKEXT_GET_CPUTYPE(mkextHeader)) {
3503 OSKextLog(/* kext */ NULL,
3504 kOSKextLogErrorLevel |
3505 kOSKextLogArchiveFlag,
3506 "Mkext archive does not match the running kernel's CPU type.");
3507 result = kOSKextReturnArchNotFound;
3508 goto finish;
3509 }
3510 }
3511
3512 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3513 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3514 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3515 mkextPlistCompressedSize;
3516 if (mkextPlistEnd > mkextEnd) {
3517 OSKextLog(/* kext */ NULL,
3518 kOSKextLogErrorLevel |
3519 kOSKextLogArchiveFlag,
3520 "Mkext archive file overrun.");
3521 result = kOSKextReturnBadData;
3522 }
3523
3524 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3525 if (mkextPlistCompressedSize) {
3526 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3527 (UInt8 *)mkextHeader + mkextPlistOffset,
3528 "plist",
3529 mkextPlistCompressedSize, mkextPlistFullSize);
3530 if (!mkextPlistUncompressedData) {
3531 goto finish;
3532 }
3533 mkextPlistDataBuffer = (const char *)
3534 mkextPlistUncompressedData->getBytesNoCopy();
3535 } else {
3536 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3537 }
3538
3539 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3540 */
3541 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3542 if (parsedXML) {
3543 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3544 }
3545 if (!mkextPlist) {
3546 const char * errorCString = "(unknown error)";
3547
3548 if (errorString && errorString->getCStringNoCopy()) {
3549 errorCString = errorString->getCStringNoCopy();
3550 } else if (parsedXML) {
3551 errorCString = "not a dictionary";
3552 }
3553 OSKextLog(/* kext */ NULL,
3554 kOSKextLogErrorLevel |
3555 kOSKextLogArchiveFlag,
3556 "Error unserializing mkext plist: %s.", errorCString);
3557 goto finish;
3558 }
3559
3560 mkextInfoDictArray = OSDynamicCast(OSArray,
3561 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3562 if (!mkextInfoDictArray) {
3563 OSKextLog(/* kext */ NULL,
3564 kOSKextLogErrorLevel |
3565 kOSKextLogArchiveFlag,
3566 "Mkext archive contains no kext info dictionaries.");
3567 goto finish;
3568 }
3569
3570 count = mkextInfoDictArray->getCount();
3571 for (i = 0; i < count; i++) {
3572 OSDictionary * infoDict;
3573
3574
3575 infoDict = OSDynamicCast(OSDictionary,
3576 mkextInfoDictArray->getObject(i));
3577
3578 /* Create the kext for the entry, then release it, because the
3579 * kext system keeps them around until explicitly removed.
3580 * Any creation/registration failures are already logged for us.
3581 */
3582 if (infoDict) {
3583 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3584
3585 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3586 if (kc_format == KCFormatFileset &&
3587 newKext &&
3588 !(newKext->isPrelinked()) &&
3589 newKext->declaresExecutable()) {
3590 result = kOSReturnError;
3591 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3592 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3593
3594 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3595 "Dynamic loading of kext denied for kext %s\n",
3596 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3597 goto finish;
3598 }
3599 }
3600 }
3601
3602 /* If the caller needs the plist, hand them back our copy
3603 */
3604 if (mkextPlistOut) {
3605 *mkextPlistOut = mkextPlist;
3606 parsedXML.detach();
3607 }
3608
3609 /* Even if we didn't keep any kexts from the mkext, we may have a load
3610 * request to process, so we are successful (no errors occurred).
3611 */
3612 result = kOSReturnSuccess;
3613
3614finish:
3615 return result;
3616}
3617
3618/* static */
3619OSReturn
3620OSKext::readMkext2Archive(
3621 OSData * mkextData,
3622 OSSharedPtr<OSDictionary> &mkextPlistOut,
3623 uint32_t * checksumPtr)
3624{
3625 OSDictionary * mkextPlist = NULL;
3626 OSReturn ret;
3627
3628 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3629 &mkextPlist,
3630 checksumPtr))) {
3631 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3632 }
3633 return ret;
3634}
3635
3636/*********************************************************************
3637*********************************************************************/
3638/* static */
3639OSSharedPtr<OSKext>
3640OSKext::withMkext2Info(
3641 OSDictionary * anInfoDict,
3642 OSData * mkextData)
3643{
3644 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3645
3646 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3647 return NULL;
3648 }
3649
3650 return newKext;
3651}
3652
3653/*********************************************************************
3654*********************************************************************/
3655bool
3656OSKext::initWithMkext2Info(
3657 OSDictionary * anInfoDict,
3658 OSData * mkextData)
3659{
3660 bool result = false;
3661 OSString * kextPath = NULL; // do not release
3662 OSNumber * executableOffsetNum = NULL; // do not release
3663 OSSharedPtr<OSData> executable;
3664
3665 if (anInfoDict == NULL || !super::init()) {
3666 goto finish;
3667 }
3668
3669 /* Get the path. Don't look for an arch-specific path property.
3670 */
3671 kextPath = OSDynamicCast(OSString,
3672 anInfoDict->getObject(kMKEXTBundlePathKey));
3673
3674 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3675 goto finish;
3676 }
3677
3678 /* If we have a path to the executable, save it.
3679 */
3680 executableRelPath.reset(OSDynamicCast(OSString,
3681 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3682
3683 /* Don't need the paths to be in the info dictionary any more.
3684 */
3685 anInfoDict->removeObject(kMKEXTBundlePathKey);
3686 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3687
3688 executableOffsetNum = OSDynamicCast(OSNumber,
3689 infoDict->getObject(kMKEXTExecutableKey));
3690 if (executableOffsetNum) {
3691 executable = createMkext2FileEntry(mkextData,
3692 executableOffsetNum, "executable");
3693 infoDict->removeObject(kMKEXTExecutableKey);
3694 if (!executable) {
3695 goto finish;
3696 }
3697 if (!setExecutable(executable.get(), mkextData, true)) {
3698 goto finish;
3699 }
3700 }
3701
3702 result = (registerIdentifier() == kOSKextInitialized);
3703finish:
3704 return result;
3705}
3706
3707/*********************************************************************
3708*********************************************************************/
3709OSSharedPtr<OSData>
3710OSKext::createMkext2FileEntry(
3711 OSData * mkextData,
3712 OSNumber * offsetNum,
3713 const char * name)
3714{
3715 OSSharedPtr<OSData> result;
3716 MkextEntryRef entryRef;
3717 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3718 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3719
3720 result = OSData::withCapacity(sizeof(entryRef));
3721 if (!result) {
3722 goto finish;
3723 }
3724
3725 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3726 entryRef.fileinfo = mkextBuffer + entryOffset;
3727 if (!result->appendValue(entryRef)) {
3728 result.reset();
3729 goto finish;
3730 }
3731
3732finish:
3733 if (!result) {
3734 OSKextLog(this,
3735 kOSKextLogErrorLevel |
3736 kOSKextLogArchiveFlag,
3737 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3738 name, getIdentifierCString());
3739 }
3740 return result;
3741}
3742
3743/*********************************************************************
3744*********************************************************************/
3745extern "C" {
3746static void * z_alloc(void *, u_int items, u_int size);
3747static void z_free(void *, void *ptr);
3748
3749typedef struct z_mem {
3750 uint32_t alloc_size;
3751 uint8_t data[0];
3752} z_mem;
3753
3754/*
3755 * Space allocation and freeing routines for use by zlib routines.
3756 */
3757void *
3758z_alloc(void * notused __unused, u_int num_items, u_int size)
3759{
3760 void * result = NULL;
3761 z_mem * zmem = NULL;
3762
3763 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3764 //Check for overflow due to multiplication
3765 if (total > UINT32_MAX) {
3766 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3767 notused, num_items, size, num_items, size);
3768 }
3769
3770 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3771 //Check for overflow due to addition
3772 if (allocSize64 > UINT32_MAX) {
3773 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3774 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3775 }
3776 uint32_t allocSize = (uint32_t)allocSize64;
3777
3778 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3779 VM_KERN_MEMORY_OSKEXT);
3780 if (!zmem) {
3781 goto finish;
3782 }
3783 zmem->alloc_size = allocSize;
3784 result = (void *)&(zmem->data);
3785finish:
3786 return result;
3787}
3788
3789void
3790z_free(void * notused __unused, void * ptr)
3791{
3792 uint32_t * skipper = (uint32_t *)ptr - 1;
3793 z_mem * zmem = (z_mem *)skipper;
3794 kfree_data(zmem, zmem->alloc_size);
3795}
3796};
3797
3798OSSharedPtr<OSData>
3799OSKext::extractMkext2FileData(
3800 UInt8 * data,
3801 const char * name,
3802 uint32_t compressedSize,
3803 uint32_t fullSize)
3804{
3805 OSSharedPtr<OSData> result;
3806 OSSharedPtr<OSData> uncompressedData; // release on error
3807
3808 uint8_t * uncompressedDataBuffer = NULL; // do not free
3809 unsigned long uncompressedSize;
3810 z_stream zstream;
3811 bool zstream_inited = false;
3812 int zlib_result;
3813
3814 /* If the file isn't compressed, we want to make a copy
3815 * so that we don't have the tie to the larger mkext file buffer any more.
3816 */
3817 if (!compressedSize) {
3818 uncompressedData = OSData::withBytes(data, fullSize);
3819 // xxx - no check for failure?
3820 result = uncompressedData;
3821 goto finish;
3822 }
3823
3824 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3825 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3826 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3827 /* How's this for cheesy? The kernel is only asked to extract
3828 * kext plists so we tailor the log messages.
3829 */
3830 if (isKernel()) {
3831 OSKextLog(this,
3832 kOSKextLogErrorLevel |
3833 kOSKextLogArchiveFlag,
3834 "Allocation failure extracting %s from mkext.", name);
3835 } else {
3836 OSKextLog(this,
3837 kOSKextLogErrorLevel |
3838 kOSKextLogArchiveFlag,
3839 "Allocation failure extracting %s from mkext for kext %s.",
3840 name, getIdentifierCString());
3841 }
3842
3843 goto finish;
3844 }
3845 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3846 if (!uncompressedData) {
3847 if (isKernel()) {
3848 OSKextLog(this,
3849 kOSKextLogErrorLevel |
3850 kOSKextLogArchiveFlag,
3851 "Allocation failure extracting %s from mkext.", name);
3852 } else {
3853 OSKextLog(this,
3854 kOSKextLogErrorLevel |
3855 kOSKextLogArchiveFlag,
3856 "Allocation failure extracting %s from mkext for kext %s.",
3857 name, getIdentifierCString());
3858 }
3859 goto finish;
3860 }
3861 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3862
3863 if (isKernel()) {
3864 OSKextLog(this,
3865 kOSKextLogDetailLevel |
3866 kOSKextLogArchiveFlag,
3867 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3868 name, compressedSize, fullSize);
3869 } else {
3870 OSKextLog(this,
3871 kOSKextLogDetailLevel |
3872 kOSKextLogArchiveFlag,
3873 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3874 getIdentifierCString(), name, compressedSize, fullSize);
3875 }
3876
3877 bzero(&zstream, sizeof(zstream));
3878 zstream.next_in = (UInt8 *)data;
3879 zstream.avail_in = compressedSize;
3880
3881 zstream.next_out = uncompressedDataBuffer;
3882 zstream.avail_out = fullSize;
3883
3884 zstream.zalloc = z_alloc;
3885 zstream.zfree = z_free;
3886
3887 zlib_result = inflateInit(&zstream);
3888 if (Z_OK != zlib_result) {
3889 if (isKernel()) {
3890 OSKextLog(this,
3891 kOSKextLogErrorLevel |
3892 kOSKextLogArchiveFlag,
3893 "Mkext error; zlib inflateInit failed (%d) for %s.",
3894 zlib_result, name);
3895 } else {
3896 OSKextLog(this,
3897 kOSKextLogErrorLevel |
3898 kOSKextLogArchiveFlag,
3899 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3900 getIdentifierCString(), zlib_result, name);
3901 }
3902 goto finish;
3903 } else {
3904 zstream_inited = true;
3905 }
3906
3907 zlib_result = inflate(&zstream, Z_FINISH);
3908
3909 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3910 uncompressedSize = zstream.total_out;
3911 } else {
3912 if (isKernel()) {
3913 OSKextLog(this,
3914 kOSKextLogErrorLevel |
3915 kOSKextLogArchiveFlag,
3916 "Mkext error; zlib inflate failed (%d) for %s.",
3917 zlib_result, name);
3918 } else {
3919 OSKextLog(this,
3920 kOSKextLogErrorLevel |
3921 kOSKextLogArchiveFlag,
3922 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3923 getIdentifierCString(), zlib_result, name);
3924 }
3925 if (zstream.msg) {
3926 OSKextLog(this,
3927 kOSKextLogErrorLevel |
3928 kOSKextLogArchiveFlag,
3929 "zlib error: %s.", zstream.msg);
3930 }
3931 goto finish;
3932 }
3933
3934 if (uncompressedSize != fullSize) {
3935 if (isKernel()) {
3936 OSKextLog(this,
3937 kOSKextLogErrorLevel |
3938 kOSKextLogArchiveFlag,
3939 "Mkext error; zlib inflate discrepancy for %s, "
3940 "uncompressed size != original size.", name);
3941 } else {
3942 OSKextLog(this,
3943 kOSKextLogErrorLevel |
3944 kOSKextLogArchiveFlag,
3945 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3946 "uncompressed size != original size.",
3947 getIdentifierCString(), name);
3948 }
3949 goto finish;
3950 }
3951
3952 result = os::move(uncompressedData);
3953
3954finish:
3955 /* Don't bother checking return, nothing we can do on fail.
3956 */
3957 if (zstream_inited) {
3958 inflateEnd(&zstream);
3959 }
3960
3961 return result;
3962}
3963
3964/*********************************************************************
3965*********************************************************************/
3966/* static */
3967OSReturn
3968OSKext::loadFromMkext(
3969 OSKextLogSpec clientLogFilter,
3970 char * mkextBuffer,
3971 uint32_t mkextBufferLength,
3972 char ** logInfoOut,
3973 uint32_t * logInfoLengthOut)
3974{
3975 OSReturn result = kOSReturnError;
3976 OSReturn tempResult = kOSReturnError;
3977
3978 OSSharedPtr<OSData> mkextData;
3979 OSSharedPtr<OSDictionary> mkextPlist;
3980
3981 OSSharedPtr<OSArray> logInfoArray;
3982 OSSharedPtr<OSSerialize> serializer;
3983
3984 OSString * predicate = NULL; // do not release
3985 OSDictionary * requestArgs = NULL; // do not release
3986
3987 OSString * kextIdentifier = NULL; // do not release
3988 OSNumber * startKextExcludeNum = NULL; // do not release
3989 OSNumber * startMatchingExcludeNum = NULL; // do not release
3990 OSBoolean * delayAutounloadBool = NULL; // do not release
3991 OSArray * personalityNames = NULL; // do not release
3992
3993 /* Default values for these two options: regular autounload behavior,
3994 * load all kexts, send no personalities.
3995 */
3996 Boolean delayAutounload = false;
3997 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3998 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3999
4000 IORecursiveLockLock(sKextLock);
4001
4002 if (logInfoOut) {
4003 *logInfoOut = NULL;
4004 *logInfoLengthOut = 0;
4005 }
4006
4007 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
4008
4009 OSKextLog(/* kext */ NULL,
4010 kOSKextLogDebugLevel |
4011 kOSKextLogIPCFlag,
4012 "Received kext load request from user space.");
4013
4014 /* Regardless of processing, the fact that we have gotten here means some
4015 * user-space program is up and talking to us, so we'll switch our kext
4016 * registration to reflect that.
4017 */
4018 if (!sUserLoadsActive) {
4019 OSKextLog(/* kext */ NULL,
4020 kOSKextLogProgressLevel |
4021 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
4022 "Switching to late startup (user-space) kext loading policy.");
4023
4024 sUserLoadsActive = true;
4025 }
4026
4027 if (!sLoadEnabled) {
4028 OSKextLog(/* kext */ NULL,
4029 kOSKextLogErrorLevel |
4030 kOSKextLogLoadFlag,
4031 "Kext loading is disabled.");
4032 result = kOSKextReturnDisabled;
4033 goto finish;
4034 }
4035
4036 /* Note that we do not set a dealloc function on this OSData
4037 * object! No references to it can remain after the loadFromMkext()
4038 * call since we are in a MIG function, and will vm_deallocate()
4039 * the buffer.
4040 */
4041 mkextData = OSData::withBytesNoCopy(mkextBuffer,
4042 mkextBufferLength);
4043 if (!mkextData) {
4044 OSKextLog(/* kext */ NULL,
4045 kOSKextLogErrorLevel |
4046 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4047 "Failed to create wrapper for kext load request.");
4048 result = kOSKextReturnNoMemory;
4049 goto finish;
4050 }
4051
4052 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
4053 if (result != kOSReturnSuccess) {
4054 OSKextLog(/* kext */ NULL,
4055 kOSKextLogErrorLevel |
4056 kOSKextLogLoadFlag,
4057 "Failed to read kext load request.");
4058 goto finish;
4059 }
4060
4061 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
4062 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
4063 OSKextLog(/* kext */ NULL,
4064 kOSKextLogErrorLevel |
4065 kOSKextLogLoadFlag,
4066 "Received kext load request with no predicate; skipping.");
4067 result = kOSKextReturnInvalidArgument;
4068 goto finish;
4069 }
4070
4071 requestArgs = OSDynamicCast(OSDictionary,
4072 mkextPlist->getObject(kKextRequestArgumentsKey));
4073 if (!requestArgs || !requestArgs->getCount()) {
4074 OSKextLog(/* kext */ NULL,
4075 kOSKextLogErrorLevel |
4076 kOSKextLogLoadFlag,
4077 "Received kext load request with no arguments.");
4078 result = kOSKextReturnInvalidArgument;
4079 goto finish;
4080 }
4081
4082 kextIdentifier = OSDynamicCast(OSString,
4083 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
4084
4085 if (!kextIdentifier) {
4086 OSKextLog(/* kext */ NULL,
4087 kOSKextLogErrorLevel |
4088 kOSKextLogLoadFlag,
4089 "Received kext load request with no kext identifier.");
4090 result = kOSKextReturnInvalidArgument;
4091 goto finish;
4092 }
4093
4094 startKextExcludeNum = OSDynamicCast(OSNumber,
4095 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
4096 startMatchingExcludeNum = OSDynamicCast(OSNumber,
4097 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
4098 delayAutounloadBool = OSDynamicCast(OSBoolean,
4099 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
4100 personalityNames = OSDynamicCast(OSArray,
4101 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
4102
4103 if (delayAutounloadBool) {
4104 delayAutounload = delayAutounloadBool->getValue();
4105 }
4106 if (startKextExcludeNum) {
4107 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
4108 }
4109 if (startMatchingExcludeNum) {
4110 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
4111 }
4112
4113 OSKextLog(/* kext */ NULL,
4114 kOSKextLogProgressLevel |
4115 kOSKextLogIPCFlag,
4116 "Received request from user space to load kext %s.",
4117 kextIdentifier->getCStringNoCopy());
4118
4119 /* Load the kext, with no deferral, since this is a load from outside
4120 * the kernel.
4121 * xxx - Would like a better way to handle the default values for the
4122 * xxx - start/match opt args.
4123 */
4124 result = OSKext::loadKextWithIdentifier(
4125 kextIdentifier,
4126 /* kextRef */ NULL,
4127 /* allowDefer */ false,
4128 delayAutounload,
4129 startKextExcludeLevel,
4130 startMatchingExcludeLevel,
4131 personalityNames);
4132 if (result != kOSReturnSuccess) {
4133 goto finish;
4134 }
4135 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
4136 * for matching via a separate IOKit calldown.
4137 */
4138
4139finish:
4140
4141 /* Gather up the collected log messages for user space. Any
4142 * error messages past this call will not make it up as log messages
4143 * but will be in the system log.
4144 */
4145 logInfoArray = OSKext::clearUserSpaceLogFilter();
4146
4147 if (logInfoArray && logInfoOut && logInfoLengthOut) {
4148 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
4149 logInfoOut, logInfoLengthOut);
4150 if (tempResult != kOSReturnSuccess) {
4151 result = tempResult;
4152 }
4153 }
4154
4155 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
4156
4157 IORecursiveLockUnlock(sKextLock);
4158
4159 /* Note: mkextDataObject will have been retained by every kext w/an
4160 * executable in it. That should all have been flushed out at the
4161 * and of the load operation, but you never know....
4162 */
4163 if (mkextData && mkextData->getRetainCount() > 1) {
4164 OSKextLog(/* kext */ NULL,
4165 kOSKextLogErrorLevel |
4166 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4167 "Kext load request buffer from user space still retained by a kext; "
4168 "probable memory leak.");
4169 }
4170
4171 return result;
4172}
4173
4174#endif // CONFIG_KXLD
4175
4176/*********************************************************************
4177*********************************************************************/
4178/* static */
4179OSReturn
4180OSKext::serializeLogInfo(
4181 OSArray * logInfoArray,
4182 char ** logInfoOut,
4183 uint32_t * logInfoLengthOut)
4184{
4185 OSReturn result = kOSReturnError;
4186 char * buffer = NULL;
4187 kern_return_t kmem_result = KERN_FAILURE;
4188 OSSharedPtr<OSSerialize> serializer;
4189 char * logInfo = NULL; // returned by reference
4190 uint32_t logInfoLength = 0;
4191
4192 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4193 OSKextLog(/* kext */ NULL,
4194 kOSKextLogErrorLevel |
4195 kOSKextLogIPCFlag,
4196 format: "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4197 /* Bad programmer. */
4198 result = kOSKextReturnInvalidArgument;
4199 goto finish;
4200 }
4201
4202 serializer = OSSerialize::withCapacity(capacity: 0);
4203 if (!serializer) {
4204 OSKextLog(/* kext */ NULL,
4205 kOSKextLogErrorLevel |
4206 kOSKextLogIPCFlag,
4207 format: "Failed to create serializer on log info for request from user space.");
4208 /* Incidental error; we're going to (try to) allow the request
4209 * itself to succeed. */
4210 } else {
4211 if (!logInfoArray->serialize(serializer: serializer.get())) {
4212 OSKextLog(/* kext */ NULL,
4213 kOSKextLogErrorLevel |
4214 kOSKextLogIPCFlag,
4215 format: "Failed to serialize log info for request from user space.");
4216 /* Incidental error; we're going to (try to) allow the request
4217 * itself to succeed. */
4218 } else {
4219 logInfo = serializer->text();
4220 logInfoLength = serializer->getLength();
4221
4222 kmem_result = kmem_alloc(map: kernel_map, addrp: (vm_offset_t *)&buffer, size: round_page(x: logInfoLength),
4223 flags: KMA_DATA, VM_KERN_MEMORY_OSKEXT);
4224 if (kmem_result != KERN_SUCCESS) {
4225 OSKextLog(/* kext */ NULL,
4226 kOSKextLogErrorLevel |
4227 kOSKextLogIPCFlag,
4228 format: "Failed to copy log info for request from user space.");
4229 /* Incidental error; we're going to (try to) allow the request
4230 * to succeed. */
4231 } else {
4232 /* 11981737 - clear uninitialized data in last page */
4233 bzero(s: (void *)(buffer + logInfoLength),
4234 n: (round_page(x: logInfoLength) - logInfoLength));
4235 memcpy(dst: buffer, src: logInfo, n: logInfoLength);
4236 *logInfoOut = buffer;
4237 *logInfoLengthOut = logInfoLength;
4238 }
4239 }
4240 }
4241
4242 result = kOSReturnSuccess;
4243finish:
4244 return result;
4245}
4246
4247#if PRAGMA_MARK
4248#pragma mark Instance Management Methods
4249#endif
4250/*********************************************************************
4251*********************************************************************/
4252OSSharedPtr<OSKext>
4253OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4254{
4255 OSSharedPtr<OSKext> foundKext;
4256
4257 IORecursiveLockLock(lock: sKextLock);
4258 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4259 IORecursiveLockUnlock(lock: sKextLock);
4260
4261 return foundKext;
4262}
4263
4264/*********************************************************************
4265*********************************************************************/
4266OSSharedPtr<OSKext>
4267OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4268{
4269 return OSKext::lookupKextWithIdentifier(kextIdentifier: kextIdentifier->getCStringNoCopy());
4270}
4271
4272/*********************************************************************
4273*********************************************************************/
4274OSSharedPtr<OSKext>
4275OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4276{
4277 OSSharedPtr<OSKext> foundDext;
4278 foundDext.reset();
4279
4280 IORecursiveLockLock(lock: sKextLock);
4281 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4282 if (dext != NULL && dext->isDriverKit()) {
4283 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(aDataObj: dextUniqueIdentifier)) {
4284 foundDext.reset(p: dext, OSRetain);
4285 }
4286 }
4287 IORecursiveLockUnlock(lock: sKextLock);
4288
4289 return foundDext;
4290}
4291
4292/*********************************************************************
4293*********************************************************************/
4294OSSharedPtr<OSKext>
4295OSKext::lookupKextWithLoadTag(uint32_t aTag)
4296{
4297 OSSharedPtr<OSKext> foundKext; // returned
4298 uint32_t i, j;
4299 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4300 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4301
4302 IORecursiveLockLock(lock: sKextLock);
4303
4304 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4305 for (i = 0; i < count[j]; i++) {
4306 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4307 if (thisKext->getLoadTag() == aTag) {
4308 foundKext.reset(p: thisKext, OSRetain);
4309 goto finish;
4310 }
4311 }
4312 }
4313
4314finish:
4315 IORecursiveLockUnlock(lock: sKextLock);
4316
4317 return foundKext;
4318}
4319
4320/*********************************************************************
4321*********************************************************************/
4322OSSharedPtr<OSKext>
4323OSKext::lookupKextWithAddress(vm_address_t address)
4324{
4325 OSSharedPtr<OSKext> foundKext; // returned
4326 uint32_t count, i;
4327 kmod_info_t *kmod_info;
4328 vm_address_t originalAddress;
4329#if defined(__arm64__)
4330 uint64_t textExecBase;
4331 size_t textExecSize;
4332#endif /* defined(__arm64__) */
4333
4334 originalAddress = address;
4335#if __has_feature(ptrauth_calls)
4336 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4337#endif /* __has_feature(ptrauth_calls) */
4338
4339 IORecursiveLockLock(lock: sKextLock);
4340
4341 count = sLoadedKexts->getCount();
4342 for (i = 0; i < count; i++) {
4343 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4344 if (thisKext == sKernelKext) {
4345 continue;
4346 }
4347 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4348 kmod_info = thisKext->kmod_info;
4349 vm_address_t kext_start = kmod_info->address;
4350 vm_address_t kext_end = kext_start + kmod_info->size;
4351 if ((kext_start <= address) && (address < kext_end)) {
4352 foundKext.reset(p: thisKext, OSRetain);
4353 goto finish;
4354 }
4355#if defined(__arm64__)
4356 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4357
4358 /**
4359 * If the addresses within the Mach-O are unslid, then manually
4360 * slide any addresses coming from the Mach-O before usage.
4361 */
4362 if (thisKext->flags.unslidMachO) {
4363 textExecBase = (uintptr_t) ml_static_slide(vaddr: (vm_offset_t) textExecBase);
4364 }
4365
4366 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4367 foundKext.reset(p: thisKext, OSRetain);
4368 goto finish;
4369 }
4370#endif /* defined (__arm64__) */
4371 }
4372 }
4373 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4374 foundKext.reset(p: sKernelKext, OSRetain);
4375 goto finish;
4376 }
4377 /*
4378 * DriverKit userspace executables do not have a kernel linkedExecutable,
4379 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4380 * here, so use the original address passed to this method.
4381 *
4382 * This is supposed to be used for logging reasons only. When logd
4383 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4384 * remove it here before checking it against the LoadTag.
4385 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4386 */
4387
4388 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4389 count = sLoadedDriverKitKexts->getCount();
4390 for (i = 0; i < count; i++) {
4391 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4392 if (thisKext->getLoadTag() == address) {
4393 foundKext.reset(p: thisKext, OSRetain);
4394 }
4395 }
4396
4397finish:
4398 IORecursiveLockUnlock(lock: sKextLock);
4399
4400 return foundKext;
4401}
4402
4403OSSharedPtr<OSData>
4404OSKext::copyKextUUIDForAddress(OSNumber *address)
4405{
4406 OSSharedPtr<OSData> uuid;
4407 OSSharedPtr<OSKext> kext;
4408
4409 if (!address) {
4410 return NULL;
4411 }
4412
4413#if CONFIG_MACF
4414 /* Is the calling process allowed to query kext info? */
4415 if (current_task() != kernel_task) {
4416 int macCheckResult = 0;
4417 kauth_cred_t cred = NULL;
4418
4419 cred = kauth_cred_get_with_ref();
4420 macCheckResult = mac_kext_check_query(cred);
4421 kauth_cred_unref(&cred);
4422
4423 if (macCheckResult != 0) {
4424 OSKextLog(/* kext */ NULL,
4425 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4426 format: "Failed to query kext UUID (MAC policy error 0x%x).",
4427 macCheckResult);
4428 return NULL;
4429 }
4430 }
4431#endif
4432
4433 uintptr_t slidAddress = ml_static_slide(vaddr: (uintptr_t)address->unsigned64BitValue());
4434 if (slidAddress != 0) {
4435 kext = lookupKextWithAddress(address: slidAddress);
4436 if (kext) {
4437 uuid = kext->copyTextUUID();
4438 }
4439 }
4440
4441 if (!uuid) {
4442 /*
4443 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4444 * a kext. This might have happened because the log message came from a dext.
4445 *
4446 * Try again with the original address.
4447 */
4448 kext = lookupKextWithAddress(address: (vm_address_t)address->unsigned64BitValue());
4449 if (kext && kext->isDriverKit()) {
4450 uuid = kext->copyTextUUID();
4451 }
4452 }
4453
4454 return uuid;
4455}
4456
4457/*********************************************************************
4458*********************************************************************/
4459OSSharedPtr<OSKext>
4460OSKext::lookupKextWithUUID(uuid_t wanted)
4461{
4462 OSSharedPtr<OSKext> foundKext; // returned
4463 uint32_t j, i;
4464 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4465 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4466
4467
4468 IORecursiveLockLock(lock: sKextLock);
4469
4470 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4471 for (i = 0; i < count[j]; i++) {
4472 OSKext * thisKext = NULL;
4473
4474 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4475 if (!thisKext) {
4476 continue;
4477 }
4478
4479 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4480 if (!uuid_data) {
4481 continue;
4482 }
4483
4484 uuid_t uuid;
4485 memcpy(dst: &uuid, src: uuid_data->getBytesNoCopy(), n: sizeof(uuid));
4486
4487 if (0 == uuid_compare(uu1: wanted, uu2: uuid)) {
4488 foundKext.reset(p: thisKext, OSRetain);
4489 goto finish;
4490 }
4491 }
4492 }
4493finish:
4494 IORecursiveLockUnlock(lock: sKextLock);
4495
4496 return foundKext;
4497}
4498
4499
4500
4501
4502/*********************************************************************
4503*********************************************************************/
4504/* static */
4505bool
4506OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4507{
4508 bool result = false;
4509 OSKext * foundKext = NULL; // returned
4510
4511 IORecursiveLockLock(lock: sKextLock);
4512
4513 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4514 if (foundKext && foundKext->isLoaded()) {
4515 result = true;
4516 }
4517
4518 IORecursiveLockUnlock(lock: sKextLock);
4519
4520 return result;
4521}
4522
4523/*********************************************************************
4524* xxx - should spawn a separate thread so a kext can safely have
4525* xxx - itself unloaded.
4526*********************************************************************/
4527/* static */
4528OSReturn
4529OSKext::removeKext(
4530 OSKext * aKext,
4531#if CONFIG_EMBEDDED
4532 __unused
4533#endif
4534 bool terminateServicesAndRemovePersonalitiesFlag)
4535{
4536#if CONFIG_EMBEDDED
4537 if (!aKext->isDriverKit()) {
4538 OSKextLog(aKext,
4539 kOSKextLogErrorLevel |
4540 kOSKextLogKextBookkeepingFlag,
4541 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4542 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4543
4544 return kOSReturnSuccess;
4545 }
4546#endif /* CONFIG_EMBEDDED */
4547 OSReturn result = kOSKextReturnInUse;
4548 OSKext * checkKext = NULL; // do not release
4549#if CONFIG_MACF
4550 int macCheckResult = 0;
4551 kauth_cred_t cred = NULL;
4552#endif
4553
4554 IORecursiveLockLock(lock: sKextLock);
4555
4556 /* If the kext has no identifier, it failed to init
4557 * so isn't in sKextsByID and it isn't loaded.
4558 */
4559 if (!aKext->getIdentifier()) {
4560 result = kOSReturnSuccess;
4561 goto finish;
4562 }
4563
4564 checkKext = OSDynamicCast(OSKext,
4565 sKextsByID->getObject(aKext->getIdentifier()));
4566 if (checkKext != aKext) {
4567 result = kOSKextReturnNotFound;
4568 goto finish;
4569 }
4570
4571 if (aKext->isLoaded() || aKext->isDriverKit()) {
4572#if CONFIG_MACF
4573 if (current_task() != kernel_task) {
4574 cred = kauth_cred_get_with_ref();
4575 macCheckResult = mac_kext_check_unload(cred, identifier: aKext->getIdentifierCString());
4576 kauth_cred_unref(&cred);
4577 }
4578
4579 if (macCheckResult != 0) {
4580 result = kOSReturnError;
4581 OSKextLog(aKext,
4582 kOSKextLogErrorLevel |
4583 kOSKextLogKextBookkeepingFlag,
4584 format: "Failed to remove kext %s (MAC policy error 0x%x).",
4585 aKext->getIdentifierCString(), macCheckResult);
4586 goto finish;
4587 }
4588#endif
4589
4590 /* make sure there are no resource requests in flight - 17187548 */
4591 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4592 goto finish;
4593 }
4594 if (aKext->flags.unloadUnsupported) {
4595 result = kOSKextReturnInUse;
4596 OSKextLog(aKext,
4597 kOSKextLogErrorLevel |
4598 kOSKextLogKextBookkeepingFlag,
4599 format: "Can't remove kext %s; unsupported by cache.",
4600 aKext->getIdentifierCString());
4601 goto finish;
4602 }
4603
4604 /* If we are terminating, send the request to the IOCatalogue
4605 * (which will actually call us right back but that's ok we have
4606 * a recursive lock don't you know) but do not ask the IOCatalogue
4607 * to call back with an unload, we'll do that right here.
4608 */
4609 if (terminateServicesAndRemovePersonalitiesFlag) {
4610 result = gIOCatalogue->terminateDriversForModule(
4611 moduleName: aKext->getIdentifierCString(), /* unload */ false);
4612 if (result != kOSReturnSuccess) {
4613 OSKextLog(aKext,
4614 kOSKextLogErrorLevel |
4615 kOSKextLogKextBookkeepingFlag,
4616 format: "Can't remove kext %s; services failed to terminate - 0x%x.",
4617 aKext->getIdentifierCString(), result);
4618 goto finish;
4619 }
4620 }
4621
4622 result = aKext->unload();
4623 if (result != kOSReturnSuccess) {
4624 OSKextLog(aKext,
4625 kOSKextLogErrorLevel |
4626 kOSKextLogKextBookkeepingFlag,
4627 format: "Can't remove kext %s; kext failed to unload - 0x%x.",
4628 aKext->getIdentifierCString(), result);
4629 goto finish;
4630 }
4631 }
4632
4633 /* Remove personalities as requested. This is a bit redundant for a loaded
4634 * kext as IOCatalogue::terminateDriversForModule() removes driver
4635 * personalities, but it doesn't restart matching, which we always want
4636 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4637 * that happens.
4638 */
4639 if (terminateServicesAndRemovePersonalitiesFlag) {
4640 aKext->removePersonalitiesFromCatalog();
4641 }
4642
4643 if (aKext->isInFileset()) {
4644 OSKextLog(aKext,
4645 kOSKextLogProgressLevel |
4646 kOSKextLogKextBookkeepingFlag,
4647 format: "Fileset kext %s unloaded.",
4648 aKext->getIdentifierCString());
4649 } else {
4650 OSKextLog(aKext,
4651 kOSKextLogProgressLevel |
4652 kOSKextLogKextBookkeepingFlag,
4653 format: "Removing kext %s.",
4654 aKext->getIdentifierCString());
4655
4656 sKextsByID->removeObject(aKey: aKext->getIdentifier());
4657 }
4658 result = kOSReturnSuccess;
4659
4660finish:
4661 IORecursiveLockUnlock(lock: sKextLock);
4662 return result;
4663}
4664
4665/*********************************************************************
4666*********************************************************************/
4667/* static */
4668OSReturn
4669OSKext::removeKextWithIdentifier(
4670 const char * kextIdentifier,
4671 bool terminateServicesAndRemovePersonalitiesFlag)
4672{
4673 OSReturn result = kOSReturnError;
4674
4675 IORecursiveLockLock(lock: sKextLock);
4676
4677 OSKext * aKext = OSDynamicCast(OSKext,
4678 sKextsByID->getObject(kextIdentifier));
4679 if (!aKext) {
4680 result = kOSKextReturnNotFound;
4681 OSKextLog(/* kext */ NULL,
4682 kOSKextLogErrorLevel |
4683 kOSKextLogKextBookkeepingFlag,
4684 format: "Can't remove kext %s - not found.",
4685 kextIdentifier);
4686 goto finish;
4687 }
4688
4689 result = OSKext::removeKext(aKext,
4690 terminateServicesAndRemovePersonalitiesFlag);
4691
4692finish:
4693 IORecursiveLockUnlock(lock: sKextLock);
4694
4695 return result;
4696}
4697
4698/*********************************************************************
4699*********************************************************************/
4700/* static */
4701OSReturn
4702OSKext::removeKextWithLoadTag(
4703 OSKextLoadTag loadTag,
4704 bool terminateServicesAndRemovePersonalitiesFlag)
4705{
4706 OSReturn result = kOSReturnError;
4707 OSKext * foundKext = NULL;
4708 uint32_t i, j;
4709 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4710 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4711
4712
4713 IORecursiveLockLock(lock: sKextLock);
4714
4715 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4716 for (i = 0; i < count[j]; i++) {
4717 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4718 if (thisKext->loadTag == loadTag) {
4719 foundKext = thisKext;
4720 break;
4721 }
4722 }
4723 }
4724
4725 if (!foundKext) {
4726 result = kOSKextReturnNotFound;
4727 OSKextLog(/* kext */ NULL,
4728 kOSKextLogErrorLevel |
4729 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4730 format: "Can't remove kext with load tag %d - not found.",
4731 loadTag);
4732 goto finish;
4733 }
4734
4735 result = OSKext::removeKext(aKext: foundKext,
4736 terminateServicesAndRemovePersonalitiesFlag);
4737
4738finish:
4739 IORecursiveLockUnlock(lock: sKextLock);
4740
4741 return result;
4742}
4743
4744/*********************************************************************
4745*********************************************************************/
4746OSSharedPtr<OSDictionary>
4747OSKext::copyKexts(void)
4748{
4749 OSSharedPtr<OSDictionary> result;
4750
4751 IORecursiveLockLock(lock: sKextLock);
4752 result = OSDynamicPtrCast<OSDictionary>(source: sKextsByID->copyCollection());
4753 IORecursiveLockUnlock(lock: sKextLock);
4754
4755 return result;
4756}
4757
4758/*********************************************************************
4759*********************************************************************/
4760#define BOOTER_KEXT_PREFIX "Driver-"
4761
4762typedef struct _DeviceTreeBuffer {
4763 uint32_t paddr;
4764 uint32_t length;
4765} _DeviceTreeBuffer;
4766
4767/*********************************************************************
4768* Create a dictionary of excluded kexts from the given booter data.
4769*********************************************************************/
4770/* static */
4771void
4772OSKext::createExcludeListFromBooterData(
4773 OSDictionary * theDictionary,
4774 OSCollectionIterator * theIterator )
4775{
4776 OSString * deviceTreeName = NULL; // do not release
4777 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4778 char * booterDataPtr = NULL; // do not release
4779 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4780 char * infoDictAddr = NULL; // do not release
4781 OSSharedPtr<OSObject> parsedXML;
4782 OSDictionary * theInfoDict = NULL; // do not release
4783
4784 theIterator->reset();
4785
4786 /* look for AppleKextExcludeList.kext */
4787 while ((deviceTreeName =
4788 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4789 const char * devTreeNameCString;
4790 OSData * deviceTreeEntry; // do not release
4791 OSString * myBundleID; // do not release
4792
4793 deviceTreeEntry =
4794 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4795 if (!deviceTreeEntry) {
4796 continue;
4797 }
4798
4799 /* Make sure it is a kext */
4800 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4801 if (strncmp(s1: devTreeNameCString, BOOTER_KEXT_PREFIX,
4802 n: (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4803 OSKextLog(NULL,
4804 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4805 format: "\"%s\" not a kext",
4806 devTreeNameCString);
4807 continue;
4808 }
4809
4810 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4811 deviceTreeEntry->getBytesNoCopy(start: 0, numBytes: sizeof(deviceTreeBuffer));
4812 if (!deviceTreeBuffer) {
4813 continue;
4814 }
4815
4816 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4817 if (!booterDataPtr) {
4818 continue;
4819 }
4820
4821 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4822 if (!kextFileInfo->infoDictPhysAddr ||
4823 !kextFileInfo->infoDictLength) {
4824 continue;
4825 }
4826
4827 infoDictAddr = (char *)
4828 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4829 if (!infoDictAddr) {
4830 continue;
4831 }
4832
4833 parsedXML = OSUnserializeXML(buffer: infoDictAddr);
4834 if (!parsedXML) {
4835 continue;
4836 }
4837
4838 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4839 if (!theInfoDict) {
4840 continue;
4841 }
4842
4843 myBundleID =
4844 OSDynamicCast(OSString,
4845 theInfoDict->getObject(kCFBundleIdentifierKey));
4846 if (myBundleID &&
4847 strcmp( s1: myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4848 boolean_t updated = updateExcludeList(infoDict: theInfoDict);
4849 if (!updated) {
4850 /* 25322874 */
4851 panic("Missing OSKextExcludeList dictionary");
4852 }
4853 break;
4854 }
4855 } // while ( (deviceTreeName = ...) )
4856
4857 return;
4858}
4859
4860/*********************************************************************
4861* Create a dictionary of excluded kexts from the given prelink
4862* info (kernelcache).
4863*********************************************************************/
4864/* static */
4865void
4866OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4867{
4868 OSDictionary * myInfoDict = NULL; // do not release
4869 OSString * myBundleID; // do not release
4870 u_int i;
4871
4872 /* Find the Apple Kext Exclude List. */
4873 for (i = 0; i < theInfoArray->getCount(); i++) {
4874 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4875 if (!myInfoDict) {
4876 continue;
4877 }
4878 myBundleID =
4879 OSDynamicCast(OSString,
4880 myInfoDict->getObject(kCFBundleIdentifierKey));
4881 if (myBundleID &&
4882 strcmp( s1: myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4883 boolean_t updated = updateExcludeList(infoDict: myInfoDict);
4884 if (!updated) {
4885 /* 25322874 */
4886 panic("Missing OSKextExcludeList dictionary");
4887 }
4888 break;
4889 }
4890 } // for (i = 0; i < theInfoArray->getCount()...
4891
4892 return;
4893}
4894
4895/* static */
4896boolean_t
4897OSKext::updateExcludeList(OSDictionary *infoDict)
4898{
4899 OSDictionary *myTempDict = NULL; // do not free
4900 OSString *myTempString = NULL; // do not free
4901 OSKextVersion newVersion = 0;
4902 boolean_t updated = false;
4903
4904 if (!infoDict) {
4905 return false;
4906 }
4907
4908 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4909 if (!myTempDict) {
4910 return false;
4911 }
4912
4913 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4914 if (!myTempString) {
4915 return false;
4916 }
4917
4918 newVersion = OSKextParseVersionString(versionString: myTempString->getCStringNoCopy());
4919 if (newVersion == 0) {
4920 return false;
4921 }
4922
4923 IORecursiveLockLock(lock: sKextLock);
4924
4925 if (newVersion > sExcludeListVersion) {
4926 sExcludeListByID = OSDictionary::withDictionary(dict: myTempDict, capacity: 0);
4927 sExcludeListVersion = newVersion;
4928 updated = true;
4929 }
4930
4931 IORecursiveLockUnlock(lock: sKextLock);
4932 return updated;
4933}
4934
4935#if PRAGMA_MARK
4936#pragma mark Accessors
4937#endif
4938
4939/*********************************************************************
4940*********************************************************************/
4941const OSObject *
4942OSKext::getBundleExecutable(void)
4943{
4944 return infoDict->getObject(kCFBundleExecutableKey);
4945}
4946
4947/*********************************************************************
4948*********************************************************************/
4949const OSSymbol *
4950OSKext::getIdentifier(void)
4951{
4952 return bundleID.get();
4953}
4954
4955/*********************************************************************
4956* A kext must have a bundle identifier to even survive initialization;
4957* this is guaranteed to exist past then.
4958*********************************************************************/
4959const char *
4960OSKext::getIdentifierCString(void)
4961{
4962 return bundleID->getCStringNoCopy();
4963}
4964
4965/*********************************************************************
4966*********************************************************************/
4967OSKextVersion
4968OSKext::getVersion(void)
4969{
4970 return version;
4971}
4972
4973/*********************************************************************
4974*********************************************************************/
4975OSKextVersion
4976OSKext::getCompatibleVersion(void)
4977{
4978 return compatibleVersion;
4979}
4980
4981/*********************************************************************
4982*********************************************************************/
4983bool
4984OSKext::isLibrary(void)
4985{
4986 return getCompatibleVersion() > 0;
4987}
4988
4989/*********************************************************************
4990*********************************************************************/
4991bool
4992OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4993{
4994 if ((compatibleVersion > -1 && version > -1) &&
4995 (compatibleVersion <= version && aVersion <= version)) {
4996 return true;
4997 }
4998 return false;
4999}
5000
5001/*********************************************************************
5002*********************************************************************/
5003bool
5004OSKext::declaresExecutable(void)
5005{
5006 if (isDriverKit()) {
5007 return false;
5008 }
5009 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
5010}
5011
5012/*********************************************************************
5013*********************************************************************/
5014OSData *
5015OSKext::getExecutable(void)
5016{
5017 OSData * result = NULL;
5018 OSSharedPtr<OSData> extractedExecutable;
5019
5020 if (flags.builtin) {
5021 return sKernelKext->linkedExecutable.get();
5022 }
5023
5024 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
5025 if (result) {
5026 return result;
5027 }
5028
5029#if CONFIG_KXLD
5030 OSData * mkextExecutableRef = NULL; // do not release
5031 mkextExecutableRef = OSDynamicCast(OSData,
5032 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
5033
5034 if (mkextExecutableRef) {
5035 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
5036 mkextExecutableRef->getBytesNoCopy();
5037 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
5038 if (mkextVersion == MKEXT_VERS_2) {
5039 mkext2_file_entry * fileinfo =
5040 (mkext2_file_entry *)mkextEntryRef->fileinfo;
5041 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
5042 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
5043 extractedExecutable = extractMkext2FileData(
5044 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
5045 compressedSize, fullSize);
5046 } else {
5047 OSKextLog(this, kOSKextLogErrorLevel |
5048 kOSKextLogArchiveFlag,
5049 "Kext %s - unknown mkext version 0x%x for executable.",
5050 getIdentifierCString(), mkextVersion);
5051 }
5052
5053 /* Regardless of success, remove the mkext executable,
5054 * and drop one reference on the mkext. (setExecutable() does not
5055 * replace, it removes, or panics if asked to replace.)
5056 */
5057 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
5058 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
5059
5060 if (extractedExecutable && extractedExecutable->getLength()) {
5061 if (!setExecutable(extractedExecutable.get())) {
5062 goto finish;
5063 }
5064 result = extractedExecutable.get();
5065 } else {
5066 goto finish;
5067 }
5068 }
5069
5070finish:
5071#endif // CONFIG_KXLD
5072 return result;
5073}
5074
5075/*********************************************************************
5076*********************************************************************/
5077bool
5078OSKext::isInterface(void)
5079{
5080 return flags.interface;
5081}
5082
5083/*********************************************************************
5084*********************************************************************/
5085bool
5086OSKext::isKernel(void)
5087{
5088 return this == sKernelKext;
5089}
5090
5091/*********************************************************************
5092*********************************************************************/
5093bool
5094OSKext::isKernelComponent(void)
5095{
5096 return flags.kernelComponent ? true : false;
5097}
5098
5099/*********************************************************************
5100*********************************************************************/
5101bool
5102OSKext::isExecutable(void)
5103{
5104 return !isKernel() && !isInterface() && declaresExecutable();
5105}
5106
5107/*********************************************************************
5108*********************************************************************/
5109bool
5110OSKext::isSpecialKernelBinary(void)
5111{
5112#if CONFIG_SPTM
5113 return (this->kmod_info) &&
5114 ((this->kmod_info->id == kOSKextSPTMLoadTag) ||
5115 (this->kmod_info->id == kOSKextTXMLoadTag));
5116#else
5117 return false;
5118#endif
5119}
5120
5121/*********************************************************************
5122* We might want to check this recursively for all dependencies,
5123* since a subtree of dependencies could get loaded before we hit
5124* a dependency that isn't safe-boot-loadable.
5125*
5126* xxx - Might want to return false if OSBundleEnableKextLogging or
5127* OSBundleDebugLevel
5128* or IOKitDebug is nonzero too (we used to do that, but I don't see
5129* the point except it's usually development drivers, which might
5130* cause panics on startup, that have those properties). Heh; could
5131* use a "kx" boot-arg!
5132*********************************************************************/
5133bool
5134OSKext::isLoadableInSafeBoot(void)
5135{
5136 bool result = false;
5137 OSString * required = NULL; // do not release
5138
5139 if (isKernel()) {
5140 result = true;
5141 goto finish;
5142 }
5143
5144 if (isDriverKit()) {
5145 result = true;
5146 goto finish;
5147 }
5148
5149 required = OSDynamicCast(OSString,
5150 getPropertyForHostArch(kOSBundleRequiredKey));
5151 if (!required) {
5152 goto finish;
5153 }
5154 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5155 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5156 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5157 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5158 required->isEqualTo(kOSBundleRequiredConsole)) {
5159 result = true;
5160 }
5161
5162finish:
5163 return result;
5164}
5165
5166/*********************************************************************
5167*********************************************************************/
5168bool
5169OSKext::isPrelinked(void)
5170{
5171 return flags.prelinked ? true : false;
5172}
5173
5174/*********************************************************************
5175*********************************************************************/
5176bool
5177OSKext::isLoaded(void)
5178{
5179 return flags.loaded ? true : false;
5180}
5181
5182/*********************************************************************
5183*********************************************************************/
5184bool
5185OSKext::isStarted(void)
5186{
5187 return flags.started ? true : false;
5188}
5189
5190/*********************************************************************
5191*********************************************************************/
5192bool
5193OSKext::isCPPInitialized(void)
5194{
5195 return flags.CPPInitialized;
5196}
5197
5198/*********************************************************************
5199*********************************************************************/
5200void
5201OSKext::setCPPInitialized(bool initialized)
5202{
5203 flags.CPPInitialized = initialized;
5204}
5205
5206/*********************************************************************
5207*********************************************************************/
5208uint32_t
5209OSKext::getLoadTag(void)
5210{
5211 return loadTag;
5212}
5213
5214/*********************************************************************
5215*********************************************************************/
5216void
5217OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5218{
5219 if (linkedExecutable) {
5220 *loadSize = linkedExecutable->getLength();
5221
5222 /* If we have a kmod_info struct, calculated the wired size
5223 * from that. Otherwise it's the full load size.
5224 */
5225 if (kmod_info) {
5226 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5227 } else {
5228 *wiredSize = *loadSize;
5229 }
5230 } else {
5231 *wiredSize = 0;
5232 *loadSize = 0;
5233 }
5234}
5235
5236/*********************************************************************
5237*********************************************************************/
5238OSSharedPtr<OSData>
5239OSKext::copyUUID(void)
5240{
5241 OSSharedPtr<OSData> result;
5242 OSData * theExecutable = NULL; // do not release
5243 const kernel_mach_header_t * header;
5244
5245 /* An interface kext doesn't have a linked executable with an LC_UUID,
5246 * we create one when it's linked.
5247 */
5248 if (interfaceUUID) {
5249 result = interfaceUUID;
5250 goto finish;
5251 }
5252
5253 if (flags.builtin || isInterface()) {
5254 return sKernelKext->copyUUID();
5255 }
5256
5257 if (isDriverKit() && infoDict) {
5258 return driverKitUUID;
5259 }
5260
5261 /* For real kexts, try to get the UUID from the linked executable,
5262 * or if is hasn't been linked yet, the unrelocated executable.
5263 */
5264 theExecutable = linkedExecutable.get();
5265 if (!theExecutable) {
5266 theExecutable = getExecutable();
5267 }
5268
5269 if (!theExecutable) {
5270 goto finish;
5271 }
5272
5273 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5274 result = copyMachoUUID(header);
5275
5276finish:
5277 return result;
5278}
5279
5280/*********************************************************************
5281*********************************************************************/
5282OSSharedPtr<OSData>
5283OSKext::copyTextUUID(void)
5284{
5285 if (flags.builtin) {
5286 return copyMachoUUID(header: (const kernel_mach_header_t *)kmod_info->address);
5287 }
5288 return copyUUID();
5289}
5290
5291/*********************************************************************
5292*********************************************************************/
5293OSSharedPtr<OSData>
5294OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5295{
5296 OSSharedPtr<OSData> result;
5297 const struct load_command * load_cmd = NULL;
5298 const struct uuid_command * uuid_cmd = NULL;
5299 uint32_t i;
5300
5301 load_cmd = (const struct load_command *)&header[1];
5302
5303 if (header->magic != MH_MAGIC_KERNEL) {
5304 OSKextLog(NULL,
5305 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5306 format: "%s: bad header %p",
5307 __func__,
5308 header);
5309 goto finish;
5310 }
5311
5312 for (i = 0; i < header->ncmds; i++) {
5313 if (load_cmd->cmd == LC_UUID) {
5314 uuid_cmd = (struct uuid_command *)load_cmd;
5315 result = OSData::withValue(value: uuid_cmd->uuid);
5316 goto finish;
5317 }
5318 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5319 }
5320
5321finish:
5322 return result;
5323}
5324
5325void
5326OSKext::setDriverKitUUID(OSData *uuid)
5327{
5328 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5329 OSSafeReleaseNULL(uuid);
5330 }
5331}
5332
5333OSData *
5334OSKext::getDextUniqueID(void)
5335{
5336 if (isDriverKit() && dextUniqueID != NULL) {
5337 return dextUniqueID.get();
5338 }
5339
5340 return NULL;
5341}
5342
5343/*
5344 * In case a DextUniqueID exists this function returns
5345 * an allocated char* with the hexadecimal represantition of
5346 * DextUniqueID.
5347 * The returned pinter needs to be freed with kfree_data, the
5348 * size of the allocated buffer is returned in size.
5349 */
5350static const char *
5351getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5352{
5353 if (dextUniqueID != NULL) {
5354 char *s_buffer = NULL;
5355 unsigned int d_length = dextUniqueID->getLength();
5356 /*
5357 * We are converting in hex, so for every byte we will have
5358 * 2 hex chars and one last \0.
5359 */
5360 unsigned int s_length = d_length * 2 + 1;
5361 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5362
5363 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5364 int cpos = 0;
5365 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5366 int ret = snprintf(s_buffer + cpos, count: s_length - cpos - 1, "%02X", uid[i]);
5367 if (ret <= 0) {
5368 break;
5369 }
5370 cpos += ret;
5371 }
5372 *size = s_length;
5373
5374 return s_buffer;
5375 }
5376
5377 return NULL;
5378}
5379
5380/*
5381 * Atomically swaps the olddext with newdext.
5382 * olddext will be unloaded, so it might be freed
5383 * after this call unless it was previously retained.
5384 *
5385 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5386 */
5387void
5388OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5389{
5390 OSReturn result;
5391 const OSSymbol * dextID = olddext->getIdentifier();
5392 OSData * oldDextUniqueIdentifier = olddext->getDextUniqueID();
5393 OSSharedPtr<OSArray> new_personalities;
5394 OSSharedPtr<OSString> kextIdentifier;
5395 __assert_only bool lock_held = IORecursiveLockHaveLock(lock: sKextLock);
5396 assert(lock_held);
5397
5398 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5399 dextID->retain();
5400
5401 if (newdext != NULL) {
5402 __assert_only bool eq = dextID->isEqualTo(aSymbol: newdext->getIdentifier());
5403 assert(eq);
5404 }
5405
5406 if (newdext != NULL) {
5407 /*
5408 * Swap the catalog personalities.
5409 */
5410 new_personalities = newdext->copyPersonalitiesArray();
5411 olddext->updatePersonalitiesInCatalog(upgradedPersonalities: new_personalities.get());
5412 }
5413
5414 if (NULL != oldDextUniqueIdentifier) {
5415 oldDextUniqueIdentifier->retain();
5416 }
5417
5418 /*
5419 * Unload the dext.
5420 */
5421 result = olddext->unload();
5422 if (result != kOSReturnSuccess) {
5423 OSKextLog(NULL,
5424 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5425 format: "Cannot unload dext for upgrade %s: %d\n",
5426 dextID->getCStringNoCopy(), result);
5427 }
5428
5429 if (newdext != NULL) {
5430 /*
5431 * Swap the dexts on the OSKext dictionary.
5432 * This might free the dext.
5433 */
5434 sKextsByID->setObject(aKey: dextID, anObject: newdext);
5435 } else {
5436 /*
5437 * Remove the old dext
5438 */
5439 removeKext(aKext: olddext, terminateServicesAndRemovePersonalitiesFlag: true);
5440 }
5441
5442 /*
5443 * Inform userspace.
5444 */
5445 if (newdext != NULL) {
5446 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), dextUniqueIdentifier: newdext->getDextUniqueID());
5447 if (result != kOSReturnSuccess) {
5448 OSKextLog(NULL,
5449 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5450 format: "Cannot send upgrade notification for %s\n",
5451 dextID->getCStringNoCopy());
5452 }
5453 } else {
5454 // notify dext removal
5455 queueKextNotification(kKextRequestPredicateUnloadNotification,
5456 OSDynamicCast(OSString, dextID), dextUniqueIdentifier: oldDextUniqueIdentifier);
5457 }
5458
5459 OSSafeReleaseNULL(dextID);
5460 OSSafeReleaseNULL(oldDextUniqueIdentifier);
5461}
5462
5463/*
5464 * To be called with sKextLock held.
5465 * NOTE: this could unload the olddext.
5466 */
5467bool
5468OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5469{
5470 const char * dextIDCS = newdext->getIdentifierCString();
5471 __assert_only bool old_isDext = olddext->isDriverKit();
5472 __assert_only bool new_isDext = newdext->isDriverKit();
5473 __assert_only bool lock_held = IORecursiveLockHaveLock(lock: sKextLock);
5474
5475 assert(old_isDext && new_isDext);
5476 assert(lock_held);
5477
5478 /*
5479 * New dext and old dext have the same ID.
5480 * We use this ID as key on the OSKext
5481 * dictionarys/arrays.
5482 */
5483 const OSSymbol * dextID = newdext->getIdentifier();
5484 __assert_only bool eq = dextID->isEqualTo(aSymbol: olddext->getIdentifier());
5485 assert(eq);
5486
5487 /*
5488 * Set this OSKect as to update.
5489 * Note that this flags will never be removed once set.
5490 * When a OSKext is marked, it will be substitued by a new
5491 * OSKext, and every subsystem having a reference on this
5492 * OSKext need to know they have check if they can use
5493 * this OSKext or look for a new one.
5494 */
5495 olddext->flags.dextToReplace = 1;
5496
5497 /*
5498 * Check if the current OSKext has any
5499 * userspace processes launched.
5500 * In this case we cannot upgrade and we have to
5501 * delay the upgrade until all processes
5502 * are done.
5503 */
5504 if (olddext->dextLaunchedCount == 0) {
5505 /*
5506 * Be sure that if there are no launched dexts, no
5507 * pending upgrades exist.
5508 * This is an error if it happens, as the decrement
5509 * should have removed the dext from sDriverKitToUpgradeByID
5510 * in case it reached 0.
5511 */
5512 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(aKey: dextID);
5513 if (pending_upgdare != NULL) {
5514 OSKextLog(NULL,
5515 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5516 format: "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5517 dextIDCS);
5518 goto out;
5519 }
5520
5521 replaceDextInternal(olddext, newdext);
5522 return true;
5523 }
5524
5525out:
5526
5527 /*
5528 * Delay the upgrade.
5529 * Make the new dext available in sDriverKitToUpgradeByID.
5530 * In case there was already a pending upgrade, this will
5531 * overwrite it.
5532 */
5533 sDriverKitToUpgradeByID->setObject(aKey: dextID, anObject: newdext);
5534 return false;
5535}
5536
5537/*
5538 * To be called with sKextLock held.
5539 * NOTE: this could unload the dext.
5540 */
5541bool
5542OSKext::removeDext(OSKext *dext)
5543{
5544 __assert_only bool dext_isDext = dext->isDriverKit();
5545 __assert_only bool lock_held = IORecursiveLockHaveLock(lock: sKextLock);
5546 IOReturn result;
5547
5548 assert(dext_isDext);
5549 assert(lock_held);
5550
5551 /*
5552 * Set this OSKext to be unloaded when all running instances exit.
5553 */
5554 dext->flags.dextToReplace = 1;
5555
5556 result = gIOCatalogue->terminateDriversForModule(
5557 moduleName: dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5558 if (result != kOSReturnSuccess) {
5559 OSKextLog(aKext: dext,
5560 kOSKextLogErrorLevel |
5561 kOSKextLogKextBookkeepingFlag,
5562 format: "%s services failed to terminate - 0x%x.",
5563 dext->getIdentifierCString(), result);
5564 }
5565
5566 dext->removePersonalitiesFromCatalog();
5567 sDriverKitToUpgradeByID->removeObject(aKey: dext->getIdentifier());
5568
5569 /*
5570 * Check if the current OSKext has any
5571 * userspace processes launched.
5572 * In this case we cannot unload and we have to
5573 * delay the unload until all processes
5574 * are done.
5575 */
5576 if (dext->dextLaunchedCount == 0) {
5577 replaceDextInternal(olddext: dext, NULL);
5578 return true;
5579 }
5580
5581 return false;
5582}
5583
5584bool
5585OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5586{
5587 bool ret = false;
5588 __assert_only bool isDext = dext->isDriverKit();
5589 assert(isDext);
5590
5591 const char * dextIDCS = dext->getIdentifierCString();
5592 OSData *myDextUniqueID = dext->getDextUniqueID();
5593
5594 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5595 OSKextLog(aKext: dext,
5596 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5597 format: "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5598 dextIDCS);
5599 return ret;
5600 }
5601
5602 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5603 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: myDextUniqueID, size: &dextUniqueIDCStringSize);
5604 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueID: dextUniqueIDToMatch, size: &dextUniqueIDToMatchCStringSize);
5605 assert(dextUniqueIDCString != NULL);
5606 assert(dextUniqueIDToMatchCString != NULL);
5607
5608 IORecursiveLockLock(lock: sKextLock);
5609
5610 /*
5611 * Check that the dext we are referencing is the same
5612 * looked for the match.
5613 */
5614 if (myDextUniqueID->isEqualTo(aDataObj: dextUniqueIDToMatch)) {
5615 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5616 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5617 OSKextLog(aKext: dext,
5618 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5619 format: "Too many dexts launched for %s UniqueID %s\n",
5620 dextIDCS, dextUniqueIDCString);
5621 } else {
5622 dext->dextLaunchedCount++;
5623 ret = true;
5624
5625 OSKextLog(aKext: dext,
5626 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5627 format: "New dext launched for %s UniqueID %s",
5628 dextIDCS, dextUniqueIDCString);
5629 }
5630 } else {
5631 OSKextLog(aKext: dext,
5632 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5633 format: "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5634 dextIDCS, dextUniqueIDCString);
5635 }
5636 } else {
5637 OSKextLog(aKext: dext,
5638 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5639 format: "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5640 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5641 }
5642
5643 IORecursiveLockUnlock(lock: sKextLock);
5644
5645 if (dextUniqueIDCString != NULL) {
5646 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5647 }
5648 if (dextUniqueIDToMatchCString != NULL) {
5649 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5650 }
5651 return ret;
5652}
5653
5654bool
5655OSKext::decrementDextLaunchCount(OSString *bundleID)
5656{
5657 bool ret = false;
5658 const char * dextIDCS;
5659 OSData *myDextUniqueID;
5660 unsigned int dextUniqueIDCStringSize = 0;
5661 const char * dextUniqueIDCString = NULL;
5662 OSKext* dext = NULL;
5663
5664 if (!bundleID) {
5665 return ret;
5666 }
5667 dextIDCS = bundleID->getCStringNoCopy();
5668
5669 IORecursiveLockLock(lock: sKextLock);
5670
5671 /*
5672 * Look for the dext with the bundle it. This
5673 * call is triggered only if a previous increment was
5674 * performed. It means that the dext could have not
5675 * been upgraded as its dextLaunchedCount was at least 1.
5676 * Because of this it still needs to be available
5677 * in sKextsByID.
5678 */
5679 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5680 if (!dext || !dext->isDriverKit()) {
5681 OSKextLog(NULL,
5682 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5683 format: "Cannot find dext for %s, cannot decrement dext launches\n",
5684 dextIDCS);
5685
5686 goto out_locked;
5687 }
5688
5689 myDextUniqueID = dext->getDextUniqueID();
5690 if (!myDextUniqueID) {
5691 OSKextLog(aKext: dext,
5692 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5693 format: "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5694 dextIDCS);
5695
5696 goto out_locked;
5697 }
5698 dextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: myDextUniqueID, size: &dextUniqueIDCStringSize);
5699 assert(dextUniqueIDCString != NULL);
5700
5701 if (dext->dextLaunchedCount == 0) {
5702 OSKextLog(aKext: dext,
5703 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5704 format: "Over decrementing dext launch for %s UniqueID %s\n",
5705 dextIDCS, dextUniqueIDCString);
5706
5707 goto out_locked;
5708 }
5709
5710 dext->dextLaunchedCount--;
5711
5712 OSKextLog(aKext: dext,
5713 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5714 format: "Dext terminated for %s UniqueID %s",
5715 dextIDCS, dextUniqueIDCString);
5716
5717 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5718 /*
5719 * Find the upgraded dext.
5720 */
5721 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5722 if (newdext) {
5723 OSKextLog(aKext: dext,
5724 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5725 format: "Dext upgrade for %s UniqueID %s",
5726 dextIDCS, dextUniqueIDCString);
5727 replaceDextInternal(olddext: dext, newdext);
5728 /* NOTE dext could have been freed past this point */
5729
5730 sDriverKitToUpgradeByID->removeObject(aKey: dextIDCS);
5731 } else {
5732 OSKextLog(aKext: dext,
5733 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5734 format: "Dext unload for %s UniqueID %s",
5735 dextIDCS, dextUniqueIDCString);
5736 replaceDextInternal(olddext: dext, NULL);
5737 }
5738
5739 ret = true;
5740 }
5741out_locked:
5742 IORecursiveLockUnlock(lock: sKextLock);
5743
5744 if (dextUniqueIDCString != NULL) {
5745 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5746 }
5747
5748 return ret;
5749}
5750
5751/*********************************************************************
5752*********************************************************************/
5753#if defined (__arm__)
5754#include <arm/arch.h>
5755#endif
5756
5757#if defined (__x86_64__)
5758#define ARCHNAME "x86_64"
5759#elif defined (__arm64__)
5760#define ARCHNAME "arm64"
5761#elif defined (__arm__)
5762
5763#if defined (__ARM_ARCH_7S__)
5764#define ARCHNAME "armv7s"
5765#elif defined (__ARM_ARCH_7F__)
5766#define ARCHNAME "armv7f"
5767#elif defined (__ARM_ARCH_7K__)
5768#define ARCHNAME "armv7k"
5769#elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5770#define ARCHNAME "armv7"
5771#elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5772#define ARCHNAME "armv6"
5773#endif
5774
5775#elif defined (__arm64__)
5776#define ARCHNAME "arm64"
5777#else
5778#error architecture not supported
5779#endif
5780
5781#define ARCH_SEPARATOR_CHAR '_'
5782
5783static char *
5784makeHostArchKey(const char * key, size_t * keySizeOut)
5785{
5786 char * result = NULL;
5787 size_t keyLength = strlen(s: key);
5788 size_t keySize;
5789
5790 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5791 */
5792 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5793 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5794
5795 if (!result) {
5796 goto finish;
5797 }
5798 strlcpy(dst: result, src: key, n: keySize);
5799 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5800 result[keyLength] = '\0';
5801 strlcat(dst: result, ARCHNAME, n: keySize);
5802 *keySizeOut = keySize;
5803
5804finish:
5805 return result;
5806}
5807
5808/*********************************************************************
5809*********************************************************************/
5810OSObject *
5811OSKext::getPropertyForHostArch(const char * key)
5812{
5813 OSObject * result = NULL;// do not release
5814 size_t hostArchKeySize = 0;
5815 char * hostArchKey = NULL;// must kfree
5816
5817 if (!key || !infoDict) {
5818 goto finish;
5819 }
5820
5821 /* Some properties are not allowed to be arch-variant:
5822 * - Any CFBundle... property.
5823 * - OSBundleIsInterface.
5824 * - OSKernelResource.
5825 */
5826 if (STRING_HAS_PREFIX(key, "OS") ||
5827 STRING_HAS_PREFIX(key, "IO")) {
5828 hostArchKey = makeHostArchKey(key, keySizeOut: &hostArchKeySize);
5829 if (!hostArchKey) {
5830 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5831 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5832 format: "Allocation failure.");
5833 goto finish;
5834 }
5835 result = infoDict->getObject(aKey: hostArchKey);
5836 }
5837
5838 if (!result) {
5839 result = infoDict->getObject(aKey: key);
5840 }
5841
5842finish:
5843 if (hostArchKey) {
5844 kfree_data(hostArchKey, hostArchKeySize);
5845 }
5846 return result;
5847}
5848
5849#if PRAGMA_MARK
5850#pragma mark Load/Start/Stop/Unload
5851#endif
5852
5853#define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5854
5855/*********************************************************************
5856* sExcludeListByID is a dictionary with keys / values of:
5857* key = bundleID string of kext we will not allow to load
5858* value = version string(s) of the kext that is to be denied loading.
5859* The version strings can be comma delimited. For example if kext
5860* com.foocompany.fookext has two versions that we want to deny
5861* loading then the version strings might look like:
5862* 1.0.0, 1.0.1
5863* If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5864* not load the kext.
5865*
5866* Value may also be in the form of "LE 2.0.0" (version numbers
5867* less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5868* number less than 2.0.0 will not load)
5869*
5870* NOTE - we cannot use the characters "<=" or "<" because we have code
5871* that serializes plists and treats '<' as a special character.
5872*********************************************************************/
5873bool
5874OSKext::isInExcludeList(void)
5875{
5876 OSString * versionString = NULL; // do not release
5877 char * versionCString = NULL; // do not free
5878 size_t i;
5879 boolean_t wantLessThan = false;
5880 boolean_t wantLessThanEqualTo = false;
5881 boolean_t isInExcludeList = true;
5882 char myBuffer[32];
5883
5884 IORecursiveLockLock(lock: sKextLock);
5885
5886 if (!sExcludeListByID) {
5887 isInExcludeList = false;
5888 } else {
5889 /* look up by bundleID in our exclude list and if found get version
5890 * string (or strings) that we will not allow to load
5891 */
5892 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5893 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5894 isInExcludeList = false;
5895 }
5896 }
5897
5898 IORecursiveLockUnlock(lock: sKextLock);
5899
5900 if (!isInExcludeList) {
5901 return false;
5902 }
5903
5904 /* parse version strings */
5905 versionCString = (char *) versionString->getCStringNoCopy();
5906
5907 /* look for "LT" or "LE" form of version string, must be in first two
5908 * positions.
5909 */
5910 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5911 wantLessThan = true;
5912 versionCString += 2;
5913 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5914 wantLessThanEqualTo = true;
5915 versionCString += 2;
5916 }
5917
5918 for (i = 0; *versionCString != 0x00; versionCString++) {
5919 /* skip whitespace */
5920 if (isWhiteSpace(*versionCString)) {
5921 continue;
5922 }
5923
5924 /* peek ahead for version string separator or null terminator */
5925 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5926 /* OK, we have a version string */
5927 myBuffer[i++] = *versionCString;
5928 myBuffer[i] = 0x00;
5929
5930 OSKextVersion excludeVers;
5931 excludeVers = OSKextParseVersionString(versionString: myBuffer);
5932
5933 if (wantLessThanEqualTo) {
5934 if (version <= excludeVers) {
5935 return true;
5936 }
5937 } else if (wantLessThan) {
5938 if (version < excludeVers) {
5939 return true;
5940 }
5941 } else if (version == excludeVers) {
5942 return true;
5943 }
5944
5945 /* reset for the next (if any) version string */
5946 i = 0;
5947 wantLessThan = false;
5948 wantLessThanEqualTo = false;
5949 } else {
5950 /* save valid version character */
5951 myBuffer[i++] = *versionCString;
5952
5953 /* make sure bogus version string doesn't overrun local buffer */
5954 if (i >= sizeof(myBuffer)) {
5955 break;
5956 }
5957 }
5958 }
5959
5960 return false;
5961}
5962
5963/*********************************************************************
5964* sNonLoadableKextsByID is a dictionary with keys / values of:
5965* key = bundleID string of kext we will not allow to load
5966* value = boolean (true == loadable, false == not loadable)
5967*
5968* Only kexts which are in the AuxKC will be marked as "not loadble,"
5969* i.e., the value for the kext's bundleID will be false. All kexts in
5970* the primary and system KCs will always be marked as "loadable."
5971*
5972* This list ultimately comes from kexts which have been uninstalled
5973* in user space by deleting the kext from disk, but which have not
5974* yet been removed from the AuxKC. Because the user could choose to
5975* re-install the exact same version of the kext, we need to keep
5976* a dictionary of boolean values so that user space only needs to
5977* keep a simple list of "uninstalled" or "missing" bundles. When
5978* a bundle is re-installed, the iokit daemon can use the
5979* AucKCBundleAvailable predicate to set the individual kext's
5980* availability to true.
5981*********************************************************************/
5982bool
5983OSKext::isLoadable(void)
5984{
5985 bool isLoadable = true;
5986
5987 if (kc_type != KCKindAuxiliary) {
5988 /* this filtering only applies to kexts in the auxkc */
5989 return true;
5990 }
5991
5992 IORecursiveLockLock(lock: sKextLock);
5993
5994 if (sNonLoadableKextsByID) {
5995 /* look up by bundleID in our exclude list and if found get version
5996 * string (or strings) that we will not allow to load
5997 */
5998 OSBoolean *loadableVal;
5999 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
6000 if (loadableVal && !loadableVal->getValue()) {
6001 isLoadable = false;
6002 }
6003 }
6004 IORecursiveLockUnlock(lock: sKextLock);
6005
6006 return isLoadable;
6007}
6008
6009/*********************************************************************
6010*********************************************************************/
6011/* static */
6012OSReturn
6013OSKext::loadKextWithIdentifier(
6014 const char * kextIdentifierCString,
6015 Boolean allowDeferFlag,
6016 Boolean delayAutounloadFlag,
6017 OSKextExcludeLevel startOpt,
6018 OSKextExcludeLevel startMatchingOpt,
6019 OSArray * personalityNames)
6020{
6021 OSReturn result = kOSReturnError;
6022 OSSharedPtr<OSString> kextIdentifier;
6023
6024 kextIdentifier = OSString::withCString(cString: kextIdentifierCString);
6025 if (!kextIdentifier) {
6026 result = kOSKextReturnNoMemory;
6027 goto finish;
6028 }
6029 result = OSKext::loadKextWithIdentifier(kextIdentifier: kextIdentifier.get(),
6030 NULL /* kextRef */,
6031 allowDeferFlag, delayAutounloadFlag,
6032 startOpt, startMatchingOpt, personalityNames);
6033
6034finish:
6035 return result;
6036}
6037
6038OSReturn
6039OSKext::loadKextWithIdentifier(
6040 OSString * kextIdentifier,
6041 OSSharedPtr<OSObject> &kextRef,
6042 Boolean allowDeferFlag,
6043 Boolean delayAutounloadFlag,
6044 OSKextExcludeLevel startOpt,
6045 OSKextExcludeLevel startMatchingOpt,
6046 OSArray * personalityNames)
6047{
6048 OSObject * kextRefRaw = NULL;
6049 OSReturn result;
6050
6051 result = loadKextWithIdentifier(kextIdentifier,
6052 kextRef: &kextRefRaw,
6053 allowDeferFlag,
6054 delayAutounloadFlag,
6055 startOpt,
6056 startMatchingOpt,
6057 personalityNames);
6058 if ((kOSReturnSuccess == result) && kextRefRaw) {
6059 kextRef.reset(p: kextRefRaw, OSNoRetain);
6060 }
6061 return result;
6062}
6063
6064/*********************************************************************
6065*********************************************************************/
6066OSReturn
6067OSKext::loadKextWithIdentifier(
6068 OSString * kextIdentifier,
6069 OSObject ** kextRef,
6070 Boolean allowDeferFlag,
6071 Boolean delayAutounloadFlag,
6072 OSKextExcludeLevel startOpt,
6073 OSKextExcludeLevel startMatchingOpt,
6074 OSArray * personalityNames)
6075{
6076 OSReturn result = kOSReturnError;
6077 OSReturn pingResult = kOSReturnError;
6078 OSKext * theKext = NULL; // do not release
6079 OSSharedPtr<OSDictionary> loadRequest;
6080 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6081
6082 if (kextRef) {
6083 *kextRef = NULL;
6084 }
6085
6086 IORecursiveLockLock(lock: sKextLock);
6087
6088 if (!kextIdentifier) {
6089 result = kOSKextReturnInvalidArgument;
6090 goto finish;
6091 }
6092
6093 OSKext::recordIdentifierRequest(kextIdentifier);
6094
6095 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6096 if (!theKext) {
6097 if (!allowDeferFlag) {
6098 OSKextLog(/* kext */ NULL,
6099 kOSKextLogErrorLevel |
6100 kOSKextLogLoadFlag,
6101 format: "Can't load kext %s - not found.",
6102 kextIdentifier->getCStringNoCopy());
6103 goto finish;
6104 }
6105
6106 if (!sKernelRequestsEnabled) {
6107 OSKextLog(aKext: theKext,
6108 kOSKextLogErrorLevel |
6109 kOSKextLogLoadFlag,
6110 format: "Can't load kext %s - requests to user space are disabled.",
6111 kextIdentifier->getCStringNoCopy());
6112 result = kOSKextReturnDisabled;
6113 goto finish;
6114 }
6115
6116 /* Create a new request unless one is already sitting
6117 * in sKernelRequests for this bundle identifier
6118 */
6119 kextIdentifierSymbol = OSSymbol::withString(aString: kextIdentifier);
6120 if (!sPostedKextLoadIdentifiers->containsObject(anObject: kextIdentifierSymbol.get())) {
6121 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
6122 requestP&: loadRequest);
6123 if (result != kOSReturnSuccess) {
6124 goto finish;
6125 }
6126 if (!_OSKextSetRequestArgument(requestDict: loadRequest.get(),
6127 kKextRequestArgumentBundleIdentifierKey, value: kextIdentifier)) {
6128 result = kOSKextReturnNoMemory;
6129 goto finish;
6130 }
6131 if (!sKernelRequests->setObject(loadRequest.get())) {
6132 result = kOSKextReturnNoMemory;
6133 goto finish;
6134 }
6135
6136 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6137 result = kOSKextReturnNoMemory;
6138 goto finish;
6139 }
6140
6141 OSKextLog(aKext: theKext,
6142 kOSKextLogDebugLevel |
6143 kOSKextLogLoadFlag,
6144 format: "Kext %s not found; queued load request to user space.",
6145 kextIdentifier->getCStringNoCopy());
6146 }
6147
6148 pingResult = OSKext::pingIOKitDaemon();
6149 if (pingResult == kOSKextReturnDisabled) {
6150 OSKextLog(/* kext */ NULL,
6151 msgLogSpec: ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
6152 kOSKextLogLoadFlag,
6153 format: "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
6154 kextIdentifier->getCStringNoCopy());
6155 }
6156
6157 result = kOSKextReturnDeferred;
6158 goto finish;
6159 }
6160
6161 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6162
6163 if (result != kOSReturnSuccess) {
6164 OSKextLog(aKext: theKext,
6165 kOSKextLogErrorLevel |
6166 kOSKextLogLoadFlag,
6167 format: "Failed to load kext %s (error 0x%x).",
6168 kextIdentifier->getCStringNoCopy(), (int)result);
6169
6170 if (theKext->kc_type == KCKindUnknown) {
6171 OSKext::removeKext(aKext: theKext,
6172 /* terminateService/removePersonalities */ terminateServicesAndRemovePersonalitiesFlag: true);
6173 }
6174 goto finish;
6175 }
6176
6177 if (delayAutounloadFlag) {
6178 OSKextLog(aKext: theKext,
6179 kOSKextLogProgressLevel |
6180 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6181 format: "Setting delayed autounload for %s.",
6182 kextIdentifier->getCStringNoCopy());
6183 theKext->flags.delayAutounload = 1;
6184 }
6185
6186finish:
6187 if ((kOSReturnSuccess == result) && kextRef) {
6188 *kextRef = theKext;
6189 theKext->matchingRefCount++;
6190 theKext->retain();
6191 }
6192
6193 IORecursiveLockUnlock(lock: sKextLock);
6194
6195 return result;
6196}
6197
6198/*********************************************************************
6199*********************************************************************/
6200/* static */
6201OSReturn
6202OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6203{
6204 OSReturn result = kOSReturnError;
6205
6206 OSBoolean *delayAutounloadBool = NULL; // do not release
6207 OSNumber *startKextExcludeNum = NULL; // do not release
6208 OSNumber *startMatchingExcludeNum = NULL; // do not release
6209 OSArray *personalityNames = NULL; // do not release
6210
6211 /*
6212 * Default values for these options:
6213 * regular autounload behavior
6214 * start the kext
6215 * send all personalities to the catalog
6216 */
6217 Boolean delayAutounload = false;
6218 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6219 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6220
6221 IORecursiveLockLock(lock: sKextLock);
6222
6223 OSKextLog(/* kext */ NULL,
6224 kOSKextLogDebugLevel |
6225 kOSKextLogIPCFlag,
6226 format: "Received kext KC load request from user space.");
6227
6228 /* Regardless of processing, the fact that we have gotten here means some
6229 * user-space program is up and talking to us, so we'll switch our kext
6230 * registration to reflect that.
6231 */
6232 if (!sUserLoadsActive) {
6233 OSKextLog(/* kext */ NULL,
6234 kOSKextLogProgressLevel |
6235 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6236 format: "Switching to late startup (user-space) kext loading policy.");
6237 sUserLoadsActive = true;
6238 }
6239
6240 delayAutounloadBool = OSDynamicCast(OSBoolean,
6241 _OSKextGetRequestArgument(requestDict,
6242 kKextRequestArgumentDelayAutounloadKey));
6243 startKextExcludeNum = OSDynamicCast(OSNumber,
6244 _OSKextGetRequestArgument(requestDict,
6245 kKextRequestArgumentStartExcludeKey));
6246 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6247 _OSKextGetRequestArgument(requestDict,
6248 kKextRequestArgumentStartMatchingExcludeKey));
6249 personalityNames = OSDynamicCast(OSArray,
6250 _OSKextGetRequestArgument(requestDict,
6251 kKextRequestArgumentPersonalityNamesKey));
6252
6253 if (delayAutounloadBool) {
6254 delayAutounload = delayAutounloadBool->getValue();
6255 }
6256 if (startKextExcludeNum) {
6257 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6258 }
6259 if (startMatchingExcludeNum) {
6260 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6261 }
6262
6263 OSKextLog(/* kext */ NULL,
6264 kOSKextLogProgressLevel |
6265 kOSKextLogIPCFlag,
6266 format: "Received request from user space to load KC kext %s.",
6267 theKext->getIdentifierCString());
6268
6269 /* this could be in the Auxiliary KC, so record the load request */
6270 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6271
6272 /*
6273 * Load the kext
6274 */
6275 result = theKext->load(startOpt: startKextExcludeLevel,
6276 startMatchingOpt: startMatchingExcludeLevel, personalityNames);
6277
6278 if (result != kOSReturnSuccess) {
6279 OSKextLog(aKext: theKext,
6280 kOSKextLogErrorLevel |
6281 kOSKextLogLoadFlag,
6282 format: "Failed to load kext %s (error 0x%x).",
6283 theKext->getIdentifierCString(), (int)result);
6284
6285 OSKext::removeKext(aKext: theKext,
6286 /* terminateService/removePersonalities */ terminateServicesAndRemovePersonalitiesFlag: true);
6287 goto finish;
6288 } else {
6289 OSKextLog(aKext: theKext,
6290 kOSKextLogProgressLevel |
6291 kOSKextLogLoadFlag,
6292 format: "Kext %s Loaded successfully from %s KC",
6293 theKext->getIdentifierCString(), theKext->getKCTypeString());
6294 }
6295
6296 if (delayAutounload) {
6297 OSKextLog(aKext: theKext,
6298 kOSKextLogProgressLevel |
6299 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6300 format: "Setting delayed autounload for %s.",
6301 theKext->getIdentifierCString());
6302 theKext->flags.delayAutounload = 1;
6303 }
6304
6305finish:
6306 IORecursiveLockUnlock(lock: sKextLock);
6307
6308 return result;
6309}
6310
6311/*********************************************************************
6312*********************************************************************/
6313/* static */
6314OSReturn
6315OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6316{
6317 OSReturn result = kOSReturnError;
6318 OSDictionary *anInfoDict = NULL; // do not release
6319
6320 anInfoDict = OSDynamicCast(OSDictionary,
6321 _OSKextGetRequestArgument(requestDict,
6322 kKextRequestArgumentCodelessInfoKey));
6323 if (anInfoDict == NULL) {
6324 OSKextLog(/* kext */ NULL,
6325 kOSKextLogErrorLevel |
6326 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6327 format: "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6328 kextIdentifier->getCStringNoCopy());
6329 return kOSKextReturnInvalidArgument;
6330 }
6331
6332 IORecursiveLockLock(lock: sKextLock);
6333
6334 OSKextLog(/* kext */ NULL,
6335 kOSKextLogProgressLevel |
6336 kOSKextLogIPCFlag,
6337 format: "Received request from user space to load codeless kext %s.",
6338 kextIdentifier->getCStringNoCopy());
6339
6340 {
6341 // instantiate a new kext, and don't hold a reference
6342 // (the kext subsystem will hold one implicitly)
6343 OSKextInitResult ret;
6344 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, result: &ret);
6345 if (!newKext) {
6346 /*
6347 * We might have failed to create a new OSKext
6348 * because the old one should still be used.
6349 * Check if that is the case.
6350 */
6351 if (ret != kOSKextInitFailure) {
6352 result = kOSReturnSuccess;
6353 goto finish;
6354 }
6355 OSKextLog(/* kext */ NULL,
6356 kOSKextLogErrorLevel |
6357 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6358 format: "Could not instantiate codeless kext.");
6359 result = kOSKextReturnNotLoadable;
6360 goto finish;
6361 }
6362 if (!kextIdentifier->isEqualTo(cString: newKext->getIdentifierCString())) {
6363 OSKextLog(/* kext */ NULL,
6364 kOSKextLogErrorLevel |
6365 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6366 format: "Codeless kext identifiers don't match '%s' != '%s'",
6367 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6368
6369 OSKext::removeKext(aKext: newKext.get(), terminateServicesAndRemovePersonalitiesFlag: false);
6370 result = kOSKextReturnInvalidArgument;
6371 goto finish;
6372 }
6373
6374 /* Record the request for the codeless kext */
6375 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6376
6377 result = kOSReturnSuccess;
6378 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6379 result = newKext->sendPersonalitiesToCatalog(startMatching: true, NULL);
6380 }
6381
6382finish:
6383 IORecursiveLockUnlock(lock: sKextLock);
6384
6385 return result;
6386}
6387
6388/*********************************************************************
6389*********************************************************************/
6390/* static */
6391void
6392OSKext::dropMatchingReferences(
6393 OSSet * kexts)
6394{
6395 IORecursiveLockLock(lock: sKextLock);
6396 kexts->iterateObjects(block: ^bool (OSObject * obj) {
6397 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6398 if (!thisKext) {
6399 return false;
6400 }
6401 thisKext->matchingRefCount--;
6402 return false;
6403 });
6404 IORecursiveLockUnlock(lock: sKextLock);
6405}
6406
6407/*********************************************************************
6408*********************************************************************/
6409/* static */
6410void
6411OSKext::recordIdentifierRequest(
6412 OSString * kextIdentifier)
6413{
6414 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6415 bool fail = false;
6416
6417 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6418 goto finish;
6419 }
6420
6421 kextIdentifierSymbol = OSSymbol::withString(aString: kextIdentifier);
6422 if (!kextIdentifierSymbol) {
6423 // xxx - this is really a basic alloc failure
6424 fail = true;
6425 goto finish;
6426 }
6427
6428 IORecursiveLockLock(lock: sKextLock);
6429 if (!sAllKextLoadIdentifiers->containsObject(anObject: kextIdentifierSymbol.get())) {
6430 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6431 fail = true;
6432 } else {
6433 // xxx - need to find a way to associate this whole func w/the kext
6434 OSKextLog(/* kext */ NULL,
6435 // xxx - check level
6436 kOSKextLogStepLevel |
6437 kOSKextLogArchiveFlag,
6438 format: "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6439 kextIdentifier->getCStringNoCopy());
6440 }
6441 }
6442 IORecursiveLockUnlock(lock: sKextLock);
6443
6444finish:
6445
6446 if (fail) {
6447 OSKextLog(/* kext */ NULL,
6448 kOSKextLogErrorLevel |
6449 kOSKextLogArchiveFlag,
6450 format: "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6451 kextIdentifier->getCStringNoCopy());
6452 }
6453 return;
6454}
6455
6456/*********************************************************************
6457*********************************************************************/
6458OSReturn
6459OSKext::load(
6460 OSKextExcludeLevel startOpt,
6461 OSKextExcludeLevel startMatchingOpt,
6462 OSArray * personalityNames)
6463{
6464 OSReturn result = kOSReturnError;
6465 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6466 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6467 unsigned int i, count;
6468 Boolean alreadyLoaded = false;
6469 OSKext * lastLoadedKext = NULL; // do not release
6470
6471 if (isInExcludeList()) {
6472 OSKextLog(aKext: this,
6473 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6474 kOSKextLogLoadFlag,
6475 format: "Kext %s is in exclude list, not loadable",
6476 getIdentifierCString());
6477
6478 result = kOSKextReturnNotLoadable;
6479 goto finish;
6480 }
6481 if (!isLoadable()) {
6482 OSKextLog(aKext: this,
6483 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6484 kOSKextLogLoadFlag,
6485 format: "Kext %s is not loadable",
6486 getIdentifierCString());
6487
6488 result = kOSKextReturnNotLoadable;
6489 goto finish;
6490 }
6491
6492 if (isLoaded()) {
6493 alreadyLoaded = true;
6494 result = kOSReturnSuccess;
6495
6496 OSKextLog(aKext: this,
6497 kOSKextLogDebugLevel |
6498 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6499 format: "Kext %s is already loaded.",
6500 getIdentifierCString());
6501 goto loaded;
6502 }
6503
6504#if CONFIG_MACF
6505 /*
6506 * On kxld and on embedded, only call into the MAC hook when on a
6507 * user thread, for access control over userspace kextloads.
6508 *
6509 * On non-kxld systems, additionally check the MAC hook for kexts in
6510 * the Pageable and Aux KCs, regardless of whether we are on a user
6511 * thread or not. This means on Apple silicon devices that the MAC
6512 * hook will only be useful to block 3rd party kexts loaded via
6513 * matching, and any kexts loaded from userspace kextloads.
6514 *
6515 * Note that this should _not_ be called on kexts loaded from the
6516 * kernel bootstrap thread as the kernel proc's cred struct is not
6517 * yet initialized! This won't happen on macOS because all the kexts
6518 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6519 */
6520 if (current_task() != kernel_task
6521#if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6522 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6523#endif
6524 ) {
6525 int macCheckResult = 0;
6526 kauth_cred_t cred = NULL;
6527
6528 cred = kauth_cred_get_with_ref();
6529 macCheckResult = mac_kext_check_load(cred, identifier: getIdentifierCString());
6530 kauth_cred_unref(&cred);
6531
6532 if (macCheckResult != 0) {
6533 result = kOSReturnError;
6534 OSKextLog(aKext: this,
6535 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6536 format: "Failed to load kext %s (MAC policy error 0x%x).",
6537 getIdentifierCString(), macCheckResult);
6538 goto finish;
6539 }
6540 }
6541#endif /* CONFIG_MACF */
6542
6543 if (!sLoadEnabled) {
6544 OSKextLog(aKext: this,
6545 kOSKextLogErrorLevel |
6546 kOSKextLogLoadFlag,
6547 format: "Kext loading is disabled (attempt to load kext %s).",
6548 getIdentifierCString());
6549 result = kOSKextReturnDisabled;
6550 goto finish;
6551 }
6552
6553 /* If we've pushed the next available load tag to the invalid value,
6554 * we can't load any more kexts.
6555 */
6556 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6557 OSKextLog(aKext: this,
6558 kOSKextLogErrorLevel |
6559 kOSKextLogLoadFlag,
6560 format: "Can't load kext %s - no more load tags to assign.",
6561 getIdentifierCString());
6562 result = kOSKextReturnNoResources;
6563 goto finish;
6564 }
6565
6566 /* This is a bit of a hack, because we shouldn't be handling
6567 * personalities within the load function.
6568 */
6569 if (!declaresExecutable()) {
6570 /* There is a special case where a non-executable kext can be loaded: the
6571 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6572 * load its metadata into the global data structures, if appropriate
6573 */
6574 if (strcmp(s1: getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6575 boolean_t updated = updateExcludeList(infoDict: infoDict.get());
6576 if (updated) {
6577 OSKextLog(aKext: this,
6578 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6579 format: "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6580 }
6581 }
6582
6583 if (isDriverKit()) {
6584 if (loadTag == 0) {
6585 sLoadedDriverKitKexts->setObject(this);
6586 loadTag = sNextLoadTag++;
6587 }
6588 }
6589 result = kOSReturnSuccess;
6590 goto loaded;
6591 }
6592
6593 /* Are we in safe boot?
6594 */
6595 if (sSafeBoot && !isLoadableInSafeBoot()) {
6596 OSKextLog(aKext: this,
6597 kOSKextLogErrorLevel |
6598 kOSKextLogLoadFlag,
6599 format: "Can't load kext %s - not loadable during safe boot.",
6600 getIdentifierCString());
6601 result = kOSKextReturnBootLevel;
6602 goto finish;
6603 }
6604
6605 OSKextLog(aKext: this,
6606 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6607 format: "Loading kext %s.",
6608 getIdentifierCString());
6609
6610#if !VM_MAPPED_KEXTS
6611 if (isPrelinked() == false) {
6612 OSKextLog(aKext: this,
6613 kOSKextLogErrorLevel |
6614 kOSKextLogLoadFlag,
6615 format: "Can't load kext %s - not in a kext collection.",
6616 getIdentifierCString());
6617 result = kOSKextReturnDisabled;
6618 goto finish;
6619 }
6620#endif /* defined(__x86_64__) */
6621
6622#if CONFIG_KXLD
6623 if (!sKxldContext) {
6624 kern_return_t kxldResult;
6625 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6626 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6627 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6628 if (kxldResult) {
6629 OSKextLog(this,
6630 kOSKextLogErrorLevel |
6631 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6632 "Can't load kext %s - failed to create link context.",
6633 getIdentifierCString());
6634 result = kOSKextReturnNoMemory;
6635 goto finish;
6636 }
6637 }
6638#endif // CONFIG_KXLD
6639
6640 /* We only need to resolve dependencies once for the whole graph, but
6641 * resolveDependencies will just return if there's no work to do, so it's
6642 * safe to call it more than once.
6643 */
6644 if (!resolveDependencies()) {
6645 // xxx - check resolveDependencies() for log msg
6646 OSKextLog(aKext: this,
6647 kOSKextLogErrorLevel |
6648 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6649 format: "Can't load kext %s - failed to resolve library dependencies.",
6650 getIdentifierCString());
6651 result = kOSKextReturnDependencies;
6652 goto finish;
6653 }
6654
6655 /* If we are excluding just the kext being loaded now (and not its
6656 * dependencies), drop the exclusion level to none so dependencies
6657 * start and/or add their personalities.
6658 */
6659 if (dependenciesStartOpt == kOSKextExcludeKext) {
6660 dependenciesStartOpt = kOSKextExcludeNone;
6661 }
6662
6663 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6664 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6665 }
6666
6667 /* Load the dependencies, recursively.
6668 */
6669 count = getNumDependencies();
6670 for (i = 0; i < count; i++) {
6671 OSKext * dependency = OSDynamicCast(OSKext,
6672 dependencies->getObject(i));
6673 if (dependency == NULL) {
6674 OSKextLog(aKext: this,
6675 kOSKextLogErrorLevel |
6676 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6677 format: "Internal error loading kext %s; dependency disappeared.",
6678 getIdentifierCString());
6679 result = kOSKextReturnInternalError;
6680 goto finish;
6681 }
6682
6683 /* Dependencies must be started accorting to the opt,
6684 * but not given the personality names of the main kext.
6685 */
6686 result = dependency->load(startOpt: dependenciesStartOpt,
6687 startMatchingOpt: dependenciesStartMatchingOpt,
6688 /* personalityNames */ NULL);
6689 if (result != KERN_SUCCESS) {
6690 OSKextLog(aKext: this,
6691 kOSKextLogErrorLevel |
6692 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6693 format: "Dependency %s of kext %s failed to load.",
6694 dependency->getIdentifierCString(),
6695 getIdentifierCString());
6696
6697 OSKext::removeKext(aKext: dependency,
6698 /* terminateService/removePersonalities */ terminateServicesAndRemovePersonalitiesFlag: true);
6699 result = kOSKextReturnDependencyLoadError;
6700
6701 goto finish;
6702 }
6703 }
6704
6705 result = loadExecutable();
6706 if (result != KERN_SUCCESS) {
6707 goto finish;
6708 }
6709
6710 pendingPgoHead.next = &pendingPgoHead;
6711 pendingPgoHead.prev = &pendingPgoHead;
6712
6713 // The kernel PRNG is not initialized when the first kext is
6714 // loaded, so use early random
6715 uuid_generate_early_random(out: instance_uuid);
6716 account = IOMallocType(OSKextAccount);
6717
6718 account->loadTag = kmod_info->id;
6719 account->site.refcount = 0;
6720 account->site.flags = VM_TAG_KMOD;
6721
6722#if DEVELOPMENT || DEBUG
6723 /* Setup the task reference group. */
6724 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6725 "task_%s", getIdentifierCString());
6726 account->task_refgrp.grp_name = account->task_refgrp_name;
6727 account->task_refgrp.grp_parent = &task_external_refgrp;
6728 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6729 os_ref_log_init(&account->task_refgrp);
6730#endif /* DEVELOPMENT || DEBUG */
6731
6732 account->kext = this;
6733 if (gIOSurfaceIdentifier == bundleID) {
6734 vm_tag_alloc(site: &account->site);
6735 gIOSurfaceTag = account->site.tag;
6736 }
6737
6738 flags.loaded = true;
6739
6740 /* Add the kext to the list of loaded kexts and update the kmod_info
6741 * struct to point to that of the last loaded kext (which is the way
6742 * it's always been done, though I'd rather do them in order now).
6743 */
6744 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6745 sLoadedKexts->setObject(this);
6746
6747 /* Keep the kernel itself out of the kmod list.
6748 */
6749 if (lastLoadedKext->isKernel()) {
6750 lastLoadedKext = NULL;
6751 }
6752
6753 if (lastLoadedKext) {
6754 kmod_info->next = lastLoadedKext->kmod_info;
6755 }
6756
6757 notifyKextLoadObservers(this, kmod_info);
6758
6759 /* Make the global kmod list point at the just-loaded kext. Note that the
6760 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6761 * although we do report it in kextstat these days by using the newer
6762 * OSArray of loaded kexts, which does contain it.
6763 *
6764 * (The OSKext object representing the kernel doesn't even have a kmod_info
6765 * struct, though I suppose we could stick a pointer to it from the
6766 * static struct in OSRuntime.cpp.)
6767 */
6768 kmod = kmod_info;
6769
6770 /* Save the list of loaded kexts in case we panic.
6771 */
6772 OSKext::saveLoadedKextPanicList();
6773
6774 if (isExecutable()) {
6775 OSKext::updateLoadedKextSummaries();
6776 savePanicString(/* isLoading */ true);
6777
6778#if CONFIG_DTRACE
6779 registerWithDTrace();
6780#else
6781 jettisonLinkeditSegment();
6782#endif /* CONFIG_DTRACE */
6783
6784#if !VM_MAPPED_KEXTS
6785 /* If there is a page (or more) worth of padding after the end
6786 * of the last data section but before the end of the data segment
6787 * then free it in the same manner the LinkeditSegment is freed
6788 */
6789 jettisonDATASegmentPadding();
6790#endif
6791 }
6792
6793loaded:
6794 if (isExecutable() && !flags.started) {
6795 if (startOpt == kOSKextExcludeNone) {
6796 result = start();
6797 if (result != kOSReturnSuccess) {
6798 OSKextLog(aKext: this,
6799 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6800 format: "Kext %s start failed (result 0x%x).",
6801 getIdentifierCString(), result);
6802 result = kOSKextReturnStartStopError;
6803 }
6804 }
6805 }
6806
6807 /* If not excluding matching, send the personalities to the kernel.
6808 * This never affects the result of the load operation.
6809 * This is a bit of a hack, because we shouldn't be handling
6810 * personalities within the load function.
6811 */
6812 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6813 result = sendPersonalitiesToCatalog(startMatching: true, personalityNames);
6814 }
6815
6816finish:
6817
6818 if (result != kOSReturnSuccess) {
6819 OSKextLog(aKext: this,
6820 kOSKextLogErrorLevel |
6821 kOSKextLogLoadFlag,
6822 format: "Kext %s failed to load (0x%x).",
6823 getIdentifierCString(), (int)result);
6824 } else if (!alreadyLoaded) {
6825 OSKextLog(aKext: this,
6826 kOSKextLogProgressLevel |
6827 kOSKextLogLoadFlag,
6828 format: "Kext %s loaded.",
6829 getIdentifierCString());
6830
6831 queueKextNotification(kKextRequestPredicateLoadNotification,
6832 OSDynamicCast(OSString, bundleID.get()), dextUniqueIdentifier: getDextUniqueID());
6833 }
6834 return result;
6835}
6836
6837#if CONFIG_KXLD
6838/*********************************************************************
6839*
6840*********************************************************************/
6841static char *
6842strdup(const char * string)
6843{
6844 char * result = NULL;
6845 size_t size;
6846
6847 if (!string) {
6848 goto finish;
6849 }
6850
6851 size = 1 + strlen(string);
6852 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6853 if (!result) {
6854 goto finish;
6855 }
6856
6857 memcpy(result, string, size);
6858
6859finish:
6860 return result;
6861}
6862#endif // CONFIG_KXLD
6863
6864/*********************************************************************
6865*
6866*********************************************************************/
6867
6868kernel_section_t *
6869OSKext::lookupSection(const char *segname, const char *secname)
6870{
6871 kernel_section_t * found_section = NULL;
6872 kernel_mach_header_t * mh = NULL;
6873 kernel_segment_command_t * seg = NULL;
6874 kernel_section_t * sec = NULL;
6875
6876 if (!linkedExecutable) {
6877 return NULL;
6878 }
6879
6880 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6881
6882 for (seg = firstsegfromheader(header: mh); seg != NULL; seg = nextsegfromheader(header: mh, seg)) {
6883 if (0 != strncmp(s1: seg->segname, s2: segname, n: sizeof(seg->segname))) {
6884 continue;
6885 }
6886
6887 for (sec = firstsect(sgp: seg); sec != NULL; sec = nextsect(sgp: seg, sp: sec)) {
6888 if (0 == strncmp(s1: sec->sectname, s2: secname, n: sizeof(sec->sectname))) {
6889 found_section = sec;
6890 goto out;
6891 }
6892 }
6893 }
6894
6895out:
6896 return found_section;
6897}
6898
6899/*********************************************************************
6900*
6901*********************************************************************/
6902
6903OSReturn
6904OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6905{
6906 OSReturn result = kOSKextReturnBadData;
6907 kernel_mach_header_t * mh = NULL;
6908 kernel_segment_command_t * seg = NULL;
6909 kernel_segment_command_t * linkeditSeg = NULL;
6910 kernel_section_t * sec = NULL;
6911 char * linkeditBase = NULL;
6912 bool haveLinkeditBase = false;
6913 char * relocBase = NULL;
6914 bool haveRelocBase = false;
6915 struct dysymtab_command * dysymtab = NULL;
6916 struct linkedit_data_command * segmentSplitInfo = NULL;
6917 struct symtab_command * symtab = NULL;
6918 kernel_nlist_t * sym = NULL;
6919 struct relocation_info * reloc = NULL;
6920 uint32_t i = 0;
6921 int reloc_size;
6922 vm_offset_t new_kextsize;
6923 kc_format format = KCFormatUnknown;
6924
6925 if (linkedExecutable == NULL || flags.builtin) {
6926 result = kOSReturnSuccess;
6927 goto finish;
6928 }
6929
6930 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6931 if (kernel_mach_header_is_in_fileset(mh)) {
6932 // kexts in filesets are slid as part of collection sliding
6933 result = kOSReturnSuccess;
6934 goto finish;
6935 }
6936
6937 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6938
6939 for (seg = firstsegfromheader(header: mh); seg != NULL; seg = nextsegfromheader(header: mh, seg)) {
6940 if (!seg->vmaddr) {
6941 continue;
6942 }
6943
6944 seg->vmaddr = ml_static_slide(vaddr: seg->vmaddr);
6945
6946#if KASLR_KEXT_DEBUG
6947 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6948 seg->segname,
6949 (unsigned long)ml_static_unslide(seg->vmaddr),
6950 (unsigned long)seg->vmaddr);
6951#endif
6952
6953 if (!haveRelocBase) {
6954 relocBase = (char *) seg->vmaddr;
6955 haveRelocBase = true;
6956 }
6957 if (!strcmp(s1: seg->segname, s2: "__LINKEDIT")) {
6958 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6959 haveLinkeditBase = true;
6960 linkeditSeg = seg;
6961 }
6962 for (sec = firstsect(sgp: seg); sec != NULL; sec = nextsect(sgp: seg, sp: sec)) {
6963 sec->addr = ml_static_slide(vaddr: sec->addr);
6964
6965#if KASLR_KEXT_DEBUG
6966 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6967 sec->sectname,
6968 (unsigned long)ml_static_unslide(sec->addr),
6969 (unsigned long)sec->addr);
6970#endif
6971 }
6972 }
6973
6974 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6975
6976 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6977
6978 if (symtab != NULL && doCoalescedSlides == false) {
6979 /* Some pseudo-kexts have symbol tables without segments.
6980 * Ignore them. */
6981 if (symtab->nsyms > 0 && haveLinkeditBase) {
6982 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6983 for (i = 0; i < symtab->nsyms; i++) {
6984 if (sym[i].n_type & N_STAB) {
6985 continue;
6986 }
6987 sym[i].n_value = ml_static_slide(vaddr: sym[i].n_value);
6988
6989#if KASLR_KEXT_DEBUG
6990#define MAX_SYMS_TO_LOG 5
6991 if (i < MAX_SYMS_TO_LOG) {
6992 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6993 (unsigned long)ml_static_unslide(sym[i].n_value),
6994 (unsigned long)sym[i].n_value);
6995 }
6996#endif
6997 }
6998 }
6999 }
7000
7001 if (dysymtab != NULL && doCoalescedSlides == false) {
7002 if (dysymtab->nextrel > 0) {
7003 OSKextLog(aKext: this,
7004 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7005 kOSKextLogLinkFlag,
7006 format: "Sliding kext %s: External relocations found.",
7007 getIdentifierCString());
7008 goto finish;
7009 }
7010
7011 if (dysymtab->nlocrel > 0) {
7012 if (!haveLinkeditBase) {
7013 OSKextLog(aKext: this,
7014 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7015 kOSKextLogLinkFlag,
7016 format: "Sliding kext %s: No linkedit segment.",
7017 getIdentifierCString());
7018 goto finish;
7019 }
7020
7021 if (!haveRelocBase) {
7022 OSKextLog(aKext: this,
7023 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7024 kOSKextLogLinkFlag,
7025#if __x86_64__
7026 "Sliding kext %s: No writable segments.",
7027#else
7028 format: "Sliding kext %s: No segments.",
7029#endif
7030 getIdentifierCString());
7031 goto finish;
7032 }
7033
7034 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
7035 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
7036
7037 for (i = 0; i < dysymtab->nlocrel; i++) {
7038 if (reloc[i].r_extern != 0
7039 || reloc[i].r_type != 0
7040 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
7041 ) {
7042 OSKextLog(aKext: this,
7043 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7044 kOSKextLogLinkFlag,
7045 format: "Sliding kext %s: Unexpected relocation found.",
7046 getIdentifierCString());
7047 goto finish;
7048 }
7049 if (reloc[i].r_pcrel != 0) {
7050 continue;
7051 }
7052 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
7053 *relocAddr = ml_static_slide(vaddr: *relocAddr);
7054
7055#if KASLR_KEXT_DEBUG
7056#define MAX_DYSYMS_TO_LOG 5
7057 if (i < MAX_DYSYMS_TO_LOG) {
7058 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
7059 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
7060 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
7061 }
7062#endif
7063 }
7064
7065 /* We should free these relocations, not just delete the reference to them.
7066 * <rdar://problem/10535549> Free relocations from PIE kexts.
7067 *
7068 * For now, we do not free LINKEDIT for kexts with split segments.
7069 */
7070 new_kextsize = round_page(x: kmod_info->size - reloc_size);
7071 if (new_kextsize > UINT_MAX) {
7072 OSKextLog(aKext: this,
7073 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7074 kOSKextLogLinkFlag,
7075 format: "Kext %s: new kext size is too large.",
7076 getIdentifierCString());
7077 goto finish;
7078 }
7079 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
7080 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
7081 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
7082 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
7083 size_t bytes_remaining = endofkext - endofrelocInfo;
7084 OSSharedPtr<OSData> new_osdata;
7085
7086 /* fix up symbol offsets if they are after the dsymtab local relocs */
7087 if (symtab) {
7088 if (dysymtab->locreloff < symtab->symoff) {
7089 symtab->symoff -= reloc_size;
7090 }
7091 if (dysymtab->locreloff < symtab->stroff) {
7092 symtab->stroff -= reloc_size;
7093 }
7094 }
7095 if (dysymtab->locreloff < dysymtab->extreloff) {
7096 dysymtab->extreloff -= reloc_size;
7097 }
7098
7099 /* move data behind reloc info down to new offset */
7100 if (endofrelocInfo < endofkext) {
7101 memcpy(dst: reloc, src: (void *)endofrelocInfo, n: bytes_remaining);
7102 }
7103
7104 /* Create a new OSData for the smaller kext object and reflect
7105 * new linkedit segment size.
7106 */
7107 linkeditSeg->vmsize = round_page(x: linkeditSeg->vmsize - reloc_size);
7108 linkeditSeg->filesize = linkeditSeg->vmsize;
7109
7110 new_osdata = OSData::withBytesNoCopy(bytes: (void *)kmod_info->address, numBytes: (unsigned int)new_kextsize);
7111 if (new_osdata) {
7112 /* Fix up kmod info and linkedExecutable.
7113 */
7114 kmod_info->size = new_kextsize;
7115 /*
7116 * Fileset KCs are mapped as a whole by iBoot.
7117 * Individual kext executables should not be unmapped
7118 * by xnu.
7119 * Doing so may result in panics like rdar://85419651
7120 */
7121 if (PE_get_kc_format(type: kc_type, format: &format) && (format == KCFormatFileset)) {
7122 new_osdata->setDeallocFunction(NULL);
7123 } else { // Not from a Fileset KC
7124#if VM_MAPPED_KEXTS
7125 new_osdata->setDeallocFunction(osdata_kext_free);
7126#else
7127 new_osdata->setDeallocFunction(osdata_phys_free);
7128#endif
7129 }
7130 linkedExecutable->setDeallocFunction(NULL);
7131 linkedExecutable = os::move(t&: new_osdata);
7132
7133#if VM_MAPPED_KEXTS
7134 kext_free(new_endofkext, (endofkext - new_endofkext));
7135#else
7136 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
7137#endif
7138 }
7139 }
7140 dysymtab->nlocrel = 0;
7141 dysymtab->locreloff = 0;
7142 }
7143 }
7144
7145 result = kOSReturnSuccess;
7146finish:
7147 return result;
7148}
7149
7150/*********************************************************************
7151* called only by load()
7152*********************************************************************/
7153OSReturn
7154OSKext::loadExecutable()
7155{
7156 OSReturn result = kOSReturnError;
7157 OSSharedPtr<OSArray> linkDependencies;
7158 uint32_t num_kmod_refs = 0;
7159 OSData * theExecutable = NULL; // do not release
7160 OSString * versString = NULL; // do not release
7161 const char * versCString = NULL; // do not free
7162 const char * string = NULL; // do not free
7163
7164#if CONFIG_KXLD
7165 unsigned int i;
7166 uint32_t numDirectDependencies = 0;
7167 kern_return_t kxldResult;
7168 KXLDDependency * kxlddeps = NULL; // must kfree
7169 uint32_t num_kxlddeps = 0;
7170 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7171 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7172#endif // CONFIG_KXLD
7173
7174 /* We need the version string for a variety of bits below.
7175 */
7176 versString = OSDynamicCast(OSString,
7177 getPropertyForHostArch(kCFBundleVersionKey));
7178 if (!versString) {
7179 goto finish;
7180 }
7181 versCString = versString->getCStringNoCopy();
7182
7183 if (isKernelComponent()) {
7184 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7185 if (strncmp(s1: versCString, KERNEL6_VERSION, n: strlen(KERNEL6_VERSION))) {
7186 OSKextLog(aKext: this,
7187 kOSKextLogErrorLevel |
7188 kOSKextLogLoadFlag,
7189 format: "Kernel component %s has incorrect version %s; "
7190 "expected %s.",
7191 getIdentifierCString(),
7192 versCString, KERNEL6_VERSION);
7193 result = kOSKextReturnInternalError;
7194 goto finish;
7195 } else if (strcmp(s1: versCString, s2: osrelease)) {
7196 OSKextLog(aKext: this,
7197 kOSKextLogErrorLevel |
7198 kOSKextLogLoadFlag,
7199 format: "Kernel component %s has incorrect version %s; "
7200 "expected %s.",
7201 getIdentifierCString(),
7202 versCString, osrelease);
7203 result = kOSKextReturnInternalError;
7204 goto finish;
7205 }
7206 }
7207 }
7208
7209#if defined(__x86_64__) || defined(__i386__)
7210 if (flags.resetSegmentsFromVnode) {
7211 /* Fixup the chains and slide the mach headers */
7212 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7213
7214 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7215 result = kOSKextReturnValidation;
7216 goto finish;
7217 }
7218 }
7219#endif //(__x86_64__) || defined(__i386__)
7220
7221 if (isPrelinked()) {
7222 goto register_kmod;
7223 }
7224
7225 /* <rdar://problem/21444003> all callers must be entitled */
7226 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7227 OSKextLog(aKext: this,
7228 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7229 format: "Not entitled to link kext '%s'",
7230 getIdentifierCString());
7231 result = kOSKextReturnNotPrivileged;
7232 goto finish;
7233 }
7234
7235 theExecutable = getExecutable();
7236 if (!theExecutable) {
7237 if (declaresExecutable()) {
7238 OSKextLog(aKext: this,
7239 kOSKextLogErrorLevel |
7240 kOSKextLogLoadFlag,
7241 format: "Can't load kext %s - executable is missing.",
7242 getIdentifierCString());
7243 result = kOSKextReturnValidation;
7244 goto finish;
7245 }
7246 goto register_kmod;
7247 }
7248
7249 if (isInterface()) {
7250 OSSharedPtr<OSData> executableCopy = OSData::withData(inData: theExecutable);
7251 if (executableCopy) {
7252 setLinkedExecutable(executableCopy.get());
7253 }
7254 goto register_kmod;
7255 }
7256
7257#if CONFIG_KXLD
7258 numDirectDependencies = getNumDependencies();
7259
7260 if (flags.hasBleedthrough) {
7261 linkDependencies = dependencies;
7262 } else {
7263 linkDependencies = OSArray::withArray(dependencies.get());
7264 if (!linkDependencies) {
7265 OSKextLog(this,
7266 kOSKextLogErrorLevel |
7267 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7268 "Can't allocate link dependencies to load kext %s.",
7269 getIdentifierCString());
7270 goto finish;
7271 }
7272
7273 for (i = 0; i < numDirectDependencies; ++i) {
7274 OSKext * dependencyKext = OSDynamicCast(OSKext,
7275 dependencies->getObject(i));
7276 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7277 }
7278 }
7279
7280 num_kxlddeps = linkDependencies->getCount();
7281 if (!num_kxlddeps) {
7282 OSKextLog(this,
7283 kOSKextLogErrorLevel |
7284 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7285 "Can't load kext %s - it has no library dependencies.",
7286 getIdentifierCString());
7287 goto finish;
7288 }
7289
7290 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7291 if (!kxlddeps) {
7292 OSKextLog(this,
7293 kOSKextLogErrorLevel |
7294 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7295 "Can't allocate link context to load kext %s.",
7296 getIdentifierCString());
7297 goto finish;
7298 }
7299 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7300
7301 for (i = 0; i < num_kxlddeps; ++i) {
7302 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7303
7304 if (dependency->isInterface()) {
7305 OSKext *interfaceTargetKext = NULL; //do not release
7306 OSData * interfaceTarget = NULL; //do not release
7307
7308 if (dependency->isKernelComponent()) {
7309 interfaceTargetKext = sKernelKext;
7310 interfaceTarget = sKernelKext->linkedExecutable.get();
7311 } else {
7312 interfaceTargetKext = OSDynamicCast(OSKext,
7313 dependency->dependencies->getObject(0));
7314
7315 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7316 }
7317
7318 if (!interfaceTarget) {
7319 // panic?
7320 goto finish;
7321 }
7322
7323 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7324 * it will be useful to have them in the debugger.
7325 * strdup() failing isn't critical right here so we don't check that.
7326 */
7327 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7328 kxlddeps[i].kext_size = interfaceTarget->getLength();
7329 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7330
7331 if (dependency->linkedExecutable != NULL) {
7332 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7333 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7334 } else {
7335 kxlddeps[i].interface = (u_char *) NULL;
7336 kxlddeps[i].interface_size = 0;
7337 }
7338 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7339 } else {
7340 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7341 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7342 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7343 }
7344
7345 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7346 }
7347
7348 kxldHeaderPtr = &kxld_header;
7349
7350#if DEBUG
7351 OSKextLog(this,
7352 kOSKextLogExplicitLevel |
7353 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7354 "Kext %s - calling kxld_link_file:\n"
7355 " kxld_context: %p\n"
7356 " executable: %p executable_length: %d\n"
7357 " user_data: %p\n"
7358 " kxld_dependencies: %p num_dependencies: %d\n"
7359 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7360 getIdentifierCString(), sKxldContext,
7361 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7362 this, kxlddeps, num_kxlddeps,
7363 kxldHeaderPtr, &kmod_info);
7364#endif
7365
7366 /* After this call, the linkedExecutable instance variable
7367 * should exist.
7368 */
7369 kxldResult = kxld_link_file(sKxldContext,
7370 (u_char *)theExecutable->getBytesNoCopy(),
7371 theExecutable->getLength(),
7372 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7373 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7374
7375 if (kxldResult != KERN_SUCCESS) {
7376 // xxx - add kxldResult here?
7377 OSKextLog(this,
7378 kOSKextLogErrorLevel |
7379 kOSKextLogLoadFlag,
7380 "Can't load kext %s - link failed.",
7381 getIdentifierCString());
7382 result = kOSKextReturnLinkError;
7383 goto finish;
7384 }
7385
7386 /* We've written data & instructions into kernel memory, so flush the data
7387 * cache and invalidate the instruction cache.
7388 * I/D caches are coherent on x86
7389 */
7390#if !defined(__i386__) && !defined(__x86_64__)
7391 flush_dcache(kmod_info->address, kmod_info->size, false);
7392 invalidate_icache(kmod_info->address, kmod_info->size, false);
7393#endif
7394
7395#else // !CONFIG_KXLD
7396 OSKextLog(aKext: this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7397 format: "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7398 result = kOSKextReturnLinkError;
7399 goto finish;
7400#endif // CONFIG_KXLD
7401
7402register_kmod:
7403
7404 if (isInterface()) {
7405 /* Whip up a fake kmod_info entry for the interface kext.
7406 */
7407 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7408 if (!kmod_info) {
7409 result = KERN_MEMORY_ERROR;
7410 goto finish;
7411 }
7412
7413 /* A pseudokext has almost nothing in its kmod_info struct.
7414 */
7415 kmod_info->info_version = KMOD_INFO_VERSION;
7416
7417 /* An interface kext doesn't have a linkedExecutable, so save a
7418 * copy of the UUID out of the original executable via copyUUID()
7419 * while we still have the original executable.
7420 */
7421 interfaceUUID = copyUUID();
7422 }
7423
7424 kmod_info->id = loadTag = sNextLoadTag++;
7425 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7426
7427 /* Stamp the bundle ID and version from the OSKext over anything
7428 * resident inside the kmod_info.
7429 */
7430 string = getIdentifierCString();
7431 strlcpy(dst: kmod_info->name, src: string, n: sizeof(kmod_info->name));
7432
7433 string = versCString;
7434 strlcpy(dst: kmod_info->version, src: string, n: sizeof(kmod_info->version));
7435
7436 /* Add the dependencies' kmod_info structs as kmod_references.
7437 */
7438 num_kmod_refs = getNumDependencies();
7439 if (num_kmod_refs) {
7440 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7441 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7442 if (!kmod_info->reference_list) {
7443 result = KERN_MEMORY_ERROR;
7444 goto finish;
7445 }
7446 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7447 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7448 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7449 ref->info = refKext->kmod_info;
7450 ref->info->reference_count++;
7451
7452 if (refIndex + 1 < num_kmod_refs) {
7453 ref->next = kmod_info->reference_list + refIndex + 1;
7454 }
7455 }
7456 }
7457
7458 if (kmod_info->hdr_size > UINT32_MAX) {
7459 OSKextLog(aKext: this,
7460 kOSKextLogErrorLevel |
7461 kOSKextLogLoadFlag,
7462#if __LP64__
7463 format: "Kext %s header size is too large (%lu > UINT32_MAX).",
7464#else
7465 "Kext %s header size is too large (%u > UINT32_MAX).",
7466#endif
7467 kmod_info->name,
7468 kmod_info->hdr_size);
7469 result = KERN_FAILURE;
7470 goto finish;
7471 }
7472
7473 if (kmod_info->size > UINT32_MAX) {
7474 OSKextLog(aKext: this,
7475 kOSKextLogErrorLevel |
7476 kOSKextLogLoadFlag,
7477#if __LP64__
7478 format: "Kext %s size is too large (%lu > UINT32_MAX).",
7479#else
7480 "Kext %s size is too large (%u > UINT32_MAX).",
7481#endif
7482 kmod_info->name,
7483 kmod_info->size);
7484 result = KERN_FAILURE;
7485 goto finish;
7486 }
7487
7488 if (!isInterface() && linkedExecutable) {
7489 OSKextLog(aKext: this,
7490 kOSKextLogProgressLevel |
7491 kOSKextLogLoadFlag,
7492 format: "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7493 kmod_info->name,
7494 (unsigned)kmod_info->size / PAGE_SIZE,
7495 (unsigned long)ml_static_unslide(vaddr: kmod_info->address),
7496 (unsigned)kmod_info->id);
7497 }
7498
7499 /* VM protections and wiring for the Aux KC are done at collection loading time */
7500 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7501 /* if prelinked and primary KC, VM protections are already set */
7502 result = setVMAttributes(protect: !isPrelinked() || flags.resetSegmentsFromVnode, wire: true);
7503 if (result != KERN_SUCCESS) {
7504 goto finish;
7505 }
7506 }
7507
7508#if KASAN
7509 if (linkedExecutable) {
7510 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7511 linkedExecutable->getLength(), getIdentifierCString());
7512 }
7513#else
7514 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7515 OSKextLog(aKext: this,
7516 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7517 format: "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7518 getIdentifierCString()
7519 );
7520 result = KERN_FAILURE;
7521 goto finish;
7522 }
7523#endif
7524
7525 result = kOSReturnSuccess;
7526
7527finish:
7528
7529#if CONFIG_KXLD
7530 /* Clear up locally allocated dependency info.
7531 */
7532 for (i = 0; i < num_kxlddeps; ++i) {
7533 size_t size;
7534
7535 if (kxlddeps[i].kext_name) {
7536 size = 1 + strlen(kxlddeps[i].kext_name);
7537 kfree_data(kxlddeps[i].kext_name, size);
7538 }
7539 if (kxlddeps[i].interface_name) {
7540 size = 1 + strlen(kxlddeps[i].interface_name);
7541 kfree_data(kxlddeps[i].interface_name, size);
7542 }
7543 }
7544 if (kxlddeps) {
7545 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7546 }
7547#endif // CONFIG_KXLD
7548
7549 /* We no longer need the unrelocated executable (which the linker
7550 * has altered anyhow).
7551 */
7552 setExecutable(NULL);
7553
7554 if (result != kOSReturnSuccess) {
7555 OSKextLog(aKext: this,
7556 kOSKextLogErrorLevel |
7557 kOSKextLogLoadFlag,
7558 format: "Failed to load executable for kext %s.",
7559 getIdentifierCString());
7560
7561 if (kmod_info && kmod_info->reference_list) {
7562 kfree_type(kmod_reference_t, num_kmod_refs,
7563 kmod_info->reference_list);
7564 }
7565 if (isInterface()) {
7566 kfree_type(kmod_info_t, kmod_info);
7567 kmod_info = NULL;
7568 }
7569 if (kc_type == KCKindUnknown) {
7570 kmod_info = NULL;
7571 if (linkedExecutable) {
7572 linkedExecutable.reset();
7573 }
7574 }
7575 }
7576
7577 return result;
7578}
7579
7580/* static */
7581void
7582OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7583{
7584 kernel_segment_command_t *linkeditseg = NULL;
7585
7586 linkeditseg = getsegbynamefromheader(header: mh, SEG_LINKEDIT);
7587 if (linkeditseg == NULL) {
7588 panic("FileSet booted with no Linkedit segment");
7589 }
7590
7591#if VM_MAPPED_KEXTS
7592 /* BootKC on x86_64 is not vm mapped */
7593 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7594
7595 OSKextLog(/* kext */ NULL,
7596 kOSKextLogProgressLevel |
7597 kOSKextLogGeneralFlag,
7598 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7599 linkeditseg->vmaddr, linkeditseg->vmsize);
7600#else
7601 /* BootKC on arm64 is not vm mapped, but is slid */
7602#if !CONFIG_SPTM
7603 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7604#else
7605 vm_offset_t linkedit_vmaddr = linkeditseg->vmaddr;
7606#endif
7607
7608 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7609
7610 OSKextLog(/* kext */ NULL,
7611 kOSKextLogProgressLevel |
7612 kOSKextLogGeneralFlag,
7613 format: "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7614 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7615#endif /* VM_MAPPED_KEXTS */
7616}
7617
7618/*********************************************************************
7619* The linkedit segment is used by the kext linker for dependency
7620* resolution, and by dtrace for probe initialization. We can free it
7621* for non-library kexts, since no kexts depend on non-library kexts
7622* by definition, once dtrace has been initialized.
7623*********************************************************************/
7624void
7625OSKext::jettisonLinkeditSegment(void)
7626{
7627 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7628 kernel_segment_command_t * linkedit = NULL;
7629 vm_offset_t start;
7630 vm_size_t linkeditsize, kextsize;
7631 OSSharedPtr<OSData> data;
7632 kc_format format = KCFormatUnknown;
7633
7634 if (isInFileset()) {
7635 return;
7636 }
7637
7638#if NO_KEXTD
7639 /* We can free symbol tables for all embedded kexts because we don't
7640 * support runtime kext linking.
7641 */
7642 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7643#else
7644 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7645#endif
7646 goto finish;
7647 }
7648
7649 /* Find the linkedit segment. If it's not the last segment, then freeing
7650 * it will fragment the kext into multiple VM regions, which OSKext is not
7651 * designed to handle, so we'll have to skip it.
7652 */
7653 linkedit = getsegbynamefromheader(header: machhdr, SEG_LINKEDIT);
7654 if (!linkedit) {
7655 goto finish;
7656 }
7657
7658 if (round_page(x: kmod_info->address + kmod_info->size) !=
7659 round_page(x: linkedit->vmaddr + linkedit->vmsize)) {
7660 goto finish;
7661 }
7662
7663 /* Create a new OSData for the smaller kext object.
7664 */
7665 linkeditsize = round_page(x: linkedit->vmsize);
7666 kextsize = kmod_info->size - linkeditsize;
7667 start = linkedit->vmaddr;
7668
7669 if (kextsize > UINT_MAX) {
7670 goto finish;
7671 }
7672 data = OSData::withBytesNoCopy(bytes: (void *)kmod_info->address, numBytes: (unsigned int)kextsize);
7673 if (!data) {
7674 goto finish;
7675 }
7676
7677 /* Fix the kmod info and linkedExecutable.
7678 */
7679 kmod_info->size = kextsize;
7680
7681 /*
7682 * Fileset KCs are mapped as a whole by iBoot.
7683 * Individual kext executables should not be unmapped by xnu
7684 * Doing so may result in panics like rdar://85419651
7685 */
7686 if (PE_get_kc_format(type: kc_type, format: &format) && (format == KCFormatFileset)) {
7687 data->setDeallocFunction(NULL);
7688 } else { // Not from a Fileset KC
7689#if VM_MAPPED_KEXTS
7690 data->setDeallocFunction(osdata_kext_free);
7691#else
7692 data->setDeallocFunction(osdata_phys_free);
7693#endif
7694 }
7695 linkedExecutable->setDeallocFunction(NULL);
7696 linkedExecutable = os::move(t&: data);
7697 flags.jettisonLinkeditSeg = 1;
7698
7699 /* Free the linkedit segment.
7700 */
7701#if VM_MAPPED_KEXTS
7702 kext_free(start, linkeditsize);
7703#else
7704 ml_static_mfree(start, linkeditsize);
7705#endif
7706
7707finish:
7708 return;
7709}
7710
7711/*********************************************************************
7712* If there are whole pages that are unused betweem the last section
7713* of the DATA segment and the end of the DATA segment then we can free
7714* them
7715*********************************************************************/
7716void
7717OSKext::jettisonDATASegmentPadding(void)
7718{
7719 kernel_mach_header_t * mh;
7720 kernel_segment_command_t * dataSeg;
7721 kernel_section_t * sec, * lastSec;
7722 vm_offset_t dataSegEnd, lastSecEnd;
7723 vm_size_t padSize;
7724
7725 if (flags.builtin) {
7726 return;
7727 }
7728 mh = (kernel_mach_header_t *)kmod_info->address;
7729
7730 if (isInFileset()) {
7731 return;
7732 }
7733
7734 dataSeg = getsegbynamefromheader(header: mh, SEG_DATA);
7735 if (dataSeg == NULL) {
7736 return;
7737 }
7738
7739 lastSec = NULL;
7740 sec = firstsect(sgp: dataSeg);
7741 while (sec != NULL) {
7742 lastSec = sec;
7743 sec = nextsect(sgp: dataSeg, sp: sec);
7744 }
7745
7746 if (lastSec == NULL) {
7747 return;
7748 }
7749
7750 if ((dataSeg->vmaddr != round_page(x: dataSeg->vmaddr)) ||
7751 (dataSeg->vmsize != round_page(x: dataSeg->vmsize))) {
7752 return;
7753 }
7754
7755 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7756 lastSecEnd = round_page(x: lastSec->addr + lastSec->size);
7757
7758 if (dataSegEnd <= lastSecEnd) {
7759 return;
7760 }
7761
7762 padSize = dataSegEnd - lastSecEnd;
7763
7764 if (padSize >= PAGE_SIZE) {
7765#if VM_MAPPED_KEXTS
7766 kext_free(lastSecEnd, padSize);
7767#else
7768 ml_static_mfree(lastSecEnd, padSize);
7769#endif
7770 }
7771}
7772
7773/*********************************************************************
7774*********************************************************************/
7775void
7776OSKext::setLinkedExecutable(OSData * anExecutable)
7777{
7778 if (linkedExecutable) {
7779 panic("Attempt to set linked executable on kext "
7780 "that already has one (%s).\n",
7781 getIdentifierCString());
7782 }
7783 linkedExecutable.reset(p: anExecutable, OSRetain);
7784 return;
7785}
7786
7787#if CONFIG_DTRACE
7788/*********************************************************************
7789* Go through all loaded kexts and tell them to register with dtrace.
7790* The instance method only registers if necessary.
7791*********************************************************************/
7792/* static */
7793void
7794OSKext::registerKextsWithDTrace(void)
7795{
7796 uint32_t count = sLoadedKexts->getCount();
7797 uint32_t i;
7798
7799 IORecursiveLockLock(lock: sKextLock);
7800
7801 for (i = 0; i < count; i++) {
7802 OSKext * thisKext = NULL; // do not release
7803
7804 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7805 if (!thisKext || !thisKext->isExecutable()) {
7806 continue;
7807 }
7808
7809 thisKext->registerWithDTrace();
7810 }
7811
7812 IORecursiveLockUnlock(lock: sKextLock);
7813
7814 return;
7815}
7816
7817extern "C" {
7818extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7819extern int (*dtrace_modunload)(struct kmod_info *);
7820};
7821
7822/*********************************************************************
7823*********************************************************************/
7824void
7825OSKext::registerWithDTrace(void)
7826{
7827 /* Register kext with dtrace. A dtrace_modload failure should not
7828 * prevent a kext from loading, so we ignore the return code.
7829 */
7830 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7831 uint32_t modflag = 0;
7832 OSObject * forceInit = getPropertyForHostArch(key: "OSBundleForceDTraceInit");
7833
7834 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7835 if (forceInit == kOSBooleanTrue) {
7836 OSKextLog(aKext: this,
7837 kOSKextLogBasicLevel |
7838 kOSKextLogGeneralFlag,
7839 format: "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7840 getIdentifierCString());
7841 forceInit = kOSBooleanFalse;
7842 }
7843 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7844 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7845 }
7846
7847 if (forceInit == kOSBooleanTrue) {
7848 modflag |= KMOD_DTRACE_FORCE_INIT;
7849 }
7850 if (flags.builtin) {
7851 modflag |= KMOD_DTRACE_STATIC_KEXT;
7852 }
7853
7854 (void)(*dtrace_modload)(kmod_info, modflag);
7855 flags.dtraceInitialized = true;
7856 jettisonLinkeditSegment();
7857 }
7858 return;
7859}
7860/*********************************************************************
7861*********************************************************************/
7862void
7863OSKext::unregisterWithDTrace(void)
7864{
7865 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7866 * prevent a kext from loading, so we ignore the return code.
7867 */
7868 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7869 (void)(*dtrace_modunload)(kmod_info);
7870 flags.dtraceInitialized = false;
7871 }
7872 return;
7873}
7874#endif /* CONFIG_DTRACE */
7875
7876
7877/*********************************************************************
7878* called only by loadExecutable()
7879*********************************************************************/
7880#if !VM_MAPPED_KEXTS
7881#if defined(__arm__) || defined(__arm64__)
7882static inline kern_return_t
7883OSKext_protect(
7884 kernel_mach_header_t *kext_mh,
7885 vm_map_t map,
7886 vm_map_offset_t start,
7887 vm_map_offset_t end,
7888 vm_prot_t new_prot,
7889 boolean_t set_max,
7890 kc_kind_t kc_type)
7891{
7892#pragma unused(kext_mh,map,kc_type)
7893 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7894 assert(start <= end);
7895 if (start >= end) {
7896 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7897 } else if (set_max) {
7898 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7899 } else {
7900 return ml_static_protect(start, size: end - start, new_prot);
7901 }
7902}
7903
7904static inline kern_return_t
7905OSKext_wire(
7906 kernel_mach_header_t *kext_mh,
7907 vm_map_t map,
7908 vm_map_offset_t start,
7909 vm_map_offset_t end,
7910 vm_prot_t access_type,
7911 boolean_t user_wire,
7912 kc_kind_t kc_type)
7913{
7914#pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7915 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7916}
7917#else
7918#error Unrecognized architecture
7919#endif
7920#else
7921static inline kern_return_t
7922OSKext_protect(
7923 kernel_mach_header_t *kext_mh,
7924 vm_map_t map,
7925 vm_map_offset_t start,
7926 vm_map_offset_t end,
7927 vm_prot_t new_prot,
7928 boolean_t set_max,
7929 kc_kind_t kc_type)
7930{
7931 if (start == end) { // 10538581
7932 return KERN_SUCCESS;
7933 }
7934 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7935 /*
7936 * XXX: This will probably need to be different for AuxKC and
7937 * pageableKC!
7938 */
7939 return ml_static_protect(start, end - start, new_prot);
7940 }
7941 return vm_map_protect(map, start, end, new_prot, set_max);
7942}
7943
7944static inline kern_return_t
7945OSKext_wire(
7946 kernel_mach_header_t *kext_mh,
7947 vm_map_t map,
7948 vm_map_offset_t start,
7949 vm_map_offset_t end,
7950 vm_prot_t access_type,
7951 boolean_t user_wire,
7952 kc_kind_t kc_type)
7953{
7954 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7955 /* TODO: we may need to hook this for the pageableKC */
7956 return KERN_SUCCESS;
7957 }
7958 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7959}
7960#endif
7961
7962OSReturn
7963OSKext::setVMAttributes(bool protect, bool wire)
7964{
7965 vm_map_t kext_map = NULL;
7966 kernel_segment_command_t * seg = NULL;
7967 vm_map_offset_t start_protect = 0;
7968 vm_map_offset_t start_wire = 0;
7969 vm_map_offset_t end_protect = 0;
7970 vm_map_offset_t end_wire = 0;
7971 OSReturn result = kOSReturnError;
7972
7973 if (isInterface() || !declaresExecutable() || flags.builtin) {
7974 result = kOSReturnSuccess;
7975 goto finish;
7976 }
7977
7978 /* Get the kext's vm map */
7979 kext_map = kext_get_vm_map(info: kmod_info);
7980 if (!kext_map) {
7981 result = KERN_MEMORY_ERROR;
7982 goto finish;
7983 }
7984
7985#if !VM_MAPPED_KEXTS
7986 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7987 /* This is a split kext in a prelinked kernelcache; we'll let the
7988 * platform code take care of protecting it. It is already wired.
7989 */
7990 /* TODO: Should this still allow protections for the first segment
7991 * to go through, in the event that we have a mix of split and
7992 * unsplit kexts?
7993 */
7994 result = KERN_SUCCESS;
7995 goto finish;
7996 }
7997
7998 if (isInFileset() && kc_type != KCKindPageable) {
7999 // kexts in filesets have protections setup as part of collection loading
8000 result = KERN_SUCCESS;
8001 goto finish;
8002 }
8003#endif
8004
8005 /* Protect the headers as read-only; they do not need to be wired */
8006 result = (protect) ? OSKext_protect(kext_mh: (kernel_mach_header_t *)kmod_info->address,
8007 map: kext_map, start: kmod_info->address,
8008 end: kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
8009 : KERN_SUCCESS;
8010 if (result != KERN_SUCCESS) {
8011 goto finish;
8012 }
8013
8014 /* Set the VM protections and wire down each of the segments */
8015 seg = firstsegfromheader(header: (kernel_mach_header_t *)kmod_info->address);
8016 while (seg) {
8017#if __arm__
8018 /* We build all ARM kexts, so we can ensure they are aligned */
8019 assert((seg->vmaddr & PAGE_MASK) == 0);
8020 assert((seg->vmsize & PAGE_MASK) == 0);
8021#endif
8022
8023 /*
8024 * For the non page aligned segments, the range calculation for protection
8025 * and wiring differ as follows:
8026 *
8027 * Protection: The non page aligned data at the start or at the end of the
8028 * segment is excluded from the protection. This exclusion is needed to make
8029 * sure OSKext_protect is not called twice on same page, if the page is shared
8030 * between two segments.
8031 *
8032 * Wiring: The non page aligned data at the start or at the end of the
8033 * segment is included in the wiring range, this inclusion is needed to make sure
8034 * all the data of the segment is wired.
8035 */
8036 start_protect = round_page(x: seg->vmaddr);
8037 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
8038
8039 start_wire = trunc_page(seg->vmaddr);
8040 end_wire = round_page(x: seg->vmaddr + seg->vmsize);
8041
8042 /*
8043 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
8044 * across kexts and data from kexts is not page aligned
8045 */
8046 if (protect && (end_protect > start_protect) &&
8047 ((strncmp(s1: seg->segname, SEG_LINKEDIT, n: sizeof(seg->segname)) != 0 &&
8048 strncmp(s1: seg->segname, SEG_LINKINFO, n: sizeof(seg->segname)) != 0) ||
8049 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
8050 result = OSKext_protect(kext_mh: (kernel_mach_header_t *)kmod_info->address,
8051 map: kext_map, start: start_protect, end: end_protect, new_prot: seg->maxprot, TRUE, kc_type);
8052 if (result != KERN_SUCCESS) {
8053 OSKextLog(aKext: this,
8054 kOSKextLogErrorLevel |
8055 kOSKextLogLoadFlag,
8056 format: "Kext %s failed to set maximum VM protections "
8057 "for segment %s - 0x%x.",
8058 getIdentifierCString(), seg->segname, (int)result);
8059 goto finish;
8060 }
8061
8062 result = OSKext_protect(kext_mh: (kernel_mach_header_t *)kmod_info->address,
8063 map: kext_map, start: start_protect, end: end_protect, new_prot: seg->initprot, FALSE, kc_type);
8064 if (result != KERN_SUCCESS) {
8065 OSKextLog(aKext: this,
8066 kOSKextLogErrorLevel |
8067 kOSKextLogLoadFlag,
8068 format: "Kext %s failed to set initial VM protections "
8069 "for segment %s - 0x%x.",
8070 getIdentifierCString(), seg->segname, (int)result);
8071 goto finish;
8072 }
8073 }
8074
8075 if (segmentShouldBeWired(seg) && wire) {
8076 result = OSKext_wire(kext_mh: (kernel_mach_header_t *)kmod_info->address,
8077 map: kext_map, start: start_wire, end: end_wire, access_type: seg->initprot, FALSE, kc_type);
8078 if (result != KERN_SUCCESS) {
8079 goto finish;
8080 }
8081 }
8082
8083 seg = nextsegfromheader(header: (kernel_mach_header_t *) kmod_info->address, seg);
8084 }
8085
8086finish:
8087 return result;
8088}
8089
8090/*********************************************************************
8091*********************************************************************/
8092boolean_t
8093OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
8094{
8095 return sKeepSymbols || (strncmp(s1: seg->segname, SEG_LINKEDIT, n: sizeof(seg->segname)) &&
8096 strncmp(s1: seg->segname, SEG_LINKINFO, n: sizeof(seg->segname)));
8097}
8098
8099/*********************************************************************
8100*********************************************************************/
8101OSReturn
8102OSKext::validateKextMapping(bool startFlag)
8103{
8104 OSReturn result = kOSReturnError;
8105 const char * whichOp = startFlag ? "start" : "stop";
8106 kern_return_t kern_result = 0;
8107 vm_map_t kext_map = NULL;
8108 kernel_segment_command_t * seg = NULL;
8109 mach_vm_address_t address = 0;
8110 mach_vm_size_t size = 0;
8111 uint32_t depth = 0;
8112 uint64_t kext_segbase = 0;
8113 uint64_t kext_segsize = 0;
8114 mach_msg_type_number_t count;
8115 vm_region_submap_short_info_data_64_t info;
8116 uintptr_t kext_slide = PE_get_kc_slide(type: kc_type);
8117
8118 if (flags.builtin) {
8119 return kOSReturnSuccess;
8120 }
8121
8122 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
8123 bzero(s: &info, n: sizeof(info));
8124
8125 // xxx - do we need a distinct OSReturn value for these or is "bad data"
8126 // xxx - sufficient?
8127
8128 /* Verify that the kmod_info and start/stop pointers are non-NULL.
8129 */
8130 if (!kmod_info) {
8131 OSKextLog(aKext: this,
8132 kOSKextLogErrorLevel |
8133 kOSKextLogLoadFlag,
8134 format: "Kext %s - NULL kmod_info pointer.",
8135 getIdentifierCString());
8136 result = kOSKextReturnBadData;
8137 goto finish;
8138 }
8139
8140 if (startFlag) {
8141 address = (mach_vm_address_t)kmod_info->start;
8142 } else {
8143 address = (mach_vm_address_t)kmod_info->stop;
8144 }
8145
8146 if (!address) {
8147 OSKextLog(aKext: this,
8148 kOSKextLogErrorLevel |
8149 kOSKextLogLoadFlag,
8150 format: "Kext %s - NULL module %s pointer.",
8151 getIdentifierCString(), whichOp);
8152 result = kOSKextReturnBadData;
8153 goto finish;
8154 }
8155
8156 kext_map = kext_get_vm_map(info: kmod_info);
8157 depth = (kernel_map == kext_map) ? 1 : 2;
8158 if (isInFileset()) {
8159#if defined(HAS_APPLE_PAC)
8160 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
8161#endif /* defined(HAS_APPLE_PAC) */
8162 }
8163
8164 /* Verify that the start/stop function lies within the kext's address range.
8165 */
8166 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8167 isInFileset()) {
8168 /* This will likely be how we deal with split kexts; walk the segments to
8169 * check that the function lies inside one of the segments of this kext.
8170 */
8171 for (seg = firstsegfromheader(header: (kernel_mach_header_t *)kmod_info->address);
8172 seg != NULL;
8173 seg = nextsegfromheader(header: (kernel_mach_header_t *)kmod_info->address, seg)) {
8174 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8175 kext_segbase = seg->vmaddr;
8176 kext_segsize = seg->vmsize;
8177 break;
8178 }
8179 }
8180
8181 if (!seg) {
8182 OSKextLog(aKext: this,
8183 kOSKextLogErrorLevel |
8184 kOSKextLogLoadFlag,
8185 format: "Kext %s module %s pointer is outside of kext range "
8186 "(%s %p - kext starts at %p).",
8187 getIdentifierCString(),
8188 whichOp,
8189 whichOp,
8190 (void *)(((uintptr_t)address) - kext_slide),
8191 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8192 result = kOSKextReturnBadData;
8193 goto finish;
8194 }
8195
8196 seg = NULL;
8197 } else {
8198 if (address < kmod_info->address + kmod_info->hdr_size ||
8199 kmod_info->address + kmod_info->size <= address) {
8200 OSKextLog(aKext: this,
8201 kOSKextLogErrorLevel |
8202 kOSKextLogLoadFlag,
8203 format: "Kext %s module %s pointer is outside of kext range "
8204 "(%s %p - kext at %p-%p).",
8205 getIdentifierCString(),
8206 whichOp,
8207 whichOp,
8208 (void *)(((uintptr_t)address) - kext_slide),
8209 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8210 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8211 result = kOSKextReturnBadData;
8212 goto finish;
8213 }
8214 }
8215
8216 /* Only do these checks before calling the start function;
8217 * If anything goes wrong with the mapping while the kext is running,
8218 * we'll likely have panicked well before any attempt to stop the kext.
8219 */
8220 if (startFlag) {
8221 if (!isInFileset() || kc_type != KCKindPrimary) {
8222 /*
8223 * Verify that the start/stop function is executable.
8224 */
8225 kern_result = mach_vm_region_recurse(target_task: kernel_map, address: &address, size: &size, nesting_depth: &depth,
8226 info: (vm_region_recurse_info_t)&info, infoCnt: &count);
8227 if (kern_result != KERN_SUCCESS) {
8228 OSKextLog(aKext: this,
8229 kOSKextLogErrorLevel |
8230 kOSKextLogLoadFlag,
8231 format: "Kext %s - bad %s pointer %p.",
8232 getIdentifierCString(),
8233 whichOp, (void *)ml_static_unslide(vaddr: address));
8234 result = kOSKextReturnBadData;
8235 goto finish;
8236 }
8237 } else {
8238 /*
8239 * Since kexts loaded from the primary KC are held in memory
8240 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8241 * discover that memory's protection flags. Instead, we need to
8242 * get that information from the kernel pmap itself. Above, we
8243 * (potentially) saved the size of the segment in which the address
8244 * in question was located. If we have a non-zero size, verify
8245 * that all pages in the (address, address + kext_segsize) range
8246 * are marked executable. If we somehow did not record the size
8247 * (or the base) just verify the single page that includes the address.
8248 */
8249 if (kext_segbase == 0 || kext_segsize == 0) {
8250 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8251 kext_segsize = PAGE_SIZE;
8252 }
8253 }
8254
8255#if VM_MAPPED_KEXTS
8256 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8257 ((isInFileset() && kc_type == KCKindPrimary) &&
8258 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8259 OSKextLog(this,
8260 kOSKextLogErrorLevel |
8261 kOSKextLogLoadFlag,
8262 "Kext %s - memory region containing module %s function "
8263 "is not executable.",
8264 getIdentifierCString(), whichOp);
8265 result = kOSKextReturnBadData;
8266 goto finish;
8267 }
8268#endif
8269
8270 /* Verify that the kext's segments are backed by physical memory.
8271 */
8272 seg = firstsegfromheader(header: (kernel_mach_header_t *)kmod_info->address);
8273 while (seg) {
8274 if (!verifySegmentMapping(seg)) {
8275 result = kOSKextReturnBadData;
8276 goto finish;
8277 }
8278
8279 seg = nextsegfromheader(header: (kernel_mach_header_t *) kmod_info->address, seg);
8280 }
8281 }
8282
8283 result = kOSReturnSuccess;
8284finish:
8285 return result;
8286}
8287
8288/*********************************************************************
8289*********************************************************************/
8290boolean_t
8291OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8292{
8293 mach_vm_address_t address = 0;
8294
8295 if (seg->vmsize > UINT32_MAX) {
8296 return false;
8297 }
8298
8299 if (!segmentShouldBeWired(seg)) {
8300 return true;
8301 }
8302
8303 for (address = seg->vmaddr;
8304 address < round_page(x: seg->vmaddr + seg->vmsize);
8305 address += PAGE_SIZE) {
8306 if (!pmap_find_phys(pmap: kernel_pmap, va: (vm_offset_t)address)) {
8307 OSKextLog(aKext: this,
8308 kOSKextLogErrorLevel |
8309 kOSKextLogLoadFlag,
8310 format: "Kext %s - page %p is not backed by physical memory.",
8311 getIdentifierCString(),
8312 (void *)address);
8313 return false;
8314 }
8315 }
8316
8317 return true;
8318}
8319
8320/*********************************************************************
8321*********************************************************************/
8322static void
8323OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8324{
8325 uint64_t stamp = 0;
8326 firehose_tracepoint_id_u trace_id;
8327 struct firehose_trace_uuid_info_s uuid_info_s;
8328 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8329 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8330 OSSharedPtr<OSData> uuid_data;
8331
8332 stamp = firehose_tracepoint_time(flags: firehose_activity_flags_default);
8333 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8334
8335 uuid_data = aKext->copyTextUUID();
8336 if (uuid_data) {
8337 memcpy(dst: uuid_info->ftui_uuid, src: uuid_data->getBytesNoCopy(), n: sizeof(uuid_info->ftui_uuid));
8338 }
8339
8340 uuid_info->ftui_size = size;
8341 if (aKext->isDriverKit()) {
8342 uuid_info->ftui_address = address;
8343 } else {
8344 uuid_info->ftui_address = ml_static_unslide(vaddr: address);
8345 }
8346 os_log_encoded_metadata(ftid: trace_id, stamp, pubdata: uuid_info, publen: uuid_info_len);
8347 return;
8348}
8349
8350void
8351OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8352{
8353 OSKextLogKextInfo(aKext: kext, address: kext->getLoadTag(), size: 1, code: firehose_tracepoint_code_load);
8354}
8355
8356/*********************************************************************
8357*********************************************************************/
8358OSReturn
8359OSKext::start(bool startDependenciesFlag)
8360{
8361 OSReturn result = kOSReturnError;
8362 kern_return_t (* startfunc)(kmod_info_t *, void *);
8363 unsigned int i, count;
8364 void * kmodStartData = NULL;
8365
8366 if (isStarted() || isInterface() || isKernelComponent()) {
8367 result = kOSReturnSuccess;
8368 goto finish;
8369 }
8370
8371 if (!isLoaded()) {
8372 OSKextLog(aKext: this,
8373 kOSKextLogErrorLevel |
8374 kOSKextLogLoadFlag,
8375 format: "Attempt to start nonloaded kext %s.",
8376 getIdentifierCString());
8377 result = kOSKextReturnInvalidArgument;
8378 goto finish;
8379 }
8380
8381 if (!sLoadEnabled) {
8382 OSKextLog(aKext: this,
8383 kOSKextLogErrorLevel |
8384 kOSKextLogLoadFlag,
8385 format: "Kext loading is disabled (attempt to start kext %s).",
8386 getIdentifierCString());
8387 result = kOSKextReturnDisabled;
8388 goto finish;
8389 }
8390
8391 result = validateKextMapping(/* start? */ startFlag: true);
8392 if (result != kOSReturnSuccess) {
8393 goto finish;
8394 }
8395
8396 startfunc = kmod_info->start;
8397
8398 count = getNumDependencies();
8399 for (i = 0; i < count; i++) {
8400 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8401 if (dependency == NULL) {
8402 OSKextLog(aKext: this,
8403 kOSKextLogErrorLevel |
8404 kOSKextLogLoadFlag,
8405 format: "Kext %s start - internal error, dependency disappeared.",
8406 getIdentifierCString());
8407 goto finish;
8408 }
8409 if (!dependency->isStarted()) {
8410 if (startDependenciesFlag) {
8411 OSReturn dependencyResult =
8412 dependency->start(startDependenciesFlag);
8413 if (dependencyResult != KERN_SUCCESS) {
8414 OSKextLog(aKext: this,
8415 kOSKextLogErrorLevel |
8416 kOSKextLogLoadFlag,
8417 format: "Kext %s start - dependency %s failed to start (error 0x%x).",
8418 getIdentifierCString(),
8419 dependency->getIdentifierCString(),
8420 dependencyResult);
8421 goto finish;
8422 }
8423 } else {
8424 OSKextLog(aKext: this,
8425 kOSKextLogErrorLevel |
8426 kOSKextLogLoadFlag,
8427 format: "Not starting %s - dependency %s not started yet.",
8428 getIdentifierCString(),
8429 dependency->getIdentifierCString());
8430 result = kOSKextReturnStartStopError; // xxx - make new return?
8431 goto finish;
8432 }
8433 }
8434 }
8435
8436 OSKextLog(aKext: this,
8437 kOSKextLogDetailLevel |
8438 kOSKextLogLoadFlag,
8439 format: "Kext %s calling module start function.",
8440 getIdentifierCString());
8441
8442 flags.starting = 1;
8443
8444 // Drop a log message so logd can grab the needed information to decode this kext
8445 OSKextLogKextInfo(aKext: this, address: kmod_info->address, size: kmod_info->size, code: firehose_tracepoint_code_load);
8446 result = OSRuntimeInitializeCPP(kext: this);
8447 if (result == KERN_SUCCESS) {
8448 result = startfunc(kmod_info, kmodStartData);
8449 }
8450
8451 flags.starting = 0;
8452
8453 /* On success overlap the setting of started/starting. On failure just
8454 * clear starting.
8455 */
8456 if (result == KERN_SUCCESS) {
8457 flags.started = 1;
8458
8459 // xxx - log start error from kernel?
8460 OSKextLog(aKext: this,
8461 kOSKextLogProgressLevel |
8462 kOSKextLogLoadFlag,
8463 format: "Kext %s is now started.",
8464 getIdentifierCString());
8465 } else {
8466 invokeOrCancelRequestCallbacks(
8467 /* result not actually used */ kOSKextReturnStartStopError,
8468 /* invokeFlag */ false);
8469 OSKextLog(aKext: this,
8470 kOSKextLogWarningLevel |
8471 kOSKextLogLoadFlag,
8472 format: "Kext %s did not start (return code 0x%x).",
8473 getIdentifierCString(), result);
8474 }
8475
8476finish:
8477 return result;
8478}
8479
8480/*********************************************************************
8481*********************************************************************/
8482/* static */
8483bool
8484OSKext::canUnloadKextWithIdentifier(
8485 OSString * kextIdentifier,
8486 bool checkClassesFlag)
8487{
8488 bool result = false;
8489 OSKext * aKext = NULL; // do not release
8490
8491 IORecursiveLockLock(lock: sKextLock);
8492
8493 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8494
8495 if (!aKext) {
8496 goto finish; // can't unload what's not loaded
8497 }
8498
8499 if (aKext->isLoaded()) {
8500 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8501 goto finish;
8502 }
8503 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8504 goto finish;
8505 }
8506 }
8507
8508 result = true;
8509
8510finish:
8511 IORecursiveLockUnlock(lock: sKextLock);
8512 return result;
8513}
8514
8515/*********************************************************************
8516*********************************************************************/
8517OSReturn
8518OSKext::stop(void)
8519{
8520 OSReturn result = kOSReturnError;
8521 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8522
8523 if (!isStarted() || isInterface()) {
8524 result = kOSReturnSuccess;
8525 goto finish;
8526 }
8527
8528 if (!isLoaded()) {
8529 OSKextLog(aKext: this,
8530 kOSKextLogErrorLevel |
8531 kOSKextLogLoadFlag,
8532 format: "Attempt to stop nonloaded kext %s.",
8533 getIdentifierCString());
8534 result = kOSKextReturnInvalidArgument;
8535 goto finish;
8536 }
8537
8538 /* Refuse to stop if we have clients or instances. It is up to
8539 * the caller to make sure those aren't true.
8540 */
8541 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8542 OSKextLog(aKext: this,
8543 kOSKextLogErrorLevel |
8544 kOSKextLogLoadFlag,
8545 format: "Kext %s - C++ instances; can't stop.",
8546 getIdentifierCString());
8547 result = kOSKextReturnInUse;
8548 goto finish;
8549 }
8550
8551 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8552 OSKextLog(aKext: this,
8553 kOSKextLogErrorLevel |
8554 kOSKextLogLoadFlag,
8555 format: "Kext %s - has references (linkage or tracking object); "
8556 "can't stop.",
8557 getIdentifierCString());
8558 result = kOSKextReturnInUse;
8559 goto finish;
8560 }
8561
8562 /* Note: If validateKextMapping fails on the stop & unload path,
8563 * we are in serious trouble and a kernel panic is likely whether
8564 * we stop & unload the kext or not.
8565 */
8566 result = validateKextMapping(/* start? */ startFlag: false);
8567 if (result != kOSReturnSuccess) {
8568 goto finish;
8569 }
8570
8571 stopfunc = kmod_info->stop;
8572 if (stopfunc) {
8573 OSKextLog(aKext: this,
8574 kOSKextLogDetailLevel |
8575 kOSKextLogLoadFlag,
8576 format: "Kext %s calling module stop function.",
8577 getIdentifierCString());
8578
8579 flags.stopping = 1;
8580
8581 result = stopfunc(kmod_info, /* userData */ NULL);
8582 if (result == KERN_SUCCESS) {
8583 result = OSRuntimeFinalizeCPP(kext: this);
8584 }
8585
8586 flags.stopping = 0;
8587
8588 if (result == KERN_SUCCESS) {
8589 flags.started = 0;
8590
8591 OSKextLog(aKext: this,
8592 kOSKextLogDetailLevel |
8593 kOSKextLogLoadFlag,
8594 format: "Kext %s is now stopped and ready to unload.",
8595 getIdentifierCString());
8596 } else {
8597 OSKextLog(aKext: this,
8598 kOSKextLogErrorLevel |
8599 kOSKextLogLoadFlag,
8600 format: "Kext %s did not stop (return code 0x%x).",
8601 getIdentifierCString(), result);
8602 result = kOSKextReturnStartStopError;
8603 }
8604 }
8605
8606finish:
8607 // Drop a log message so logd can update this kext's metadata
8608 OSKextLogKextInfo(aKext: this, address: kmod_info->address, size: kmod_info->size, code: firehose_tracepoint_code_unload);
8609 return result;
8610}
8611
8612/*********************************************************************
8613*********************************************************************/
8614OSReturn
8615OSKext::unload(void)
8616{
8617 OSReturn result = kOSReturnError;
8618 unsigned int index;
8619 uint32_t num_kmod_refs = 0;
8620 OSKextAccount * freeAccount;
8621 bool in_fileset = false;
8622
8623 if (!sUnloadEnabled) {
8624 OSKextLog(aKext: this,
8625 kOSKextLogErrorLevel |
8626 kOSKextLogLoadFlag,
8627 format: "Kext unloading is disabled (%s).",
8628 this->getIdentifierCString());
8629
8630 result = kOSKextReturnDisabled;
8631 goto finish;
8632 }
8633
8634 // cache this result so we don't need to access the kmod_info after
8635 // it's been potentially free'd
8636 in_fileset = isInFileset();
8637
8638 /* Refuse to unload if we have clients or instances. It is up to
8639 * the caller to make sure those aren't true.
8640 */
8641 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8642 // xxx - Don't log under errors? this is more of an info thing
8643 OSKextLog(aKext: this,
8644 kOSKextLogErrorLevel |
8645 kOSKextLogKextBookkeepingFlag,
8646 format: "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8647 getIdentifierCString(), getRetainCount());
8648 result = kOSKextReturnInUse;
8649 goto finish;
8650 }
8651
8652 if (isDriverKit()) {
8653 index = sLoadedDriverKitKexts->getNextIndexOfObject(anObject: this, index: 0);
8654 if (index != (unsigned int)-1) {
8655 sLoadedDriverKitKexts->removeObject(index);
8656 OSKextLogKextInfo(aKext: this, address: loadTag, size: 1, code: firehose_tracepoint_code_unload);
8657 loadTag = 0;
8658 }
8659 }
8660
8661 if (!isLoaded()) {
8662 result = kOSReturnSuccess;
8663 goto finish;
8664 }
8665
8666 if (isKernelComponent()) {
8667 result = kOSKextReturnInvalidArgument;
8668 goto finish;
8669 }
8670
8671 if (metaClasses && !OSMetaClass::removeClasses(metaClasses: metaClasses.get())) {
8672 OSKextLog(aKext: this,
8673 kOSKextLogErrorLevel |
8674 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8675 format: "Can't unload kext %s; classes have instances:",
8676 getIdentifierCString());
8677 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8678 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8679 result = kOSKextReturnInUse;
8680 goto finish;
8681 }
8682
8683 /* Note that the kext is unloading before running any code that
8684 * might be in the kext (request callbacks, module stop function).
8685 * We will deny certain requests made against a kext in the process
8686 * of unloading.
8687 */
8688 flags.unloading = 1;
8689
8690 /* Update the string describing the last kext to unload in case we panic.
8691 */
8692 savePanicString(/* isLoading */ false);
8693
8694 if (isStarted()) {
8695 result = stop();
8696 if (result != KERN_SUCCESS) {
8697 OSKextLog(aKext: this,
8698 kOSKextLogErrorLevel |
8699 kOSKextLogLoadFlag,
8700 format: "Kext %s can't unload - module stop returned 0x%x.",
8701 getIdentifierCString(), (unsigned)result);
8702 result = kOSKextReturnStartStopError;
8703 goto finish;
8704 }
8705 }
8706
8707 OSKextLog(aKext: this,
8708 kOSKextLogProgressLevel |
8709 kOSKextLogLoadFlag,
8710 format: "Kext %s unloading.",
8711 getIdentifierCString());
8712
8713 {
8714 struct list_head *p;
8715 struct list_head *prev;
8716 struct list_head *next;
8717 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8718 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8719 s->err = OSKextGrabPgoDataLocked(kext: this, metadata: s->metadata, instance_uuid, pSize: s->pSize, pBuffer: s->pBuffer, bufferSize: s->bufferSize);
8720 prev = p->prev;
8721 next = p->next;
8722 prev->next = next;
8723 next->prev = prev;
8724 p->prev = p;
8725 p->next = p;
8726 IORecursiveLockWakeup(lock: sKextLock, event: s, oneThread: false);
8727 }
8728 }
8729
8730
8731 /* Even if we don't call the stop function, we want to be sure we
8732 * have no OSMetaClass references before unloading the kext executable
8733 * from memory. OSMetaClasses may have pointers into the kext executable
8734 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8735 */
8736 if (metaClasses) {
8737 metaClasses->flushCollection();
8738 }
8739 (void) OSRuntimeFinalizeCPP(kext: this);
8740
8741 /* Remove the kext from the list of loaded kexts, patch the gap
8742 * in the kmod_info_t linked list, and reset "kmod" to point to the
8743 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8744 */
8745 index = sLoadedKexts->getNextIndexOfObject(anObject: this, index: 0);
8746 if (index != (unsigned int)-1) {
8747 sLoadedKexts->removeObject(index);
8748
8749 OSKext * nextKext = OSDynamicCast(OSKext,
8750 sLoadedKexts->getObject(index));
8751
8752 if (nextKext) {
8753 if (index > 0) {
8754 OSKext * gapKext = OSDynamicCast(OSKext,
8755 sLoadedKexts->getObject(index - 1));
8756
8757 nextKext->kmod_info->next = gapKext->kmod_info;
8758 } else { /* index == 0 */
8759 nextKext->kmod_info->next = NULL;
8760 }
8761 }
8762
8763 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8764 if (lastKext && !lastKext->isKernel()) {
8765 kmod = lastKext->kmod_info;
8766 } else {
8767 kmod = NULL; // clear the global kmod variable
8768 }
8769 }
8770
8771 /* Clear out the kmod references that we're keeping for compatibility
8772 * with current panic backtrace code & kgmacros.
8773 * xxx - will want to update those bits sometime and remove this.
8774 */
8775 num_kmod_refs = getNumDependencies();
8776 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8777 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8778 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8779 ref->info->reference_count--;
8780 }
8781 kfree_type(kmod_reference_t, num_kmod_refs,
8782 kmod_info->reference_list);
8783 }
8784
8785#if CONFIG_DTRACE
8786 unregisterWithDTrace();
8787#endif /* CONFIG_DTRACE */
8788
8789 notifyKextUnloadObservers(this);
8790
8791 freeAccount = NULL;
8792 lck_ticket_lock(tlock: sKextAccountsLock, grp: sKextAccountsLockGrp);
8793 account->kext = NULL;
8794 if (account->site.tag) {
8795 account->site.flags |= VM_TAG_UNLOAD;
8796 } else {
8797 freeAccount = account;
8798 }
8799
8800#if DEVELOPMENT || DEBUG
8801 assertf(account->task_refgrp.grp_count == 0,
8802 "unloading a kext with active task references");
8803#endif /* DEVELOPMENT || DEBUG */
8804
8805 lck_ticket_unlock(tlock: sKextAccountsLock);
8806 if (freeAccount) {
8807 IOFreeType(freeAccount, OSKextAccount);
8808 }
8809
8810 /* Unwire and free the linked executable.
8811 */
8812 if (linkedExecutable) {
8813#if KASAN
8814 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8815#endif
8816
8817#if VM_MAPPED_KEXTS
8818 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8819 kernel_segment_command_t *seg = NULL;
8820 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8821
8822 if (!kext_map) {
8823 OSKextLog(this,
8824 kOSKextLogErrorLevel |
8825 kOSKextLogLoadFlag,
8826 "Failed to free kext %s; couldn't find the kext map.",
8827 getIdentifierCString());
8828 result = kOSKextReturnInternalError;
8829 goto finish;
8830 }
8831
8832 OSKextLog(this,
8833 kOSKextLogProgressLevel |
8834 kOSKextLogLoadFlag,
8835 "Kext %s unwiring and unmapping linked executable.",
8836 getIdentifierCString());
8837
8838 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8839 while (seg) {
8840 if (segmentShouldBeWired(seg)) {
8841 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8842 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8843
8844 result = vm_map_unwire(kext_map, start_wire,
8845 end_wire, FALSE);
8846 if (result != KERN_SUCCESS) {
8847 OSKextLog(this,
8848 kOSKextLogErrorLevel |
8849 kOSKextLogLoadFlag,
8850 "Failed to unwire kext %s.",
8851 getIdentifierCString());
8852 result = kOSKextReturnInternalError;
8853 goto finish;
8854 }
8855 }
8856
8857 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8858 }
8859#if defined(__x86_64__) || defined(__i386__)
8860 if (in_fileset && flags.resetSegmentsFromVnode) {
8861 IORecursiveLockLock(sKextLock);
8862 resetKCFileSetSegments();
8863 IORecursiveLockUnlock(sKextLock);
8864 }
8865#endif // (__x86_64__) || defined(__i386__)
8866 }
8867#endif /* VM_MAPPED_KEXTS */
8868 if (flags.resetSegmentsFromImmutableCopy) {
8869 result = resetMutableSegments();
8870 if (result != kOSReturnSuccess) {
8871 OSKextLog(aKext: this,
8872 kOSKextLogErrorLevel |
8873 kOSKextLogLoadFlag,
8874 format: "Failed to reset kext %s.",
8875 getIdentifierCString());
8876 result = kOSKextReturnInternalError;
8877 goto finish;
8878 }
8879 }
8880 if (kc_type == KCKindUnknown) {
8881 linkedExecutable.reset();
8882 }
8883 }
8884
8885 /* An interface kext has a fake kmod_info that was allocated,
8886 * so we have to free it.
8887 */
8888 if (isInterface()) {
8889 kfree_type(kmod_info_t, kmod_info);
8890 kmod_info = NULL;
8891 }
8892
8893 if (!in_fileset) {
8894 kmod_info = NULL;
8895 }
8896
8897 flags.loaded = false;
8898 flushDependencies();
8899
8900 /* save a copy of the bundle ID for us to check when deciding to
8901 * rebuild the kernel cache file. If a kext was already in the kernel
8902 * cache and unloaded then later loaded we do not need to rebuild the
8903 * kernel cache. 9055303
8904 */
8905 if (isPrelinked()) {
8906 if (!_OSKextInUnloadedPrelinkedKexts(theBundleID: bundleID.get())) {
8907 IORecursiveLockLock(lock: sKextLock);
8908 if (sUnloadedPrelinkedKexts) {
8909 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8910 }
8911 IORecursiveLockUnlock(lock: sKextLock);
8912 }
8913 }
8914
8915 OSKextLog(aKext: this,
8916 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8917 format: "Kext %s unloaded.", getIdentifierCString());
8918
8919 queueKextNotification(kKextRequestPredicateUnloadNotification,
8920 OSDynamicCast(OSString, bundleID.get()), dextUniqueIdentifier: getDextUniqueID());
8921
8922finish:
8923 OSKext::saveLoadedKextPanicList();
8924 OSKext::updateLoadedKextSummaries();
8925
8926 flags.unloading = 0;
8927 return result;
8928}
8929
8930/*********************************************************************
8931* Assumes sKextLock is held.
8932*********************************************************************/
8933/* static */
8934OSReturn
8935OSKext::queueKextNotification(
8936 const char * notificationName,
8937 OSString * kextIdentifier,
8938 OSData * dextUniqueIdentifier)
8939{
8940 OSReturn result = kOSReturnError;
8941 OSSharedPtr<OSDictionary> loadRequest;
8942
8943 if (!kextIdentifier) {
8944 result = kOSKextReturnInvalidArgument;
8945 goto finish;
8946 }
8947
8948 /* Create a new request unless one is already sitting
8949 * in sKernelRequests for this bundle identifier
8950 */
8951 result = _OSKextCreateRequest(predicate: notificationName, requestP&: loadRequest);
8952 if (result != kOSReturnSuccess) {
8953 goto finish;
8954 }
8955 if (!_OSKextSetRequestArgument(requestDict: loadRequest.get(),
8956 kKextRequestArgumentBundleIdentifierKey, value: kextIdentifier)) {
8957 result = kOSKextReturnNoMemory;
8958 goto finish;
8959 }
8960 if (NULL != dextUniqueIdentifier) {
8961 if (!_OSKextSetRequestArgument(requestDict: loadRequest.get(),
8962 kKextRequestArgumentDriverUniqueIdentifier, value: dextUniqueIdentifier)) {
8963 result = kOSKextReturnNoMemory;
8964 goto finish;
8965 }
8966 }
8967 if (!sKernelRequests->setObject(loadRequest.get())) {
8968 result = kOSKextReturnNoMemory;
8969 goto finish;
8970 }
8971
8972 /* We might want to only queue the notification if the IOKit daemon is active,
8973 * but that wouldn't work for embedded. Note that we don't care if
8974 * the ping immediately succeeds here so don't do anything with the
8975 * result of this call.
8976 */
8977 OSKext::pingIOKitDaemon();
8978
8979 result = kOSReturnSuccess;
8980
8981finish:
8982 return result;
8983}
8984
8985
8986#if CONFIG_KXLD
8987/*********************************************************************
8988*********************************************************************/
8989static void
8990_OSKextConsiderDestroyingLinkContext(
8991 __unused thread_call_param_t p0,
8992 __unused thread_call_param_t p1)
8993{
8994 /* Take multiple locks in the correct order.
8995 */
8996 IORecursiveLockLock(sKextLock);
8997 IORecursiveLockLock(sKextInnerLock);
8998
8999 /* The first time we destroy the kxldContext is in the first
9000 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
9001 * before calling this function. Thereafter any call to this function
9002 * will actually destroy the context.
9003 */
9004 if (sConsiderUnloadsCalled && sKxldContext) {
9005 kxld_destroy_context(sKxldContext);
9006 sKxldContext = NULL;
9007 }
9008
9009 /* Free the thread_call that was allocated to execute this function.
9010 */
9011 if (sDestroyLinkContextThread) {
9012 if (!thread_call_free(sDestroyLinkContextThread)) {
9013 OSKextLog(/* kext */ NULL,
9014 kOSKextLogErrorLevel |
9015 kOSKextLogGeneralFlag,
9016 "thread_call_free() failed for kext link context.");
9017 }
9018 sDestroyLinkContextThread = NULL;
9019 }
9020
9021 IORecursiveLockUnlock(sKextInnerLock);
9022 IORecursiveLockUnlock(sKextLock);
9023
9024 return;
9025}
9026
9027/*********************************************************************
9028* Destroying the kxldContext requires checking variables under both
9029* sKextInnerLock and sKextLock, so we do it on a separate thread
9030* to avoid deadlocks with IOService, with which OSKext has a reciprocal
9031* call relationship.
9032*
9033* This function must be invoked with sKextInnerLock held.
9034* Do not call any function that takes sKextLock here!
9035*********************************************************************/
9036/* static */
9037void
9038OSKext::considerDestroyingLinkContext(void)
9039{
9040 IORecursiveLockLock(sKextInnerLock);
9041
9042 /* If we have already queued a thread to destroy the link context,
9043 * don't bother resetting; that thread will take care of it.
9044 */
9045 if (sDestroyLinkContextThread) {
9046 goto finish;
9047 }
9048
9049 /* The function to be invoked in the thread will deallocate
9050 * this thread_call, so don't share it around.
9051 */
9052 sDestroyLinkContextThread = thread_call_allocate(
9053 &_OSKextConsiderDestroyingLinkContext, NULL);
9054 if (!sDestroyLinkContextThread) {
9055 OSKextLog(/* kext */ NULL,
9056 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
9057 "Can't create thread to destroy kext link context.");
9058 goto finish;
9059 }
9060
9061 thread_call_enter(sDestroyLinkContextThread);
9062
9063finish:
9064 IORecursiveLockUnlock(sKextInnerLock);
9065 return;
9066}
9067
9068#else // !CONFIG_KXLD
9069
9070/* static */
9071void
9072OSKext::considerDestroyingLinkContext(void)
9073{
9074 return;
9075}
9076
9077#endif // CONFIG_KXLD
9078
9079#if PRAGMA_MARK
9080#pragma mark Autounload
9081#endif
9082/*********************************************************************
9083* This is a static method because the kext will be deallocated if it
9084* does unload!
9085*********************************************************************/
9086/* static */
9087OSReturn
9088OSKext::autounloadKext(OSKext * aKext)
9089{
9090 OSReturn result = kOSKextReturnInUse;
9091
9092#if NO_KEXTD
9093 /*
9094 * Do not unload prelinked kexts on platforms that do not have an
9095 * IOKit daemon as there is no way to reload the kext or restart
9096 * matching.
9097 */
9098 if (aKext->isPrelinked()) {
9099 goto finish;
9100 }
9101#endif /* defined(__x86_64__) */
9102
9103 /* Check for external references to this kext (usu. dependents),
9104 * instances of defined classes (or classes derived from them),
9105 * outstanding requests.
9106 */
9107 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
9108 !aKext->flags.autounloadEnabled ||
9109 aKext->isKernelComponent()) {
9110 goto finish;
9111 }
9112
9113 /* Skip a delay-autounload kext, once.
9114 */
9115 if (aKext->flags.delayAutounload) {
9116 OSKextLog(aKext,
9117 kOSKextLogProgressLevel |
9118 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
9119 format: "Kext %s has delayed autounload set; skipping and clearing flag.",
9120 aKext->getIdentifierCString());
9121 aKext->flags.delayAutounload = 0;
9122 goto finish;
9123 }
9124
9125 if (aKext->hasOSMetaClassInstances() ||
9126 aKext->countRequestCallbacks()) {
9127 goto finish;
9128 }
9129
9130 result = OSKext::removeKext(aKext);
9131
9132finish:
9133 return result;
9134}
9135
9136/*********************************************************************
9137*********************************************************************/
9138void
9139_OSKextConsiderUnloads(
9140 __unused thread_call_param_t p0,
9141 __unused thread_call_param_t p1)
9142{
9143 bool didUnload = false;
9144 unsigned int count, i;
9145
9146 /* Take multiple locks in the correct order
9147 * (note also sKextSummaries lock further down).
9148 */
9149 IORecursiveLockLock(lock: sKextLock);
9150 IORecursiveLockLock(lock: sKextInnerLock);
9151
9152 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
9153
9154 /* If the system is powering down, don't try to unload anything.
9155 */
9156 if (sSystemSleep) {
9157 goto finish;
9158 }
9159
9160 OSKextLog(/* kext */ NULL,
9161 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
9162 format: "Checking for unused kexts to autounload.");
9163
9164 /*****
9165 * Remove any request callbacks marked as stale,
9166 * and mark as stale any currently in flight.
9167 */
9168 count = sRequestCallbackRecords->getCount();
9169 if (count) {
9170 i = count - 1;
9171 do {
9172 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9173 sRequestCallbackRecords->getObject(i));
9174 if (callbackRecord) {
9175 OSBoolean * stale = OSDynamicCast(OSBoolean,
9176 callbackRecord->getObject(kKextRequestStaleKey));
9177
9178 if (stale == kOSBooleanTrue) {
9179 OSKext::invokeRequestCallback(callbackRecord,
9180 kOSKextReturnTimeout);
9181 } else {
9182 callbackRecord->setObject(kKextRequestStaleKey,
9183 anObject: kOSBooleanTrue);
9184 }
9185 }
9186 } while (i--);
9187 }
9188
9189 /*****
9190 * Make multiple passes through the array of loaded kexts until
9191 * we don't unload any. This handles unwinding of dependency
9192 * chains. We have to go *backwards* through the array because
9193 * kexts are removed from it when unloaded, and we cannot make
9194 * a copy or we'll mess up the retain counts we rely on to
9195 * check whether a kext will unload. If only we could have
9196 * nonretaining collections like CF has....
9197 */
9198 do {
9199 didUnload = false;
9200
9201 count = sLoadedKexts->getCount();
9202 if (count) {
9203 i = count - 1;
9204 do {
9205 OSKext * thisKext = OSDynamicCast(OSKext,
9206 sLoadedKexts->getObject(i));
9207 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(aKext: thisKext));
9208 } while (i--);
9209 }
9210 } while (didUnload);
9211
9212finish:
9213 sConsiderUnloadsPending = false;
9214 sConsiderUnloadsExecuted = true;
9215
9216 (void) OSKext::considerRebuildOfPrelinkedKernel();
9217
9218 IORecursiveLockUnlock(lock: sKextInnerLock);
9219 IORecursiveLockUnlock(lock: sKextLock);
9220
9221 return;
9222}
9223
9224/*********************************************************************
9225* Do not call any function that takes sKextLock here!
9226*********************************************************************/
9227void
9228OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9229{
9230 AbsoluteTime when;
9231
9232 IORecursiveLockLock(lock: sKextInnerLock);
9233
9234 if (!sUnloadCallout) {
9235 sUnloadCallout = thread_call_allocate(func: &_OSKextConsiderUnloads, NULL);
9236 }
9237
9238 /* we only reset delay value for unloading if we already have something
9239 * pending. rescheduleOnlyFlag should not start the count down.
9240 */
9241 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9242 goto finish;
9243 }
9244
9245 thread_call_cancel(call: sUnloadCallout);
9246 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9247#if !NO_KEXTD
9248 && sIOKitDaemonActive
9249#endif
9250 ) {
9251 clock_interval_to_deadline(interval: sConsiderUnloadDelay,
9252 scale_factor: 1000 * 1000 * 1000, result: &when);
9253
9254 OSKextLog(/* kext */ NULL,
9255 kOSKextLogProgressLevel |
9256 kOSKextLogLoadFlag,
9257 format: "%scheduling %sscan for unused kexts in %lu seconds.",
9258 sConsiderUnloadsPending ? "Res" : "S",
9259 sConsiderUnloadsCalled ? "" : "initial ",
9260 (unsigned long)sConsiderUnloadDelay);
9261
9262 sConsiderUnloadsPending = true;
9263 thread_call_enter_delayed(call: sUnloadCallout, deadline: when);
9264 }
9265
9266finish:
9267 /* The kxld context should be reused throughout boot. We mark the end of
9268 * period as the first time considerUnloads() is called, and we destroy
9269 * the first kxld context in that function. Afterwards, it will be
9270 * destroyed in flushNonloadedKexts.
9271 */
9272 if (!sConsiderUnloadsCalled) {
9273 sConsiderUnloadsCalled = true;
9274 OSKext::considerDestroyingLinkContext();
9275 }
9276
9277 IORecursiveLockUnlock(lock: sKextInnerLock);
9278 return;
9279}
9280
9281/*********************************************************************
9282* Do not call any function that takes sKextLock here!
9283*********************************************************************/
9284extern "C" {
9285IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9286IOReturn
9287OSKextSystemSleepOrWake(UInt32 messageType)
9288{
9289 IORecursiveLockLock(lock: sKextInnerLock);
9290
9291 /* If the system is going to sleep, cancel the reaper thread timer,
9292 * and note that we're in a sleep state in case it just fired but hasn't
9293 * taken the lock yet. If we are coming back from sleep, just
9294 * clear the sleep flag; IOService's normal operation will cause
9295 * unloads to be considered soon enough.
9296 */
9297 if (messageType == kIOMessageSystemWillSleep) {
9298 if (sUnloadCallout) {
9299 thread_call_cancel(call: sUnloadCallout);
9300 }
9301 sSystemSleep = true;
9302 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9303 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9304 sSystemSleep = false;
9305 clock_get_uptime(result: &sLastWakeTime);
9306 }
9307 IORecursiveLockUnlock(lock: sKextInnerLock);
9308
9309 return kIOReturnSuccess;
9310}
9311};
9312
9313
9314#if PRAGMA_MARK
9315#pragma mark Prelinked Kernel
9316#endif
9317
9318#ifdef CONFIG_KXLD
9319/*********************************************************************
9320* Do not access sConsiderUnloads... variables other than
9321* sConsiderUnloadsExecuted in this function. They are guarded by a
9322* different lock.
9323*********************************************************************/
9324/* static */
9325void
9326OSKext::considerRebuildOfPrelinkedKernel(void)
9327{
9328 static bool requestedPrelink = false;
9329 OSReturn checkResult = kOSReturnError;
9330 OSSharedPtr<OSDictionary> prelinkRequest;
9331 OSSharedPtr<OSCollectionIterator> kextIterator;
9332 const OSSymbol * thisID = NULL; // do not release
9333 bool doRebuild = false;
9334 AbsoluteTime my_abstime;
9335 UInt64 my_ns;
9336 SInt32 delta_secs;
9337
9338 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9339 if (requestedPrelink || !sPrelinkBoot) {
9340 return;
9341 }
9342
9343 /* no direct return from this point */
9344 IORecursiveLockLock(sKextLock);
9345
9346 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9347 * and any new startup kexts loaded.
9348 */
9349 if (!sConsiderUnloadsExecuted ||
9350 !sDeferredLoadSucceeded) {
9351 goto finish;
9352 }
9353
9354 /* we really only care about boot / system start up related kexts so bail
9355 * if we're here after REBUILD_MAX_TIME.
9356 */
9357 if (!_OSKextInPrelinkRebuildWindow()) {
9358 OSKextLog(/* kext */ NULL,
9359 kOSKextLogArchiveFlag,
9360 "%s prebuild rebuild has expired",
9361 __FUNCTION__);
9362 requestedPrelink = true;
9363 goto finish;
9364 }
9365
9366 /* we do not want to trigger a rebuild if we get here too close to waking
9367 * up. (see radar 10233768)
9368 */
9369 IORecursiveLockLock(sKextInnerLock);
9370
9371 clock_get_uptime(&my_abstime);
9372 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9373 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9374 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9375 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9376 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9377 }
9378 IORecursiveLockUnlock(sKextInnerLock);
9379
9380 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9381 /* too close to time of last wake from sleep */
9382 goto finish;
9383 }
9384 requestedPrelink = true;
9385
9386 /* Now it's time to see if we have a reason to rebuild. We may have done
9387 * some loads and unloads but the kernel cache didn't actually change.
9388 * We will rebuild if any kext is not marked prelinked AND is not in our
9389 * list of prelinked kexts that got unloaded. (see radar 9055303)
9390 */
9391 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9392 if (!kextIterator) {
9393 goto finish;
9394 }
9395
9396 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9397 OSKext * thisKext; // do not release
9398
9399 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9400 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9401 continue;
9402 }
9403
9404 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9405 continue;
9406 }
9407 /* kext is loaded and was not in current kernel cache so let's rebuild
9408 */
9409 doRebuild = true;
9410 OSKextLog(/* kext */ NULL,
9411 kOSKextLogArchiveFlag,
9412 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9413 thisKext->bundleID->getCStringNoCopy());
9414 break;
9415 }
9416 sUnloadedPrelinkedKexts->flushCollection();
9417
9418 if (!doRebuild) {
9419 goto finish;
9420 }
9421
9422 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9423 prelinkRequest);
9424 if (checkResult != kOSReturnSuccess) {
9425 goto finish;
9426 }
9427
9428 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9429 goto finish;
9430 }
9431
9432 OSKext::pingIOKitDaemon();
9433
9434finish:
9435 IORecursiveLockUnlock(sKextLock);
9436
9437 return;
9438}
9439
9440#else /* !CONFIG_KXLD */
9441
9442void
9443OSKext::considerRebuildOfPrelinkedKernel(void)
9444{
9445 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9446 return;
9447}
9448
9449#endif /* CONFIG_KXLD */
9450
9451#if PRAGMA_MARK
9452#pragma mark Dependencies
9453#endif
9454/*********************************************************************
9455*********************************************************************/
9456bool
9457OSKext::resolveDependencies(
9458 OSArray * loopStack)
9459{
9460 bool result = false;
9461 OSSharedPtr<OSArray> localLoopStack;
9462 bool addedToLoopStack = false;
9463 OSDictionary * libraries = NULL; // do not release
9464 OSSharedPtr<OSCollectionIterator> libraryIterator;
9465 OSString * libraryID = NULL; // do not release
9466 OSKext * libraryKext = NULL; // do not release
9467 bool hasRawKernelDependency = false;
9468 bool hasKernelDependency = false;
9469 bool hasKPIDependency = false;
9470 bool hasPrivateKPIDependency = false;
9471 unsigned int count;
9472
9473#if CONFIG_KXLD
9474 OSString * infoString = NULL; // do not release
9475 OSString * readableString = NULL; // do not release
9476#endif // CONFIG_KXLD
9477
9478 /* A kernel component will automatically have this flag set,
9479 * and a loaded kext should also have it set (as should all its
9480 * loaded dependencies).
9481 */
9482 if (flags.hasAllDependencies) {
9483 result = true;
9484 goto finish;
9485 }
9486
9487 /* Check for loops in the dependency graph.
9488 */
9489 if (loopStack) {
9490 if (loopStack->getNextIndexOfObject(anObject: this, index: 0) != (unsigned int)-1) {
9491 OSKextLog(aKext: this,
9492 kOSKextLogErrorLevel |
9493 kOSKextLogDependenciesFlag,
9494 format: "Kext %s has a dependency loop; can't resolve dependencies.",
9495 getIdentifierCString());
9496 goto finish;
9497 }
9498 } else {
9499 OSKextLog(aKext: this,
9500 kOSKextLogStepLevel |
9501 kOSKextLogDependenciesFlag,
9502 format: "Kext %s resolving dependencies.",
9503 getIdentifierCString());
9504
9505 localLoopStack = OSArray::withCapacity(capacity: 6); // any small capacity will do
9506 if (!localLoopStack) {
9507 OSKextLog(aKext: this,
9508 kOSKextLogErrorLevel |
9509 kOSKextLogDependenciesFlag,
9510 format: "Kext %s can't create bookkeeping stack to resolve dependencies.",
9511 getIdentifierCString());
9512 goto finish;
9513 }
9514 loopStack = localLoopStack.get();
9515 }
9516 if (!loopStack->setObject(this)) {
9517 OSKextLog(aKext: this,
9518 kOSKextLogErrorLevel |
9519 kOSKextLogDependenciesFlag,
9520 format: "Kext %s - internal error resolving dependencies.",
9521 getIdentifierCString());
9522 goto finish;
9523 }
9524 addedToLoopStack = true;
9525
9526 /* Purge any existing kexts in the dependency list and start over.
9527 */
9528 flushDependencies();
9529 if (dependencies) {
9530 OSKextLog(aKext: this,
9531 kOSKextLogErrorLevel |
9532 kOSKextLogDependenciesFlag,
9533 format: "Kext %s - internal error resolving dependencies.",
9534 getIdentifierCString());
9535 }
9536
9537 libraries = OSDynamicCast(OSDictionary,
9538 getPropertyForHostArch(kOSBundleLibrariesKey));
9539 if (libraries == NULL || libraries->getCount() == 0) {
9540 OSKextLog(aKext: this,
9541 kOSKextLogErrorLevel |
9542 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9543 format: "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9544 getIdentifierCString(), kOSBundleLibrariesKey);
9545 goto finish;
9546 }
9547
9548 /* Make a new array to hold the dependencies (flush freed the old one).
9549 */
9550 dependencies = OSArray::withCapacity(capacity: libraries->getCount());
9551 if (!dependencies) {
9552 OSKextLog(aKext: this,
9553 kOSKextLogErrorLevel |
9554 kOSKextLogDependenciesFlag,
9555 format: "Kext %s - can't allocate dependencies array.",
9556 getIdentifierCString());
9557 goto finish;
9558 }
9559
9560 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9561 // xxx - compat: if none were declared.
9562
9563 libraryIterator = OSCollectionIterator::withCollection(inColl: libraries);
9564 if (!libraryIterator) {
9565 OSKextLog(aKext: this,
9566 kOSKextLogErrorLevel |
9567 kOSKextLogDependenciesFlag,
9568 format: "Kext %s - can't allocate dependencies iterator.",
9569 getIdentifierCString());
9570 goto finish;
9571 }
9572
9573 while ((libraryID = OSDynamicCast(OSString,
9574 libraryIterator->getNextObject()))) {
9575 const char * library_id = libraryID->getCStringNoCopy();
9576
9577 OSString * libraryVersion = OSDynamicCast(OSString,
9578 libraries->getObject(libraryID));
9579 if (libraryVersion == NULL) {
9580 OSKextLog(aKext: this,
9581 kOSKextLogErrorLevel |
9582 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9583 format: "Kext %s - illegal type in OSBundleLibraries.",
9584 getIdentifierCString());
9585 goto finish;
9586 }
9587
9588 OSKextVersion libraryVers =
9589 OSKextParseVersionString(versionString: libraryVersion->getCStringNoCopy());
9590 if (libraryVers == -1) {
9591 OSKextLog(aKext: this,
9592 kOSKextLogErrorLevel |
9593 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9594 format: "Kext %s - invalid library version %s.",
9595 getIdentifierCString(),
9596 libraryVersion->getCStringNoCopy());
9597 goto finish;
9598 }
9599
9600 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9601 if (libraryKext == NULL) {
9602 OSKextLog(aKext: this,
9603 kOSKextLogErrorLevel |
9604 kOSKextLogDependenciesFlag,
9605 format: "Kext %s - library kext %s not found.",
9606 getIdentifierCString(), library_id);
9607 goto finish;
9608 }
9609
9610 if (!libraryKext->isCompatibleWithVersion(aVersion: libraryVers)) {
9611 OSKextLog(aKext: this,
9612 kOSKextLogErrorLevel |
9613 kOSKextLogDependenciesFlag,
9614 format: "Kext %s - library kext %s not compatible "
9615 "with requested version %s.",
9616 getIdentifierCString(), library_id,
9617 libraryVersion->getCStringNoCopy());
9618 goto finish;
9619 }
9620
9621 /* If a nonprelinked library somehow got into the mix for a
9622 * prelinked kext, at any point in the chain, we must fail
9623 * because the prelinked relocs for the library will be all wrong.
9624 */
9625 if (this->isPrelinked() &&
9626 libraryKext->declaresExecutable() &&
9627 !libraryKext->isPrelinked()) {
9628 OSKextLog(aKext: this,
9629 kOSKextLogErrorLevel |
9630 kOSKextLogDependenciesFlag,
9631 format: "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9632 getIdentifierCString(), library_id,
9633 libraryVersion->getCStringNoCopy());
9634 goto finish;
9635 }
9636
9637 if (!libraryKext->resolveDependencies(loopStack)) {
9638 goto finish;
9639 }
9640
9641 /* Add the library directly only if it has an executable to link.
9642 * Otherwise it's just used to collect other dependencies, so put
9643 * *its* dependencies on the list for this kext.
9644 */
9645 // xxx - We are losing info here; would like to make fake entries or
9646 // xxx - keep these in the dependency graph for loaded kexts.
9647 // xxx - I really want to make kernel components not a special case!
9648 if (libraryKext->declaresExecutable() ||
9649 libraryKext->isInterface()) {
9650 if (dependencies->getNextIndexOfObject(anObject: libraryKext, index: 0) == (unsigned)-1) {
9651 dependencies->setObject(libraryKext);
9652
9653 OSKextLog(aKext: this,
9654 kOSKextLogDetailLevel |
9655 kOSKextLogDependenciesFlag,
9656 format: "Kext %s added dependency %s.",
9657 getIdentifierCString(),
9658 libraryKext->getIdentifierCString());
9659 }
9660 } else {
9661 int numLibDependencies = libraryKext->getNumDependencies();
9662 OSArray * libraryDependencies = libraryKext->getDependencies();
9663 int index;
9664
9665 if (numLibDependencies) {
9666 // xxx - this msg level should be 1 lower than the per-kext one
9667 OSKextLog(aKext: this,
9668 kOSKextLogDetailLevel |
9669 kOSKextLogDependenciesFlag,
9670 format: "Kext %s pulling %d dependencies from codeless library %s.",
9671 getIdentifierCString(),
9672 numLibDependencies,
9673 libraryKext->getIdentifierCString());
9674 }
9675 for (index = 0; index < numLibDependencies; index++) {
9676 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9677 libraryDependencies->getObject(index));
9678 if (dependencies->getNextIndexOfObject(anObject: thisLibDependency, index: 0) == (unsigned)-1) {
9679 dependencies->setObject(thisLibDependency);
9680 OSKextLog(aKext: this,
9681 kOSKextLogDetailLevel |
9682 kOSKextLogDependenciesFlag,
9683 format: "Kext %s added dependency %s from codeless library %s.",
9684 getIdentifierCString(),
9685 thisLibDependency->getIdentifierCString(),
9686 libraryKext->getIdentifierCString());
9687 }
9688 }
9689 }
9690
9691 if ((strlen(s: library_id) == strlen(KERNEL_LIB)) &&
9692 0 == strncmp(s1: library_id, KERNEL_LIB, n: sizeof(KERNEL_LIB) - 1)) {
9693 hasRawKernelDependency = true;
9694 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9695 hasKernelDependency = true;
9696 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9697 hasKPIDependency = true;
9698 if (!strncmp(s1: library_id, PRIVATE_KPI, n: sizeof(PRIVATE_KPI) - 1)) {
9699 hasPrivateKPIDependency = true;
9700 }
9701 }
9702 }
9703
9704 if (hasRawKernelDependency) {
9705 OSKextLog(aKext: this,
9706 kOSKextLogErrorLevel |
9707 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9708 format: "Error - kext %s declares a dependency on %s, which is not permitted.",
9709 getIdentifierCString(), KERNEL_LIB);
9710 goto finish;
9711 }
9712#if __LP64__
9713 if (hasKernelDependency) {
9714 OSKextLog(aKext: this,
9715 kOSKextLogErrorLevel |
9716 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9717 format: "Error - kext %s declares %s dependencies. "
9718 "Only %s* dependencies are supported for 64-bit kexts.",
9719 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9720 goto finish;
9721 }
9722 if (!hasKPIDependency) {
9723 OSKextLog(aKext: this,
9724 kOSKextLogWarningLevel |
9725 kOSKextLogDependenciesFlag,
9726 format: "Warning - kext %s declares no %s* dependencies. "
9727 "If it uses any KPIs, the link may fail with undefined symbols.",
9728 getIdentifierCString(), KPI_LIB_PREFIX);
9729 }
9730#else /* __LP64__ */
9731 // xxx - will change to flatly disallow "kernel" dependencies at some point
9732 // xxx - is it invalid to do both "com.apple.kernel" and any
9733 // xxx - "com.apple.kernel.*"?
9734
9735 if (hasKernelDependency && hasKPIDependency) {
9736 OSKextLog(this,
9737 kOSKextLogWarningLevel |
9738 kOSKextLogDependenciesFlag,
9739 "Warning - kext %s has immediate dependencies on both "
9740 "%s* and %s* components; use only one style.",
9741 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9742 }
9743
9744 if (!hasKernelDependency && !hasKPIDependency) {
9745 // xxx - do we want to use validation flag for these too?
9746 OSKextLog(this,
9747 kOSKextLogWarningLevel |
9748 kOSKextLogDependenciesFlag,
9749 "Warning - %s declares no kernel dependencies; using %s.",
9750 getIdentifierCString(), KERNEL6_LIB);
9751 OSKext * kernelKext = OSDynamicCast(OSKext,
9752 sKextsByID->getObject(KERNEL6_LIB));
9753 if (kernelKext) {
9754 dependencies->setObject(kernelKext);
9755 } else {
9756 OSKextLog(this,
9757 kOSKextLogErrorLevel |
9758 kOSKextLogDependenciesFlag,
9759 "Error - Library %s not found for %s.",
9760 KERNEL6_LIB, getIdentifierCString());
9761 }
9762 }
9763
9764 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9765 * its indirect dependencies to simulate old-style linking. XXX - Should
9766 * check for duplicates.
9767 */
9768 if (!hasKPIDependency) {
9769 unsigned int i;
9770
9771 flags.hasBleedthrough = true;
9772
9773 count = getNumDependencies();
9774
9775 /* We add to the dependencies array in this loop, but do not iterate
9776 * past its original count.
9777 */
9778 for (i = 0; i < count; i++) {
9779 OSKext * dependencyKext = OSDynamicCast(OSKext,
9780 dependencies->getObject(i));
9781 dependencyKext->addBleedthroughDependencies(dependencies.get());
9782 }
9783 }
9784#endif /* __LP64__ */
9785
9786#if CONFIG_KXLD
9787 /*
9788 * If we're not dynamically linking kexts, then we don't need to check
9789 * copyright strings. The linker in user space has already done this.
9790 */
9791 if (hasPrivateKPIDependency) {
9792 bool hasApplePrefix = false;
9793 bool infoCopyrightIsValid = false;
9794 bool readableCopyrightIsValid = false;
9795
9796 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9797 APPLE_KEXT_PREFIX);
9798
9799 infoString = OSDynamicCast(OSString,
9800 getPropertyForHostArch("CFBundleGetInfoString"));
9801 if (infoString) {
9802 infoCopyrightIsValid =
9803 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9804 }
9805
9806 readableString = OSDynamicCast(OSString,
9807 getPropertyForHostArch("NSHumanReadableCopyright"));
9808 if (readableString) {
9809 readableCopyrightIsValid =
9810 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9811 }
9812
9813 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9814 OSKextLog(this,
9815 kOSKextLogErrorLevel |
9816 kOSKextLogDependenciesFlag,
9817 "Error - kext %s declares a dependency on %s. "
9818 "Only Apple kexts may declare a dependency on %s.",
9819 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9820 goto finish;
9821 }
9822 }
9823#endif // CONFIG_KXLD
9824
9825 result = true;
9826 flags.hasAllDependencies = 1;
9827
9828finish:
9829
9830 if (addedToLoopStack) {
9831 count = loopStack->getCount();
9832 if (count > 0 && (this == loopStack->getObject(index: count - 1))) {
9833 loopStack->removeObject(index: count - 1);
9834 } else {
9835 OSKextLog(aKext: this,
9836 kOSKextLogErrorLevel |
9837 kOSKextLogDependenciesFlag,
9838 format: "Kext %s - internal error resolving dependencies.",
9839 getIdentifierCString());
9840 }
9841 }
9842
9843 if (result && localLoopStack) {
9844 OSKextLog(aKext: this,
9845 kOSKextLogStepLevel |
9846 kOSKextLogDependenciesFlag,
9847 format: "Kext %s successfully resolved dependencies.",
9848 getIdentifierCString());
9849 }
9850
9851 return result;
9852}
9853
9854/*********************************************************************
9855*********************************************************************/
9856bool
9857OSKext::addBleedthroughDependencies(OSArray * anArray)
9858{
9859 bool result = false;
9860 unsigned int dependencyIndex, dependencyCount;
9861
9862 dependencyCount = getNumDependencies();
9863
9864 for (dependencyIndex = 0;
9865 dependencyIndex < dependencyCount;
9866 dependencyIndex++) {
9867 OSKext * dependency = OSDynamicCast(OSKext,
9868 dependencies->getObject(dependencyIndex));
9869 if (!dependency) {
9870 OSKextLog(aKext: this,
9871 kOSKextLogErrorLevel |
9872 kOSKextLogDependenciesFlag,
9873 format: "Kext %s - internal error propagating compatibility dependencies.",
9874 getIdentifierCString());
9875 goto finish;
9876 }
9877 if (anArray->getNextIndexOfObject(anObject: dependency, index: 0) == (unsigned int)-1) {
9878 anArray->setObject(dependency);
9879 }
9880 dependency->addBleedthroughDependencies(anArray);
9881 }
9882
9883 result = true;
9884
9885finish:
9886 return result;
9887}
9888
9889/*********************************************************************
9890*********************************************************************/
9891bool
9892OSKext::flushDependencies(bool forceFlag)
9893{
9894 bool result = false;
9895
9896 /* Only clear the dependencies if the kext isn't loaded;
9897 * we need the info for loaded kexts to track references.
9898 */
9899 if (!isLoaded() || forceFlag) {
9900 if (dependencies) {
9901 // xxx - check level
9902 OSKextLog(aKext: this,
9903 kOSKextLogProgressLevel |
9904 kOSKextLogDependenciesFlag,
9905 format: "Kext %s flushing dependencies.",
9906 getIdentifierCString());
9907 dependencies.reset();
9908 }
9909 if (!isKernelComponent()) {
9910 flags.hasAllDependencies = 0;
9911 }
9912 result = true;
9913 }
9914
9915 return result;
9916}
9917
9918/*********************************************************************
9919*********************************************************************/
9920uint32_t
9921OSKext::getNumDependencies(void)
9922{
9923 if (!dependencies) {
9924 return 0;
9925 }
9926 return dependencies->getCount();
9927}
9928
9929/*********************************************************************
9930*********************************************************************/
9931OSArray *
9932OSKext::getDependencies(void)
9933{
9934 return dependencies.get();
9935}
9936
9937bool
9938OSKext::hasDependency(const OSSymbol * depID)
9939{
9940 bool result __block;
9941
9942 if (depID == getIdentifier()) {
9943 return true;
9944 }
9945 if (!dependencies) {
9946 return false;
9947 }
9948 result = false;
9949 dependencies->iterateObjects(block: ^bool (OSObject * obj) {
9950 OSKext * kext;
9951 kext = OSDynamicCast(OSKext, obj);
9952 if (!kext) {
9953 return false;
9954 }
9955 result = (depID == kext->getIdentifier());
9956 return result;
9957 });
9958 return result;
9959}
9960
9961#if PRAGMA_MARK
9962#pragma mark OSMetaClass Support
9963#endif
9964/*********************************************************************
9965*********************************************************************/
9966OSReturn
9967OSKext::addClass(
9968 OSMetaClass * aClass,
9969 uint32_t numClasses)
9970{
9971 OSReturn result = kOSMetaClassNoInsKModSet;
9972
9973 if (!metaClasses) {
9974 metaClasses = OSSet::withCapacity(capacity: numClasses);
9975 if (!metaClasses) {
9976 goto finish;
9977 }
9978 }
9979
9980 if (metaClasses->containsObject(anObject: aClass)) {
9981 OSKextLog(aKext: this,
9982 kOSKextLogWarningLevel |
9983 kOSKextLogLoadFlag,
9984 format: "Notice - kext %s has already registered class %s.",
9985 getIdentifierCString(),
9986 aClass->getClassName());
9987 result = kOSReturnSuccess;
9988 goto finish;
9989 }
9990
9991 if (!metaClasses->setObject(aClass)) {
9992 goto finish;
9993 } else {
9994 OSKextLog(aKext: this,
9995 kOSKextLogDetailLevel |
9996 kOSKextLogLoadFlag,
9997 format: "Kext %s registered class %s.",
9998 getIdentifierCString(),
9999 aClass->getClassName());
10000 }
10001
10002 if (!flags.autounloadEnabled) {
10003 const OSMetaClass * metaScan = NULL; // do not release
10004
10005 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
10006 if (metaScan == OSTypeID(IOService)) {
10007 OSKextLog(aKext: this,
10008 kOSKextLogProgressLevel |
10009 kOSKextLogLoadFlag,
10010 format: "Kext %s has IOService subclass %s; enabling autounload.",
10011 getIdentifierCString(),
10012 aClass->getClassName());
10013
10014 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
10015 break;
10016 }
10017 }
10018 }
10019
10020 notifyAddClassObservers(this, aClass, flags);
10021
10022 result = kOSReturnSuccess;
10023
10024finish:
10025 if (result != kOSReturnSuccess) {
10026 OSKextLog(aKext: this,
10027 kOSKextLogErrorLevel |
10028 kOSKextLogLoadFlag,
10029 format: "Kext %s failed to register class %s.",
10030 getIdentifierCString(),
10031 aClass->getClassName());
10032 }
10033
10034 return result;
10035}
10036
10037/*********************************************************************
10038*********************************************************************/
10039OSReturn
10040OSKext::removeClass(
10041 OSMetaClass * aClass)
10042{
10043 OSReturn result = kOSMetaClassNoKModSet;
10044
10045 if (!metaClasses) {
10046 goto finish;
10047 }
10048
10049 if (!metaClasses->containsObject(anObject: aClass)) {
10050 OSKextLog(aKext: this,
10051 kOSKextLogWarningLevel |
10052 kOSKextLogLoadFlag,
10053 format: "Notice - kext %s asked to unregister unknown class %s.",
10054 getIdentifierCString(),
10055 aClass->getClassName());
10056 result = kOSReturnSuccess;
10057 goto finish;
10058 }
10059
10060 OSKextLog(aKext: this,
10061 kOSKextLogDetailLevel |
10062 kOSKextLogLoadFlag,
10063 format: "Kext %s unregistering class %s.",
10064 getIdentifierCString(),
10065 aClass->getClassName());
10066
10067 metaClasses->removeObject(anObject: aClass);
10068
10069 notifyRemoveClassObservers(this, aClass, flags);
10070
10071 result = kOSReturnSuccess;
10072
10073finish:
10074 if (result != kOSReturnSuccess) {
10075 OSKextLog(aKext: this,
10076 kOSKextLogErrorLevel |
10077 kOSKextLogLoadFlag,
10078 format: "Failed to unregister kext %s class %s.",
10079 getIdentifierCString(),
10080 aClass->getClassName());
10081 }
10082 return result;
10083}
10084
10085/*********************************************************************
10086*********************************************************************/
10087OSSet *
10088OSKext::getMetaClasses(void)
10089{
10090 return metaClasses.get();
10091}
10092
10093/*********************************************************************
10094*********************************************************************/
10095bool
10096OSKext::hasOSMetaClassInstances(void)
10097{
10098 bool result = false;
10099 OSSharedPtr<OSCollectionIterator> classIterator;
10100 OSMetaClass * checkClass = NULL; // do not release
10101
10102 if (!metaClasses) {
10103 goto finish;
10104 }
10105
10106 classIterator = OSCollectionIterator::withCollection(inColl: metaClasses.get());
10107 if (!classIterator) {
10108 // xxx - log alloc failure?
10109 goto finish;
10110 }
10111 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10112 if (checkClass->getInstanceCount()) {
10113 result = true;
10114 goto finish;
10115 }
10116 }
10117
10118finish:
10119 return result;
10120}
10121
10122/*********************************************************************
10123*********************************************************************/
10124/* static */
10125void
10126OSKext::reportOSMetaClassInstances(
10127 const char * kextIdentifier,
10128 OSKextLogSpec msgLogSpec)
10129{
10130 OSSharedPtr<OSKext> theKext;
10131
10132 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
10133 if (!theKext) {
10134 goto finish;
10135 }
10136
10137 theKext->reportOSMetaClassInstances(msgLogSpec);
10138finish:
10139 return;
10140}
10141
10142/*********************************************************************
10143*********************************************************************/
10144void
10145OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
10146{
10147 OSSharedPtr<OSCollectionIterator> classIterator;
10148 OSMetaClass * checkClass = NULL; // do not release
10149
10150 if (!metaClasses) {
10151 goto finish;
10152 }
10153
10154 classIterator = OSCollectionIterator::withCollection(inColl: metaClasses.get());
10155 if (!classIterator) {
10156 goto finish;
10157 }
10158 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10159 if (checkClass->getInstanceCount()) {
10160 OSKextLog(aKext: this,
10161 msgLogSpec,
10162 format: " Kext %s class %s has %d instance%s.",
10163 getIdentifierCString(),
10164 checkClass->getClassName(),
10165 checkClass->getInstanceCount(),
10166 checkClass->getInstanceCount() == 1 ? "" : "s");
10167 }
10168 }
10169
10170finish:
10171 return;
10172}
10173
10174#if PRAGMA_MARK
10175#pragma mark User-Space Requests
10176#endif
10177
10178static kern_return_t
10179patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10180{
10181 OSReturn result = kOSReturnSuccess;
10182 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10183 OSDictionary * request = NULL; //do not release
10184 IOUserServerCheckInToken * token = NULL; //do not release
10185 OSString * requestPredicate = NULL; //do not release
10186 OSSharedPtr<OSNumber> portNameNumber;
10187 mach_port_name_t portName = 0;
10188 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10189 if (!request) {
10190 OSKextLog(/* kext */ NULL,
10191 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10192 format: "Elements of request should be of type OSDictionary");
10193 result = kOSKextReturnInternalError;
10194 goto finish;
10195 }
10196 requestPredicate = _OSKextGetRequestPredicate(requestDict: request);
10197 if (!requestPredicate) {
10198 OSKextLog(/* kext */ NULL,
10199 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10200 format: "Failed to get request predicate");
10201 result = kOSKextReturnInternalError;
10202 goto finish;
10203 }
10204 // is this a dext launch?
10205 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10206 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10207 if (!token) {
10208 OSKextLog(/* kext */ NULL,
10209 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10210 format: "Could not find a IOUserServerCheckInToken in daemon launch request.");
10211 result = kOSKextReturnInternalError;
10212 goto finish;
10213 }
10214 portName = iokit_make_send_right(task: calling_task, obj: token, type: IKOT_IOKIT_IDENT);
10215 if (portName == 0 || portName == MACH_PORT_DEAD) {
10216 OSKextLog(/* kext */ NULL,
10217 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10218 format: "Could not create send right for object.");
10219 result = kOSKextReturnInternalError;
10220 goto finish;
10221 }
10222 // Store the mach port name as a OSNumber
10223 portNameNumber = OSNumber::withNumber(value: portName, CHAR_BIT * sizeof(portName));
10224 if (!portNameNumber) {
10225 OSKextLog(/* kext */ NULL,
10226 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10227 format: "Could not create OSNumber object.");
10228 result = kOSKextReturnNoMemory;
10229 goto finish;
10230 }
10231 if (!_OSKextSetRequestArgument(requestDict: request, kKextRequestArgumentCheckInToken, value: portNameNumber.get())) {
10232 OSKextLog(/* kext */ NULL,
10233 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10234 format: "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10235 result = kOSKextReturnNoMemory;
10236 goto finish;
10237 }
10238 }
10239finish:
10240 if (result != kOSReturnSuccess) {
10241 break;
10242 }
10243 }
10244 return result;
10245}
10246
10247bool
10248OSKext::iokitDaemonActive()
10249{
10250 bool result;
10251 IORecursiveLockLock(lock: sKextLock);
10252 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10253 IORecursiveLockUnlock(lock: sKextLock);
10254 return result;
10255}
10256
10257/*********************************************************************
10258* XXX - this function is a big ugly mess
10259*********************************************************************/
10260/* static */
10261OSReturn
10262OSKext::handleRequest(
10263 host_priv_t hostPriv,
10264 OSKextLogSpec clientLogFilter,
10265 char * requestBuffer,
10266 uint32_t requestLength,
10267 char ** responseOut,
10268 uint32_t * responseLengthOut,
10269 char ** logInfoOut,
10270 uint32_t * logInfoLengthOut)
10271{
10272 OSReturn result = kOSReturnError;
10273 kern_return_t kmem_result = KERN_FAILURE;
10274
10275 char * response = NULL; // returned by reference
10276 uint32_t responseLength = 0;
10277
10278 bool taskCanManageAllKCs = false;
10279 bool taskOnlyManagesBootKC = false;
10280
10281 OSSharedPtr<OSObject> parsedXML;
10282 OSDictionary * requestDict = NULL; // do not release
10283 OSSharedPtr<OSString> errorString;
10284
10285 OSSharedPtr<OSObject> responseObject;
10286
10287 OSSharedPtr<OSSerialize> serializer;
10288
10289 OSSharedPtr<OSArray> logInfoArray;
10290
10291 OSString * predicate = NULL; // do not release
10292 OSString * kextIdentifier = NULL; // do not release
10293 OSArray * kextIdentifiers = NULL; // do not release
10294 OSKext * theKext = NULL; // do not release
10295 OSBoolean * boolArg = NULL; // do not release
10296
10297
10298 IORecursiveLockLock(lock: sKextLock);
10299
10300 if (responseOut) {
10301 *responseOut = NULL;
10302 *responseLengthOut = 0;
10303 }
10304 if (logInfoOut) {
10305 *logInfoOut = NULL;
10306 *logInfoLengthOut = 0;
10307 }
10308
10309 OSKext::setUserSpaceLogFilter(userLogSpec: clientLogFilter, captureFlag: logInfoOut ? true : false);
10310
10311 /* XML must be nul-terminated.
10312 */
10313 if (requestBuffer[requestLength - 1] != '\0') {
10314 OSKextLog(/* kext */ NULL,
10315 kOSKextLogErrorLevel |
10316 kOSKextLogIPCFlag,
10317 format: "Invalid request from user space (not nul-terminated).");
10318 result = kOSKextReturnBadData;
10319 goto finish;
10320 }
10321 parsedXML = OSUnserializeXML(buffer: (const char *)requestBuffer, errorString);
10322 if (parsedXML) {
10323 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10324 }
10325 if (!requestDict) {
10326 const char * errorCString = "(unknown error)";
10327
10328 if (errorString && errorString->getCStringNoCopy()) {
10329 errorCString = errorString->getCStringNoCopy();
10330 } else if (parsedXML) {
10331 errorCString = "not a dictionary";
10332 }
10333 OSKextLog(/* kext */ NULL,
10334 kOSKextLogErrorLevel |
10335 kOSKextLogIPCFlag,
10336 format: "Error unserializing request from user space: %s.",
10337 errorCString);
10338 result = kOSKextReturnSerialization;
10339 goto finish;
10340 }
10341
10342 predicate = _OSKextGetRequestPredicate(requestDict);
10343 if (!predicate) {
10344 OSKextLog(/* kext */ NULL,
10345 kOSKextLogErrorLevel |
10346 kOSKextLogIPCFlag,
10347 format: "Recieved kext request from user space with no predicate.");
10348 result = kOSKextReturnInvalidArgument;
10349 goto finish;
10350 }
10351 OSKextLog(/* kext */ NULL,
10352 kOSKextLogDebugLevel |
10353 kOSKextLogIPCFlag,
10354 format: "Received '%s' request from user space.",
10355 predicate->getCStringNoCopy());
10356
10357 /*
10358 * All management of file sets requires an entitlement
10359 */
10360 result = kOSKextReturnNotPrivileged;
10361 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10362 predicate->isEqualTo(kKextRequestPredicateStart) ||
10363 predicate->isEqualTo(kKextRequestPredicateStop) ||
10364 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10365 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10366 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10367 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10368 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10369 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10370 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10371 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10372 if (!iokitDaemonAvailable()) {
10373 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10374 }
10375 if (hostPriv == HOST_PRIV_NULL) {
10376 OSKextLog(/* kext */ NULL,
10377 kOSKextLogErrorLevel |
10378 kOSKextLogIPCFlag,
10379 format: "Access Failure - must be root user.");
10380 goto finish;
10381 }
10382 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10383 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10384
10385 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10386 OSKextLog(/* kext */ NULL,
10387 kOSKextLogErrorLevel |
10388 kOSKextLogIPCFlag,
10389 format: "Access Failure - client not entitled to manage file sets.");
10390 goto finish;
10391 }
10392
10393 /*
10394 * The OnlyBootKC entitlement restricts the
10395 * collection-management entitlement to only managing kexts in
10396 * the BootKC. All other predicates that alter global state or
10397 * add new KCs are disallowed.
10398 */
10399 if (taskOnlyManagesBootKC &&
10400 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10401 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10402 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10403 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10404 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10405 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10406 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10407 OSKextLog(/* kext */ NULL,
10408 kOSKextLogErrorLevel |
10409 kOSKextLogIPCFlag,
10410 format: "Access Failure - client not entitled to manage non-primary KCs");
10411 goto finish;
10412 }
10413
10414 /*
10415 * If we get here, then the process either has the full KC
10416 * management entitlement, or it has the BootKC-only
10417 * entitlement and the request is about the BootKC.
10418 */
10419 }
10420
10421 /* Get common args in anticipation of use.
10422 */
10423 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10424 requestDict, kKextRequestArgumentBundleIdentifierKey));
10425 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10426 requestDict, kKextRequestArgumentBundleIdentifierKey));
10427 if (kextIdentifier) {
10428 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10429 }
10430 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10431 requestDict, kKextRequestArgumentValueKey));
10432
10433 if (taskOnlyManagesBootKC &&
10434 theKext &&
10435 theKext->isInFileset() &&
10436 theKext->kc_type != KCKindPrimary) {
10437 OSKextLog(/* kext */ NULL,
10438 kOSKextLogErrorLevel |
10439 kOSKextLogIPCFlag,
10440 format: "Access Failure - client not entitled to manage kext in non-primary KC");
10441 result = kOSKextReturnNotPrivileged;
10442 goto finish;
10443 }
10444 result = kOSKextReturnInvalidArgument;
10445
10446 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10447 if (!kextIdentifier) {
10448 OSKextLog(/* kext */ NULL,
10449 kOSKextLogErrorLevel |
10450 kOSKextLogIPCFlag,
10451 format: "Invalid arguments to kext start request.");
10452 } else if (!theKext) {
10453 OSKextLog(/* kext */ NULL,
10454 kOSKextLogErrorLevel |
10455 kOSKextLogIPCFlag,
10456 format: "Kext %s not found for start request.",
10457 kextIdentifier->getCStringNoCopy());
10458 result = kOSKextReturnNotFound;
10459 } else {
10460 result = theKext->start();
10461 }
10462 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10463 if (!kextIdentifier) {
10464 OSKextLog(/* kext */ NULL,
10465 kOSKextLogErrorLevel |
10466 kOSKextLogIPCFlag,
10467 format: "Invalid arguments to kext stop request.");
10468 } else if (!theKext) {
10469 OSKextLog(/* kext */ NULL,
10470 kOSKextLogErrorLevel |
10471 kOSKextLogIPCFlag,
10472 format: "Kext %s not found for stop request.",
10473 kextIdentifier->getCStringNoCopy());
10474 result = kOSKextReturnNotFound;
10475 } else {
10476 result = theKext->stop();
10477 }
10478 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10479 result = OSKext::setMissingAuxKCBundles(requestDict);
10480 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10481 if (!kextIdentifier) {
10482 OSKextLog(/* kext */ NULL,
10483 kOSKextLogErrorLevel |
10484 kOSKextLogIPCFlag,
10485 format: "Invalid arguments to AuxKC Bundle Available request.");
10486 } else {
10487 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10488 }
10489 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10490 if (!kextIdentifier) {
10491 OSKextLog(/* kext */ NULL,
10492 kOSKextLogErrorLevel |
10493 kOSKextLogIPCFlag,
10494 format: "Invalid arguments to kext load from KC request.");
10495 } else if (!theKext) {
10496 OSKextLog(/* kext */ NULL,
10497 kOSKextLogErrorLevel |
10498 kOSKextLogIPCFlag,
10499 format: "Kext %s not found for load from KC request.",
10500 kextIdentifier->getCStringNoCopy());
10501 result = kOSKextReturnNotFound;
10502 } else if (!theKext->isInFileset()) {
10503 OSKextLog(/* kext */ NULL,
10504 kOSKextLogErrorLevel |
10505 kOSKextLogIPCFlag,
10506 format: "Kext %s does not exist in a KC: refusing to load.",
10507 kextIdentifier->getCStringNoCopy());
10508 result = kOSKextReturnNotLoadable;
10509 } else {
10510 result = OSKext::loadKextFromKC(theKext, requestDict);
10511 }
10512 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10513 if (!kextIdentifier) {
10514 OSKextLog(/* kext */ NULL,
10515 kOSKextLogErrorLevel |
10516 kOSKextLogIPCFlag,
10517 format: "Invalid arguments to codeless kext load interface (missing identifier).");
10518 } else {
10519 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10520 }
10521 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10522 if (!kextIdentifier) {
10523 OSKextLog(/* kext */ NULL,
10524 kOSKextLogErrorLevel |
10525 kOSKextLogIPCFlag,
10526 format: "Invalid arguments to kext unload request.");
10527 } else if (!theKext) {
10528 OSKextLog(/* kext */ NULL,
10529 kOSKextLogErrorLevel |
10530 kOSKextLogIPCFlag,
10531 format: "Kext %s not found for unload request.",
10532 kextIdentifier->getCStringNoCopy());
10533 result = kOSKextReturnNotFound;
10534 } else {
10535 if (theKext->isDriverKit()) {
10536 result = OSKext::removeDext(dext: theKext);
10537 } else {
10538 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10539 _OSKextGetRequestArgument(requestDict,
10540 kKextRequestArgumentTerminateIOServicesKey));
10541 result = OSKext::removeKext(aKext: theKext, terminateServicesAndRemovePersonalitiesFlag: terminateFlag == kOSBooleanTrue);
10542 }
10543 }
10544 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10545 result = OSKext::dispatchResource(requestDict);
10546 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10547 OSNumber *lookupNum = NULL;
10548 lookupNum = OSDynamicCast(OSNumber,
10549 _OSKextGetRequestArgument(requestDict,
10550 kKextRequestArgumentLookupAddressKey));
10551
10552 responseObject = OSKext::copyKextUUIDForAddress(address: lookupNum);
10553 if (responseObject) {
10554 result = kOSReturnSuccess;
10555 } else {
10556 goto finish;
10557 }
10558 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10559 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10560 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10561 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10562 OSBoolean * delayAutounloadBool = NULL;
10563 OSObject * infoKeysRaw = NULL;
10564 OSArray * infoKeys = NULL;
10565 uint32_t infoKeysCount = 0;
10566
10567 delayAutounloadBool = OSDynamicCast(OSBoolean,
10568 _OSKextGetRequestArgument(requestDict,
10569 kKextRequestArgumentDelayAutounloadKey));
10570
10571 /* If asked to delay autounload, reset the timer if it's currently set.
10572 * (That is, don't schedule an unload if one isn't already pending.
10573 */
10574 if (delayAutounloadBool == kOSBooleanTrue) {
10575 OSKext::considerUnloads(/* rescheduleOnly? */ rescheduleOnlyFlag: true);
10576 }
10577
10578 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10579 kKextRequestArgumentInfoKeysKey);
10580 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10581 if (infoKeysRaw && !infoKeys) {
10582 OSKextLog(/* kext */ NULL,
10583 kOSKextLogErrorLevel |
10584 kOSKextLogIPCFlag,
10585 format: "Invalid arguments to kext info request.");
10586 goto finish;
10587 }
10588
10589 if (infoKeys) {
10590 infoKeysCount = infoKeys->getCount();
10591 for (uint32_t i = 0; i < infoKeysCount; i++) {
10592 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10593 OSKextLog(/* kext */ NULL,
10594 kOSKextLogErrorLevel |
10595 kOSKextLogIPCFlag,
10596 format: "Invalid arguments to kext info request.");
10597 goto finish;
10598 }
10599 }
10600 }
10601
10602 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10603 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, keys: infoKeys);
10604 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10605 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, keys: infoKeys);
10606 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10607 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10608 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10609 responseObject = OSKext::copyDextsInfo(kextIdentifiers, keys: infoKeys);
10610 }
10611
10612 if (!responseObject) {
10613 result = kOSKextReturnInternalError;
10614 } else {
10615 OSKextLog(/* kext */ NULL,
10616 kOSKextLogDebugLevel |
10617 kOSKextLogIPCFlag,
10618 format: "Returning loaded kext info.");
10619 result = kOSReturnSuccess;
10620 }
10621 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10622 /* Hand the current sKernelRequests array to the caller
10623 * (who must release it), and make a new one.
10624 */
10625 responseObject = os::move(t&: sKernelRequests);
10626 sKernelRequests = OSArray::withCapacity(capacity: 0);
10627 sPostedKextLoadIdentifiers->flushCollection();
10628 OSKextLog(/* kext */ NULL,
10629 kOSKextLogDebugLevel |
10630 kOSKextLogIPCFlag,
10631 format: "Returning kernel requests.");
10632 result = kOSReturnSuccess;
10633 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10634 /* Return the set of all requested bundle identifiers */
10635 responseObject = sAllKextLoadIdentifiers;
10636 OSKextLog(/* kext */ NULL,
10637 kOSKextLogDebugLevel |
10638 kOSKextLogIPCFlag,
10639 format: "Returning load requests.");
10640 result = kOSReturnSuccess;
10641 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10642 printf("KextLog: Loading FileSet KC(s)\n");
10643 result = OSKext::loadFileSetKexts(requestDict);
10644 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10645 bool active = iokitDaemonActive();
10646 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10647 if (sOSKextWasResetAfterUserspaceReboot) {
10648 printf("KextLog: was reset after userspace reboot\n");
10649 }
10650 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10651 } else {
10652 OSKextLog(/* kext */ NULL,
10653 kOSKextLogDebugLevel |
10654 kOSKextLogIPCFlag,
10655 format: "Received '%s' invalid request from user space.",
10656 predicate->getCStringNoCopy());
10657 goto finish;
10658 }
10659
10660 /**********
10661 * Now we have handle the request, or not. Gather up the response & logging
10662 * info to ship to user space.
10663 *********/
10664
10665 /* Note: Nothing in OSKext is supposed to retain requestDict,
10666 * but you never know....
10667 */
10668 if (requestDict->getRetainCount() > 1) {
10669 OSKextLog(/* kext */ NULL,
10670 kOSKextLogWarningLevel |
10671 kOSKextLogIPCFlag,
10672 format: "Request from user space still retained by a kext; "
10673 "probable memory leak.");
10674 }
10675
10676 if (responseOut && responseObject) {
10677 serializer = OSSerialize::withCapacity(capacity: 0);
10678 if (!serializer) {
10679 result = kOSKextReturnNoMemory;
10680 goto finish;
10681 }
10682 /*
10683 * Before serializing the kernel requests, patch the dext launch requests so
10684 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10685 * IOUserServerCheckInToken kernel object.
10686 */
10687 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10688 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10689 task_t calling_task = current_task();
10690 if (!requests) {
10691 OSKextLog(/* kext */ NULL,
10692 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10693 format: "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10694 result = kOSKextReturnInternalError;
10695 goto finish;
10696 }
10697 result = patchDextLaunchRequests(calling_task, requests);
10698 if (result != kOSReturnSuccess) {
10699 OSKextLog(/* kext */ NULL,
10700 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10701 format: "Failed to patch dext launch requests.");
10702 goto finish;
10703 }
10704 }
10705
10706 if (!responseObject->serialize(serializer: serializer.get())) {
10707 OSKextLog(/* kext */ NULL,
10708 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10709 format: "Failed to serialize response to request from user space.");
10710 result = kOSKextReturnSerialization;
10711 goto finish;
10712 }
10713
10714 response = (char *)serializer->text();
10715 responseLength = serializer->getLength();
10716 }
10717
10718 if (responseOut && response) {
10719 char * buffer;
10720
10721 /* This kmem_alloc sets the return value of the function.
10722 */
10723 kmem_result = kmem_alloc(map: kernel_map, addrp: (vm_offset_t *)&buffer,
10724 size: round_page(x: responseLength), flags: KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10725 if (kmem_result != KERN_SUCCESS) {
10726 OSKextLog(/* kext */ NULL,
10727 kOSKextLogErrorLevel |
10728 kOSKextLogIPCFlag,
10729 format: "Failed to copy response to request from user space.");
10730 result = kmem_result;
10731 goto finish;
10732 } else {
10733 /* 11981737 - clear uninitialized data in last page */
10734 bzero(s: (void *)(buffer + responseLength),
10735 n: (round_page(x: responseLength) - responseLength));
10736 memcpy(dst: buffer, src: response, n: responseLength);
10737 *responseOut = buffer;
10738 *responseLengthOut = responseLength;
10739 }
10740 }
10741
10742finish:
10743
10744 /* Gather up the collected log messages for user space. Any messages
10745 * messages past this call will not make it up as log messages but
10746 * will be in the system log. Note that we ignore the return of the
10747 * serialize; it has no bearing on the operation at hand even if we
10748 * fail to get the log messages.
10749 */
10750 logInfoArray = OSKext::clearUserSpaceLogFilter();
10751
10752 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10753 (void)OSKext::serializeLogInfo(logInfoArray: logInfoArray.get(),
10754 logInfoOut, logInfoLengthOut);
10755 }
10756
10757 IORecursiveLockUnlock(lock: sKextLock);
10758
10759 return result;
10760}
10761
10762#if PRAGMA_MARK
10763#pragma mark Linked Kext Collection Support
10764#endif
10765
10766static int
10767__whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10768{
10769 for (int i = 0; i < segCount; i++) {
10770 vm_offset_t segStart = segAddrs[i];
10771 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10772
10773 if (theAddr >= segStart && theAddr < segEnd) {
10774 return i;
10775 }
10776 }
10777 return -1;
10778}
10779
10780static void
10781__slideOldKaslrOffsets(kernel_mach_header_t *mh,
10782 kernel_segment_command_t *kextTextSeg,
10783 OSData *kaslrOffsets)
10784{
10785 static const char *plk_segNames[] = {
10786 "__TEXT",
10787 "__TEXT_EXEC",
10788 "__DATA",
10789 "__DATA_CONST",
10790 "__LINKEDIT",
10791 "__PRELINK_TEXT",
10792 "__PLK_TEXT_EXEC",
10793 "__PRELINK_DATA",
10794 "__PLK_DATA_CONST",
10795 "__PLK_LLVM_COV",
10796 "__PLK_LINKEDIT",
10797 "__PRELINK_INFO"
10798 };
10799 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10800
10801 unsigned long plk_segSizes[num_plk_seg];
10802 vm_offset_t plk_segAddrs[num_plk_seg];
10803
10804 for (size_t i = 0; i < num_plk_seg; i++) {
10805 plk_segSizes[i] = 0;
10806 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10807 }
10808
10809 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10810
10811 int slidKextAddrCount = 0;
10812 int badSlideAddr = 0;
10813 int badSlideTarget = 0;
10814
10815 struct kaslrPackedOffsets {
10816 uint32_t count; /* number of offsets */
10817 uint32_t offsetsArray[]; /* offsets to slide */
10818 };
10819 const struct kaslrPackedOffsets *myOffsets = NULL;
10820 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10821
10822 for (uint32_t j = 0; j < myOffsets->count; j++) {
10823 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10824 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10825 int slideAddrSegIndex = -1;
10826 int addrToSlideSegIndex = -1;
10827
10828 slideAddrSegIndex = __whereIsAddr(theAddr: (vm_offset_t)slideAddr, segSizes: &plk_segSizes[0], segAddrs: &plk_segAddrs[0], segCount: num_plk_seg);
10829 if (slideAddrSegIndex >= 0) {
10830 addrToSlideSegIndex = __whereIsAddr(theAddr: ml_static_slide(vaddr: *slideAddr), segSizes: &plk_segSizes[0], segAddrs: &plk_segAddrs[0], segCount: num_plk_seg);
10831 if (addrToSlideSegIndex < 0) {
10832 badSlideTarget++;
10833 continue;
10834 }
10835 } else {
10836 badSlideAddr++;
10837 continue;
10838 }
10839
10840 slidKextAddrCount++;
10841 *slideAddr = ml_static_slide(vaddr: *slideAddr);
10842 } // for ...
10843}
10844
10845
10846
10847/********************************************************************
10848* addKextsFromKextCollection
10849*
10850* Input: MachO header of kext collection. The MachO is assumed to
10851* have a section named 'info_seg_name,info_sect_name' that
10852* contains a serialized XML info dictionary. This dictionary
10853* contains a UUID, possibly a set of relocations (for older
10854* kxld-built binaries), and an array of kext personalities.
10855*
10856********************************************************************/
10857bool
10858OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10859 OSDictionary *infoDict, const char *text_seg_name,
10860 OSData **kcUUID, kc_kind_t type)
10861{
10862 bool result = false;
10863
10864 OSArray *kextArray = NULL; // do not release
10865 OSData *infoDictKCUUID = NULL; // do not release
10866 OSData *kaslrOffsets = NULL; // do not release
10867
10868 IORegistryEntry *registryRoot = NULL; // do not release
10869 OSSharedPtr<OSNumber> kcKextCount;
10870
10871 /* extract the KC UUID from the dictionary */
10872 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10873 if (infoDictKCUUID) {
10874 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10875 panic("kcUUID length is %d, expected %lu",
10876 infoDictKCUUID->getLength(), sizeof(uuid_t));
10877 }
10878 }
10879
10880 /* locate the array of kext dictionaries */
10881 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10882 if (!kextArray) {
10883 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10884 format: "The given KC has no kext info dictionaries");
10885 goto finish;
10886 }
10887
10888 /*
10889 * old-style KASLR offsets may be present in the info dictionary. If
10890 * we find them, use them and eventually slide them.
10891 */
10892 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10893
10894 /*
10895 * Before processing any kexts, locate the special kext bundle which
10896 * contains a list of kexts that we are to prevent from loading.
10897 */
10898 createExcludeListFromPrelinkInfo(theInfoArray: kextArray);
10899
10900 /*
10901 * Create OSKext objects for each kext we find in the array of kext
10902 * info plist dictionaries.
10903 */
10904 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10905 OSDictionary *kextDict = NULL;
10906 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10907 if (!kextDict) {
10908 OSKextLog(/* kext */ NULL,
10909 kOSKextLogErrorLevel |
10910 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10911 format: "Kext info dictionary for kext #%d isn't a dictionary?", i);
10912 continue;
10913 }
10914
10915 /*
10916 * Create the kext for the entry, then release it, because the
10917 * kext system keeps a reference around until the kext is
10918 * explicitly removed. Any creation/registration failures are
10919 * already logged for us.
10920 */
10921 withPrelinkedInfoDict(anInfoDict: kextDict, doCoalescedSlides: (kaslrOffsets ? TRUE : FALSE), type);
10922 }
10923
10924 /*
10925 * slide old-style kxld relocations
10926 * NOTE: this is still used on embedded KCs built with kcgen
10927 * TODO: Remove this once we use the new kext linker everywhere!
10928 */
10929 if (kaslrOffsets && vm_kernel_slide > 0) {
10930 kernel_segment_command_t *text_segment = NULL;
10931 text_segment = getsegbynamefromheader(header: mh, seg_name: text_seg_name);
10932 if (!text_segment) {
10933 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10934 format: "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10935 goto finish;
10936 }
10937
10938 __slideOldKaslrOffsets(mh, kextTextSeg: text_segment, kaslrOffsets);
10939 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10940 setAllVMAttributes();
10941 }
10942
10943 /* Store the number of prelinked kexts in the registry so we can tell
10944 * when the system has been started from a prelinked kernel.
10945 */
10946 registryRoot = IORegistryEntry::getRegistryRoot();
10947 assert(registryRoot);
10948
10949 kcKextCount = OSNumber::withNumber(value: (unsigned long long)infoDict->getCount(), numberOfBits: 8 * sizeof(uint32_t));
10950 assert(kcKextCount);
10951 if (kcKextCount) {
10952 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10953 OSNumber *num;
10954 num = OSDynamicCast(OSNumber, prop.get());
10955 if (num) {
10956 kcKextCount->addValue(value: num->unsigned64BitValue());
10957 }
10958 registryRoot->setProperty(kOSPrelinkKextCountKey, anObject: kcKextCount.get());
10959 }
10960
10961 OSKextLog(/* kext */ NULL,
10962 kOSKextLogProgressLevel |
10963 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10964 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10965 format: "%u prelinked kexts", infoDict->getCount());
10966
10967
10968 if (kcUUID && infoDictKCUUID) {
10969 *kcUUID = OSData::withData(inData: infoDictKCUUID).detach();
10970 }
10971
10972 result = true;
10973
10974finish:
10975 return result;
10976}
10977
10978bool
10979OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10980 OSDictionary *infoDict, const char *text_seg_name,
10981 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10982{
10983 OSData *result = NULL;
10984 bool success = addKextsFromKextCollection(mh,
10985 infoDict,
10986 text_seg_name,
10987 kcUUID: &result,
10988 type);
10989 if (success) {
10990 kcUUID.reset(p: result, OSNoRetain);
10991 }
10992 return success;
10993}
10994
10995static OSSharedPtr<OSObject> deferredAuxKCXML;
10996bool
10997OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10998 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10999{
11000 if (type != KCKindAuxiliary) {
11001 return false;
11002 }
11003
11004 kernel_mach_header_t *_mh;
11005 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
11006 if (!_mh || _mh != mh) {
11007 return false;
11008 }
11009
11010 if (deferredAuxKCXML) {
11011 /* only allow this to be called once */
11012 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11013 format: "An Aux KC has already been registered for deferred processing.");
11014 return false;
11015 }
11016
11017 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11018 if (!infoDict) {
11019 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11020 format: "The Aux KC has info dictionary");
11021 return false;
11022 }
11023
11024 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
11025 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
11026 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11027 format: "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
11028 return false;
11029 }
11030
11031 /*
11032 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
11033 * sysctl can return the UUID to user space which will check this
11034 * value for errors.
11035 */
11036 memcpy(dst: (void *)&auxkc_uuid, src: (const void *)kcUUID->getBytesNoCopy(),
11037 n: kcUUID->getLength());
11038 uuid_unparse_upper(uu: auxkc_uuid, out: auxkc_uuid_string);
11039 auxkc_uuid_valid = TRUE;
11040
11041 deferredAuxKCXML = parsedXML;
11042
11043 return true;
11044}
11045
11046OSSharedPtr<OSObject>
11047OSKext::consumeDeferredKextCollection(kc_kind_t type)
11048{
11049 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
11050 return NULL;
11051 }
11052
11053 return os::move(t&: deferredAuxKCXML);
11054}
11055
11056#if PRAGMA_MARK
11057#pragma mark Profile-Guided-Optimization Support
11058#endif
11059
11060// #include <InstrProfiling.h>
11061extern "C" {
11062uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
11063 const char *DataEnd,
11064 const char *CountersBegin,
11065 const char *CountersEnd,
11066 const char *NamesBegin,
11067 const char *NamesEnd);
11068int __llvm_profile_write_buffer_internal(char *Buffer,
11069 const char *DataBegin,
11070 const char *DataEnd,
11071 const char *CountersBegin,
11072 const char *CountersEnd,
11073 const char *NamesBegin,
11074 const char *NamesEnd);
11075}
11076
11077
11078static
11079void
11080OSKextPgoMetadataPut(char *pBuffer,
11081 size_t *position,
11082 size_t bufferSize,
11083 uint32_t *num_pairs,
11084 const char *key,
11085 const char *value)
11086{
11087 size_t strlen_key = strlen(s: key);
11088 size_t strlen_value = strlen(s: value);
11089 size_t len = strlen(s: key) + 1 + strlen(s: value) + 1;
11090 char *pos = pBuffer + *position;
11091 *position += len;
11092 if (pBuffer && bufferSize && *position <= bufferSize) {
11093 memcpy(dst: pos, src: key, n: strlen_key); pos += strlen_key;
11094 *(pos++) = '=';
11095 memcpy(dst: pos, src: value, n: strlen_value); pos += strlen_value;
11096 *(pos++) = 0;
11097 if (num_pairs) {
11098 (*num_pairs)++;
11099 }
11100 }
11101}
11102
11103
11104static
11105void
11106OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
11107{
11108 *position += strlen(s: key) + 1 + value_max + 1;
11109}
11110
11111
11112static
11113void
11114OSKextPgoMetadataPutAll(OSKext *kext,
11115 uuid_t instance_uuid,
11116 char *pBuffer,
11117 size_t *position,
11118 size_t bufferSize,
11119 uint32_t *num_pairs)
11120{
11121 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
11122 //log_10 2^16 ≈ 4.82
11123 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
11124 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
11125
11126 if (!pBuffer) {
11127 OSKextPgoMetadataPutMax(position, key: "INSTANCE", value_max: 36);
11128 OSKextPgoMetadataPutMax(position, key: "UUID", value_max: 36);
11129 OSKextPgoMetadataPutMax(position, key: "TIMESTAMP", value_max: max_timestamp_string_size);
11130 } else {
11131 uuid_string_t instance_uuid_string;
11132 uuid_unparse(uu: instance_uuid, out: instance_uuid_string);
11133 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11134 key: "INSTANCE", value: instance_uuid_string);
11135
11136 OSSharedPtr<OSData> uuid_data;
11137 uuid_t uuid;
11138 uuid_string_t uuid_string;
11139 uuid_data = kext->copyUUID();
11140 if (uuid_data) {
11141 memcpy(dst: uuid, src: uuid_data->getBytesNoCopy(), n: sizeof(uuid));
11142 uuid_unparse(uu: uuid, out: uuid_string);
11143 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11144 key: "UUID", value: uuid_string);
11145 }
11146
11147 clock_sec_t secs;
11148 clock_usec_t usecs;
11149 clock_get_calendar_microtime(secs: &secs, microsecs: &usecs);
11150 assert(usecs < 1000000);
11151 char timestamp[max_timestamp_string_size + 1];
11152 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
11153 snprintf(timestamp, count: sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
11154 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11155 key: "TIMESTAMP", value: timestamp);
11156 }
11157
11158 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11159 key: "NAME", value: kext->getIdentifierCString());
11160
11161 char versionCString[kOSKextVersionMaxLength];
11162 OSKextVersionGetString(aVersion: kext->getVersion(), buffer: versionCString, kOSKextVersionMaxLength);
11163 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11164 key: "VERSION", value: versionCString);
11165}
11166
11167static
11168size_t
11169OSKextPgoMetadataSize(OSKext *kext)
11170{
11171 size_t position = 0;
11172 uuid_t fakeuuid = {};
11173 OSKextPgoMetadataPutAll(kext, instance_uuid: fakeuuid, NULL, position: &position, bufferSize: 0, NULL);
11174 return position;
11175}
11176
11177int
11178OSKextGrabPgoDataLocked(OSKext *kext,
11179 bool metadata,
11180 uuid_t instance_uuid,
11181 uint64_t *pSize,
11182 char *pBuffer,
11183 uint64_t bufferSize)
11184{
11185 int err = 0;
11186
11187 kernel_section_t *sect_prf_data = NULL;
11188 kernel_section_t *sect_prf_name = NULL;
11189 kernel_section_t *sect_prf_cnts = NULL;
11190 uint64_t size;
11191 size_t metadata_size = 0;
11192 size_t offset_to_pairs = 0;
11193
11194 sect_prf_data = kext->lookupSection(segname: "__DATA", secname: "__llvm_prf_data");
11195 sect_prf_name = kext->lookupSection(segname: "__DATA", secname: "__llvm_prf_names");
11196 if (!sect_prf_name) {
11197 // kextcache sometimes truncates the section name to 15 chars
11198 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11199 sect_prf_name = kext->lookupSection(segname: "__DATA", secname: "__llvm_prf_name");
11200 }
11201 sect_prf_cnts = kext->lookupSection(segname: "__DATA", secname: "__llvm_prf_cnts");
11202
11203 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11204 err = ENOTSUP;
11205 goto out;
11206 }
11207
11208 size = __llvm_profile_get_size_for_buffer_internal(
11209 DataBegin: (const char*) sect_prf_data->addr, DataEnd: (const char*) sect_prf_data->addr + sect_prf_data->size,
11210 CountersBegin: (const char*) sect_prf_cnts->addr, CountersEnd: (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11211 NamesBegin: (const char*) sect_prf_name->addr, NamesEnd: (const char*) sect_prf_name->addr + sect_prf_name->size);
11212
11213 if (metadata) {
11214 metadata_size = OSKextPgoMetadataSize(kext);
11215 size += metadata_size;
11216 size += sizeof(pgo_metadata_footer);
11217 }
11218
11219
11220 if (pSize) {
11221 *pSize = size;
11222 }
11223
11224 if (pBuffer && bufferSize) {
11225 if (bufferSize < size) {
11226 err = ERANGE;
11227 goto out;
11228 }
11229
11230 err = __llvm_profile_write_buffer_internal(
11231 Buffer: pBuffer,
11232 DataBegin: (const char*) sect_prf_data->addr, DataEnd: (const char*) sect_prf_data->addr + sect_prf_data->size,
11233 CountersBegin: (const char*) sect_prf_cnts->addr, CountersEnd: (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11234 NamesBegin: (const char*) sect_prf_name->addr, NamesEnd: (const char*) sect_prf_name->addr + sect_prf_name->size);
11235
11236 if (err) {
11237 err = EIO;
11238 goto out;
11239 }
11240
11241 if (metadata) {
11242 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11243 if (offset_to_pairs > UINT32_MAX) {
11244 err = E2BIG;
11245 goto out;
11246 }
11247
11248 char *end_of_buffer = pBuffer + size;
11249 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11250 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11251
11252 size_t metadata_position = 0;
11253 uint32_t num_pairs = 0;
11254 OSKextPgoMetadataPutAll(kext, instance_uuid, pBuffer: metadata_buffer, position: &metadata_position, bufferSize: metadata_size, num_pairs: &num_pairs);
11255 while (metadata_position < metadata_size) {
11256 metadata_buffer[metadata_position++] = 0;
11257 }
11258
11259 struct pgo_metadata_footer footer;
11260 footer.magic = htonl(0x6d657461);
11261 footer.number_of_pairs = htonl( num_pairs );
11262 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11263 memcpy(dst: footerp, src: &footer, n: sizeof(footer));
11264 }
11265 }
11266
11267out:
11268 return err;
11269}
11270
11271
11272int
11273OSKextGrabPgoData(uuid_t uuid,
11274 uint64_t *pSize,
11275 char *pBuffer,
11276 uint64_t bufferSize,
11277 int wait_for_unload,
11278 int metadata)
11279{
11280 int err = 0;
11281 OSSharedPtr<OSKext> kext;
11282
11283
11284 IORecursiveLockLock(lock: sKextLock);
11285
11286 kext = OSKext::lookupKextWithUUID(wanted: uuid);
11287 if (!kext) {
11288 err = ENOENT;
11289 goto out;
11290 }
11291
11292 if (wait_for_unload) {
11293 OSKextGrabPgoStruct s;
11294
11295 s.metadata = metadata;
11296 s.pSize = pSize;
11297 s.pBuffer = pBuffer;
11298 s.bufferSize = bufferSize;
11299 s.err = EINTR;
11300
11301 struct list_head *prev = &kext->pendingPgoHead;
11302 struct list_head *next = kext->pendingPgoHead.next;
11303
11304 s.list_head.prev = prev;
11305 s.list_head.next = next;
11306
11307 prev->next = &s.list_head;
11308 next->prev = &s.list_head;
11309
11310 kext.reset();
11311
11312 IORecursiveLockSleep(lock: sKextLock, event: &s, THREAD_ABORTSAFE);
11313
11314 prev = s.list_head.prev;
11315 next = s.list_head.next;
11316
11317 prev->next = next;
11318 next->prev = prev;
11319
11320 err = s.err;
11321 } else {
11322 err = OSKextGrabPgoDataLocked(kext: kext.get(), metadata, instance_uuid: kext->instance_uuid, pSize, pBuffer, bufferSize);
11323 }
11324
11325out:
11326
11327 IORecursiveLockUnlock(lock: sKextLock);
11328
11329 return err;
11330}
11331
11332void
11333OSKextResetPgoCountersLock()
11334{
11335 IORecursiveLockLock(lock: sKextLock);
11336}
11337
11338void
11339OSKextResetPgoCountersUnlock()
11340{
11341 IORecursiveLockUnlock(lock: sKextLock);
11342}
11343
11344
11345extern unsigned int not_in_kdp;
11346
11347void
11348OSKextResetPgoCounters()
11349{
11350 assert(!not_in_kdp);
11351 uint32_t count = sLoadedKexts->getCount();
11352 for (uint32_t i = 0; i < count; i++) {
11353 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11354 kernel_section_t *sect_prf_cnts = kext->lookupSection(segname: "__DATA", secname: "__llvm_prf_cnts");
11355 if (!sect_prf_cnts) {
11356 continue;
11357 }
11358 memset(s: (void*)sect_prf_cnts->addr, c: 0, n: sect_prf_cnts->size);
11359 }
11360}
11361
11362OSSharedPtr<OSDictionary>
11363OSKext::copyLoadedKextInfoByUUID(
11364 OSArray * kextIdentifiers,
11365 OSArray * infoKeys)
11366{
11367 OSSharedPtr<OSDictionary> result;
11368 OSSharedPtr<OSDictionary> kextInfo;
11369 uint32_t max_count, i, j;
11370 uint32_t idCount = 0;
11371 uint32_t idIndex = 0;
11372 IORecursiveLockLock(lock: sKextLock);
11373 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11374 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11375
11376#if CONFIG_MACF
11377 /* Is the calling process allowed to query kext info? */
11378 if (current_task() != kernel_task) {
11379 int macCheckResult = 0;
11380 kauth_cred_t cred = NULL;
11381
11382 cred = kauth_cred_get_with_ref();
11383 macCheckResult = mac_kext_check_query(cred);
11384 kauth_cred_unref(&cred);
11385
11386 if (macCheckResult != 0) {
11387 OSKextLog(/* kext */ NULL,
11388 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11389 format: "Failed to query kext info (MAC policy error 0x%x).",
11390 macCheckResult);
11391 goto finish;
11392 }
11393 }
11394#endif
11395
11396 /* Empty list of UUIDs is equivalent to no list (get all).
11397 */
11398 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11399 kextIdentifiers = NULL;
11400 } else if (kextIdentifiers) {
11401 idCount = kextIdentifiers->getCount();
11402 }
11403
11404 /* Same for keys.
11405 */
11406 if (infoKeys && !infoKeys->getCount()) {
11407 infoKeys = NULL;
11408 }
11409
11410 max_count = count[0] + count[1];
11411 result = OSDictionary::withCapacity(capacity: max_count);
11412 if (!result) {
11413 goto finish;
11414 }
11415
11416 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11417 for (i = 0; i < count[j]; i++) {
11418 OSKext *thisKext = NULL; // do not release
11419 Boolean includeThis = true;
11420 uuid_t thisKextUUID;
11421 uuid_t thisKextTextUUID;
11422 OSSharedPtr<OSData> uuid_data;
11423 uuid_string_t uuid_key;
11424
11425 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11426 if (!thisKext) {
11427 continue;
11428 }
11429
11430 uuid_data = thisKext->copyUUID();
11431 if (!uuid_data) {
11432 continue;
11433 }
11434
11435 memcpy(dst: &thisKextUUID, src: uuid_data->getBytesNoCopy(), n: sizeof(thisKextUUID));
11436
11437 uuid_unparse(uu: thisKextUUID, out: uuid_key);
11438
11439 uuid_data = thisKext->copyTextUUID();
11440 if (!uuid_data) {
11441 continue;
11442 }
11443 memcpy(dst: &thisKextTextUUID, src: uuid_data->getBytesNoCopy(), n: sizeof(thisKextTextUUID));
11444
11445 /* Skip current kext if we have a list of UUIDs and
11446 * it isn't in the list.
11447 */
11448 if (kextIdentifiers) {
11449 includeThis = false;
11450
11451 for (idIndex = 0; idIndex < idCount; idIndex++) {
11452 const OSString* wantedUUID = OSDynamicCast(OSString,
11453 kextIdentifiers->getObject(idIndex));
11454
11455 uuid_t uuid;
11456 uuid_parse(in: wantedUUID->getCStringNoCopy(), uu: uuid);
11457
11458 if ((0 == uuid_compare(uu1: uuid, uu2: thisKextUUID))
11459 || (0 == uuid_compare(uu1: uuid, uu2: thisKextTextUUID))) {
11460 includeThis = true;
11461 /* Only need to find the first kext if multiple match,
11462 * ie. asking for the kernel uuid does not need to find
11463 * interface kexts or builtin static kexts.
11464 */
11465 kextIdentifiers->removeObject(index: idIndex);
11466 uuid_unparse(uu: uuid, out: uuid_key);
11467 break;
11468 }
11469 }
11470 }
11471
11472 if (!includeThis) {
11473 continue;
11474 }
11475
11476 kextInfo = thisKext->copyInfo(keys: infoKeys);
11477 if (kextInfo) {
11478 result->setObject(aKey: uuid_key, anObject: kextInfo.get());
11479 }
11480
11481 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11482 goto finish;
11483 }
11484 }
11485 }
11486
11487finish:
11488 IORecursiveLockUnlock(lock: sKextLock);
11489
11490 return result;
11491}
11492
11493/*********************************************************************
11494*********************************************************************/
11495/* static */
11496OSSharedPtr<OSDictionary>
11497OSKext::copyKextCollectionInfo(
11498 OSDictionary *requestDict,
11499 OSArray *infoKeys)
11500{
11501 OSSharedPtr<OSDictionary> result;
11502 OSString *collectionType = NULL;
11503 OSObject *rawLoadedState = NULL;
11504 OSString *loadedState = NULL;
11505
11506 kc_kind_t kc_request_kind = KCKindUnknown;
11507 bool onlyLoaded = false;
11508 bool onlyUnloaded = false;
11509
11510#if CONFIG_MACF
11511 /* Is the calling process allowed to query kext info? */
11512 if (current_task() != kernel_task) {
11513 int macCheckResult = 0;
11514 kauth_cred_t cred = NULL;
11515
11516 cred = kauth_cred_get_with_ref();
11517 macCheckResult = mac_kext_check_query(cred);
11518 kauth_cred_unref(&cred);
11519
11520 if (macCheckResult != 0) {
11521 OSKextLog(/* kext */ NULL,
11522 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11523 format: "Failed to query kext info (MAC policy error 0x%x).",
11524 macCheckResult);
11525 goto finish;
11526 }
11527 }
11528#endif
11529
11530 if (infoKeys && !infoKeys->getCount()) {
11531 infoKeys = NULL;
11532 }
11533
11534 collectionType = OSDynamicCast(OSString,
11535 _OSKextGetRequestArgument(requestDict,
11536 kKextRequestArgumentCollectionTypeKey));
11537 if (!collectionType) {
11538 OSKextLog(/* kext */ NULL,
11539 kOSKextLogErrorLevel |
11540 kOSKextLogIPCFlag,
11541 format: "Invalid '%s' argument to kext collection info request.",
11542 kKextRequestArgumentCollectionTypeKey);
11543 goto finish;
11544 }
11545 if (collectionType->isEqualTo(kKCTypePrimary)) {
11546 kc_request_kind = KCKindPrimary;
11547 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11548 kc_request_kind = KCKindPageable;
11549 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11550 kc_request_kind = KCKindAuxiliary;
11551 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11552 kc_request_kind = KCKindNone;
11553 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11554 OSKextLog(/* kext */ NULL,
11555 kOSKextLogErrorLevel |
11556 kOSKextLogIPCFlag,
11557 format: "Invalid '%s' argument value '%s' to kext collection info request.",
11558 kKextRequestArgumentCollectionTypeKey,
11559 collectionType->getCStringNoCopy());
11560 goto finish;
11561 }
11562
11563 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11564 kKextRequestArgumentLoadedStateKey);
11565 if (rawLoadedState) {
11566 loadedState = OSDynamicCast(OSString, rawLoadedState);
11567 if (!loadedState) {
11568 OSKextLog(/* kext */ NULL,
11569 kOSKextLogErrorLevel |
11570 kOSKextLogIPCFlag,
11571 format: "Invalid '%s' argument to kext collection info request.",
11572 kKextRequestArgumentLoadedStateKey);
11573 goto finish;
11574 }
11575 }
11576 if (loadedState) {
11577 if (loadedState->isEqualTo(cString: "Loaded")) {
11578 onlyLoaded = true;
11579 } else if (loadedState->isEqualTo(cString: "Unloaded")) {
11580 onlyUnloaded = true;
11581 } else if (!loadedState->isEqualTo(cString: "Any")) {
11582 OSKextLog(/* kext */ NULL,
11583 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11584 format: "Invalid '%s' argument value '%s' for '%s' collection info",
11585 kKextRequestArgumentLoadedStateKey,
11586 loadedState->getCStringNoCopy(),
11587 collectionType->getCStringNoCopy());
11588 goto finish;
11589 }
11590 }
11591
11592 result = OSDictionary::withCapacity(capacity: sKextsByID->getCount());
11593 if (!result) {
11594 goto finish;
11595 }
11596
11597 IORecursiveLockLock(lock: sKextLock);
11598 { // start block scope
11599 sKextsByID->iterateObjects(block: ^bool (const OSSymbol *thisKextID, OSObject *obj)
11600 {
11601 OSKext *thisKext = NULL; // do not release
11602 OSSharedPtr<OSDictionary> kextInfo;
11603
11604 (void)thisKextID;
11605
11606 thisKext = OSDynamicCast(OSKext, obj);
11607 if (!thisKext) {
11608 return false;
11609 }
11610
11611 /*
11612 * skip the kext if it came from the wrong collection type
11613 * (and the caller requested a specific type)
11614 */
11615 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11616 return false;
11617 }
11618
11619 /*
11620 * respect the caller's desire to find only loaded or
11621 * unloaded kexts
11622 */
11623 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(anObject: thisKext, index: 0))) {
11624 return false;
11625 }
11626 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(anObject: thisKext, index: 0))) {
11627 return false;
11628 }
11629
11630 kextInfo = thisKext->copyInfo(keys: infoKeys);
11631 if (kextInfo) {
11632 result->setObject(aKey: thisKext->getIdentifier(), anObject: kextInfo.get());
11633 }
11634 return false;
11635 });
11636 } // end block scope
11637 IORecursiveLockUnlock(lock: sKextLock);
11638
11639finish:
11640 return result;
11641}
11642
11643/* static */
11644OSSharedPtr<OSArray>
11645OSKext::copyDextsInfo(
11646 OSArray *kextIdentifiers,
11647 OSArray *infoKeys)
11648{
11649 OSSharedPtr<OSArray> result = NULL;
11650 uint32_t idCount = 0;
11651 bool getActive = false;
11652 bool getLoaded = false;
11653 bool getUnloaded = false;
11654 bool getPendingUpgrade = false;
11655 unsigned int avgDextCount = 0;
11656
11657#if CONFIG_MACF
11658 /* Is the calling process allowed to query dext info? */
11659 if (current_task() != kernel_task) {
11660 int macCheckResult = 0;
11661 kauth_cred_t cred = NULL;
11662
11663 cred = kauth_cred_get_with_ref();
11664 macCheckResult = mac_kext_check_query(cred);
11665 kauth_cred_unref(&cred);
11666
11667 if (macCheckResult != 0) {
11668 OSKextLog(/* kext */ NULL,
11669 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11670 format: "Failed to query kext info (MAC policy error 0x%x).",
11671 macCheckResult);
11672 goto finish;
11673 }
11674 }
11675#endif
11676 /*
11677 * No infoKeys means return everything we
11678 * know about the dexts.
11679 */
11680 if (infoKeys && !infoKeys->getCount()) {
11681 infoKeys = NULL;
11682 }
11683
11684 /*
11685 * Empty list of bundle ids is equivalent to
11686 * no list (get all).
11687 */
11688 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11689 kextIdentifiers = NULL;
11690 } else if (kextIdentifiers) {
11691 idCount = kextIdentifiers->getCount();
11692 }
11693
11694 /*
11695 * Caller can specify which state of dexts to query.
11696 */
11697 if (infoKeys && _OSArrayContainsCString(array: infoKeys, kOSBundleDextStateActiveKey)) {
11698 getActive = true;
11699 }
11700 if (infoKeys && _OSArrayContainsCString(array: infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11701 getLoaded = true;
11702 }
11703 if (infoKeys && _OSArrayContainsCString(array: infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11704 getUnloaded = true;
11705 }
11706 if (infoKeys && _OSArrayContainsCString(array: infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11707 getPendingUpgrade = true;
11708 }
11709
11710 /*
11711 * By default we are going to return all active and pendingUpgrade dexts
11712 * only.
11713 */
11714 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11715 getActive = true;
11716 getPendingUpgrade = true;
11717 }
11718
11719 /*
11720 * We return a dictionary of dexts
11721 * for every group requested.
11722 */
11723 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11724 result = OSArray::withCapacity(capacity: avgDextCount);
11725 if (!result) {
11726 goto finish;
11727 }
11728
11729 IORecursiveLockLock(lock: sKextLock);
11730 { // start block scope
11731 if (getActive || getLoaded || getUnloaded) {
11732 sKextsByID->iterateObjects(block: ^bool (const OSSymbol *thisKextID, OSObject *obj)
11733 {
11734 OSKext *thisKext = NULL; // do not release
11735 OSSharedPtr<OSDictionary> kextInfo;
11736 Boolean includeThis = true;
11737 (void)thisKextID;
11738
11739 thisKext = OSDynamicCast(OSKext, obj);
11740 if (!thisKext || !thisKext->isDriverKit()) {
11741 return false;
11742 }
11743
11744 /*
11745 * Skip current dext if we have a list of bundle IDs and
11746 * it isn't in the list.
11747 */
11748 if (kextIdentifiers) {
11749 includeThis = false;
11750
11751 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11752 const OSString * thisRequestID = OSDynamicCast(OSString,
11753 kextIdentifiers->getObject(idIndex));
11754 if (thisKextID->isEqualTo(anObject: thisRequestID)) {
11755 includeThis = true;
11756 break;
11757 }
11758 }
11759 }
11760
11761 if (!includeThis) {
11762 return false;
11763 }
11764
11765 OSSharedPtr<OSString> state;
11766 if (sLoadedDriverKitKexts->getNextIndexOfObject(anObject: thisKext, index: 0) == -1U) {
11767 if (!(getActive || getUnloaded)) {
11768 return false;
11769 }
11770 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11771 } else {
11772 if (!(getActive || getLoaded)) {
11773 return false;
11774 }
11775 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11776 }
11777
11778 kextInfo = thisKext->copyInfo(keys: infoKeys);
11779 if (kextInfo) {
11780 kextInfo->setObject(kOSBundleDextStateKey, anObject: state.get());
11781 result->setObject(kextInfo.get());
11782 }
11783
11784 return false;
11785 });
11786 }
11787
11788 if (getPendingUpgrade) {
11789 sDriverKitToUpgradeByID->iterateObjects(block: ^bool (const OSSymbol *thisKextID, OSObject *obj)
11790 {
11791 OSKext *thisKext = NULL; // do not release
11792 OSSharedPtr<OSDictionary> kextInfo;
11793 Boolean includeThis = true;
11794 (void)thisKextID;
11795
11796 thisKext = OSDynamicCast(OSKext, obj);
11797 if (!thisKext) {
11798 return false;
11799 }
11800 __assert_only bool isDext = thisKext->isDriverKit();
11801 assert(isDext == true);
11802
11803 /*
11804 * Skip current dext if we have a list of bundle IDs and
11805 * it isn't in the list.
11806 */
11807 if (kextIdentifiers) {
11808 includeThis = false;
11809
11810 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11811 const OSString * thisRequestID = OSDynamicCast(OSString,
11812 kextIdentifiers->getObject(idIndex));
11813 if (thisKextID->isEqualTo(anObject: thisRequestID)) {
11814 includeThis = true;
11815 break;
11816 }
11817 }
11818 }
11819
11820 if (!includeThis) {
11821 return false;
11822 }
11823
11824 kextInfo = thisKext->copyInfo(keys: infoKeys);
11825 if (kextInfo) {
11826 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11827 kextInfo->setObject(kOSBundleDextStateKey, anObject: state.get());
11828 result->setObject(kextInfo.get());
11829 }
11830 return false;
11831 });
11832 }
11833 } // end block scope
11834 IORecursiveLockUnlock(lock: sKextLock);
11835finish:
11836 return result;
11837}
11838
11839/*********************************************************************
11840*********************************************************************/
11841/* static */
11842OSSharedPtr<OSDictionary>
11843OSKext::copyLoadedKextInfo(
11844 OSArray * kextIdentifiers,
11845 OSArray * infoKeys)
11846{
11847 OSSharedPtr<OSDictionary> result;
11848 uint32_t idCount = 0;
11849 bool onlyLoaded;
11850
11851 IORecursiveLockLock(lock: sKextLock);
11852
11853#if CONFIG_MACF
11854 /* Is the calling process allowed to query kext info? */
11855 if (current_task() != kernel_task) {
11856 int macCheckResult = 0;
11857 kauth_cred_t cred = NULL;
11858
11859 cred = kauth_cred_get_with_ref();
11860 macCheckResult = mac_kext_check_query(cred);
11861 kauth_cred_unref(&cred);
11862
11863 if (macCheckResult != 0) {
11864 OSKextLog(/* kext */ NULL,
11865 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11866 format: "Failed to query kext info (MAC policy error 0x%x).",
11867 macCheckResult);
11868 goto finish;
11869 }
11870 }
11871#endif
11872
11873 /* Empty list of bundle ids is equivalent to no list (get all).
11874 */
11875 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11876 kextIdentifiers = NULL;
11877 } else if (kextIdentifiers) {
11878 idCount = kextIdentifiers->getCount();
11879 }
11880
11881 /* Same for keys.
11882 */
11883 if (infoKeys && !infoKeys->getCount()) {
11884 infoKeys = NULL;
11885 }
11886
11887 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(array: infoKeys, kOSBundleAllPrelinkedKey));
11888
11889 result = OSDictionary::withCapacity(capacity: 128);
11890 if (!result) {
11891 goto finish;
11892 }
11893
11894#if 0
11895 OSKextLog(/* kext */ NULL,
11896 kOSKextLogErrorLevel |
11897 kOSKextLogGeneralFlag,
11898 "kaslr: vm_kernel_slide 0x%lx \n",
11899 vm_kernel_slide);
11900 OSKextLog(/* kext */ NULL,
11901 kOSKextLogErrorLevel |
11902 kOSKextLogGeneralFlag,
11903 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11904 vm_kernel_stext, vm_kernel_etext);
11905 OSKextLog(/* kext */ NULL,
11906 kOSKextLogErrorLevel |
11907 kOSKextLogGeneralFlag,
11908 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11909 vm_kernel_base, vm_kernel_top);
11910 OSKextLog(/* kext */ NULL,
11911 kOSKextLogErrorLevel |
11912 kOSKextLogGeneralFlag,
11913 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11914 vm_kext_base, vm_kext_top);
11915 OSKextLog(/* kext */ NULL,
11916 kOSKextLogErrorLevel |
11917 kOSKextLogGeneralFlag,
11918 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11919 vm_prelink_stext, vm_prelink_etext);
11920 OSKextLog(/* kext */ NULL,
11921 kOSKextLogErrorLevel |
11922 kOSKextLogGeneralFlag,
11923 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11924 vm_prelink_sinfo, vm_prelink_einfo);
11925 OSKextLog(/* kext */ NULL,
11926 kOSKextLogErrorLevel |
11927 kOSKextLogGeneralFlag,
11928 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11929 vm_slinkedit, vm_elinkedit);
11930#endif
11931 { // start block scope
11932 sKextsByID->iterateObjects(block: ^bool (const OSSymbol * thisKextID, OSObject * obj)
11933 {
11934 OSKext * thisKext = NULL; // do not release
11935 Boolean includeThis = true;
11936 OSSharedPtr<OSDictionary> kextInfo;
11937
11938 thisKext = OSDynamicCast(OSKext, obj);
11939 if (!thisKext) {
11940 return false;
11941 }
11942
11943 /* Skip current kext if not yet started and caller didn't request all.
11944 */
11945 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(anObject: thisKext, index: 0))) {
11946 return false;
11947 }
11948
11949 /* Skip current kext if we have a list of bundle IDs and
11950 * it isn't in the list.
11951 */
11952 if (kextIdentifiers) {
11953 includeThis = false;
11954
11955 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11956 const OSString * thisRequestID = OSDynamicCast(OSString,
11957 kextIdentifiers->getObject(idIndex));
11958 if (thisKextID->isEqualTo(anObject: thisRequestID)) {
11959 includeThis = true;
11960 break;
11961 }
11962 }
11963 }
11964
11965 if (!includeThis) {
11966 return false;
11967 }
11968
11969 kextInfo = thisKext->copyInfo(keys: infoKeys);
11970 if (kextInfo) {
11971 result->setObject(aKey: thisKext->getIdentifier(), anObject: kextInfo.get());
11972 }
11973 return false;
11974 });
11975 } // end block scope
11976
11977finish:
11978 IORecursiveLockUnlock(lock: sKextLock);
11979
11980 return result;
11981}
11982
11983/*********************************************************************
11984* Any info that needs to do allocations must goto finish on alloc
11985* failure. Info that is just a lookup should just not set the object
11986* if the info does not exist.
11987*********************************************************************/
11988#define _OSKextLoadInfoDictCapacity (12)
11989
11990OSSharedPtr<OSDictionary>
11991OSKext::copyInfo(OSArray * infoKeys)
11992{
11993 OSSharedPtr<OSDictionary> result;
11994 bool success = false;
11995 OSSharedPtr<OSData> headerData;
11996 OSSharedPtr<OSData> logData;
11997 OSSharedPtr<OSNumber> cpuTypeNumber;
11998 OSSharedPtr<OSNumber> cpuSubtypeNumber;
11999 OSString * versionString = NULL; // do not release
12000 OSString * bundleType = NULL; // do not release
12001 uint32_t executablePathCStringSize = 0;
12002 char * executablePathCString = NULL; // must kfree
12003 OSSharedPtr<OSString> executablePathString;
12004 OSSharedPtr<OSData> uuid;
12005 OSSharedPtr<OSArray> dependencyLoadTags;
12006 OSSharedPtr<OSCollectionIterator> metaClassIterator;
12007 OSSharedPtr<OSArray> metaClassInfo;
12008 OSSharedPtr<OSDictionary> metaClassDict;
12009 OSMetaClass * thisMetaClass = NULL; // do not release
12010 OSSharedPtr<OSString> metaClassName;
12011 OSSharedPtr<OSString> superclassName;
12012 kc_format_t kcformat;
12013 uint32_t count, i;
12014
12015 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
12016 if (!result) {
12017 goto finish;
12018 }
12019
12020
12021 /* Empty keys means no keys, but NULL is quicker to check.
12022 */
12023 if (infoKeys && !infoKeys->getCount()) {
12024 infoKeys = NULL;
12025 }
12026
12027 if (!PE_get_primary_kc_format(type: &kcformat)) {
12028 goto finish;
12029 }
12030
12031 /* Headers, CPU type, and CPU subtype.
12032 */
12033 if (!infoKeys ||
12034 _OSArrayContainsCString(array: infoKeys, kOSBundleMachOHeadersKey) ||
12035 _OSArrayContainsCString(array: infoKeys, kOSBundleLogStringsKey) ||
12036 _OSArrayContainsCString(array: infoKeys, kOSBundleCPUTypeKey) ||
12037 _OSArrayContainsCString(array: infoKeys, kOSBundleCPUSubtypeKey)) {
12038 if (linkedExecutable && !isInterface()) {
12039 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
12040 linkedExecutable->getBytesNoCopy();
12041
12042#if !SECURE_KERNEL || XNU_TARGET_OS_OSX
12043 // do not return macho header info on shipping embedded - 19095897
12044 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleMachOHeadersKey)) {
12045 kernel_mach_header_t * temp_kext_mach_hdr;
12046 struct load_command * lcp;
12047
12048 headerData = OSData::withBytes(bytes: kext_mach_hdr,
12049 numBytes: (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
12050 if (!headerData) {
12051 goto finish;
12052 }
12053
12054 // unslide any vmaddrs we return to userspace - 10726716
12055 temp_kext_mach_hdr = (kernel_mach_header_t *)
12056 headerData->getBytesNoCopy();
12057 if (temp_kext_mach_hdr == NULL) {
12058 goto finish;
12059 }
12060
12061 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
12062 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
12063 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12064 kernel_segment_command_t * segp;
12065 kernel_section_t * secp;
12066
12067 segp = (kernel_segment_command_t *) lcp;
12068 // 10543468 - if we jettisoned __LINKEDIT clear size info
12069 if (flags.jettisonLinkeditSeg) {
12070 if (strncmp(s1: segp->segname, SEG_LINKEDIT, n: sizeof(segp->segname)) == 0) {
12071 segp->vmsize = 0;
12072 segp->fileoff = 0;
12073 segp->filesize = 0;
12074 }
12075 }
12076
12077#if __arm__ || __arm64__
12078 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
12079 // and unslide them to avoid vm assertion failures / kernel logging breakage.
12080 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
12081 segp->vmaddr = gVirtBase;
12082 for (secp = firstsect(sgp: segp); secp != NULL; secp = nextsect(sgp: segp, sp: secp)) {
12083 secp->size = 0; // paranoia :)
12084 secp->addr = gVirtBase;
12085 }
12086 }
12087#endif
12088
12089#if 0
12090 OSKextLog(/* kext */ NULL,
12091 kOSKextLogErrorLevel |
12092 kOSKextLogGeneralFlag,
12093 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
12094 __FUNCTION__, segp->segname, segp->vmaddr,
12095 VM_KERNEL_UNSLIDE(segp->vmaddr),
12096 segp->vmsize, segp->nsects);
12097 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
12098 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
12099 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
12100 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
12101 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
12102 OSKextLog(/* kext */ NULL,
12103 kOSKextLogErrorLevel |
12104 kOSKextLogGeneralFlag,
12105 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
12106 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
12107 }
12108#endif
12109 segp->vmaddr = ml_static_unslide(vaddr: segp->vmaddr);
12110
12111 for (secp = firstsect(sgp: segp); secp != NULL; secp = nextsect(sgp: segp, sp: secp)) {
12112 secp->addr = ml_static_unslide(vaddr: secp->addr);
12113 }
12114 }
12115 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
12116 }
12117 result->setObject(kOSBundleMachOHeadersKey, anObject: headerData.get());
12118 }
12119#endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
12120
12121 if (_OSArrayContainsCString(array: infoKeys, kOSBundleLogStringsKey)) {
12122 osLogDataHeaderRef *header;
12123 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12124
12125 void *os_log_data = NULL;
12126 void *cstring_data = NULL;
12127 void *asan_cstring_data = NULL;
12128 unsigned long os_log_size = 0;
12129 unsigned long cstring_size = 0;
12130 unsigned long asan_cstring_size = 0;
12131 uint32_t os_log_offset = 0;
12132 uint32_t cstring_offset = 0;
12133 uint32_t asan_cstring_offset = 0;
12134 bool res;
12135
12136 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
12137 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
12138 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
12139
12140 /*
12141 * If the addresses in the Mach-O header are unslid, manually
12142 * slide them to allow for dereferencing.
12143 */
12144 if (flags.unslidMachO) {
12145 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide(vaddr: (vm_offset_t)os_log_data) : nullptr;
12146 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide(vaddr: (vm_offset_t)cstring_data) : nullptr;
12147 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide(vaddr: (vm_offset_t)asan_cstring_data) : nullptr;
12148 }
12149
12150 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
12151 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
12152 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
12153
12154 header = (osLogDataHeaderRef *) headerBytes;
12155 header->version = OS_LOG_HDR_VERSION;
12156 header->sect_count = NUM_OS_LOG_SECTIONS;
12157 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
12158 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
12159 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
12160 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
12161 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
12162 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
12163
12164
12165 logData = OSData::withValue(value: *header);
12166 if (!logData) {
12167 goto finish;
12168 }
12169 res = logData->appendBytes(bytes: &(header->sections[0]), numBytes: (u_int)(header->sect_count * sizeof(header->sections[0])));
12170 if (!res) {
12171 goto finish;
12172 }
12173 if (os_log_data) {
12174 res = logData->appendBytes(bytes: os_log_data, numBytes: (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12175 if (!res) {
12176 goto finish;
12177 }
12178 }
12179 if (cstring_data) {
12180 res = logData->appendBytes(bytes: cstring_data, numBytes: (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12181 if (!res) {
12182 goto finish;
12183 }
12184 }
12185 if (asan_cstring_data) {
12186 res = logData->appendBytes(bytes: asan_cstring_data, numBytes: (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12187 if (!res) {
12188 goto finish;
12189 }
12190 }
12191 result->setObject(kOSBundleLogStringsKey, anObject: logData.get());
12192 }
12193
12194 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleCPUTypeKey)) {
12195 cpuTypeNumber = OSNumber::withNumber(
12196 value: (uint64_t) kext_mach_hdr->cputype,
12197 numberOfBits: 8 * sizeof(kext_mach_hdr->cputype));
12198 if (!cpuTypeNumber) {
12199 goto finish;
12200 }
12201 result->setObject(kOSBundleCPUTypeKey, anObject: cpuTypeNumber.get());
12202 }
12203
12204 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleCPUSubtypeKey)) {
12205 cpuSubtypeNumber = OSNumber::withNumber(
12206 value: (uint64_t) kext_mach_hdr->cpusubtype,
12207 numberOfBits: 8 * sizeof(kext_mach_hdr->cpusubtype));
12208 if (!cpuSubtypeNumber) {
12209 goto finish;
12210 }
12211 result->setObject(kOSBundleCPUSubtypeKey, anObject: cpuSubtypeNumber.get());
12212 }
12213 } else {
12214 if (isDriverKit() && _OSArrayContainsCString(array: infoKeys, kOSBundleLogStringsKey)) {
12215 osLogDataHeaderRef *header;
12216 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12217 bool res;
12218
12219 header = (osLogDataHeaderRef *) headerBytes;
12220 header->version = OS_LOG_HDR_VERSION;
12221 header->sect_count = NUM_OS_LOG_SECTIONS;
12222 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12223 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12224 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12225 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12226 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12227 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12228
12229 logData = OSData::withValue(value: *header);
12230 if (!logData) {
12231 goto finish;
12232 }
12233 res = logData->appendBytes(bytes: &(header->sections[0]), numBytes: (u_int)(header->sect_count * sizeof(header->sections[0])));
12234 if (!res) {
12235 goto finish;
12236 }
12237 result->setObject(kOSBundleLogStringsKey, anObject: logData.get());
12238 }
12239 }
12240 }
12241
12242 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12243 */
12244 result->setObject(kCFBundleIdentifierKey, anObject: bundleID.get());
12245
12246 /* kOSBundleDextUniqueIdentifierKey if present.
12247 */
12248 if (isDriverKit() && dextUniqueID != NULL) {
12249 result->setObject(kOSBundleDextUniqueIdentifierKey, anObject: dextUniqueID.get());
12250 }
12251
12252 /* CFBundlePackageType
12253 */
12254 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12255 if (bundleType) {
12256 result->setObject(kCFBundlePackageTypeKey, anObject: bundleType);
12257 }
12258
12259 /* CFBundleVersion.
12260 */
12261 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kCFBundleVersionKey)) {
12262 versionString = OSDynamicCast(OSString,
12263 getPropertyForHostArch(kCFBundleVersionKey));
12264 if (versionString) {
12265 result->setObject(kCFBundleVersionKey, anObject: versionString);
12266 }
12267 }
12268
12269 /* OSBundleCompatibleVersion.
12270 */
12271 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleCompatibleVersionKey)) {
12272 versionString = OSDynamicCast(OSString,
12273 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12274 if (versionString) {
12275 result->setObject(kOSBundleCompatibleVersionKey, anObject: versionString);
12276 }
12277 }
12278
12279 /* Path.
12280 */
12281 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundlePathKey)) {
12282 if (path) {
12283 result->setObject(kOSBundlePathKey, anObject: path.get());
12284 }
12285 }
12286
12287
12288 /* OSBundleExecutablePath.
12289 */
12290 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleExecutablePathKey)) {
12291 if (path && executableRelPath) {
12292 uint32_t pathLength = path->getLength(); // gets incremented below
12293
12294 // +1 for slash, +1 for \0
12295 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12296
12297 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12298 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12299 if (!executablePathCString) {
12300 goto finish;
12301 }
12302 strlcpy(dst: executablePathCString, src: path->getCStringNoCopy(),
12303 n: executablePathCStringSize);
12304 executablePathCString[pathLength++] = '/';
12305 executablePathCString[pathLength++] = '\0';
12306 strlcat(dst: executablePathCString, src: executableRelPath->getCStringNoCopy(),
12307 n: executablePathCStringSize);
12308
12309 executablePathString = OSString::withCString(cString: executablePathCString);
12310
12311 if (!executablePathString) {
12312 goto finish;
12313 }
12314
12315 result->setObject(kOSBundleExecutablePathKey, anObject: executablePathString.get());
12316 } else if (flags.builtin) {
12317 result->setObject(kOSBundleExecutablePathKey, anObject: bundleID.get());
12318 } else if (isDriverKit()) {
12319 if (path) {
12320 // +1 for slash, +1 for \0
12321 uint32_t pathLength = path->getLength();
12322 executablePathCStringSize = pathLength + 2;
12323
12324 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12325 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12326 if (!executablePathCString) {
12327 goto finish;
12328 }
12329 strlcpy(dst: executablePathCString, src: path->getCStringNoCopy(), n: executablePathCStringSize);
12330 executablePathCString[pathLength++] = '/';
12331 executablePathCString[pathLength++] = '\0';
12332
12333 executablePathString = OSString::withCString(cString: executablePathCString);
12334
12335 if (!executablePathString) {
12336 goto finish;
12337 }
12338
12339 result->setObject(kOSBundleExecutablePathKey, anObject: executablePathString.get());
12340 }
12341 }
12342 }
12343
12344 /* UUID, if the kext has one.
12345 */
12346 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleUUIDKey)) {
12347 uuid = copyUUID();
12348 if (uuid) {
12349 result->setObject(kOSBundleUUIDKey, anObject: uuid.get());
12350 }
12351 }
12352 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleTextUUIDKey)) {
12353 uuid = copyTextUUID();
12354 if (uuid) {
12355 result->setObject(kOSBundleTextUUIDKey, anObject: uuid.get());
12356 }
12357 }
12358
12359 /*
12360 * Info.plist digest
12361 */
12362 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSKextInfoPlistDigestKey)) {
12363 OSData *digest;
12364 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12365 if (digest) {
12366 result->setObject(kOSKextInfoPlistDigestKey, anObject: digest);
12367 }
12368 }
12369
12370 /*
12371 * Collection type
12372 */
12373 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSKextBundleCollectionTypeKey)) {
12374 result->setObject(kOSKextBundleCollectionTypeKey, anObject: OSString::withCString(cString: getKCTypeString()));
12375 }
12376
12377 /*
12378 * Collection availability
12379 */
12380 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSKextAuxKCAvailabilityKey)) {
12381 result->setObject(kOSKextAuxKCAvailabilityKey,
12382 anObject: isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12383 }
12384
12385 /*
12386 * Allows user load
12387 */
12388 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleAllowUserLoadKey)) {
12389 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12390 if (allowUserLoad) {
12391 result->setObject(kOSBundleAllowUserLoadKey, anObject: allowUserLoad);
12392 }
12393 }
12394
12395 /*
12396 * Bundle Dependencies (OSBundleLibraries)
12397 */
12398 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleLibrariesKey)) {
12399 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12400 if (libraries) {
12401 result->setObject(kOSBundleLibrariesKey, anObject: libraries);
12402 }
12403 }
12404
12405 /*****
12406 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12407 */
12408 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSKernelResourceKey)) {
12409 result->setObject(kOSKernelResourceKey,
12410 anObject: isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12411 }
12412
12413 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleIsInterfaceKey)) {
12414 result->setObject(kOSBundleIsInterfaceKey,
12415 anObject: isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12416 }
12417
12418 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundlePrelinkedKey)) {
12419 result->setObject(kOSBundlePrelinkedKey,
12420 anObject: isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12421 }
12422
12423 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleStartedKey)) {
12424 result->setObject(kOSBundleStartedKey,
12425 anObject: isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12426 }
12427
12428 /* LoadTag (Index).
12429 */
12430 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleLoadTagKey)) {
12431 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(value: (unsigned long long)loadTag,
12432 /* numBits */ numberOfBits: 8 * sizeof(loadTag));
12433 if (!scratchNumber) {
12434 goto finish;
12435 }
12436 result->setObject(kOSBundleLoadTagKey, anObject: scratchNumber.get());
12437 }
12438
12439 /* LoadAddress, LoadSize.
12440 */
12441 if (!infoKeys ||
12442 _OSArrayContainsCString(array: infoKeys, kOSBundleLoadAddressKey) ||
12443 _OSArrayContainsCString(array: infoKeys, kOSBundleLoadSizeKey) ||
12444 _OSArrayContainsCString(array: infoKeys, kOSBundleExecLoadAddressKey) ||
12445 _OSArrayContainsCString(array: infoKeys, kOSBundleExecLoadSizeKey) ||
12446 _OSArrayContainsCString(array: infoKeys, kOSBundleWiredSizeKey)) {
12447 bool is_dext = isDriverKit();
12448 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12449 /* These go to userspace via serialization, so we don't want any doubts
12450 * about their size.
12451 */
12452 uint64_t loadAddress = 0;
12453 uint32_t loadSize = 0;
12454 uint32_t wiredSize = 0;
12455 uint64_t execLoadAddress = 0;
12456 uint32_t execLoadSize = 0;
12457
12458 /* Interfaces always report 0 load address & size.
12459 * Just the way they roll.
12460 *
12461 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12462 * xxx - shouldn't have one!
12463 */
12464
12465 if (flags.builtin || linkedExecutable) {
12466 kernel_mach_header_t *mh = NULL;
12467 kernel_segment_command_t *seg = NULL;
12468
12469 if (flags.builtin) {
12470 loadAddress = kmod_info->address;
12471 loadSize = (uint32_t)kmod_info->size;
12472 } else {
12473 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12474 loadSize = linkedExecutable->getLength();
12475 }
12476 mh = (kernel_mach_header_t *)loadAddress;
12477 loadAddress = ml_static_unslide(vaddr: loadAddress);
12478
12479 /* Walk through the kext, looking for the first executable
12480 * segment in case we were asked for its size/address.
12481 */
12482 for (seg = firstsegfromheader(header: mh); seg != NULL; seg = nextsegfromheader(header: mh, seg)) {
12483 if (seg->initprot & VM_PROT_EXECUTE) {
12484 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(vaddr: seg->vmaddr);
12485 execLoadSize = (uint32_t)seg->vmsize;
12486 break;
12487 }
12488 }
12489
12490 /* If we have a kmod_info struct, calculated the wired size
12491 * from that. Otherwise it's the full load size.
12492 */
12493 if (kmod_info) {
12494 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12495 } else {
12496 wiredSize = loadSize;
12497 }
12498 } else if (is_dext) {
12499 /*
12500 * DriverKit userspace executables do not have a kernel linkedExecutable,
12501 * so we "fake" their address range with the LoadTag.
12502 */
12503 if (loadTag) {
12504 loadAddress = execLoadAddress = loadTag;
12505 loadSize = execLoadSize = 1;
12506 }
12507 }
12508
12509 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleLoadAddressKey)) {
12510 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12511 value: (unsigned long long)(loadAddress),
12512 /* numBits */ numberOfBits: 8 * sizeof(loadAddress));
12513 if (!scratchNumber) {
12514 goto finish;
12515 }
12516 result->setObject(kOSBundleLoadAddressKey, anObject: scratchNumber.get());
12517 }
12518 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12519 if ((!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleCacheLoadAddressKey))
12520 && loadAddress && loadSize) {
12521 void *baseAddress = PE_get_kc_baseaddress(type: KCKindPrimary);
12522 if (!baseAddress) {
12523 goto finish;
12524 }
12525
12526 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12527 value: (unsigned long long)ml_static_unslide(vaddr: (vm_offset_t)baseAddress),
12528 /* numBits */ numberOfBits: 8 * sizeof(loadAddress));
12529 if (!scratchNumber) {
12530 goto finish;
12531 }
12532 result->setObject(kOSBundleCacheLoadAddressKey, anObject: scratchNumber.get());
12533 }
12534 if ((!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleKextsInKernelTextKey))
12535 && (this == sKernelKext) && gBuiltinKmodsCount) {
12536 result->setObject(kOSBundleKextsInKernelTextKey, anObject: kOSBooleanTrue);
12537 }
12538 }
12539
12540 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleExecLoadAddressKey)) {
12541 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12542 value: (unsigned long long)(execLoadAddress),
12543 /* numBits */ numberOfBits: 8 * sizeof(execLoadAddress));
12544 if (!scratchNumber) {
12545 goto finish;
12546 }
12547 result->setObject(kOSBundleExecLoadAddressKey, anObject: scratchNumber.get());
12548 }
12549 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleLoadSizeKey)) {
12550 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12551 value: (unsigned long long)(loadSize),
12552 /* numBits */ numberOfBits: 8 * sizeof(loadSize));
12553 if (!scratchNumber) {
12554 goto finish;
12555 }
12556 result->setObject(kOSBundleLoadSizeKey, anObject: scratchNumber.get());
12557 }
12558 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleExecLoadSizeKey)) {
12559 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12560 value: (unsigned long long)(execLoadSize),
12561 /* numBits */ numberOfBits: 8 * sizeof(execLoadSize));
12562 if (!scratchNumber) {
12563 goto finish;
12564 }
12565 result->setObject(kOSBundleExecLoadSizeKey, anObject: scratchNumber.get());
12566 }
12567 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleWiredSizeKey)) {
12568 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12569 value: (unsigned long long)(wiredSize),
12570 /* numBits */ numberOfBits: 8 * sizeof(wiredSize));
12571 if (!scratchNumber) {
12572 goto finish;
12573 }
12574 result->setObject(kOSBundleWiredSizeKey, anObject: scratchNumber.get());
12575 }
12576 }
12577 }
12578
12579 /* OSBundleDependencies. In descending order for
12580 * easy compatibility with kextstat(8).
12581 */
12582 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleDependenciesKey)) {
12583 if ((count = getNumDependencies())) {
12584 dependencyLoadTags = OSArray::withCapacity(capacity: count);
12585 result->setObject(kOSBundleDependenciesKey, anObject: dependencyLoadTags.get());
12586
12587 i = count - 1;
12588 do {
12589 OSKext * dependency = OSDynamicCast(OSKext,
12590 dependencies->getObject(i));
12591
12592 if (!dependency) {
12593 continue;
12594 }
12595 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12596 value: (unsigned long long)dependency->getLoadTag(),
12597 /* numBits*/ numberOfBits: 8 * sizeof(loadTag));
12598 if (!scratchNumber) {
12599 goto finish;
12600 }
12601 dependencyLoadTags->setObject(scratchNumber.get());
12602 } while (i--);
12603 }
12604 }
12605
12606 /* OSBundleMetaClasses.
12607 */
12608 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleClassesKey)) {
12609 if (metaClasses && metaClasses->getCount()) {
12610 metaClassIterator = OSCollectionIterator::withCollection(inColl: metaClasses.get());
12611 metaClassInfo = OSArray::withCapacity(capacity: metaClasses->getCount());
12612 if (!metaClassIterator || !metaClassInfo) {
12613 goto finish;
12614 }
12615 result->setObject(kOSBundleClassesKey, anObject: metaClassInfo.get());
12616
12617 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12618 metaClassIterator->getNextObject()))) {
12619 metaClassDict = OSDictionary::withCapacity(capacity: 3);
12620 if (!metaClassDict) {
12621 goto finish;
12622 }
12623
12624 metaClassName = OSString::withCString(cString: thisMetaClass->getClassName());
12625 if (thisMetaClass->getSuperClass()) {
12626 superclassName = OSString::withCString(
12627 cString: thisMetaClass->getSuperClass()->getClassName());
12628 }
12629 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(value: thisMetaClass->getInstanceCount(),
12630 numberOfBits: 8 * sizeof(unsigned int));
12631
12632 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12633 * of course.
12634 */
12635 if (!metaClassDict || !metaClassName || !scratchNumber) {
12636 goto finish;
12637 }
12638
12639 metaClassInfo->setObject(metaClassDict.get());
12640 metaClassDict->setObject(kOSMetaClassNameKey, anObject: metaClassName.get());
12641 if (superclassName) {
12642 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, anObject: superclassName.get());
12643 }
12644 metaClassDict->setObject(kOSMetaClassTrackingCountKey, anObject: scratchNumber.get());
12645 }
12646 }
12647 }
12648
12649 /* OSBundleRetainCount.
12650 */
12651 if (!infoKeys || _OSArrayContainsCString(array: infoKeys, kOSBundleRetainCountKey)) {
12652 {
12653 int kextRetainCount = getRetainCount() - 1;
12654 if (isLoaded()) {
12655 kextRetainCount--;
12656 }
12657 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12658 value: (int)kextRetainCount,
12659 /* numBits*/ numberOfBits: 8 * sizeof(int));
12660 if (scratchNumber) {
12661 result->setObject(kOSBundleRetainCountKey, anObject: scratchNumber.get());
12662 }
12663 }
12664 }
12665
12666 success = true;
12667
12668finish:
12669 if (executablePathCString) {
12670 kfree_data(executablePathCString, executablePathCStringSize);
12671 }
12672 if (!success) {
12673 result.reset();
12674 }
12675 return result;
12676}
12677
12678/*********************************************************************
12679*********************************************************************/
12680/* static */
12681bool
12682OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12683{
12684 bool ok;
12685 OSSharedPtr<OSKext> kext;
12686
12687 IORecursiveLockLock(lock: sKextLock);
12688 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12689 IORecursiveLockUnlock(lock: sKextLock);
12690
12691 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12692 return false;
12693 }
12694 snprintf(pathResult, count: pathSize, "%s/Contents/MacOS/%s",
12695 kext->path->getCStringNoCopy(),
12696 kext->userExecutableRelPath->getCStringNoCopy());
12697 ok = true;
12698
12699 return ok;
12700}
12701
12702/*********************************************************************
12703*********************************************************************/
12704/* static */
12705OSReturn
12706OSKext::requestResource(
12707 const char * kextIdentifierCString,
12708 const char * resourceNameCString,
12709 OSKextRequestResourceCallback callback,
12710 void * context,
12711 OSKextRequestTag * requestTagOut)
12712{
12713 OSReturn result = kOSReturnError;
12714 OSSharedPtr<OSKext> callbackKext; // looked up
12715
12716 OSKextRequestTag requestTag = -1;
12717 OSSharedPtr<OSNumber> requestTagNum;
12718 OSSharedPtr<OSDictionary> requestDict;
12719 OSSharedPtr<OSString> kextIdentifier;
12720 OSSharedPtr<OSString> resourceName;
12721
12722 OSSharedPtr<OSDictionary> callbackRecord;
12723 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12724
12725 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12726
12727 IORecursiveLockLock(lock: sKextLock);
12728
12729 if (requestTagOut) {
12730 *requestTagOut = kOSKextRequestTagInvalid;
12731 }
12732
12733 /* If requests to user space are disabled, don't go any further */
12734 if (!sKernelRequestsEnabled) {
12735 OSKextLog(/* kext */ NULL,
12736 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12737 format: "Can't request resource %s for %s - requests to user space are disabled.",
12738 resourceNameCString,
12739 kextIdentifierCString);
12740 result = kOSKextReturnDisabled;
12741 goto finish;
12742 }
12743
12744 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12745 result = kOSKextReturnInvalidArgument;
12746 goto finish;
12747 }
12748
12749 callbackKext = OSKext::lookupKextWithAddress(address: (vm_address_t)callback);
12750 if (!callbackKext) {
12751 OSKextLog(/* kext */ NULL,
12752 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12753 format: "Resource request has bad callback address.");
12754 result = kOSKextReturnInvalidArgument;
12755 goto finish;
12756 }
12757 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12758 OSKextLog(/* kext */ NULL,
12759 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12760 format: "Resource request callback is in a kext that is not started.");
12761 result = kOSKextReturnInvalidArgument;
12762 goto finish;
12763 }
12764
12765 /* Do not allow any new requests to be made on a kext that is unloading.
12766 */
12767 if (callbackKext->flags.stopping) {
12768 result = kOSKextReturnStopping;
12769 goto finish;
12770 }
12771
12772 /* If we're wrapped the next available request tag around to the negative
12773 * numbers, we can't service any more requests.
12774 */
12775 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12776 OSKextLog(/* kext */ NULL,
12777 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12778 format: "No more request tags available; restart required.");
12779 result = kOSKextReturnNoResources;
12780 goto finish;
12781 }
12782 requestTag = sNextRequestTag++;
12783
12784 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12785 requestP&: requestDict);
12786 if (result != kOSReturnSuccess) {
12787 goto finish;
12788 }
12789
12790 kextIdentifier = OSString::withCString(cString: kextIdentifierCString);
12791 resourceName = OSString::withCString(cString: resourceNameCString);
12792 requestTagNum = OSNumber::withNumber(value: (long long unsigned int)requestTag,
12793 numberOfBits: 8 * sizeof(requestTag));
12794 if (!kextIdentifier ||
12795 !resourceName ||
12796 !requestTagNum ||
12797 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12798 kKextRequestArgumentBundleIdentifierKey, value: kextIdentifier.get()) ||
12799 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12800 kKextRequestArgumentNameKey, value: resourceName.get()) ||
12801 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12802 kKextRequestArgumentRequestTagKey, value: requestTagNum.get())) {
12803 result = kOSKextReturnNoMemory;
12804 goto finish;
12805 }
12806
12807 callbackRecord = OSDynamicPtrCast<OSDictionary>(source: requestDict->copyCollection());
12808 if (!callbackRecord) {
12809 result = kOSKextReturnNoMemory;
12810 goto finish;
12811 }
12812 // we validate callback address at call time
12813 callbackWrapper = OSValueObjectWithValue(value: callback);
12814 if (context) {
12815 contextWrapper = OSValueObjectWithValue(value: context);
12816 }
12817 if (!callbackWrapper || !_OSKextSetRequestArgument(requestDict: callbackRecord.get(),
12818 kKextRequestArgumentCallbackKey, value: callbackWrapper.get())) {
12819 result = kOSKextReturnNoMemory;
12820 goto finish;
12821 }
12822
12823 if (context) {
12824 if (!contextWrapper || !_OSKextSetRequestArgument(requestDict: callbackRecord.get(),
12825 kKextRequestArgumentContextKey, value: contextWrapper.get())) {
12826 result = kOSKextReturnNoMemory;
12827 goto finish;
12828 }
12829 }
12830
12831 /* Only post the requests after all the other potential failure points
12832 * have been passed.
12833 */
12834 if (!sKernelRequests->setObject(requestDict.get()) ||
12835 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12836 result = kOSKextReturnNoMemory;
12837 goto finish;
12838 }
12839
12840 OSKext::pingIOKitDaemon();
12841
12842 result = kOSReturnSuccess;
12843 if (requestTagOut) {
12844 *requestTagOut = requestTag;
12845 }
12846
12847finish:
12848
12849 /* If we didn't succeed, yank the request & callback
12850 * from their holding arrays.
12851 */
12852 if (result != kOSReturnSuccess) {
12853 unsigned int index;
12854
12855 index = sKernelRequests->getNextIndexOfObject(anObject: requestDict.get(), index: 0);
12856 if (index != (unsigned int)-1) {
12857 sKernelRequests->removeObject(index);
12858 }
12859 index = sRequestCallbackRecords->getNextIndexOfObject(anObject: callbackRecord.get(), index: 0);
12860 if (index != (unsigned int)-1) {
12861 sRequestCallbackRecords->removeObject(index);
12862 }
12863 }
12864
12865 OSKext::considerUnloads(/* rescheduleOnly? */ rescheduleOnlyFlag: true);
12866
12867 IORecursiveLockUnlock(lock: sKextLock);
12868
12869 return result;
12870}
12871
12872OSReturn
12873OSKext::requestDaemonLaunch(
12874 OSString *kextIdentifier,
12875 OSString *serverName,
12876 OSNumber *serverTag,
12877 OSBoolean *reslide,
12878 IOUserServerCheckInToken * checkInToken,
12879 OSData *serverDUI)
12880{
12881 OSReturn result = kOSReturnError;
12882 OSSharedPtr<OSDictionary> requestDict;
12883 unsigned int size = 0;
12884 const char *dextUniqueIDCString = NULL;
12885
12886 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12887 return kOSKextReturnInvalidArgument;
12888 }
12889
12890 if (serverDUI != NULL) {
12891 dextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: serverDUI, size: &size);
12892 }
12893
12894 IORecursiveLockLock(lock: sKextLock);
12895
12896 OSKextLog(/* kext */ NULL,
12897 kOSKextLogDebugLevel |
12898 kOSKextLogGeneralFlag,
12899 format: "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12900 kextIdentifier->getCStringNoCopy(),
12901 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12902 serverName->getCStringNoCopy(),
12903 serverTag->unsigned64BitValue(),
12904 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12905 );
12906
12907 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestP&: requestDict);
12908 if (result != kOSReturnSuccess) {
12909 goto finish;
12910 }
12911
12912 if (!_OSKextSetRequestArgument(requestDict: requestDict.get(),
12913 kKextRequestArgumentBundleIdentifierKey, value: kextIdentifier) ||
12914 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12915 kKextRequestArgumentDriverExtensionServerName, value: serverName) ||
12916 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12917 kKextRequestArgumentDriverExtensionServerTag, value: serverTag) ||
12918 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12919 kKextRequestArgumentDriverExtensionReslideSharedCache, value: reslide) ||
12920 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12921 kKextRequestArgumentCheckInToken, value: checkInToken)) {
12922 result = kOSKextReturnNoMemory;
12923 goto finish;
12924 }
12925
12926 if (serverDUI) {
12927 if (!_OSKextSetRequestArgument(requestDict: requestDict.get(),
12928 kOSBundleDextUniqueIdentifierKey, value: serverDUI)) {
12929 result = kOSKextReturnNoMemory;
12930 goto finish;
12931 }
12932 }
12933
12934 /* Only post the requests after all the other potential failure points
12935 * have been passed.
12936 */
12937 if (!sKernelRequests->setObject(requestDict.get())) {
12938 result = kOSKextReturnNoMemory;
12939 goto finish;
12940 }
12941 OSKext::pingIOKitDaemon();
12942
12943 result = kOSReturnSuccess;
12944finish:
12945 IORecursiveLockUnlock(lock: sKextLock);
12946 if (dextUniqueIDCString) {
12947 kfree_data(dextUniqueIDCString, size);
12948 }
12949 return result;
12950}
12951
12952OSReturn
12953OSKext::notifyDextUpgrade(
12954 OSString *kextIdentifier,
12955 OSData *dextUniqueIdentifier)
12956{
12957 OSReturn result = kOSReturnError;
12958 OSSharedPtr<OSDictionary> requestDict;
12959 unsigned int size = 0;
12960 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueID: dextUniqueIdentifier, size: &size);
12961 assert(dextUniqueIDCString != NULL);
12962
12963 IORecursiveLockLock(lock: sKextLock);
12964
12965 OSKextLog(NULL,
12966 kOSKextLogDebugLevel |
12967 kOSKextLogGeneralFlag,
12968 format: "Notifying of dext upgrade for %s with UniqueID %s",
12969 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12970
12971 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestP&: requestDict);
12972 if (result != kOSReturnSuccess) {
12973 goto finish;
12974 }
12975
12976 if (!_OSKextSetRequestArgument(requestDict: requestDict.get(),
12977 kKextRequestArgumentBundleIdentifierKey, value: kextIdentifier) ||
12978 !_OSKextSetRequestArgument(requestDict: requestDict.get(),
12979 kKextRequestArgumentDriverUniqueIdentifier, value: dextUniqueIdentifier)) {
12980 result = kOSKextReturnNoMemory;
12981 goto finish;
12982 }
12983
12984 /* Only post the requests after all the other potential failure points
12985 * have been passed.
12986 */
12987 if (!sKernelRequests->setObject(requestDict.get())) {
12988 result = kOSKextReturnNoMemory;
12989 goto finish;
12990 }
12991 OSKext::pingIOKitDaemon();
12992
12993 result = kOSReturnSuccess;
12994finish:
12995 IORecursiveLockUnlock(lock: sKextLock);
12996
12997 if (dextUniqueIDCString != NULL) {
12998 kfree_data(dextUniqueIDCString, size);
12999 }
13000 return result;
13001}
13002
13003/*********************************************************************
13004* Assumes sKextLock is held.
13005*********************************************************************/
13006/* static */
13007OSReturn
13008OSKext::dequeueCallbackForRequestTag(
13009 OSKextRequestTag requestTag,
13010 OSSharedPtr<OSDictionary> &callbackRecordOut)
13011{
13012 OSDictionary * callbackRecordOutRaw = NULL;
13013 OSReturn result;
13014
13015 result = dequeueCallbackForRequestTag(requestTag,
13016 callbackRecordOut: &callbackRecordOutRaw);
13017
13018 if (kOSReturnSuccess == result) {
13019 callbackRecordOut.reset(p: callbackRecordOutRaw, OSNoRetain);
13020 }
13021
13022 return result;
13023}
13024OSReturn
13025OSKext::dequeueCallbackForRequestTag(
13026 OSKextRequestTag requestTag,
13027 OSDictionary ** callbackRecordOut)
13028{
13029 OSReturn result = kOSReturnError;
13030 OSSharedPtr<OSNumber> requestTagNum;
13031
13032 requestTagNum = OSNumber::withNumber(value: (long long unsigned int)requestTag,
13033 numberOfBits: 8 * sizeof(requestTag));
13034 if (!requestTagNum) {
13035 goto finish;
13036 }
13037
13038 result = OSKext::dequeueCallbackForRequestTag(requestTagNum: requestTagNum.get(),
13039 callbackRecordOut);
13040
13041finish:
13042 return result;
13043}
13044
13045/*********************************************************************
13046* Assumes sKextLock is held.
13047*********************************************************************/
13048/* static */
13049OSReturn
13050OSKext::dequeueCallbackForRequestTag(
13051 OSNumber * requestTagNum,
13052 OSSharedPtr<OSDictionary> &callbackRecordOut)
13053{
13054 OSDictionary * callbackRecordOutRaw = NULL;
13055 OSReturn result;
13056
13057 result = dequeueCallbackForRequestTag(requestTagNum,
13058 callbackRecordOut: &callbackRecordOutRaw);
13059
13060 if (kOSReturnSuccess == result) {
13061 callbackRecordOut.reset(p: callbackRecordOutRaw, OSNoRetain);
13062 }
13063
13064 return result;
13065}
13066OSReturn
13067OSKext::dequeueCallbackForRequestTag(
13068 OSNumber * requestTagNum,
13069 OSDictionary ** callbackRecordOut)
13070{
13071 OSReturn result = kOSKextReturnInvalidArgument;
13072 OSDictionary * callbackRecord = NULL; // retain if matched!
13073 OSNumber * callbackTagNum = NULL; // do not release
13074 unsigned int count, i;
13075
13076 result = kOSReturnError;
13077 count = sRequestCallbackRecords->getCount();
13078 for (i = 0; i < count; i++) {
13079 callbackRecord = OSDynamicCast(OSDictionary,
13080 sRequestCallbackRecords->getObject(i));
13081 if (!callbackRecord) {
13082 goto finish;
13083 }
13084
13085 /* If we don't find a tag, we basically have a leak here. Maybe
13086 * we should just remove it.
13087 */
13088 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
13089 callbackRecord, kKextRequestArgumentRequestTagKey));
13090 if (!callbackTagNum) {
13091 goto finish;
13092 }
13093
13094 /* We could be even more paranoid and check that all the incoming
13095 * args match what's in the callback record.
13096 */
13097 if (callbackTagNum->isEqualTo(aNumber: requestTagNum)) {
13098 if (callbackRecordOut) {
13099 *callbackRecordOut = callbackRecord;
13100 callbackRecord->retain();
13101 }
13102 sRequestCallbackRecords->removeObject(index: i);
13103 result = kOSReturnSuccess;
13104 goto finish;
13105 }
13106 }
13107 result = kOSKextReturnNotFound;
13108
13109finish:
13110 return result;
13111}
13112
13113
13114/*********************************************************************
13115* Busy timeout triage
13116*********************************************************************/
13117/* static */
13118bool
13119OSKext::pendingIOKitDaemonRequests(void)
13120{
13121 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
13122}
13123
13124/*********************************************************************
13125* Acquires and releases sKextLock
13126*
13127* This function is designed to be called by kernelmanagerd and driverkitd
13128* and it gathers all codeless kext and dext personalities, and then attempts
13129* to map a System (pageable) KC and an Auxiliary (aux) KC.
13130*
13131* The pageable and aux KC can be loaded only once at boot time.
13132* Even if the pageable or aux KC fail to load - this function will
13133* not allow a new pageable or aux KC to be installed by subsequent calls.
13134* This is done to avoid security issues where userspace has been compromised
13135* or the pageable kc has been tampered with and the attacker
13136* attempts to re-load a malicious variant.
13137* However dexts can be dynamically loaded, so this function can be used
13138* to request the installation of a new set of dexts even after boot time.
13139*
13140*
13141*
13142* Return: if a KC fails to load the return value will contain:
13143* kOSKextReturnKCLoadFailure. If the pageable KC fails,
13144* the return value will contain kOSKextReturnKCLoadFailureSystemKC.
13145* Similarly, if the aux kc load fails, the return value will
13146* contain kOSKextReturnKCLoadFailureAuxKC. The two values
13147* compose with each other and with kOSKextReturnKCLoadFailure.
13148*********************************************************************/
13149/* static */
13150OSReturn
13151OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
13152{
13153 static bool daemon_ready = false;
13154
13155 OSReturn ret = kOSKextReturnInvalidArgument;
13156 OSReturn kcerr = 0;
13157 bool start_matching = false;
13158
13159 bool allow_fileset_load = !daemon_ready;
13160#if !(defined(__x86_64__) || defined(__i386__))
13161 /* never allow KCs full of kexts on non-x86 machines */
13162 allow_fileset_load = false;
13163#endif
13164
13165 /*
13166 * Change with 70582300
13167 */
13168#if 0 || !defined(VM_MAPPED_KEXTS)
13169 /*
13170 * On platforms that don't support the SystemKC or a file-backed
13171 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13172 * needs to be queried before we load any codeless kexts or release
13173 * any 3rd party kexts to run. On platforms that support a file-backed
13174 * AuxKC, this process is done via the kext audit mechanism.
13175 */
13176
13177 printf("KextLog: waiting for kext receipt to be queried.\n");
13178 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13179 IOSleep(30);
13180 }
13181#endif /* !VM_MAPPED_KEXTS */
13182
13183 /*
13184 * Get the args from the request. Right now we need the file
13185 * name for the pageable and the aux kext collection file sets.
13186 */
13187 OSDictionary * requestArgs = NULL; // do not release
13188 OSString * pageable_filepath = NULL; // do not release
13189 OSString * aux_filepath = NULL; // do not release
13190 OSArray * codeless_kexts = NULL; // do not release
13191
13192 kernel_mach_header_t *akc_mh = NULL;
13193
13194 requestArgs = OSDynamicCast(OSDictionary,
13195 requestDict->getObject(kKextRequestArgumentsKey));
13196
13197 if (requestArgs == NULL) {
13198 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13199 format: "KextLog: No arguments in plist for loading fileset kext\n");
13200 printf("KextLog: No arguments in plist for loading fileset kext\n");
13201 return ret;
13202 }
13203
13204 ret = kOSKextReturnDisabled;
13205
13206 IORecursiveLockLock(lock: sKextLock);
13207
13208 if (!sLoadEnabled) {
13209 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13210 format: "KextLog: Kext loading is disabled (attempt to load KCs).");
13211 IORecursiveLockUnlock(lock: sKextLock);
13212 return ret;
13213 }
13214
13215 pageable_filepath = OSDynamicCast(OSString,
13216 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13217
13218 if (allow_fileset_load && pageable_filepath != NULL) {
13219 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13220
13221 ret = OSKext::loadKCFileSet(filepath: pageable_filepath->getCStringNoCopy(), type: KCKindPageable);
13222 if (ret) {
13223 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13224 format: "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13225
13226 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13227 ret = kOSKextReturnKCLoadFailure;
13228 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13229 goto try_auxkc;
13230 }
13231 /*
13232 * Even if the AuxKC fails to load, we still want to send
13233 * the System KC personalities to the catalog for matching
13234 */
13235 start_matching = true;
13236 } else if (pageable_filepath != NULL) {
13237 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13238 format: "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13239 ret = kOSKextReturnUnsupported;
13240 }
13241
13242try_auxkc:
13243 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(type: KCKindAuxiliary);
13244 if (akc_mh) {
13245 /*
13246 * If we try to load a deferred AuxKC, then don't ever attempt
13247 * a filesystem map of a file
13248 */
13249 allow_fileset_load = false;
13250
13251 /*
13252 * This function is only called once per boot, so we haven't
13253 * yet loaded an AuxKC. If we have registered the AuxKC mach
13254 * header, that means that the kext collection has been placed
13255 * in memory for us by the booter, and is waiting for us to
13256 * process it. Grab the deferred XML plist of info
13257 * dictionaries and add all the kexts.
13258 */
13259 OSSharedPtr<OSObject> parsedXML;
13260 OSSharedPtr<OSData> loaded_kcUUID;
13261 OSDictionary *infoDict;
13262 parsedXML = consumeDeferredKextCollection(type: KCKindAuxiliary);
13263 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13264#if !defined(VM_MAPPED_KEXTS)
13265 /*
13266 * On platforms where we don't dynamically wire-down / page-in
13267 * kext memory, we need to maintain the invariant that if the
13268 * AuxKC in memory does not contain a kext receipt, then we
13269 * should not load any of the kexts.
13270 */
13271 size_t receipt_sz = 0;
13272 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13273 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13274 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13275 ret = kOSKextReturnKCLoadFailure;
13276 goto try_codeless;
13277 }
13278#endif
13279 if (infoDict) {
13280 bool added;
13281 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13282 added = OSKext::addKextsFromKextCollection(mh: akc_mh, infoDict,
13283 kPrelinkTextSegment, kcUUID&: loaded_kcUUID, type: KCKindAuxiliary);
13284 if (!loaded_kcUUID) {
13285 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13286 format: "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13287 } else if (!added) {
13288 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13289 format: "KextLog: WARNING: Failed to load AuxKC from memory.");
13290 }
13291 /* only return success if the pageable load (above) was successful */
13292 if (ret != kOSKextReturnKCLoadFailure) {
13293 ret = kOSReturnSuccess;
13294 }
13295 /* the registration of the AuxKC parsed out the KC's UUID already */
13296 } else {
13297 if (daemon_ready) {
13298 /*
13299 * Complain, but don't return an error if this isn't the first time the
13300 * IOKit daemon is checking in. If the daemon ever restarts, we will
13301 * hit this case because we've already consumed the deferred personalities.
13302 * We return success here so that a call to this function from a restarted
13303 * daemon with no codeless kexts will succeed.
13304 */
13305 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13306 format: "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13307 if (ret != kOSKextReturnKCLoadFailure) {
13308 ret = kOSReturnSuccess;
13309 }
13310 } else {
13311 /* this is a real error case */
13312 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13313 format: "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13314 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13315 ret = kOSKextReturnKCLoadFailure;
13316 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13317 }
13318 }
13319 }
13320
13321 aux_filepath = OSDynamicCast(OSString,
13322 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13323 if (allow_fileset_load && aux_filepath != NULL) {
13324 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13325
13326 ret = OSKext::loadKCFileSet(filepath: aux_filepath->getCStringNoCopy(), type: KCKindAuxiliary);
13327 if (ret) {
13328 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13329 format: "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13330
13331 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13332 ret = kOSKextReturnKCLoadFailure;
13333 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13334 goto try_codeless;
13335 }
13336 start_matching = true;
13337 } else if (aux_filepath != NULL) {
13338 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13339 format: "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13340 if (ret != kOSKextReturnKCLoadFailure) {
13341 ret = kOSKextReturnUnsupported;
13342 }
13343 }
13344
13345try_codeless:
13346 /*
13347 * Load codeless kexts last so that there is no possibilty of a
13348 * codeless kext bundle ID preventing a kext in the system KC from
13349 * loading
13350 */
13351 codeless_kexts = OSDynamicCast(OSArray,
13352 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13353 if (codeless_kexts != NULL) {
13354 uint32_t count = codeless_kexts->getCount();
13355 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13356 format: "KextLog: loading %d codeless kexts/dexts", count);
13357 for (uint32_t i = 0; i < count; i++) {
13358 OSDictionary *infoDict;
13359 infoDict = OSDynamicCast(OSDictionary,
13360 codeless_kexts->getObject(i));
13361 if (!infoDict) {
13362 continue;
13363 }
13364 // instantiate a new kext, and don't hold a reference
13365 // (the kext subsystem will hold one implicitly)
13366 OSKext::withCodelessInfo(anInfoDict: infoDict, NULL);
13367 }
13368 /* ignore errors that are not KC load failures */
13369 if (ret != kOSKextReturnKCLoadFailure) {
13370 ret = kOSReturnSuccess;
13371 }
13372 start_matching = true;
13373 }
13374
13375 /* send personalities to the IOCatalog once */
13376 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13377 OSKext::sendAllKextPersonalitiesToCatalog(startMatching: true);
13378 /*
13379 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13380 * things as active and start all the delayed matching: the
13381 * dext and codeless kext personalities should have all been
13382 * delivered via this one call.
13383 */
13384 if (!daemon_ready) {
13385 OSKext::setIOKitDaemonActive();
13386 OSKext::setDeferredLoadSucceeded(TRUE);
13387 IOService::iokitDaemonLaunched();
13388 }
13389 if (sOSKextWasResetAfterUserspaceReboot) {
13390 sOSKextWasResetAfterUserspaceReboot = false;
13391 OSKext::setIOKitDaemonActive();
13392 IOService::startDeferredMatches();
13393 }
13394 }
13395
13396 if (ret == kOSKextReturnKCLoadFailure) {
13397 ret |= kcerr;
13398 }
13399
13400 /*
13401 * Only allow this function to attempt to load the pageable and
13402 * aux KCs once per boot.
13403 */
13404 daemon_ready = true;
13405
13406 IORecursiveLockUnlock(lock: sKextLock);
13407
13408 return ret;
13409}
13410
13411OSReturn
13412OSKext::resetMutableSegments(void)
13413{
13414 kernel_segment_command_t *seg = NULL;
13415 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13416 u_int index = 0;
13417 OSKextSavedMutableSegment *savedSegment = NULL;
13418 uintptr_t kext_slide = PE_get_kc_slide(type: kc_type);
13419 OSReturn err;
13420
13421 if (!savedMutableSegments) {
13422 OSKextLog(aKext: this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13423 format: "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13424 err = kOSKextReturnInternalError;
13425 goto finish;
13426 }
13427
13428 for (seg = firstsegfromheader(header: k_mh), index = 0; seg; seg = nextsegfromheader(header: k_mh, seg)) {
13429 if (!segmentIsMutable(seg)) {
13430 continue;
13431 }
13432 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13433 uint64_t vmsize = seg->vmsize;
13434 err = kOSKextReturnInternalError;
13435 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13436 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13437 assert(savedSegment);
13438 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13439 OSKextLog(aKext: this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13440 format: "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(s: seg->segname, n: sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13441 err = savedSegment->restoreContents(seg);
13442 if (err != kOSReturnSuccess) {
13443 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13444 }
13445 }
13446 }
13447 if (err != kOSReturnSuccess) {
13448 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13449 }
13450 }
13451 err = kOSReturnSuccess;
13452finish:
13453 return err;
13454}
13455
13456
13457/*********************************************************************
13458* Assumes sKextLock is held.
13459*********************************************************************/
13460/* static */
13461OSReturn
13462OSKext::loadKCFileSet(
13463 const char *filepath,
13464 kc_kind_t type)
13465{
13466#if VM_MAPPED_KEXTS
13467 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13468 OSReturn err;
13469 struct vnode *vp = NULL;
13470 void *fileset_control;
13471 off_t fsize;
13472 bool pageable = (type == KCKindPageable);
13473
13474 if ((pageable && pageableKCloaded) ||
13475 (!pageable && auxKCloaded)) {
13476 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13477 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13478
13479 return kOSKextReturnInvalidArgument;
13480 }
13481
13482 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13483 if (!pageable && !pageableKCloaded) {
13484 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13485 "Trying to load the Aux KC without loading the Pageable KC");
13486 return kOSKextReturnInvalidArgument;
13487 }
13488
13489 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13490
13491 if (fileset_control == NULL) {
13492 printf("Could not get memory control object for file %s", filepath);
13493
13494 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13495 "Could not get memory control object for file %s", filepath);
13496 return kOSKextReturnInvalidArgument;
13497 }
13498 if (vp == NULL) {
13499 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13500 "Could not find vnode for file %s", filepath);
13501 return kOSKextReturnInvalidArgument;
13502 }
13503
13504 kernel_mach_header_t *mh = NULL;
13505 uintptr_t slide = 0;
13506
13507#if CONFIG_CSR
13508 /*
13509 * When SIP is enabled, the KC we map must be SIP-protected
13510 */
13511 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13512 struct vnode_attr va;
13513 int error;
13514 VATTR_INIT(&va);
13515 VATTR_WANTED(&va, va_flags);
13516 error = vnode_getattr(vp, &va, vfs_context_current());
13517 if (error) {
13518 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13519 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13520 err = kOSKextReturnInternalError;
13521 goto finish;
13522 }
13523 if (!(va.va_flags & SF_RESTRICTED)) {
13524 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13525 "Path to KC '%s' is not SIP-protected", filepath);
13526 err = kOSKextReturnInvalidArgument;
13527 goto finish;
13528 }
13529 }
13530#endif
13531
13532 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13533 if (err) {
13534 printf("KextLog: mapKCFileSet returned %d\n", err);
13535
13536 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13537 "mapKCFileSet returned %d\n", err);
13538
13539 err = kOSKextReturnInvalidArgument;
13540 }
13541
13542#if CONFIG_CSR
13543finish:
13544#endif
13545 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13546 assert(vp != NULL);
13547 if (err == kOSReturnSuccess) {
13548 PE_set_kc_vp(type, vp);
13549 if (pageable) {
13550 pageableKCloaded = true;
13551 } else {
13552 auxKCloaded = true;
13553 }
13554 } else {
13555 vnode_put(vp);
13556 }
13557
13558 return err;
13559#else
13560 (void)filepath;
13561 (void)type;
13562 return kOSKextReturnUnsupported;
13563#endif // VM_MAPPED_KEXTS
13564}
13565
13566#if defined(__x86_64__) || defined(__i386__)
13567/*********************************************************************
13568* Assumes sKextLock is held.
13569*********************************************************************/
13570/* static */
13571OSReturn
13572OSKext::mapKCFileSet(
13573 void *control,
13574 vm_size_t fsize,
13575 kernel_mach_header_t **mhp,
13576 off_t file_offset,
13577 uintptr_t *slidep,
13578 bool pageable,
13579 void *map_entry_list)
13580{
13581 bool fileset_load = false;
13582 kern_return_t ret;
13583 OSReturn err;
13584 kernel_section_t *infoPlistSection = NULL;
13585 OSDictionary *infoDict = NULL;
13586
13587 OSSharedPtr<OSObject> parsedXML;
13588 OSSharedPtr<OSString> errorString;
13589 OSSharedPtr<OSData> loaded_kcUUID;
13590
13591 /* Check if initial load for file set */
13592 if (*mhp == NULL) {
13593 fileset_load = true;
13594
13595 /* Get a page aligned address from kext map to map the file */
13596 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13597 if (pagealigned_addr == 0) {
13598 return kOSKextReturnNoMemory;
13599 }
13600
13601 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13602
13603 /* Allocate memory for bailout mechanism */
13604 map_entry_list = allocate_kcfileset_map_entry_list();
13605 if (map_entry_list == NULL) {
13606 return kOSKextReturnNoMemory;
13607 }
13608 }
13609
13610 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13611 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13612 /* mhp and slideptr are updated by mapKCTextSegment */
13613 if (err) {
13614 if (fileset_load) {
13615 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13616 }
13617 return err;
13618 }
13619
13620 /* Initialize the kc header globals */
13621 if (fileset_load) {
13622 if (pageable) {
13623 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13624 } else {
13625 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13626 }
13627 }
13628
13629 /* Iterate through all the segments and map necessary segments */
13630 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13631 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13632 vm_map_offset_t start;
13633 kernel_mach_header_t *k_mh = NULL;
13634 kernel_segment_command_t * seg = NULL;
13635 struct fileset_entry_command *fse = NULL;
13636
13637 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13638 seg = (kernel_segment_command_t *)lcp;
13639 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13640 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13641 fse = (struct fileset_entry_command *)lcp;
13642 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13643
13644 /* Map the segments of the mach-o binary */
13645 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13646 if (err) {
13647 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13648 return kOSKextReturnInvalidArgument;
13649 }
13650 continue;
13651 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13652 /* Check if the Aux KC is built pageable style */
13653 if (!pageable && !fileset_load && !auxKCloaded) {
13654 resetAuxKCSegmentOnUnload = true;
13655 }
13656 continue;
13657 } else {
13658 continue;
13659 }
13660
13661 if (fileset_load) {
13662 if (seg->vmsize == 0) {
13663 continue;
13664 }
13665
13666 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13667 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13668 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13669 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13670 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13671 continue;
13672 }
13673 } else {
13674 if (seg->vmsize == 0) {
13675 continue;
13676 }
13677
13678 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13679 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13680 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13681 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13682 continue;
13683 }
13684 }
13685
13686 ret = vm_map_kcfileset_segment(
13687 &start, seg->vmsize,
13688 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13689
13690 if (ret != KERN_SUCCESS) {
13691 if (fileset_load) {
13692 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13693 }
13694 return kOSKextReturnInvalidArgument;
13695 }
13696 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13697 }
13698
13699 /* Return if regular mach-o */
13700 if (!fileset_load) {
13701 return 0;
13702 }
13703
13704 /*
13705 * Fixup for the Pageable KC and the Aux KC is done by
13706 * i386_slide_kext_collection_mh_addrs, but it differs in
13707 * following ways:
13708 *
13709 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13710 * The fixup of kext segments and kext load commands are done at kext
13711 * load time by calling i386_slide_individual_kext.
13712 *
13713 * AuxKC old style: Fixup all the segments and all the load commands.
13714 *
13715 * AuxKC pageable style: Same as the Pageable KC.
13716 */
13717 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13718 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13719 if (ret != KERN_SUCCESS) {
13720 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13721 return kOSKextReturnInvalidArgument;
13722 }
13723
13724 /* Get the prelink info dictionary */
13725 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13726 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13727 if (parsedXML) {
13728 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13729 }
13730
13731 if (!infoDict) {
13732 const char *errorCString = "(unknown error)";
13733
13734 if (errorString && errorString->getCStringNoCopy()) {
13735 errorCString = errorString->getCStringNoCopy();
13736 } else if (parsedXML) {
13737 errorCString = "not a dictionary";
13738 }
13739 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13740 "Error unserializing kext info plist section: %s.", errorCString);
13741 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13742 return kOSKextReturnInvalidArgument;
13743 }
13744
13745 /* Validate that the Kext Collection is prelinked to the loaded KC */
13746 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13747 if (err) {
13748 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13749 return kOSKextReturnInvalidArgument;
13750 }
13751
13752 /* Set Protection of Segments */
13753 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13754
13755 OSKext::addKextsFromKextCollection(*mhp,
13756 infoDict, kPrelinkTextSegment,
13757 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13758
13759 /* Copy in the KC UUID */
13760 if (!loaded_kcUUID) {
13761 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13762 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13763 } else if (pageable) {
13764 pageablekc_uuid_valid = TRUE;
13765 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13766 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13767 } else {
13768 auxkc_uuid_valid = TRUE;
13769 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13770 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13771 }
13772
13773 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13774
13775 return 0;
13776}
13777
13778/*********************************************************************
13779* Assumes sKextLock is held.
13780*********************************************************************/
13781/* static */
13782OSReturn
13783OSKext::mapKCTextSegment(
13784 void *control,
13785 kernel_mach_header_t **mhp,
13786 off_t file_offset,
13787 uintptr_t *slidep,
13788 void *map_entry_list)
13789{
13790 kern_return_t ret;
13791 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13792 PAGE_MASK);
13793 vm_map_offset_t load_command_map_size = 0;
13794 kernel_mach_header_t *base_mh = *mhp;
13795
13796 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13797 ret = vm_map_kcfileset_segment(
13798 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13799 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13800
13801 if (ret != KERN_SUCCESS) {
13802 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13803
13804 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13805 "Failed to map mach header of kc fileset with error %d", ret);
13806 return kOSKextReturnInvalidArgument;
13807 }
13808
13809 if (slidep) {
13810 /* Verify that it's an MH_FILESET */
13811 if (base_mh->filetype != MH_FILESET) {
13812 printf("Kext Log: mapKCTextSegment mach header filetype"
13813 " is not an MH_FILESET, it is %x", base_mh->filetype);
13814
13815 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13816 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13817
13818 /* Unmap the mach header */
13819 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13820 return kOSKextReturnInvalidArgument;
13821 }
13822 }
13823
13824 /* Map the remaining pages of load commands */
13825 if (base_mh->sizeofcmds > mach_header_map_size) {
13826 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13827 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13828
13829 /* Map the load commands */
13830 ret = vm_map_kcfileset_segment(
13831 &load_command_addr, load_command_map_size,
13832 (memory_object_control_t)control, file_offset + mach_header_map_size,
13833 (VM_PROT_READ | VM_PROT_WRITE));
13834
13835 if (ret != KERN_SUCCESS) {
13836 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13837 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13838 "Failed to map load commands of kc fileset with error %d", ret);
13839
13840 /* Unmap the mach header */
13841 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13842 return kOSKextReturnInvalidArgument;
13843 }
13844 }
13845
13846 kernel_segment_command_t *text_seg;
13847 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13848
13849 /* Calculate the slide and vm addr of mach header */
13850 if (slidep) {
13851 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13852 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13853 }
13854
13855 /* Cache the text segment size and file offset before unmapping */
13856 vm_map_offset_t text_segment_size = text_seg->vmsize;
13857 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13858 vm_prot_t text_maxprot = text_seg->maxprot;
13859
13860 /* Unmap the first page and loadcommands and map the text segment */
13861 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13862 assert(ret == KERN_SUCCESS);
13863
13864 if (load_command_map_size) {
13865 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13866 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13867 assert(ret == KERN_SUCCESS);
13868 }
13869
13870 /* Map the text segment at actual vm addr specified in fileset */
13871 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13872 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13873 if (ret != KERN_SUCCESS) {
13874 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13875 "Failed to map Text segment of kc fileset with error %d", ret);
13876 return kOSKextReturnInvalidArgument;
13877 }
13878
13879 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13880 return 0;
13881}
13882
13883/*********************************************************************
13884* Assumes sKextLock is held.
13885*********************************************************************/
13886/* static */
13887OSReturn
13888OSKext::protectKCFileSet(
13889 kernel_mach_header_t *mh,
13890 kc_kind_t type)
13891{
13892 vm_map_t kext_map = g_kext_map;
13893 kernel_segment_command_t * seg = NULL;
13894 vm_map_offset_t start = 0;
13895 vm_map_offset_t end = 0;
13896 OSReturn ret = 0;
13897
13898 /* Set VM permissions */
13899 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13900 while (seg) {
13901 start = round_page(seg->vmaddr);
13902 end = trunc_page(seg->vmaddr + seg->vmsize);
13903
13904 /*
13905 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13906 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13907 * for the Aux KC as well.
13908 */
13909 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13910 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13911 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13912 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13913 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13914 ret = OSKext_protect((kernel_mach_header_t *)mh,
13915 kext_map, start, end, seg->maxprot, TRUE, type);
13916 if (ret != KERN_SUCCESS) {
13917 printf("OSKext protect failed with error %d", ret);
13918 return kOSKextReturnInvalidArgument;
13919 }
13920
13921 ret = OSKext_protect((kernel_mach_header_t *)mh,
13922 kext_map, start, end, seg->initprot, FALSE, type);
13923 if (ret != KERN_SUCCESS) {
13924 printf("OSKext protect failed with error %d", ret);
13925 return kOSKextReturnInvalidArgument;
13926 }
13927
13928 ret = OSKext_wire((kernel_mach_header_t *)mh,
13929 kext_map, start, end, seg->initprot, FALSE, type);
13930 if (ret != KERN_SUCCESS) {
13931 printf("OSKext wire failed with error %d", ret);
13932 return kOSKextReturnInvalidArgument;
13933 }
13934 }
13935
13936 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13937 }
13938
13939 return 0;
13940}
13941
13942/*********************************************************************
13943* Assumes sKextLock is held.
13944*********************************************************************/
13945/* static */
13946void
13947OSKext::freeKCFileSetcontrol(void)
13948{
13949 PE_reset_all_kc_vp();
13950}
13951
13952/*********************************************************************
13953* Assumes sKextLock is held.
13954*
13955* resetKCFileSetSegments: Kext start function expects data segment to
13956* be pristine on every load, unmap the dirty segments on unload and
13957* remap them from FileSet on disk. Remap all segments of kext since
13958* fixups are done per kext and not per segment.
13959*********************************************************************/
13960OSReturn
13961OSKext::resetKCFileSetSegments(void)
13962{
13963 kernel_segment_command_t *seg = NULL;
13964 kernel_segment_command_t *text_seg;
13965 uint32_t text_fileoff;
13966 kernel_mach_header_t *k_mh = NULL;
13967 uintptr_t slide;
13968 struct vnode *vp = NULL;
13969 void *fileset_control = NULL;
13970 bool pageable = (kc_type == KCKindPageable);
13971 OSReturn err;
13972 kern_return_t kr;
13973
13974 /* Check the vnode reference is still available */
13975 vp = (struct vnode *)PE_get_kc_vp(kc_type);
13976 if (vp == NULL) {
13977 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13978 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
13979 return kOSKextReturnInternalError;
13980 }
13981
13982 fileset_control = ubc_getobject(vp, 0);
13983 assert(fileset_control != NULL);
13984
13985 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13986 "Kext %s resetting all segments", getIdentifierCString());
13987
13988 k_mh = (kernel_mach_header_t *)kmod_info->address;
13989 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
13990 text_fileoff = text_seg->fileoff;
13991 slide = PE_get_kc_slide(kc_type);
13992
13993 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
13994 while (seg) {
13995 if (seg->vmsize == 0) {
13996 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13997 continue;
13998 }
13999
14000 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
14001 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
14002 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
14003 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
14004 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14005 continue;
14006 }
14007
14008 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
14009 assert(kr == KERN_SUCCESS);
14010 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14011 }
14012
14013 /* Unmap the text segment */
14014 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
14015 assert(kr == KERN_SUCCESS);
14016
14017 /* Map all the segments of the kext */
14018 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
14019 if (err) {
14020 panic("Could not reset segments of a mapped kext, error %x", err);
14021 }
14022
14023 /* Update address in kmod_info, since it has been reset */
14024 if (kmod_info->address) {
14025 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
14026 }
14027
14028 return 0;
14029}
14030
14031/*********************************************************************
14032* Mechanism to track all segment mapping while mapping KC fileset.
14033*********************************************************************/
14034
14035struct kcfileset_map_entry {
14036 vm_map_offset_t me_start;
14037 vm_map_offset_t me_size;
14038};
14039
14040struct kcfileset_map_entry_list {
14041 int kme_list_count;
14042 int kme_list_index;
14043 struct kcfileset_map_entry kme_list[];
14044};
14045
14046#define KCFILESET_MAP_ENTRY_MAX (16380)
14047
14048static void *
14049allocate_kcfileset_map_entry_list(void)
14050{
14051 struct kcfileset_map_entry_list *entry_list;
14052
14053 entry_list = kalloc_type(struct kcfileset_map_entry_list,
14054 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
14055
14056 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
14057 entry_list->kme_list_index = 0;
14058 return entry_list;
14059}
14060
14061static void
14062add_kcfileset_map_entry(
14063 void *map_entry_list,
14064 vm_map_offset_t start,
14065 vm_map_offset_t size)
14066{
14067 if (map_entry_list == NULL) {
14068 return;
14069 }
14070
14071 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14072
14073 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
14074 panic("Ran out of map kc fileset list");
14075 }
14076
14077 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
14078 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
14079
14080 entry_list->kme_list_index++;
14081}
14082
14083static void
14084deallocate_kcfileset_map_entry_list_and_unmap_entries(
14085 void *map_entry_list,
14086 boolean_t unmap_entries,
14087 bool pageable)
14088{
14089 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14090
14091 if (unmap_entries) {
14092 for (int i = 0; i < entry_list->kme_list_index; i++) {
14093 kern_return_t ret;
14094 ret = vm_unmap_kcfileset_segment(
14095 &(entry_list->kme_list[i].me_start),
14096 entry_list->kme_list[i].me_size);
14097 assert(ret == KERN_SUCCESS);
14098 }
14099
14100 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
14101 }
14102
14103 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
14104 KCFILESET_MAP_ENTRY_MAX, entry_list);
14105}
14106
14107/*********************************************************************
14108* Mechanism to map kext segment.
14109*********************************************************************/
14110
14111kern_return_t
14112vm_map_kcfileset_segment(
14113 vm_map_offset_t *start,
14114 vm_map_offset_t size,
14115 void *control,
14116 vm_object_offset_t fileoffset,
14117 vm_prot_t max_prot)
14118{
14119 vm_map_kernel_flags_t vmk_flags = {
14120 .vmf_fixed = true,
14121 .vmkf_no_copy_on_read = true,
14122 .vmkf_cs_enforcement_override = true,
14123 .vm_tag = VM_KERN_MEMORY_OSKEXT,
14124 };
14125 kern_return_t ret;
14126
14127 /* Add Write to max prot to allow fixups */
14128 max_prot = max_prot | VM_PROT_WRITE;
14129
14130 /*
14131 * Map the segments from file as COPY mappings to
14132 * make sure changes on disk to the file does not affect
14133 * mapped segments.
14134 */
14135 ret = vm_map_enter_mem_object_control(
14136 g_kext_map,
14137 start,
14138 size,
14139 (mach_vm_offset_t)0,
14140 vmk_flags,
14141 (memory_object_control_t)control,
14142 fileoffset,
14143 TRUE, /* copy */
14144 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
14145 VM_INHERIT_NONE);
14146
14147 return ret;
14148}
14149
14150kern_return_t
14151vm_unmap_kcfileset_segment(
14152 vm_map_offset_t *start,
14153 vm_map_offset_t size)
14154{
14155 return mach_vm_deallocate(g_kext_map, *start, size);
14156}
14157
14158#endif //(__x86_64__) || defined(__i386__)
14159
14160/*********************************************************************
14161* Assumes sKextLock is held.
14162*********************************************************************/
14163/* static */
14164OSReturn
14165OSKext::validateKCFileSetUUID(
14166 OSDictionary *infoDict,
14167 kc_kind_t type)
14168{
14169 OSReturn ret = kOSReturnSuccess;
14170
14171 if (!kernelcache_uuid_valid) {
14172 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14173 format: "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14174 ret = kOSKextReturnInvalidArgument;
14175 goto finish;
14176 }
14177 ret = OSKext::validateKCUUIDfromPrelinkInfo(loaded_kcuuid: &kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14178 if (ret != 0) {
14179 goto finish;
14180 }
14181
14182#if defined(__x86_64__) || defined(__i386__)
14183 /* Check if the Aux KC is prelinked to correct Pageable KC */
14184 if (type == KCKindAuxiliary) {
14185 if (!pageablekc_uuid_valid) {
14186 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14187 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14188 ret = kOSKextReturnInvalidArgument;
14189 goto finish;
14190 }
14191 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14192 if (ret != 0) {
14193 goto finish;
14194 }
14195 }
14196#endif //(__x86_64__) || defined(__i386__)
14197
14198 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14199finish:
14200 return ret;
14201}
14202
14203/*********************************************************************
14204* Assumes sKextLock is held.
14205*********************************************************************/
14206/* static */
14207OSReturn
14208OSKext::validateKCUUIDfromPrelinkInfo(
14209 uuid_t *loaded_kcuuid,
14210 kc_kind_t type,
14211 OSDictionary *infoDict,
14212 const char *uuid_key)
14213{
14214 /* extract the UUID from the dictionary */
14215 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14216 if (!prelinkinfoKCUUID) {
14217 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14218 format: "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14219 return kOSKextReturnInvalidArgument;
14220 }
14221
14222 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14223 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14224 format: "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14225 return kOSKextReturnInvalidArgument;
14226 }
14227
14228 if (memcmp(s1: (void *)loaded_kcuuid, s2: (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14229 n: prelinkinfoKCUUID->getLength())) {
14230 OSData *info_dict_uuid;
14231 uuid_string_t info_dict_uuid_str = {};
14232 uuid_string_t expected_uuid_str = {};
14233 uuid_string_t given_uuid_str = {};
14234 uuid_t given_uuid;
14235
14236 /* extract the KC UUID from the dictionary */
14237 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14238 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14239 uuid_t tmp_uuid;
14240 memcpy(dst: tmp_uuid, src: (const void *)info_dict_uuid->getBytesNoCopy(), n: sizeof(tmp_uuid));
14241 uuid_unparse(uu: tmp_uuid, out: info_dict_uuid_str);
14242 }
14243
14244 uuid_unparse(uu: *loaded_kcuuid, out: expected_uuid_str);
14245 memcpy(dst: given_uuid, src: (const void *)prelinkinfoKCUUID->getBytesNoCopy(), n: sizeof(given_uuid));
14246 uuid_unparse(uu: given_uuid, out: given_uuid_str);
14247
14248 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14249 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14250 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14251 format: "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14252 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14253 if (type == KCKindPageable && sPanicOnKCMismatch) {
14254 panic("System KC UUID %s linked against %s, but %s is loaded",
14255 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14256 }
14257 return kOSKextReturnInvalidArgument;
14258 }
14259
14260 return 0;
14261}
14262
14263/*********************************************************************
14264* Assumes sKextLock is held.
14265*********************************************************************/
14266/* static */
14267OSReturn
14268OSKext::dispatchResource(OSDictionary * requestDict)
14269{
14270 OSReturn result = kOSReturnError;
14271 OSSharedPtr<OSDictionary> callbackRecord;
14272 OSNumber * requestTag = NULL; // do not release
14273 OSNumber * requestResult = NULL; // do not release
14274 OSData * dataObj = NULL; // do not release
14275 uint32_t dataLength = 0;
14276 const void * dataPtr = NULL; // do not free
14277 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14278 OSKextRequestResourceCallback callback = NULL;
14279 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14280 void * context = NULL; // do not free
14281 OSSharedPtr<OSKext> callbackKext;
14282
14283 /* Get the args from the request. Right now we need the tag
14284 * to look up the callback record, and the result for invoking the callback.
14285 */
14286 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14287 kKextRequestArgumentRequestTagKey));
14288 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14289 kKextRequestArgumentResultKey));
14290 if (!requestTag || !requestResult) {
14291 result = kOSKextReturnInvalidArgument;
14292 goto finish;
14293 }
14294
14295 /* Look for a callback record matching this request's tag.
14296 */
14297 result = dequeueCallbackForRequestTag(requestTagNum: requestTag, callbackRecordOut&: callbackRecord);
14298 if (result != kOSReturnSuccess) {
14299 goto finish;
14300 }
14301
14302 /*****
14303 * Get the context pointer of the callback record (if there is one).
14304 */
14305 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14306 callbackRecord.get(), kKextRequestArgumentContextKey));
14307 context = _OSKextExtractPointer(wrapper: contextWrapper);
14308 if (contextWrapper && !context) {
14309 goto finish;
14310 }
14311
14312 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14313 _OSKextGetRequestArgument(callbackRecord.get(),
14314 kKextRequestArgumentCallbackKey));
14315 callback = _OSKextExtractCallbackPointer(wrapper: callbackWrapper);
14316 if (!callback) {
14317 goto finish;
14318 }
14319
14320 /* Check for a data obj. We might not have one and that's ok, that means
14321 * we didn't find the requested resource, and we still have to tell the
14322 * caller that via the callback.
14323 */
14324 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14325 kKextRequestArgumentValueKey));
14326 if (dataObj) {
14327 dataPtr = dataObj->getBytesNoCopy();
14328 dataLength = dataObj->getLength();
14329 }
14330
14331 callbackKext = OSKext::lookupKextWithAddress(address: (vm_address_t)callback);
14332 if (!callbackKext) {
14333 OSKextLog(/* kext */ NULL,
14334 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14335 format: "Can't invoke callback for resource request; ");
14336 goto finish;
14337 }
14338 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14339 OSKextLog(/* kext */ NULL,
14340 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14341 format: "Can't invoke kext resource callback; ");
14342 goto finish;
14343 }
14344
14345 (void)callback(requestTag->unsigned32BitValue(),
14346 (OSReturn)requestResult->unsigned32BitValue(),
14347 dataPtr, dataLength, context);
14348
14349 result = kOSReturnSuccess;
14350
14351finish:
14352 return result;
14353}
14354
14355/*********************************************************************
14356* Assumes sKextLock is held.
14357*********************************************************************/
14358/* static */
14359OSReturn
14360OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14361{
14362 OSSharedPtr<OSDictionary> missingIDs;
14363 OSArray *bundleIDList = NULL; // do not release
14364
14365 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14366 requestDict, kKextRequestArgumentMissingBundleIDs));
14367 if (!bundleIDList) {
14368 return kOSKextReturnInvalidArgument;
14369 }
14370
14371 missingIDs = OSDictionary::withCapacity(capacity: bundleIDList->getCount());
14372 if (!missingIDs) {
14373 return kOSKextReturnNoMemory;
14374 }
14375
14376 uint32_t count, i;
14377 count = bundleIDList->getCount();
14378 for (i = 0; i < count; i++) {
14379 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14380 if (thisID) {
14381 missingIDs->setObject(aKey: thisID, anObject: kOSBooleanFalse);
14382 }
14383 }
14384
14385 sNonLoadableKextsByID.reset(p: missingIDs.get(), OSRetain);
14386
14387 return kOSReturnSuccess;
14388}
14389
14390/*********************************************************************
14391* Assumes sKextLock is held.
14392*********************************************************************/
14393/* static */
14394OSReturn
14395OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14396{
14397 bool loadable = true;
14398 if (!kextIdentifier) {
14399 return kOSKextReturnInvalidArgument;
14400 }
14401
14402 if (requestDict) {
14403 OSBoolean *loadableArg;
14404 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14405 requestDict, kKextRequestArgumentBundleAvailability));
14406 /* If we find the "Bundle Available" arg, and it's false, then
14407 * mark the bundle ID as _not_ loadable
14408 */
14409 if (loadableArg && !loadableArg->getValue()) {
14410 loadable = false;
14411 }
14412 }
14413
14414 if (!sNonLoadableKextsByID) {
14415 sNonLoadableKextsByID = OSDictionary::withCapacity(capacity: 1);
14416 }
14417
14418 sNonLoadableKextsByID->setObject(aKey: kextIdentifier, anObject: OSBoolean::withBoolean(value: loadable));
14419
14420 OSKextLog(/* kext */ NULL,
14421 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14422 format: "KextLog: AuxKC bundle %s marked as %s",
14423 kextIdentifier->getCStringNoCopy(),
14424 (loadable ? "loadable" : "NOT loadable"));
14425
14426 return kOSReturnSuccess;
14427}
14428
14429/*********************************************************************
14430*********************************************************************/
14431/* static */
14432void
14433OSKext::invokeRequestCallback(
14434 OSDictionary * callbackRecord,
14435 OSReturn callbackResult)
14436{
14437 OSString * predicate = _OSKextGetRequestPredicate(requestDict: callbackRecord);
14438 OSSharedPtr<OSNumber> resultNum;
14439
14440 if (!predicate) {
14441 goto finish;
14442 }
14443
14444 resultNum = OSNumber::withNumber(value: (long long unsigned int)callbackResult,
14445 numberOfBits: 8 * sizeof(callbackResult));
14446 if (!resultNum) {
14447 goto finish;
14448 }
14449
14450 /* Insert the result into the callback record and dispatch it as if it
14451 * were the reply coming down from user space.
14452 */
14453 _OSKextSetRequestArgument(requestDict: callbackRecord, kKextRequestArgumentResultKey,
14454 value: resultNum.get());
14455
14456 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14457 /* This removes the pending callback record.
14458 */
14459 OSKext::dispatchResource(requestDict: callbackRecord);
14460 }
14461
14462finish:
14463 return;
14464}
14465
14466/*********************************************************************
14467* Assumes sKextLock is held.
14468*********************************************************************/
14469/* static */
14470OSReturn
14471OSKext::cancelRequest(
14472 OSKextRequestTag requestTag,
14473 void ** contextOut)
14474{
14475 OSReturn result = kOSKextReturnNoMemory;
14476 OSSharedPtr<OSDictionary> callbackRecord;
14477 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14478
14479 IORecursiveLockLock(lock: sKextLock);
14480 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14481 callbackRecordOut&: callbackRecord);
14482 IORecursiveLockUnlock(lock: sKextLock);
14483
14484 if (result == kOSReturnSuccess && contextOut) {
14485 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14486 _OSKextGetRequestArgument(callbackRecord.get(),
14487 kKextRequestArgumentContextKey));
14488 *contextOut = _OSKextExtractPointer(wrapper: contextWrapper);
14489 }
14490
14491 return result;
14492}
14493
14494/*********************************************************************
14495* Assumes sKextLock is held.
14496*********************************************************************/
14497void
14498OSKext::invokeOrCancelRequestCallbacks(
14499 OSReturn callbackResult,
14500 bool invokeFlag)
14501{
14502 unsigned int count, i;
14503
14504 count = sRequestCallbackRecords->getCount();
14505 if (!count) {
14506 goto finish;
14507 }
14508
14509 i = count - 1;
14510 do {
14511 OSDictionary * request = OSDynamicCast(OSDictionary,
14512 sRequestCallbackRecords->getObject(i));
14513
14514 if (!request) {
14515 continue;
14516 }
14517 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14518 _OSKextGetRequestArgument(request,
14519 kKextRequestArgumentCallbackKey));
14520
14521 if (!callbackWrapper) {
14522 sRequestCallbackRecords->removeObject(index: i);
14523 continue;
14524 }
14525
14526 vm_address_t callbackAddress = (vm_address_t)
14527 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14528
14529 if ((kmod_info->address <= callbackAddress) &&
14530 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14531 if (invokeFlag) {
14532 /* This removes the callback record.
14533 */
14534 invokeRequestCallback(callbackRecord: request, callbackResult);
14535 } else {
14536 sRequestCallbackRecords->removeObject(index: i);
14537 }
14538 }
14539 } while (i--);
14540
14541finish:
14542 return;
14543}
14544
14545/*********************************************************************
14546* Assumes sKextLock is held.
14547*********************************************************************/
14548uint32_t
14549OSKext::countRequestCallbacks(void)
14550{
14551 uint32_t result = 0;
14552 unsigned int count, i;
14553
14554 count = sRequestCallbackRecords->getCount();
14555 if (!count) {
14556 goto finish;
14557 }
14558
14559 i = count - 1;
14560 do {
14561 OSDictionary * request = OSDynamicCast(OSDictionary,
14562 sRequestCallbackRecords->getObject(i));
14563
14564 if (!request) {
14565 continue;
14566 }
14567 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14568 _OSKextGetRequestArgument(request,
14569 kKextRequestArgumentCallbackKey));
14570
14571 if (!callbackWrapper) {
14572 continue;
14573 }
14574
14575 vm_address_t callbackAddress = (vm_address_t)
14576 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14577
14578 if ((kmod_info->address <= callbackAddress) &&
14579 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14580 result++;
14581 }
14582 } while (i--);
14583
14584finish:
14585 return result;
14586}
14587
14588/*********************************************************************
14589*********************************************************************/
14590static OSReturn
14591_OSKextCreateRequest(
14592 const char * predicate,
14593 OSSharedPtr<OSDictionary> & requestR)
14594{
14595 OSReturn result = kOSKextReturnNoMemory;
14596 OSSharedPtr<OSDictionary> request;
14597
14598 request = OSDictionary::withCapacity(capacity: 2);
14599 if (!request) {
14600 goto finish;
14601 }
14602 result = _OSDictionarySetCStringValue(dict: request.get(),
14603 kKextRequestPredicateKey, value: predicate);
14604 if (result != kOSReturnSuccess) {
14605 goto finish;
14606 }
14607 result = kOSReturnSuccess;
14608
14609finish:
14610 if (result == kOSReturnSuccess) {
14611 requestR = os::move(t&: request);
14612 }
14613
14614 return result;
14615}
14616
14617/*********************************************************************
14618*********************************************************************/
14619static OSString *
14620_OSKextGetRequestPredicate(OSDictionary * requestDict)
14621{
14622 return OSDynamicCast(OSString,
14623 requestDict->getObject(kKextRequestPredicateKey));
14624}
14625
14626/*********************************************************************
14627*********************************************************************/
14628static OSObject *
14629_OSKextGetRequestArgument(
14630 OSDictionary * requestDict,
14631 const char * argName)
14632{
14633 OSDictionary * args = OSDynamicCast(OSDictionary,
14634 requestDict->getObject(kKextRequestArgumentsKey));
14635 if (args) {
14636 return args->getObject(aKey: argName);
14637 }
14638 return NULL;
14639}
14640
14641/*********************************************************************
14642*********************************************************************/
14643static bool
14644_OSKextSetRequestArgument(
14645 OSDictionary * requestDict,
14646 const char * argName,
14647 OSMetaClassBase * value)
14648{
14649 OSDictionary * args = OSDynamicCast(OSDictionary,
14650 requestDict->getObject(kKextRequestArgumentsKey));
14651 OSSharedPtr<OSDictionary> newArgs;
14652 if (!args) {
14653 newArgs = OSDictionary::withCapacity(capacity: 2);
14654 args = newArgs.get();
14655 if (!args) {
14656 goto finish;
14657 }
14658 requestDict->setObject(kKextRequestArgumentsKey, anObject: args);
14659 }
14660 if (args) {
14661 return args->setObject(aKey: argName, anObject: value);
14662 }
14663finish:
14664 return false;
14665}
14666
14667/*********************************************************************
14668*********************************************************************/
14669template <typename T>
14670static T *
14671_OSKextExtractPointer(OSValueObject<T *> * wrapper)
14672{
14673 if (!wrapper) {
14674 return nullptr;
14675 }
14676 return wrapper->getRef();
14677}
14678
14679/*********************************************************************
14680*********************************************************************/
14681static OSKextRequestResourceCallback
14682_OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14683{
14684 if (!wrapper) {
14685 return nullptr;
14686 }
14687 return wrapper->getRef();
14688}
14689
14690
14691/*********************************************************************
14692*********************************************************************/
14693static OSReturn
14694_OSDictionarySetCStringValue(
14695 OSDictionary * dict,
14696 const char * cKey,
14697 const char * cValue)
14698{
14699 OSReturn result = kOSKextReturnNoMemory;
14700 OSSharedPtr<const OSSymbol> key;
14701 OSSharedPtr<OSString> value;
14702
14703 key = OSSymbol::withCString(cString: cKey);
14704 value = OSString::withCString(cString: cValue);
14705 if (!key || !value) {
14706 goto finish;
14707 }
14708 if (dict->setObject(aKey: key.get(), anObject: value.get())) {
14709 result = kOSReturnSuccess;
14710 }
14711
14712finish:
14713 return result;
14714}
14715
14716/*********************************************************************
14717*********************************************************************/
14718static bool
14719_OSArrayContainsCString(
14720 OSArray * array,
14721 const char * cString)
14722{
14723 bool result = false;
14724 OSSharedPtr<const OSSymbol> symbol;
14725 uint32_t count, i;
14726
14727 if (!array || !cString) {
14728 goto finish;
14729 }
14730
14731 symbol = OSSymbol::withCStringNoCopy(cString);
14732 if (!symbol) {
14733 goto finish;
14734 }
14735
14736 count = array->getCount();
14737 for (i = 0; i < count; i++) {
14738 OSObject * thisObject = array->getObject(index: i);
14739 if (symbol->isEqualTo(anObject: thisObject)) {
14740 result = true;
14741 goto finish;
14742 }
14743 }
14744
14745finish:
14746 return result;
14747}
14748
14749#if CONFIG_KXLD
14750/*********************************************************************
14751* We really only care about boot / system start up related kexts.
14752* We return true if we're less than REBUILD_MAX_TIME since start up,
14753* otherwise return false.
14754*********************************************************************/
14755bool
14756_OSKextInPrelinkRebuildWindow(void)
14757{
14758 static bool outside_the_window = false;
14759 AbsoluteTime my_abstime;
14760 UInt64 my_ns;
14761 SInt32 my_secs;
14762
14763 if (outside_the_window) {
14764 return false;
14765 }
14766 clock_get_uptime(&my_abstime);
14767 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14768 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14769 if (my_secs > REBUILD_MAX_TIME) {
14770 outside_the_window = true;
14771 return false;
14772 }
14773 return true;
14774}
14775#endif /* CONFIG_KXLD */
14776
14777/*********************************************************************
14778*********************************************************************/
14779bool
14780_OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14781{
14782 int unLoadedCount, i;
14783 bool result = false;
14784
14785 IORecursiveLockLock(lock: sKextLock);
14786
14787 if (sUnloadedPrelinkedKexts == NULL) {
14788 goto finish;
14789 }
14790 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14791 if (unLoadedCount == 0) {
14792 goto finish;
14793 }
14794
14795 for (i = 0; i < unLoadedCount; i++) {
14796 const OSSymbol * myBundleID; // do not release
14797
14798 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14799 if (!myBundleID) {
14800 continue;
14801 }
14802 if (theBundleID->isEqualTo(cString: myBundleID->getCStringNoCopy())) {
14803 result = true;
14804 break;
14805 }
14806 }
14807finish:
14808 IORecursiveLockUnlock(lock: sKextLock);
14809 return result;
14810}
14811
14812#if PRAGMA_MARK
14813#pragma mark Personalities (IOKit Drivers)
14814#endif
14815/*********************************************************************
14816*********************************************************************/
14817/* static */
14818OSSharedPtr<OSArray>
14819OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14820{
14821 OSSharedPtr<OSArray> result;
14822 OSSharedPtr<OSCollectionIterator> kextIterator;
14823 OSSharedPtr<OSArray> personalities;
14824
14825 OSString * kextID = NULL; // do not release
14826 OSKext * theKext = NULL; // do not release
14827
14828 IORecursiveLockLock(lock: sKextLock);
14829
14830 /* Let's conservatively guess that any given kext has around 3
14831 * personalities for now.
14832 */
14833 result = OSArray::withCapacity(capacity: sKextsByID->getCount() * 3);
14834 if (!result) {
14835 goto finish;
14836 }
14837
14838 kextIterator = OSCollectionIterator::withCollection(inColl: sKextsByID.get());
14839 if (!kextIterator) {
14840 goto finish;
14841 }
14842
14843 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14844 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14845 if (theKext->flags.requireExplicitLoad) {
14846 OSKextLog(aKext: theKext,
14847 kOSKextLogDebugLevel |
14848 kOSKextLogLoadFlag,
14849 format: "Kext %s requires an explicit kextload; "
14850 "omitting its personalities.",
14851 theKext->getIdentifierCString());
14852 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14853 personalities = theKext->copyPersonalitiesArray();
14854 if (!personalities) {
14855 continue;
14856 }
14857 result->merge(otherArray: personalities.get());
14858 } else {
14859 // xxx - check for better place to put this log msg
14860 OSKextLog(aKext: theKext,
14861 kOSKextLogWarningLevel |
14862 kOSKextLogLoadFlag,
14863 format: "Kext %s is not loadable during safe boot; "
14864 "omitting its personalities.",
14865 theKext->getIdentifierCString());
14866 }
14867 }
14868
14869finish:
14870 IORecursiveLockUnlock(lock: sKextLock);
14871
14872 return result;
14873}
14874
14875/*********************************************************************
14876*********************************************************************/
14877/* static */
14878void
14879OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14880{
14881 int numPersonalities = 0;
14882
14883 OSKextLog(/* kext */ NULL,
14884 kOSKextLogStepLevel |
14885 kOSKextLogLoadFlag,
14886 format: "Sending all eligible registered kexts' personalities "
14887 "to the IOCatalogue %s.",
14888 startMatching ? "and starting matching" : "but not starting matching");
14889
14890 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14891 /* filterSafeBootFlag */ true);
14892
14893 if (personalities) {
14894 gIOCatalogue->addDrivers(array: personalities.get(), doNubMatching: startMatching);
14895 numPersonalities = personalities->getCount();
14896 }
14897
14898 OSKextLog(/* kext */ NULL,
14899 kOSKextLogStepLevel |
14900 kOSKextLogLoadFlag,
14901 format: "%d kext personalit%s sent to the IOCatalogue; %s.",
14902 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14903 startMatching ? "matching started" : "matching not started");
14904 return;
14905}
14906
14907/*********************************************************************
14908* Do not make a deep copy, just convert the IOKitPersonalities dict
14909* to an array for sending to the IOCatalogue.
14910*********************************************************************/
14911OSSharedPtr<OSArray>
14912OSKext::copyPersonalitiesArray(void)
14913{
14914 OSSharedPtr<OSArray> result;
14915 OSDictionary * personalities = NULL; // do not release
14916 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14917
14918 OSString * personalityName = NULL; // do not release
14919 OSString * personalityBundleIdentifier = NULL; // do not release
14920
14921 personalities = OSDynamicCast(OSDictionary,
14922 getPropertyForHostArch(kIOKitPersonalitiesKey));
14923 if (!personalities) {
14924 goto finish;
14925 }
14926
14927 result = OSArray::withCapacity(capacity: personalities->getCount());
14928 if (!result) {
14929 goto finish;
14930 }
14931
14932 personalitiesIterator =
14933 OSCollectionIterator::withCollection(inColl: personalities);
14934 if (!personalitiesIterator) {
14935 goto finish;
14936 }
14937 while ((personalityName = OSDynamicCast(OSString,
14938 personalitiesIterator->getNextObject()))) {
14939 OSDictionary * personality = OSDynamicCast(OSDictionary,
14940 personalities->getObject(personalityName));
14941
14942 if (personality) {
14943 /******
14944 * If the personality doesn't have a CFBundleIdentifier, or if it
14945 * differs from the kext's, insert the kext's ID so we can find it.
14946 * The publisher ID is used to remove personalities from bundles
14947 * correctly.
14948 */
14949 personalityBundleIdentifier = OSDynamicCast(OSString,
14950 personality->getObject(kCFBundleIdentifierKey));
14951
14952 if (!personalityBundleIdentifier) {
14953 personality->setObject(kCFBundleIdentifierKey, anObject: bundleID.get());
14954 } else if (!personalityBundleIdentifier->isEqualTo(aString: bundleID.get())) {
14955 personality->setObject(kIOPersonalityPublisherKey, anObject: bundleID.get());
14956 }
14957 }
14958
14959 result->setObject(personality);
14960 }
14961
14962finish:
14963 return result;
14964}
14965
14966/*********************************************************************
14967* Might want to change this to a bool return?
14968*********************************************************************/
14969OSReturn
14970OSKext::sendPersonalitiesToCatalog(
14971 bool startMatching,
14972 OSArray * personalityNames)
14973{
14974 OSReturn result = kOSReturnSuccess;
14975 OSSharedPtr<OSArray> personalitiesToSend;
14976 OSDictionary * kextPersonalities = NULL; // do not release
14977 int count, i;
14978
14979 if (!sLoadEnabled) {
14980 OSKextLog(aKext: this,
14981 kOSKextLogErrorLevel |
14982 kOSKextLogLoadFlag,
14983 format: "Kext loading is disabled (attempt to start matching for kext %s).",
14984 getIdentifierCString());
14985 result = kOSKextReturnDisabled;
14986 goto finish;
14987 }
14988
14989 if (sSafeBoot && !isLoadableInSafeBoot()) {
14990 OSKextLog(aKext: this,
14991 kOSKextLogErrorLevel |
14992 kOSKextLogLoadFlag,
14993 format: "Kext %s is not loadable during safe boot; "
14994 "not sending personalities to the IOCatalogue.",
14995 getIdentifierCString());
14996 result = kOSKextReturnNotLoadable;
14997 goto finish;
14998 }
14999
15000 if (!personalityNames || !personalityNames->getCount()) {
15001 personalitiesToSend = copyPersonalitiesArray();
15002 } else {
15003 kextPersonalities = OSDynamicCast(OSDictionary,
15004 getPropertyForHostArch(kIOKitPersonalitiesKey));
15005 if (!kextPersonalities || !kextPersonalities->getCount()) {
15006 // not an error
15007 goto finish;
15008 }
15009 personalitiesToSend = OSArray::withCapacity(capacity: 0);
15010 if (!personalitiesToSend) {
15011 result = kOSKextReturnNoMemory;
15012 goto finish;
15013 }
15014 count = personalityNames->getCount();
15015 for (i = 0; i < count; i++) {
15016 OSString * name = OSDynamicCast(OSString,
15017 personalityNames->getObject(i));
15018 if (!name) {
15019 continue;
15020 }
15021 OSDictionary * personality = OSDynamicCast(OSDictionary,
15022 kextPersonalities->getObject(name));
15023 if (personality) {
15024 personalitiesToSend->setObject(personality);
15025 }
15026 }
15027 }
15028 if (personalitiesToSend) {
15029 unsigned numPersonalities = personalitiesToSend->getCount();
15030 OSKextLog(aKext: this,
15031 kOSKextLogStepLevel |
15032 kOSKextLogLoadFlag,
15033 format: "Kext %s sending %d personalit%s to the IOCatalogue%s.",
15034 getIdentifierCString(),
15035 numPersonalities,
15036 numPersonalities > 1 ? "ies" : "y",
15037 startMatching ? " and starting matching" : " but not starting matching");
15038 gIOCatalogue->addDrivers(array: personalitiesToSend.get(), doNubMatching: startMatching);
15039 }
15040finish:
15041 return result;
15042}
15043
15044/*********************************************************************
15045* xxx - We should allow removing the kext's declared personalities,
15046* xxx - even with other bundle identifiers.
15047*********************************************************************/
15048void
15049OSKext::removePersonalitiesFromCatalog(void)
15050{
15051 OSSharedPtr<OSDictionary> personality;
15052
15053 personality = OSDictionary::withCapacity(capacity: 1);
15054 if (!personality) {
15055 goto finish;
15056 }
15057 personality->setObject(kCFBundleIdentifierKey, anObject: getIdentifier());
15058
15059 OSKextLog(aKext: this,
15060 kOSKextLogStepLevel |
15061 kOSKextLogLoadFlag,
15062 format: "Kext %s removing all personalities naming it from the IOCatalogue.",
15063 getIdentifierCString());
15064
15065 /* Have the IOCatalog remove all personalities matching this kext's
15066 * bundle ID and trigger matching anew.
15067 */
15068 gIOCatalogue->removeDrivers(matching: personality.get(), /* startMatching */ doNubMatching: true);
15069
15070finish:
15071 return;
15072}
15073
15074void
15075OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
15076{
15077 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
15078 return;
15079 }
15080
15081 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(capacity: 1);
15082 if (!personalityToRemove) {
15083 return;
15084 }
15085
15086 /*
15087 * Create a personality dictionary with just the bundleID.
15088 * We will remove any personality that has a matching bundleID,
15089 * irrespective of which other keys are present on the dictionary.
15090 */
15091 personalityToRemove->setObject(kCFBundleIdentifierKey, anObject: getIdentifier());
15092 gIOCatalogue->exchangeDrivers(matchingForRemove: personalityToRemove.get(), personalitiesToAdd: upgradedPersonalities, doNubMatching: true);
15093}
15094
15095#if PRAGMA_MARK
15096#pragma mark Logging
15097#endif
15098/*********************************************************************
15099* Do not call any function that takes sKextLock here!
15100*********************************************************************/
15101/* static */
15102OSKextLogSpec
15103OSKext::setUserSpaceLogFilter(
15104 OSKextLogSpec newUserLogFilter,
15105 bool captureFlag)
15106{
15107 OSKextLogSpec result;
15108 bool allocError = false;
15109
15110 /* Do not call any function that takes sKextLoggingLock during
15111 * this critical block. That means do logging after.
15112 */
15113 IOLockLock(sKextLoggingLock);
15114
15115 result = sUserSpaceKextLogFilter;
15116 sUserSpaceKextLogFilter = newUserLogFilter;
15117
15118 if (newUserLogFilter && captureFlag &&
15119 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
15120 // xxx - do some measurements for a good initial capacity?
15121 sUserSpaceLogSpecArray = OSArray::withCapacity(capacity: 0);
15122 sUserSpaceLogMessageArray = OSArray::withCapacity(capacity: 0);
15123
15124 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
15125 allocError = true;
15126 }
15127 }
15128
15129 IOLockUnlock(sKextLoggingLock);
15130
15131 /* If the config flag itself is changing, log the state change
15132 * going both ways, before setting up the user-space log arrays,
15133 * so that this is only logged in the kernel.
15134 */
15135 if (result != newUserLogFilter) {
15136 OSKextLog(/* kext */ NULL,
15137 kOSKextLogDebugLevel |
15138 kOSKextLogGeneralFlag,
15139 format: "User-space log flags changed from 0x%x to 0x%x.",
15140 result, newUserLogFilter);
15141 }
15142 if (allocError) {
15143 OSKextLog(/* kext */ NULL,
15144 kOSKextLogErrorLevel |
15145 kOSKextLogGeneralFlag,
15146 format: "Failed to allocate user-space log message arrays.");
15147 }
15148
15149 return result;
15150}
15151
15152/*********************************************************************
15153* Do not call any function that takes sKextLock here!
15154*********************************************************************/
15155/* static */
15156OSSharedPtr<OSArray>
15157OSKext::clearUserSpaceLogFilter(void)
15158{
15159 OSSharedPtr<OSArray> result;
15160 OSKextLogSpec oldLogFilter;
15161 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
15162
15163 /* Do not call any function that takes sKextLoggingLock during
15164 * this critical block. That means do logging after.
15165 */
15166 IOLockLock(sKextLoggingLock);
15167
15168 result = OSArray::withCapacity(capacity: 2);
15169 if (result) {
15170 result->setObject(sUserSpaceLogSpecArray.get());
15171 result->setObject(sUserSpaceLogMessageArray.get());
15172 }
15173 sUserSpaceLogSpecArray.reset();
15174 sUserSpaceLogMessageArray.reset();
15175
15176 oldLogFilter = sUserSpaceKextLogFilter;
15177 sUserSpaceKextLogFilter = newLogFilter;
15178
15179 IOLockUnlock(sKextLoggingLock);
15180
15181 /* If the config flag itself is changing, log the state change
15182 * going both ways, after tearing down the user-space log
15183 * arrays, so this is only logged within the kernel.
15184 */
15185 if (oldLogFilter != newLogFilter) {
15186 OSKextLog(/* kext */ NULL,
15187 kOSKextLogDebugLevel |
15188 kOSKextLogGeneralFlag,
15189 format: "User-space log flags changed from 0x%x to 0x%x.",
15190 oldLogFilter, newLogFilter);
15191 }
15192
15193 return result;
15194}
15195
15196
15197/*********************************************************************
15198* Do not call any function that takes sKextLock here!
15199*********************************************************************/
15200/* static */
15201OSKextLogSpec
15202OSKext::getUserSpaceLogFilter(void)
15203{
15204 OSKextLogSpec result;
15205
15206 IOLockLock(sKextLoggingLock);
15207 result = sUserSpaceKextLogFilter;
15208 IOLockUnlock(sKextLoggingLock);
15209
15210 return result;
15211}
15212
15213/*********************************************************************
15214* This function is called by OSMetaClass during kernel C++ setup.
15215* Be careful what you access here; assume only OSKext::initialize()
15216* has been called.
15217*
15218* Do not call any function that takes sKextLock here!
15219*********************************************************************/
15220#define VTRESET "\033[0m"
15221
15222#define VTBOLD "\033[1m"
15223#define VTUNDER "\033[4m"
15224
15225#define VTRED "\033[31m"
15226#define VTGREEN "\033[32m"
15227#define VTYELLOW "\033[33m"
15228#define VTBLUE "\033[34m"
15229#define VTMAGENTA "\033[35m"
15230#define VTCYAN "\033[36m"
15231
15232inline const char *
15233colorForFlags(OSKextLogSpec flags)
15234{
15235 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15236
15237 switch (logLevel) {
15238 case kOSKextLogErrorLevel:
15239 return VTRED VTBOLD;
15240 case kOSKextLogWarningLevel:
15241 return VTRED;
15242 case kOSKextLogBasicLevel:
15243 return VTYELLOW VTUNDER;
15244 case kOSKextLogProgressLevel:
15245 return VTYELLOW;
15246 case kOSKextLogStepLevel:
15247 return VTGREEN;
15248 case kOSKextLogDetailLevel:
15249 return VTCYAN;
15250 case kOSKextLogDebugLevel:
15251 return VTMAGENTA;
15252 default:
15253 return ""; // white
15254 }
15255}
15256
15257inline bool
15258logSpecMatch(
15259 OSKextLogSpec msgLogSpec,
15260 OSKextLogSpec logFilter)
15261{
15262 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15263 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15264 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15265
15266 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15267 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15268 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15269
15270 /* Explicit messages always get logged.
15271 */
15272 if (msgLevel == kOSKextLogExplicitLevel) {
15273 return true;
15274 }
15275
15276 /* Warnings and errors are logged regardless of the flags.
15277 */
15278 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15279 return true;
15280 }
15281
15282 /* A verbose message that isn't for a logging-enabled kext and isn't global
15283 * does *not* get logged.
15284 */
15285 if (!msgKextGlobal && !filterKextGlobal) {
15286 return false;
15287 }
15288
15289 /* Warnings and errors are logged regardless of the flags.
15290 * All other messages must fit the flags and
15291 * have a level at or below the filter.
15292 *
15293 */
15294 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15295 return true;
15296 }
15297 return false;
15298}
15299
15300extern "C" {
15301void
15302OSKextLog(
15303 OSKext * aKext,
15304 OSKextLogSpec msgLogSpec,
15305 const char * format, ...)
15306{
15307 va_list argList;
15308
15309 va_start(argList, format);
15310 OSKextVLog(aKext, msgLogSpec, format, srcArgList: argList);
15311 va_end(argList);
15312}
15313
15314void
15315OSKextVLog(
15316 OSKext * aKext,
15317 OSKextLogSpec msgLogSpec,
15318 const char * format,
15319 va_list srcArgList)
15320{
15321 bool logForKernel = false;
15322 bool logForUser = false;
15323 va_list argList;
15324 char stackBuffer[120];
15325 uint32_t length = 0;
15326 char * allocBuffer = NULL; // must kfree
15327 OSSharedPtr<OSNumber> logSpecNum;
15328 OSSharedPtr<OSString> logString;
15329 char * buffer = stackBuffer; // do not free
15330
15331 IOLockLock(sKextLoggingLock);
15332
15333 /* Set the kext/global bit in the message spec if we have no
15334 * kext or if the kext requests logging.
15335 */
15336 if (!aKext || aKext->flags.loggingEnabled) {
15337 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15338 }
15339
15340 logForKernel = logSpecMatch(msgLogSpec, logFilter: sKernelLogFilter);
15341 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15342 logForUser = logSpecMatch(msgLogSpec, logFilter: sUserSpaceKextLogFilter);
15343 }
15344
15345 if (!(logForKernel || logForUser)) {
15346 goto finish;
15347 }
15348
15349 /* No goto from here until past va_end()!
15350 */
15351 va_copy(argList, srcArgList);
15352 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15353 va_end(argList);
15354
15355 if (length + 1 >= sizeof(stackBuffer)) {
15356 allocBuffer = (char *)kalloc_data_tag(length + 1,
15357 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15358 if (!allocBuffer) {
15359 goto finish;
15360 }
15361
15362 /* No goto from here until past va_end()!
15363 */
15364 va_copy(argList, srcArgList);
15365 vsnprintf(allocBuffer, length + 1, format, argList);
15366 va_end(argList);
15367
15368 buffer = allocBuffer;
15369 }
15370
15371 /* If user space wants the log message, queue it up.
15372 */
15373 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15374 logSpecNum = OSNumber::withNumber(value: msgLogSpec, numberOfBits: 8 * sizeof(msgLogSpec));
15375 logString = OSString::withCString(cString: buffer);
15376 if (logSpecNum && logString) {
15377 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15378 sUserSpaceLogMessageArray->setObject(logString.get());
15379 }
15380 }
15381
15382 /* Always log messages from the kernel according to the kernel's
15383 * log flags.
15384 */
15385 if (logForKernel) {
15386 /* If we are in console mode and have a custom log filter,
15387 * colorize the log message.
15388 */
15389 if (sBootArgLogFilterFound) {
15390 const char * color = ""; // do not free
15391 color = colorForFlags(flags: msgLogSpec);
15392 printf("%s%s%s\n", colorForFlags(flags: msgLogSpec),
15393 buffer, color[0] ? VTRESET : "");
15394 } else {
15395 printf("%s\n", buffer);
15396 }
15397 }
15398
15399finish:
15400 IOLockUnlock(sKextLoggingLock);
15401
15402 if (allocBuffer) {
15403 kfree_data(allocBuffer, length + 1);
15404 }
15405 return;
15406}
15407
15408#if KASLR_IOREG_DEBUG
15409
15410#define IOLOG_INDENT( the_indention ) \
15411{ \
15412 int i; \
15413 for ( i = 0; i < (the_indention); i++ ) { \
15414 IOLog(" "); \
15415 } \
15416}
15417
15418extern vm_offset_t vm_kernel_stext;
15419extern vm_offset_t vm_kernel_etext;
15420extern mach_vm_offset_t kext_alloc_base;
15421extern mach_vm_offset_t kext_alloc_max;
15422
15423bool ScanForAddrInObject(OSObject * theObject,
15424 int indent );
15425
15426bool
15427ScanForAddrInObject(OSObject * theObject,
15428 int indent)
15429{
15430 const OSMetaClass * myTypeID;
15431 OSSharedPtr<OSCollectionIterator> myIter;
15432 OSSymbol * myKey;
15433 OSObject * myValue;
15434 bool myResult = false;
15435
15436 if (theObject == NULL) {
15437 IOLog("%s: theObject is NULL \n",
15438 __FUNCTION__);
15439 return myResult;
15440 }
15441
15442 myTypeID = OSTypeIDInst(theObject);
15443
15444 if (myTypeID == OSTypeID(OSDictionary)) {
15445 OSDictionary * myDictionary;
15446
15447 myDictionary = OSDynamicCast(OSDictionary, theObject);
15448 myIter = OSCollectionIterator::withCollection( myDictionary );
15449 if (myIter == NULL) {
15450 return myResult;
15451 }
15452
15453 // !! reset the iterator
15454 myIter->reset();
15455
15456 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15457 bool myTempResult;
15458
15459 myValue = myDictionary->getObject(myKey);
15460 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15461 if (myTempResult) {
15462 // if we ever get a true result return true
15463 myResult = true;
15464 IOLOG_INDENT(indent);
15465 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15466 }
15467 }
15468
15469 // !! release the iterator
15470 myIter.reset();
15471 } else if (myTypeID == OSTypeID(OSArray)) {
15472 OSArray * myArray;
15473
15474 myArray = OSDynamicCast(OSArray, theObject);
15475 myIter = OSCollectionIterator::withCollection(myArray);
15476 if (myIter == NULL) {
15477 return myResult;
15478 }
15479 // !! reset the iterator
15480 myIter->reset();
15481
15482 while ((myValue = myIter->getNextObject())) {
15483 bool myTempResult;
15484 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15485 if (myTempResult) {
15486 // if we ever get a true result return true
15487 myResult = true;
15488 IOLOG_INDENT(indent);
15489 IOLog("OSArray: \n");
15490 }
15491 }
15492 // !! release the iterator
15493 myIter.reset();
15494 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15495 // should we look for addresses in strings?
15496 } else if (myTypeID == OSTypeID(OSData)) {
15497 void * * myPtrPtr;
15498 unsigned int myLen;
15499 OSData * myDataObj;
15500
15501 myDataObj = OSDynamicCast(OSData, theObject);
15502 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15503 myLen = myDataObj->getLength();
15504
15505 if (myPtrPtr && myLen && myLen > 7) {
15506 int i;
15507 int myPtrCount = (myLen / sizeof(void *));
15508
15509 for (i = 0; i < myPtrCount; i++) {
15510 UInt64 numberValue = (UInt64) * (myPtrPtr);
15511
15512 if (kext_alloc_max != 0 &&
15513 numberValue >= kext_alloc_base &&
15514 numberValue < kext_alloc_max) {
15515 OSSharedPtr<OSKext> myKext;
15516 // IOLog("found OSData %p in kext map %p to %p \n",
15517 // *(myPtrPtr),
15518 // (void *) kext_alloc_base,
15519 // (void *) kext_alloc_max);
15520
15521 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15522 if (myKext) {
15523 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15524 *(myPtrPtr),
15525 myKext->getIdentifierCString());
15526 }
15527 myResult = true;
15528 }
15529 if (vm_kernel_etext != 0 &&
15530 numberValue >= vm_kernel_stext &&
15531 numberValue < vm_kernel_etext) {
15532 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15533 *(myPtrPtr),
15534 (void *) vm_kernel_stext,
15535 (void *) vm_kernel_etext);
15536 myResult = true;
15537 }
15538 myPtrPtr++;
15539 }
15540 }
15541 } else if (myTypeID == OSTypeID(OSBoolean)) {
15542 // do nothing here...
15543 } else if (myTypeID == OSTypeID(OSNumber)) {
15544 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15545
15546 UInt64 numberValue = number->unsigned64BitValue();
15547
15548 if (kext_alloc_max != 0 &&
15549 numberValue >= kext_alloc_base &&
15550 numberValue < kext_alloc_max) {
15551 OSSharedPtr<OSKext> myKext;
15552 IOLog("found OSNumber in kext map %p to %p \n",
15553 (void *) kext_alloc_base,
15554 (void *) kext_alloc_max);
15555 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15556
15557 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15558 if (myKext) {
15559 IOLog("found in kext \"%s\" \n",
15560 myKext->getIdentifierCString());
15561 }
15562
15563 myResult = true;
15564 }
15565 if (vm_kernel_etext != 0 &&
15566 numberValue >= vm_kernel_stext &&
15567 numberValue < vm_kernel_etext) {
15568 IOLog("found OSNumber in kernel text segment %p to %p \n",
15569 (void *) vm_kernel_stext,
15570 (void *) vm_kernel_etext);
15571 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15572 myResult = true;
15573 }
15574 }
15575#if 0
15576 else {
15577 const OSMetaClass* myMetaClass = NULL;
15578
15579 myMetaClass = theObject->getMetaClass();
15580 if (myMetaClass) {
15581 IOLog("class %s \n", myMetaClass->getClassName());
15582 } else {
15583 IOLog("Unknown object \n" );
15584 }
15585 }
15586#endif
15587
15588 return myResult;
15589}
15590#endif // KASLR_KEXT_DEBUG
15591}; /* extern "C" */
15592
15593#if PRAGMA_MARK
15594#pragma mark Backtrace Dump & kmod_get_info() support
15595#endif
15596/*********************************************************************
15597* This function must be safe to call in panic context.
15598*********************************************************************/
15599/* static */
15600void
15601OSKext::printKextsInBacktrace(
15602 vm_offset_t * addr __unused,
15603 unsigned int cnt __unused,
15604 int (* printf_func)(const char *fmt, ...) __unused,
15605 uint32_t flags __unused)
15606{
15607 addr64_t summary_page = 0;
15608 addr64_t last_summary_page = 0;
15609
15610 if (kPrintKextsLock & flags) {
15611 if (!sKextSummariesLock) {
15612 return;
15613 }
15614 IOLockLock(sKextSummariesLock);
15615 }
15616
15617 if (!gLoadedKextSummaries) {
15618 (*printf_func)(" can't perform kext scan: no kext summary");
15619 goto finish;
15620 }
15621
15622 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15623 last_summary_page = round_page(x: summary_page + sLoadedKextSummariesAllocSize);
15624 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15625 if (pmap_find_phys(pmap: kernel_pmap, va: summary_page) == 0) {
15626 (*printf_func)(" can't perform kext scan: "
15627 "missing kext summary page %p", summary_page);
15628 goto finish;
15629 }
15630 }
15631
15632 foreachKextInBacktrace(addr, cnt, flags: 0, handler: ^(OSKextLoadedKextSummary *summary, uint32_t index) {
15633 if (index == 0 && !(kPrintKextsTerse & flags)) {
15634 (*printf_func)(" Kernel Extensions in backtrace:\n");
15635 }
15636
15637 printSummary(summary, printf_func, flags);
15638 });
15639
15640finish:
15641 if (kPrintKextsLock & flags) {
15642 IOLockUnlock(sKextSummariesLock);
15643 }
15644
15645 return;
15646}
15647
15648void
15649OSKext::foreachKextInBacktrace(
15650 vm_offset_t * addr,
15651 uint32_t cnt,
15652 uint32_t flags,
15653 void (^ handler)(OSKextLoadedKextSummary *summary, uint32_t index))
15654{
15655 uint32_t n = 0;
15656
15657 if (kPrintKextsLock & flags) {
15658 if (!sKextSummariesLock) {
15659 return;
15660 }
15661 IOLockLock(sKextSummariesLock);
15662 }
15663
15664 for (uint32_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15665 OSKextLoadedKextSummary * summary;
15666
15667 summary = gLoadedKextSummaries->summaries + i;
15668 if (!summary->address) {
15669 continue;
15670 }
15671
15672 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15673 continue;
15674 }
15675
15676 handler(summary, n++);
15677 }
15678
15679 if (kPrintKextsLock & flags) {
15680 IOLockUnlock(sKextSummariesLock);
15681 }
15682}
15683
15684/*********************************************************************
15685* This function must be safe to call in panic context.
15686*********************************************************************/
15687/* static */
15688boolean_t
15689OSKext::summaryIsInBacktrace(
15690 OSKextLoadedKextSummary * summary,
15691 vm_offset_t * addr,
15692 unsigned int cnt)
15693{
15694 u_int i = 0;
15695
15696 for (i = 0; i < cnt; i++) {
15697 vm_offset_t kscan_addr = addr[i];
15698#if __has_feature(ptrauth_calls)
15699 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15700#endif /* __has_feature(ptrauth_calls) */
15701 if ((kscan_addr >= summary->text_exec_address) &&
15702 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15703 return TRUE;
15704 }
15705 }
15706
15707 return FALSE;
15708}
15709
15710/*
15711 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15712 * sKextSummariesLock held.
15713 */
15714OSKextLoadedKextSummary *
15715OSKext::summaryForAddress(uintptr_t addr)
15716{
15717#if __has_feature(ptrauth_calls)
15718 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15719#endif /* __has_feature(ptrauth_calls) */
15720 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15721 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15722 if (!summary->address) {
15723 continue;
15724 }
15725
15726#if VM_MAPPED_KEXTS
15727 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15728 * support split kexts, but we also may unmap the kexts, which can
15729 * race with the above codepath (see OSKext::unload). As such,
15730 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15731 */
15732 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15733 return summary;
15734 }
15735#else
15736 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15737 kernel_segment_command_t *seg;
15738
15739 for (seg = firstsegfromheader(header: mh); seg != NULL; seg = nextsegfromheader(header: mh, seg)) {
15740 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15741 return summary;
15742 }
15743 }
15744#endif
15745 }
15746
15747 /* addr did not map to any kext */
15748 return NULL;
15749}
15750
15751/* static */
15752void *
15753OSKext::kextForAddress(const void *address)
15754{
15755 OSKextActiveAccount * active;
15756 OSKext * kext = NULL;
15757 uint32_t baseIdx;
15758 uint32_t lim;
15759 uintptr_t addr = (uintptr_t) address;
15760 size_t i;
15761
15762 if (!addr) {
15763 return NULL;
15764 }
15765#if __has_feature(ptrauth_calls)
15766 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15767#endif /* __has_feature(ptrauth_calls) */
15768
15769 if (sKextAccountsCount) {
15770 lck_ticket_lock(tlock: sKextAccountsLock, grp: sKextAccountsLockGrp);
15771 // bsearch sKextAccounts list
15772 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15773 active = &sKextAccounts[baseIdx + (lim >> 1)];
15774 if ((addr >= active->address) && (addr < active->address_end)) {
15775 kext = active->account->kext;
15776 if (kext && kext->kmod_info) {
15777 lck_ticket_unlock(tlock: sKextAccountsLock);
15778 return (void *)kext->kmod_info->address;
15779 }
15780 break;
15781 } else if (addr > active->address) {
15782 // move right
15783 baseIdx += (lim >> 1) + 1;
15784 lim--;
15785 }
15786 // else move left
15787 }
15788 lck_ticket_unlock(tlock: sKextAccountsLock);
15789 }
15790 if (kernel_text_contains(addr)) {
15791 return (void *)&_mh_execute_header;
15792 }
15793 if (gLoadedKextSummaries) {
15794 IOLockLock(sKextSummariesLock);
15795 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15796 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15797 if (addr >= summary->address && addr < summary->address + summary->size) {
15798 void *kextAddress = (void *)summary->address;
15799 IOLockUnlock(sKextSummariesLock);
15800 return kextAddress;
15801 }
15802 }
15803 IOLockUnlock(sKextSummariesLock);
15804 }
15805
15806 return NULL;
15807}
15808
15809/* static */
15810kern_return_t
15811OSKext::summaryForAddressExt(
15812 const void * address,
15813 OSKextLoadedKextSummary * summary)
15814{
15815 kern_return_t result = KERN_FAILURE;
15816 const OSKextLoadedKextSummary * foundSummary = NULL;
15817
15818 /*
15819 * This needs to be safe to call even before the lock has been initialized
15820 * in OSKext::initialize(), as we might get here from the ksancov runtime
15821 * when instrumenting XNU itself with sanitizer coverage.
15822 */
15823 if (!sKextSummariesLock) {
15824 return result;
15825 }
15826
15827 IOLockLock(sKextSummariesLock);
15828 if (gLoadedKextSummaries) {
15829 foundSummary = summaryForAddress(addr: (uintptr_t)address);
15830 if (foundSummary) {
15831 memcpy(dst: summary, src: foundSummary, n: sizeof(*summary));
15832 result = KERN_SUCCESS;
15833 } else {
15834 result = KERN_NOT_FOUND;
15835 }
15836 }
15837 IOLockUnlock(sKextSummariesLock);
15838
15839 return result;
15840}
15841
15842/*
15843 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15844 * Safe to call in panic context.
15845 */
15846static OSKextLoadedKextSummary *
15847findSummary(uint32_t tagID)
15848{
15849 OSKextLoadedKextSummary * summary;
15850 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15851 summary = gLoadedKextSummaries->summaries + i;
15852 if (summary->loadTag == tagID) {
15853 return summary;
15854 }
15855 }
15856 return NULL;
15857}
15858
15859/*********************************************************************
15860* This function must be safe to call in panic context.
15861*********************************************************************/
15862void
15863OSKext::printSummary(
15864 OSKextLoadedKextSummary * summary,
15865 int (* printf_func)(const char *fmt, ...),
15866 uint32_t flags)
15867{
15868 kmod_reference_t * kmod_ref = NULL;
15869 uuid_string_t uuid;
15870 char version[kOSKextVersionMaxLength];
15871 uint64_t tmpAddr;
15872 uint64_t tmpSize;
15873 OSKextLoadedKextSummary *dependencySummary;
15874
15875 if (!OSKextVersionGetString(aVersion: summary->version, buffer: version, bufferSize: sizeof(version))) {
15876 strlcpy(dst: version, src: "unknown version", n: sizeof(version));
15877 }
15878 (void) uuid_unparse(uu: summary->uuid, out: uuid);
15879
15880#if defined(__arm__) || defined(__arm64__)
15881 tmpAddr = summary->text_exec_address;
15882 tmpSize = summary->text_exec_size;
15883#else
15884 tmpAddr = summary->address;
15885 tmpSize = summary->size;
15886#endif
15887 if (kPrintKextsUnslide & flags) {
15888 tmpAddr = ml_static_unslide(vaddr: tmpAddr);
15889 }
15890 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15891 (kPrintKextsTerse & flags) ? "" : " ",
15892 summary->name, version, uuid,
15893 tmpAddr, tmpAddr + tmpSize - 1);
15894
15895 if (kPrintKextsTerse & flags) {
15896 return;
15897 }
15898
15899 /* print dependency info */
15900 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15901 kmod_ref;
15902 kmod_ref = kmod_ref->next) {
15903 kmod_info_t * rinfo;
15904
15905 if (pmap_find_phys(pmap: kernel_pmap, va: (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15906 (*printf_func)(" kmod dependency scan stopped "
15907 "due to missing dependency page: %p\n",
15908 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide(vaddr: (vm_offset_t)kmod_ref) : kmod_ref);
15909 break;
15910 }
15911 rinfo = kmod_ref->info;
15912
15913 if (pmap_find_phys(pmap: kernel_pmap, va: (addr64_t)((uintptr_t)rinfo)) == 0) {
15914 (*printf_func)(" kmod dependency scan stopped "
15915 "due to missing kmod page: %p\n",
15916 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide(vaddr: (vm_offset_t)rinfo) : rinfo);
15917 break;
15918 }
15919
15920 if (!rinfo->address) {
15921 continue; // skip fake entries for built-ins
15922 }
15923
15924 dependencySummary = findSummary(tagID: rinfo->id);
15925 uuid[0] = 0x00;
15926 tmpAddr = rinfo->address;
15927 tmpSize = rinfo->size;
15928 if (dependencySummary) {
15929 (void) uuid_unparse(uu: dependencySummary->uuid, out: uuid);
15930#if defined(__arm__) || defined(__arm64__)
15931 tmpAddr = dependencySummary->text_exec_address;
15932 tmpSize = dependencySummary->text_exec_size;
15933#endif
15934 }
15935
15936 if (kPrintKextsUnslide & flags) {
15937 tmpAddr = ml_static_unslide(vaddr: tmpAddr);
15938 }
15939 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15940 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15941 }
15942 return;
15943}
15944
15945
15946#if !defined(__arm__) && !defined(__arm64__)
15947/*******************************************************************************
15948* substitute() looks at an input string (a pointer within a larger buffer)
15949* for a match to a substring, and on match it writes the marker & substitution
15950* character to an output string, updating the scan (from) and
15951* output (to) indexes as appropriate.
15952*******************************************************************************/
15953static int substitute(
15954 const char * scan_string,
15955 char * string_out,
15956 uint32_t * to_index,
15957 uint32_t * from_index,
15958 const char * substring,
15959 char marker,
15960 char substitution);
15961
15962/* string_out must be at least KMOD_MAX_NAME bytes.
15963 */
15964static int
15965substitute(
15966 const char * scan_string,
15967 char * string_out,
15968 uint32_t * to_index,
15969 uint32_t * from_index,
15970 const char * substring,
15971 char marker,
15972 char substitution)
15973{
15974 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
15975
15976 /* On a substring match, append the marker (if there is one) and then
15977 * the substitution character, updating the output (to) index accordingly.
15978 * Then update the input (from) length by the length of the substring
15979 * that got replaced.
15980 */
15981 if (!strncmp(scan_string, substring, substring_length)) {
15982 if (marker) {
15983 string_out[(*to_index)++] = marker;
15984 }
15985 string_out[(*to_index)++] = substitution;
15986 (*from_index) += substring_length;
15987 return 1;
15988 }
15989 return 0;
15990}
15991
15992/*******************************************************************************
15993* compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
15994* KMOD_MAX_NAME characters and performs various substitutions of common
15995* prefixes & substrings as defined by tables in kext_panic_report.h.
15996*******************************************************************************/
15997static void compactIdentifier(
15998 const char * identifier,
15999 char * identifier_out,
16000 char ** identifier_out_end);
16001
16002static void
16003compactIdentifier(
16004 const char * identifier,
16005 char * identifier_out,
16006 char ** identifier_out_end)
16007{
16008 uint32_t from_index, to_index;
16009 uint32_t scan_from_index = 0;
16010 uint32_t scan_to_index = 0;
16011 subs_entry_t * subs_entry = NULL;
16012 int did_sub = 0;
16013
16014 from_index = to_index = 0;
16015 identifier_out[0] = '\0';
16016
16017 /* Replace certain identifier prefixes with shorter @+character sequences.
16018 * Check the return value of substitute() so we only replace the prefix.
16019 */
16020 for (subs_entry = &kext_identifier_prefix_subs[0];
16021 subs_entry->substring && !did_sub;
16022 subs_entry++) {
16023 did_sub = substitute(identifier, identifier_out,
16024 &scan_to_index, &scan_from_index,
16025 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
16026 }
16027 did_sub = 0;
16028
16029 /* Now scan through the identifier looking for the common substrings
16030 * and replacing them with shorter !+character sequences via substitute().
16031 */
16032 for (/* see above */;
16033 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
16034 /* see loop */) {
16035 const char * scan_string = &identifier[scan_from_index];
16036
16037 did_sub = 0;
16038
16039 if (scan_from_index) {
16040 for (subs_entry = &kext_identifier_substring_subs[0];
16041 subs_entry->substring && !did_sub;
16042 subs_entry++) {
16043 did_sub = substitute(scan_string, identifier_out,
16044 &scan_to_index, &scan_from_index,
16045 subs_entry->substring, '!', subs_entry->substitute);
16046 }
16047 }
16048
16049 /* If we didn't substitute, copy the input character to the output.
16050 */
16051 if (!did_sub) {
16052 identifier_out[scan_to_index++] = identifier[scan_from_index++];
16053 }
16054 }
16055
16056 identifier_out[scan_to_index] = '\0';
16057 if (identifier_out_end) {
16058 *identifier_out_end = &identifier_out[scan_to_index];
16059 }
16060
16061 return;
16062}
16063#endif /* !defined(__arm__) && !defined(__arm64__) */
16064
16065/*******************************************************************************
16066* assemble_identifier_and_version() adds to a string buffer a compacted
16067* bundle identifier followed by a version string.
16068*******************************************************************************/
16069
16070/* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
16071 */
16072static size_t assemble_identifier_and_version(
16073 kmod_info_t * kmod_info,
16074 char * identPlusVers,
16075 size_t bufSize);
16076
16077static size_t
16078assemble_identifier_and_version(
16079 kmod_info_t * kmod_info,
16080 char * identPlusVers,
16081 size_t bufSize)
16082{
16083 size_t result = 0;
16084
16085#if defined(__arm__) || defined(__arm64__)
16086 result = strlcpy(dst: identPlusVers, src: kmod_info->name, KMOD_MAX_NAME);
16087#else
16088 compactIdentifier(kmod_info->name, identPlusVers, NULL);
16089 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
16090#endif
16091 identPlusVers[result++] = '\t'; // increment for real char
16092 identPlusVers[result] = '\0'; // don't increment for nul char
16093 result = strlcat(dst: identPlusVers, src: kmod_info->version, n: bufSize);
16094 if (result >= bufSize) {
16095 identPlusVers[bufSize - 1] = '\0';
16096 result = bufSize - 1;
16097 }
16098
16099 return result;
16100}
16101
16102/*******************************************************************************
16103* Assumes sKextLock is held.
16104*******************************************************************************/
16105/* static */
16106int
16107OSKext::saveLoadedKextPanicListTyped(
16108 const char * prefix,
16109 int invertFlag,
16110 int libsFlag,
16111 char * paniclist,
16112 uint32_t list_size)
16113{
16114 int result = -1;
16115 unsigned int count, i;
16116
16117 count = sLoadedKexts->getCount();
16118 if (!count) {
16119 goto finish;
16120 }
16121
16122 i = count - 1;
16123 do {
16124 OSObject * rawKext = sLoadedKexts->getObject(index: i);
16125 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
16126 int match;
16127 size_t identPlusVersLength;
16128 size_t tempLen;
16129 char identPlusVers[2 * KMOD_MAX_NAME];
16130
16131 if (!rawKext) {
16132 printf("OSKext::saveLoadedKextPanicListTyped - "
16133 "NULL kext in loaded kext list; continuing\n");
16134 continue;
16135 }
16136
16137 if (!theKext) {
16138 printf("OSKext::saveLoadedKextPanicListTyped - "
16139 "Kext type cast failed in loaded kext list; continuing\n");
16140 continue;
16141 }
16142
16143 /* Skip all built-in kexts.
16144 */
16145 if (theKext->isKernelComponent()) {
16146 continue;
16147 }
16148
16149 kmod_info_t * kmod_info = theKext->kmod_info;
16150
16151 /* Filter for kmod name (bundle identifier).
16152 */
16153 match = !strncmp(s1: kmod_info->name, s2: prefix, n: strnlen(s: prefix, KMOD_MAX_NAME));
16154 if ((match && invertFlag) || (!match && !invertFlag)) {
16155 continue;
16156 }
16157
16158 /* Filter for libraries (kexts that have a compatible version).
16159 */
16160 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
16161 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
16162 continue;
16163 }
16164
16165 if (!kmod_info ||
16166 !pmap_find_phys(pmap: kernel_pmap, va: (addr64_t)((uintptr_t)kmod_info))) {
16167 printf("kext scan stopped due to missing kmod_info page: %p\n",
16168 kmod_info);
16169 goto finish;
16170 }
16171
16172 identPlusVersLength = assemble_identifier_and_version(kmod_info,
16173 identPlusVers,
16174 bufSize: sizeof(identPlusVers));
16175 if (!identPlusVersLength) {
16176 printf("error saving loaded kext info\n");
16177 goto finish;
16178 }
16179
16180 /* make sure everything fits and we null terminate.
16181 */
16182 tempLen = strlcat(dst: paniclist, src: identPlusVers, n: list_size);
16183 if (tempLen >= list_size) {
16184 // panic list is full, keep it and null terminate
16185 paniclist[list_size - 1] = 0x00;
16186 result = 0;
16187 goto finish;
16188 }
16189 tempLen = strlcat(dst: paniclist, src: "\n", n: list_size);
16190 if (tempLen >= list_size) {
16191 // panic list is full, keep it and null terminate
16192 paniclist[list_size - 1] = 0x00;
16193 result = 0;
16194 goto finish;
16195 }
16196 } while (i--);
16197
16198 result = 0;
16199finish:
16200
16201 return result;
16202}
16203
16204/*********************************************************************
16205*********************************************************************/
16206/* static */
16207void
16208OSKext::saveLoadedKextPanicList(void)
16209{
16210 char * newlist = NULL;
16211 uint32_t newlist_size = 0;
16212
16213 newlist_size = KEXT_PANICLIST_SIZE;
16214 newlist = (char *)kalloc_data_tag(newlist_size,
16215 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
16216
16217 if (!newlist) {
16218 OSKextLog(/* kext */ NULL,
16219 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
16220 format: "Couldn't allocate kext panic log buffer.");
16221 goto finish;
16222 }
16223
16224 newlist[0] = '\0';
16225
16226 // non-"com.apple." kexts
16227 if (OSKext::saveLoadedKextPanicListTyped(prefix: "com.apple.", /* invert? */ invertFlag: 1,
16228 /* libs? */ libsFlag: -1, paniclist: newlist, list_size: newlist_size) != 0) {
16229 goto finish;
16230 }
16231 // "com.apple." nonlibrary kexts
16232 if (OSKext::saveLoadedKextPanicListTyped(prefix: "com.apple.", /* invert? */ invertFlag: 0,
16233 /* libs? */ libsFlag: 0, paniclist: newlist, list_size: newlist_size) != 0) {
16234 goto finish;
16235 }
16236 // "com.apple." library kexts
16237 if (OSKext::saveLoadedKextPanicListTyped(prefix: "com.apple.", /* invert? */ invertFlag: 0,
16238 /* libs? */ libsFlag: 1, paniclist: newlist, list_size: newlist_size) != 0) {
16239 goto finish;
16240 }
16241
16242 if (loaded_kext_paniclist) {
16243 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16244 }
16245 loaded_kext_paniclist = newlist;
16246 newlist = NULL;
16247 loaded_kext_paniclist_size = newlist_size;
16248
16249finish:
16250 if (newlist) {
16251 kfree_data(newlist, newlist_size);
16252 }
16253 return;
16254}
16255
16256/*********************************************************************
16257* Assumes sKextLock is held.
16258*********************************************************************/
16259void
16260OSKext::savePanicString(bool isLoading)
16261{
16262 u_long len;
16263
16264 if (!kmod_info) {
16265 return; // do not goto finish here b/c of lock
16266 }
16267
16268 len = assemble_identifier_and_version( kmod_info,
16269 identPlusVers: (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16270 bufSize: (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16271 if (!len) {
16272 printf("error saving unloaded kext info\n");
16273 goto finish;
16274 }
16275
16276 if (isLoading) {
16277 last_loaded_strlen = len;
16278 last_loaded_address = (void *)kmod_info->address;
16279 last_loaded_size = kmod_info->size;
16280 clock_get_uptime(result: &last_loaded_timestamp);
16281 } else {
16282 last_unloaded_strlen = len;
16283 last_unloaded_address = (void *)kmod_info->address;
16284 last_unloaded_size = kmod_info->size;
16285 clock_get_uptime(result: &last_unloaded_timestamp);
16286 }
16287
16288finish:
16289 return;
16290}
16291
16292/*********************************************************************
16293*********************************************************************/
16294/* static */
16295void
16296OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16297{
16298 if (last_loaded_strlen) {
16299 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16300 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16301 last_loaded_strlen, last_loaded_str_buf,
16302 last_loaded_address, last_loaded_size);
16303 }
16304
16305 if (last_unloaded_strlen) {
16306 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16307 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16308 last_unloaded_strlen, last_unloaded_str_buf,
16309 last_unloaded_address, last_unloaded_size);
16310 }
16311
16312 printf_func("loaded kexts:\n");
16313 if (loaded_kext_paniclist &&
16314 pmap_find_phys(pmap: kernel_pmap, va: (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16315 loaded_kext_paniclist[0]) {
16316 printf_func("%.*s",
16317 strnlen(s: loaded_kext_paniclist, n: loaded_kext_paniclist_size),
16318 loaded_kext_paniclist);
16319 } else {
16320 printf_func("(none)\n");
16321 }
16322 return;
16323}
16324
16325/*********************************************************************
16326* Assumes sKextLock is held.
16327*********************************************************************/
16328/* static */
16329void
16330OSKext::updateLoadedKextSummaries(void)
16331{
16332 kern_return_t result = KERN_FAILURE;
16333 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16334 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16335 OSKext *aKext;
16336 vm_map_offset_t start, end;
16337 size_t summarySize = 0;
16338 size_t size;
16339 u_int count;
16340 u_int maxKexts;
16341 u_int i, j;
16342 OSKextActiveAccount * accountingList;
16343 OSKextActiveAccount * prevAccountingList;
16344 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16345
16346 prevAccountingList = NULL;
16347 prevAccountingListCount = 0;
16348
16349#if DEVELOPMENT || DEBUG
16350 if (IORecursiveLockHaveLock(sKextLock) == false) {
16351 panic("sKextLock must be held");
16352 }
16353#endif
16354
16355 IOLockLock(sKextSummariesLock);
16356
16357 count = sLoadedKexts->getCount();
16358 for (i = 0, maxKexts = 0; i < count; ++i) {
16359 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16360 maxKexts += (aKext && (aKext->isExecutable() || aKext->isSpecialKernelBinary()));
16361 }
16362
16363 if (!maxKexts) {
16364 goto finish;
16365 }
16366 if (maxKexts < kOSKextTypicalLoadCount) {
16367 maxKexts = kOSKextTypicalLoadCount;
16368 }
16369
16370 /* Calculate the size needed for the new summary headers.
16371 */
16372
16373 size = sizeof(*gLoadedKextSummaries);
16374 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16375 size = round_page(x: size);
16376
16377 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16378 if (gLoadedKextSummaries) {
16379 kmem_free(map: kernel_map, addr: (vm_offset_t)gLoadedKextSummaries, size: sLoadedKextSummariesAllocSize);
16380 gLoadedKextSummaries = NULL;
16381 gLoadedKextSummariesTimestamp = mach_absolute_time();
16382 sLoadedKextSummariesAllocSize = 0;
16383 }
16384 result = kmem_alloc(map: kernel_map, addrp: (vm_offset_t *)&summaryHeaderAlloc, size,
16385 flags: KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16386 if (result != KERN_SUCCESS) {
16387 goto finish;
16388 }
16389 summaryHeader = summaryHeaderAlloc;
16390 summarySize = size;
16391 } else {
16392 summaryHeader = gLoadedKextSummaries;
16393 summarySize = sLoadedKextSummariesAllocSize;
16394
16395 start = (vm_map_offset_t) summaryHeader;
16396 end = start + summarySize;
16397 result = vm_map_protect(map: kernel_map,
16398 start,
16399 end,
16400 VM_PROT_DEFAULT,
16401 FALSE);
16402 if (result != KERN_SUCCESS) {
16403 goto finish;
16404 }
16405 }
16406
16407 /* Populate the summary header.
16408 */
16409
16410 bzero(s: summaryHeader, n: summarySize);
16411 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16412 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16413
16414 /* Populate each kext summary.
16415 */
16416
16417 count = sLoadedKexts->getCount();
16418 accountingListAlloc = 0;
16419 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16420 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16421 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16422 continue;
16423 }
16424
16425 aKext->updateLoadedKextSummary(summary: &summaryHeader->summaries[j++]);
16426 summaryHeader->numSummaries++;
16427 accountingListAlloc++;
16428 }
16429
16430 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16431 accountingListCount = 0;
16432 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16433 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16434 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16435 continue;
16436 }
16437
16438 OSKextActiveAccount activeAccount;
16439 aKext->updateActiveAccount(accountp: &activeAccount);
16440 // order by address
16441 for (idx = 0; idx < accountingListCount; idx++) {
16442 if (activeAccount.address < accountingList[idx].address) {
16443 break;
16444 }
16445 }
16446 bcopy(src: &accountingList[idx], dst: &accountingList[idx + 1], n: (accountingListCount - idx) * sizeof(accountingList[0]));
16447 accountingList[idx] = activeAccount;
16448 accountingListCount++;
16449 }
16450 assert(accountingListCount == accountingListAlloc);
16451 /* Write protect the buffer and move it into place.
16452 */
16453
16454 start = (vm_map_offset_t) summaryHeader;
16455 end = start + summarySize;
16456
16457 result = vm_map_protect(map: kernel_map, start, end, VM_PROT_READ, FALSE);
16458 if (result != KERN_SUCCESS) {
16459 goto finish;
16460 }
16461
16462 gLoadedKextSummaries = summaryHeader;
16463 gLoadedKextSummariesTimestamp = mach_absolute_time();
16464 sLoadedKextSummariesAllocSize = summarySize;
16465 summaryHeaderAlloc = NULL;
16466
16467 /* Call the magic breakpoint function through a static function pointer so
16468 * the compiler can't optimize the function away.
16469 */
16470 if (sLoadedKextSummariesUpdated) {
16471 (*sLoadedKextSummariesUpdated)();
16472 }
16473
16474 lck_ticket_lock(tlock: sKextAccountsLock, grp: sKextAccountsLockGrp);
16475 prevAccountingList = sKextAccounts;
16476 prevAccountingListCount = sKextAccountsCount;
16477 sKextAccounts = accountingList;
16478 sKextAccountsCount = accountingListCount;
16479 lck_ticket_unlock(tlock: sKextAccountsLock);
16480
16481finish:
16482 IOLockUnlock(sKextSummariesLock);
16483
16484 /* If we had to allocate a new buffer but failed to generate the summaries,
16485 * free that now.
16486 */
16487 if (summaryHeaderAlloc) {
16488 kmem_free(map: kernel_map, addr: (vm_offset_t)summaryHeaderAlloc, size: summarySize);
16489 }
16490 if (prevAccountingList) {
16491 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16492 }
16493
16494 return;
16495}
16496
16497/*********************************************************************
16498*********************************************************************/
16499void
16500OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16501{
16502 OSSharedPtr<OSData> uuid;
16503
16504 strlcpy(dst: summary->name, src: getIdentifierCString(),
16505 n: sizeof(summary->name));
16506
16507 uuid = copyUUID();
16508 if (uuid) {
16509 memcpy(dst: summary->uuid, src: uuid->getBytesNoCopy(), n: sizeof(summary->uuid));
16510 }
16511
16512 if (flags.builtin) {
16513// this value will stop lldb from parsing the mach-o header
16514// summary->address = UINT64_MAX;
16515// summary->size = 0;
16516 summary->address = kmod_info->address;
16517 summary->size = kmod_info->size;
16518 } else {
16519 summary->address = kmod_info->address;
16520 summary->size = kmod_info->size;
16521 }
16522 summary->version = getVersion();
16523 summary->loadTag = kmod_info->id;
16524 summary->flags = 0;
16525 summary->reference_list = (uint64_t) kmod_info->reference_list;
16526
16527 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16528 if (summary->text_exec_address == 0) {
16529 // Fallback to __TEXT
16530 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16531 }
16532
16533 /**
16534 * If the addresses within the Mach-O are unslid, then manually slide any
16535 * addresses coming from the Mach-O as higher layer software using these
16536 * summaries expects a slid address here.
16537 */
16538 if (flags.unslidMachO) {
16539 summary->text_exec_address = (uint64_t) ml_static_slide(vaddr: (vm_offset_t) summary->text_exec_address);
16540 }
16541
16542 return;
16543}
16544
16545/*********************************************************************
16546*********************************************************************/
16547
16548void
16549OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16550{
16551 kernel_mach_header_t *hdr = NULL;
16552 kernel_segment_command_t *seg = NULL;
16553
16554 bzero(s: accountp, n: sizeof(*accountp));
16555
16556 hdr = (kernel_mach_header_t *)kmod_info->address;
16557 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16558 /*
16559 * If this kext supports split segments (or is in a new
16560 * MH_FILESET kext collection), use the first
16561 * executable segment as the range for instructions
16562 * (and thus for backtracing.
16563 */
16564 for (seg = firstsegfromheader(header: hdr); seg != NULL; seg = nextsegfromheader(header: hdr, seg)) {
16565 if (seg->initprot & VM_PROT_EXECUTE) {
16566 break;
16567 }
16568 }
16569 }
16570 if (seg) {
16571 accountp->address = seg->vmaddr;
16572 if (accountp->address) {
16573 accountp->address_end = seg->vmaddr + seg->vmsize;
16574 }
16575 } else {
16576 /* For non-split kexts and for kexts without executable
16577 * segments, just use the kmod_info range (as the kext
16578 * is either all in one range or should not show up in
16579 * instruction backtraces).
16580 */
16581 accountp->address = kmod_info->address;
16582 if (accountp->address) {
16583 accountp->address_end = kmod_info->address + kmod_info->size;
16584 }
16585 }
16586
16587 accountp->account = this->account;
16588}
16589
16590bool
16591OSKext::isDriverKit(void)
16592{
16593 OSString *bundleType;
16594
16595 if (infoDict) {
16596 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16597 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16598 return TRUE;
16599 }
16600 }
16601 return FALSE;
16602}
16603
16604bool
16605OSKext::isInFileset(void)
16606{
16607 if (!kmod_info) {
16608 goto check_prelinked;
16609 }
16610
16611 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16612 return true;
16613 }
16614
16615check_prelinked:
16616 if (isPrelinked()) {
16617 /*
16618 * If we haven't setup kmod_info yet, but we know
16619 * we're loading a prelinked kext in an MH_FILESET KC,
16620 * then return true
16621 */
16622 kc_format_t kc_format;
16623 if (PE_get_primary_kc_format(type: &kc_format) && kc_format == KCFormatFileset) {
16624 return true;
16625 }
16626 }
16627 return false;
16628}
16629
16630OSSharedPtr<OSDextStatistics>
16631OSKext::copyDextStatistics(void)
16632{
16633 return dextStatistics;
16634}
16635
16636bool
16637OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16638{
16639 kern_return_t result;
16640 if (!super::init()) {
16641 return false;
16642 }
16643 if (seg == nullptr) {
16644 return false;
16645 }
16646 result = kmem_alloc(map: kernel_map, addrp: (vm_offset_t *)&data, size: seg->vmsize,
16647 flags: KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16648 if (result != KERN_SUCCESS) {
16649 return false;
16650 }
16651 memcpy(dst: (void *)data, src: (const void *)seg->vmaddr, n: seg->vmsize);
16652 savedSegment = seg;
16653 vmsize = seg->vmsize;
16654 vmaddr = seg->vmaddr;
16655 return true;
16656}
16657
16658OSSharedPtr<OSKextSavedMutableSegment>
16659OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16660{
16661 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16662 if (me && !me->initWithSegment(seg)) {
16663 return nullptr;
16664 }
16665 return me;
16666}
16667
16668void
16669OSKextSavedMutableSegment::free(void)
16670{
16671 if (data) {
16672 kmem_free(map: kernel_map, addr: (vm_offset_t)data, size: vmsize);
16673 }
16674}
16675
16676vm_offset_t
16677OSKextSavedMutableSegment::getVMAddr() const
16678{
16679 return vmaddr;
16680}
16681
16682vm_offset_t
16683OSKextSavedMutableSegment::getVMSize() const
16684{
16685 return vmsize;
16686}
16687
16688OSReturn
16689OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16690{
16691 if (seg != savedSegment) {
16692 return kOSKextReturnInvalidArgument;
16693 }
16694 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16695 return kOSKextReturnInvalidArgument;
16696 }
16697 memcpy(dst: (void *)seg->vmaddr, src: data, n: vmsize);
16698 return kOSReturnSuccess;
16699}
16700
16701extern "C" kern_return_t
16702OSKextSetReceiptQueried(void)
16703{
16704 OSKextLog(/* kext */ NULL,
16705 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16706 format: "Setting kext receipt as queried");
16707
16708 IOService::publishResource(kOSKextReceiptQueried, value: kOSBooleanTrue);
16709 return KERN_SUCCESS;
16710}
16711
16712extern "C" const vm_allocation_site_t *
16713OSKextGetAllocationSiteForCaller(uintptr_t address)
16714{
16715 OSKextActiveAccount * active;
16716 vm_allocation_site_t * site;
16717 vm_allocation_site_t * releasesite;
16718
16719 uint32_t baseIdx;
16720 uint32_t lim;
16721#if __has_feature(ptrauth_calls)
16722 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16723#endif /* __has_feature(ptrauth_calls) */
16724
16725 lck_ticket_lock(tlock: sKextAccountsLock, grp: sKextAccountsLockGrp);
16726 site = releasesite = NULL;
16727
16728 // bsearch sKextAccounts list
16729 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16730 active = &sKextAccounts[baseIdx + (lim >> 1)];
16731 if ((address >= active->address) && (address < active->address_end)) {
16732 site = &active->account->site;
16733 if (!site->tag) {
16734 vm_tag_alloc_locked(site, releasesiteP: &releasesite);
16735 }
16736 break;
16737 } else if (address > active->address) {
16738 // move right
16739 baseIdx += (lim >> 1) + 1;
16740 lim--;
16741 }
16742 // else move left
16743 }
16744 lck_ticket_unlock(tlock: sKextAccountsLock);
16745 if (releasesite) {
16746 kern_allocation_name_release(allocation: releasesite);
16747 }
16748
16749 return site;
16750}
16751
16752#if DEVELOPMENT || DEBUG
16753extern "C" void
16754OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16755{
16756 OSKextActiveAccount * active;
16757
16758 uint32_t baseIdx;
16759 uint32_t lim;
16760#if __has_feature(ptrauth_calls)
16761 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16762#endif /* __has_feature(ptrauth_calls) */
16763
16764 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16765
16766 // bsearch sKextAccounts list
16767 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16768 active = &sKextAccounts[baseIdx + (lim >> 1)];
16769 if ((address >= active->address) && (address < active->address_end)) {
16770 cb(&active->account->task_refgrp);
16771 break;
16772 } else if (address > active->address) {
16773 // move right
16774 baseIdx += (lim >> 1) + 1;
16775 lim--;
16776 }
16777 // else move left
16778 }
16779 lck_ticket_unlock(sKextAccountsLock);
16780}
16781#endif /* DEVELOPMENT || DEBUG */
16782
16783extern "C" uint32_t
16784OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16785{
16786 OSKextAccount * account = (typeof(account))site;
16787 const char * kname;
16788
16789 if (name) {
16790 if (account->kext) {
16791 kname = account->kext->getIdentifierCString();
16792 } else {
16793 kname = "<>";
16794 }
16795 strlcpy(dst: name, src: kname, n: namelen);
16796 }
16797
16798 return account->loadTag;
16799}
16800
16801extern "C" void
16802OSKextFreeSite(vm_allocation_site_t * site)
16803{
16804 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16805 IOFreeType(freeAccount, OSKextAccount);
16806}
16807
16808/*********************************************************************
16809*********************************************************************/
16810
16811#if CONFIG_IMAGEBOOT
16812int
16813OSKextGetUUIDForName(const char *name, uuid_t uuid)
16814{
16815 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(kextIdentifier: name);
16816 if (!kext) {
16817 return 1;
16818 }
16819
16820 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16821 if (uuid_data) {
16822 memcpy(dst: uuid, src: uuid_data->getBytesNoCopy(), n: sizeof(uuid_t));
16823 return 0;
16824 }
16825
16826 return 1;
16827}
16828#endif
16829
16830
16831
16832class OSDextCrash : public OSObject {
16833 OSDeclareDefaultStructors(OSDextCrash);
16834public:
16835 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16836 uint64_t getTimestamp();
16837
16838private:
16839 virtual bool initWithTimestamp(uint64_t timestamp);
16840 uint64_t fTimestamp;
16841};
16842
16843OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16844
16845OSSharedPtr<OSDextCrash>
16846OSDextCrash::withTimestamp(uint64_t timestamp)
16847{
16848 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16849 if (!result->initWithTimestamp(timestamp)) {
16850 return NULL;
16851 }
16852 return result;
16853}
16854
16855bool
16856OSDextCrash::initWithTimestamp(uint64_t timestamp)
16857{
16858 if (!OSObject::init()) {
16859 return false;
16860 }
16861 fTimestamp = timestamp;
16862 return true;
16863}
16864
16865uint64_t
16866OSDextCrash::getTimestamp()
16867{
16868 return fTimestamp;
16869}
16870
16871OSSharedPtr<OSDextStatistics>
16872OSDextStatistics::create()
16873{
16874 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16875 if (!result->init()) {
16876 return NULL;
16877 }
16878 return result;
16879}
16880
16881bool
16882OSDextStatistics::init()
16883{
16884 if (!OSObject::init()) {
16885 return false;
16886 }
16887
16888 lock = IOLockAlloc();
16889 crashes = OSArray::withCapacity(capacity: kMaxDextCrashesInOneDay);
16890 return true;
16891}
16892
16893void
16894OSDextStatistics::free()
16895{
16896 if (lock) {
16897 IOLockFree(lock);
16898 }
16899 crashes.reset();
16900 OSObject::free();
16901}
16902
16903OSDextCrashPolicy
16904OSDextStatistics::recordCrash()
16905{
16906 size_t i = 0;
16907 uint64_t timestamp = mach_continuous_time();
16908 uint64_t interval;
16909 nanoseconds_to_absolutetime(nanoseconds: 86400 * NSEC_PER_SEC /* 1 day */, result: &interval);
16910 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16911 OSDextCrashPolicy policy;
16912
16913 IOLockLock(lock);
16914 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16915 for (i = 0; i < crashes->getCount();) {
16916 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16917 assert(current != NULL);
16918 if (current->getTimestamp() < lastTimestamp) {
16919 crashes->removeObject(index: i);
16920 } else {
16921 i++;
16922 }
16923 }
16924
16925 crashes->setObject(crash);
16926
16927 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16928 policy = kOSDextCrashPolicyReboot;
16929 } else {
16930 policy = kOSDextCrashPolicyNone;
16931 }
16932
16933 IOLockUnlock(lock);
16934
16935 return policy;
16936}
16937
16938size_t
16939OSDextStatistics::getCrashCount()
16940{
16941 size_t result = 0;
16942 IOLockLock(lock);
16943 result = crashes->getCount();
16944 IOLockUnlock(lock);
16945 return result;
16946}
16947
16948static int
16949sysctl_willuserspacereboot
16950(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16951{
16952 int new_value = 0, old_value = 0, changed = 0;
16953 int error = sysctl_io_number(req, bigValue: old_value, valueSize: sizeof(int), pValue: &new_value, changed: &changed);
16954 if (error) {
16955 return error;
16956 }
16957 if (changed) {
16958 OSKext::willUserspaceReboot();
16959 }
16960 return 0;
16961}
16962
16963static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16964 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16965 NULL, 0, sysctl_willuserspacereboot, "I", "");
16966