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
31 extern "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 PRAGMA_MARK
91 #pragma mark External & Internal Function Protos
92 #endif
93 /*********************************************************************
94 *********************************************************************/
95 extern "C" {
96 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
97 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
98
99 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
100 extern int dtrace_keep_kernel_symbols(void);
101
102 #if defined(__x86_64__) || defined(__i386__)
103 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
104 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
105 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
106 static void *allocate_kcfileset_map_entry_list(void);
107 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
108 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
109 int vnode_put(struct vnode *vp);
110 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
111 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
112 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
113 void * ubc_getobject(struct vnode *vp, __unused int flags);
114 #endif //(__x86_64__) || defined(__i386__)
115 }
116
117 extern unsigned long gVirtBase;
118 extern unsigned long gPhysBase;
119 extern vm_map_t g_kext_map;
120
121 bool pageableKCloaded = false;
122 bool auxKCloaded = false;
123 bool resetAuxKCSegmentOnUnload = false;
124
125 extern boolean_t pageablekc_uuid_valid;
126 extern uuid_t pageablekc_uuid;
127 extern uuid_string_t pageablekc_uuid_string;
128
129 extern boolean_t auxkc_uuid_valid;
130 extern uuid_t auxkc_uuid;
131 extern uuid_string_t auxkc_uuid_string;
132
133 static OSReturn _OSKextCreateRequest(
134 const char * predicate,
135 OSSharedPtr<OSDictionary> & requestP);
136 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
137 static OSObject * _OSKextGetRequestArgument(
138 OSDictionary * requestDict,
139 const char * argName);
140 static bool _OSKextSetRequestArgument(
141 OSDictionary * requestDict,
142 const char * argName,
143 OSMetaClassBase * value);
144 template <typename T>
145 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
146 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
147 static OSReturn _OSDictionarySetCStringValue(
148 OSDictionary * dict,
149 const char * key,
150 const char * value);
151 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
152 #if CONFIG_KXLD
153 static bool _OSKextInPrelinkRebuildWindow(void);
154 #endif
155
156 // We really should add containsObject() & containsCString to OSCollection & subclasses.
157 // So few pad slots, though....
158 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
159 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
160
161 static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
162
163 /* Prelinked arm kexts do not have VM entries because the method we use to
164 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
165 * not work on ARM. To get around that, we must free prelinked kext
166 * executables with ml_static_mfree() instead of kext_free().
167 */
168 #if __i386__ || __x86_64__
169 #define VM_MAPPED_KEXTS 1
170 #define KASLR_KEXT_DEBUG 0
171 #define KASLR_IOREG_DEBUG 0
172 #elif __arm__ || __arm64__
173 #define VM_MAPPED_KEXTS 0
174 #define KASLR_KEXT_DEBUG 0
175 #else
176 #error Unsupported architecture
177 #endif
178
179 #if PRAGMA_MARK
180 #pragma mark Constants & Macros
181 #endif
182 /*********************************************************************
183 * Constants & Macros
184 *********************************************************************/
185
186 /* Use this number to create containers.
187 */
188 #define kOSKextTypicalLoadCount (150)
189 #define kOSKextTypicalUpgradeCount (5)
190
191 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
192 * A loaded kext will no dependents or external retains will have 2 retains.
193 */
194 #define kOSKextMinRetainCount (1)
195 #define kOSKextMinLoadedRetainCount (2)
196
197 #define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
198 #define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
199
200 /**********
201 * Strings and substrings used in dependency resolution.
202 */
203 #define APPLE_KEXT_PREFIX "com.apple."
204 #define KERNEL_LIB "com.apple.kernel"
205
206 #define PRIVATE_KPI "com.apple.kpi.private"
207
208 /* Version for compatbility pseudokexts (com.apple.kernel.*),
209 * compatible back to v6.0.
210 */
211 #define KERNEL6_LIB "com.apple.kernel.6.0"
212 #define KERNEL6_VERSION "7.9.9"
213
214 #define KERNEL_LIB_PREFIX "com.apple.kernel."
215 #define KPI_LIB_PREFIX "com.apple.kpi."
216
217 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
218
219 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
220 #define MINIMUM_WAKEUP_SECONDS (30)
221
222 /*********************************************************************
223 * infoDict keys for internally-stored data. Saves on ivar slots for
224 * objects we don't keep around past boot time or during active load.
225 *********************************************************************/
226
227 /* A usable, uncompressed file is stored under this key.
228 */
229 #define _kOSKextExecutableKey "_OSKextExecutable"
230
231 /* An indirect reference to the executable file from an mkext
232 * is stored under this key.
233 */
234 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
235
236 /* If the file is contained in a larger buffer laid down by the booter or
237 * sent from user space, the OSKext stores that OSData under this key so that
238 * references are properly tracked. This is always an mkext, right now.
239 */
240 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
241
242 #define OS_LOG_HDR_VERSION 1
243 #define NUM_OS_LOG_SECTIONS 3
244
245 #define OS_LOG_SECT_IDX 0
246 #define CSTRING_SECT_IDX 1
247 #define ASAN_CSTRING_SECT_IDX 2
248
249 #if PRAGMA_MARK
250 #pragma mark Typedefs
251 #endif
252 /*********************************************************************
253 * Typedefs
254 *********************************************************************/
255
256 /*********************************************************************
257 * osLogDataHeaderRef describes the header information of an OSData
258 * object that is returned when querying for kOSBundleLogStringsKey.
259 * We currently return information regarding 2 sections - os_log and
260 * cstring. In the case that the os_log section doesn't exist, we just
261 * return an offset and length of 0 for that section.
262 *********************************************************************/
263 typedef struct osLogDataHeader {
264 uint32_t version;
265 uint32_t sect_count;
266 struct {
267 uint32_t sect_offset;
268 uint32_t sect_size;
269 } sections[0];
270 } osLogDataHeaderRef;
271
272 /*********************************************************************
273 * MkextEntryRef describes the contents of an OSData object
274 * referencing a file entry from an mkext so that we can uncompress
275 * (if necessary) and extract it on demand.
276 *
277 * It contains the mkextVersion in case we ever wind up supporting
278 * multiple mkext formats. Mkext format 1 is officially retired as of
279 * Snow Leopard.
280 *********************************************************************/
281 typedef struct MkextEntryRef {
282 mkext_basic_header * mkext; // beginning of whole mkext file
283 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
284 } MkextEntryRef;
285
286 #if PRAGMA_MARK
287 #pragma mark Global and static Module Variables
288 #endif
289 /*********************************************************************
290 * Global & static variables, used to keep track of kexts.
291 *********************************************************************/
292
293 static bool sPrelinkBoot = false;
294 static bool sSafeBoot = false;
295 static bool sKeepSymbols = false;
296 static bool sPanicOnKCMismatch = false;
297 static bool sOSKextWasResetAfterUserspaceReboot = false;
298
299 /*********************************************************************
300 * sKextLock is the principal lock for OSKext, and guards all static
301 * and global variables not owned by other locks (declared further
302 * below). It must be taken by any entry-point method or function,
303 * including internal functions called on scheduled threads.
304 *
305 * sKextLock and sKextInnerLock are recursive due to multiple functions
306 * that are called both externally and internally. The other locks are
307 * nonrecursive.
308 *
309 * Which locks are taken depends on what they protect, but if more than
310 * one must be taken, they must always be locked in this order
311 * (and unlocked in reverse order) to prevent deadlocks:
312 *
313 * 1. sKextLock
314 * 2. sKextInnerLock
315 * 3. sKextSummariesLock
316 * 4. sKextLoggingLock
317 */
318 static IORecursiveLock * sKextLock = NULL;
319
320 static OSSharedPtr<OSDictionary> sKextsByID;
321 static OSSharedPtr<OSDictionary> sExcludeListByID;
322 static OSKextVersion sExcludeListVersion = 0;
323 static OSSharedPtr<OSArray> sLoadedKexts;
324 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
325 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
326 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
327 static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
328
329 // Requests to the IOKit daemon waiting to be picked up.
330 static OSSharedPtr<OSArray> sKernelRequests;
331 // Identifier of kext load requests in sKernelRequests
332 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
333 static OSSharedPtr<OSArray> sRequestCallbackRecords;
334
335 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
336 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
337 #if CONFIG_KXLD
338 static KXLDContext * sKxldContext = NULL;
339 #endif
340 static uint32_t sNextLoadTag = 0;
341 static uint32_t sNextRequestTag = 0;
342
343 static bool sUserLoadsActive = false;
344 static bool sIOKitDaemonActive = false;
345 static bool sDeferredLoadSucceeded = false;
346 static bool sConsiderUnloadsExecuted = false;
347
348 #if NO_KEXTD
349 static bool sKernelRequestsEnabled = false;
350 #else
351 static bool sKernelRequestsEnabled = true;
352 #endif
353 static bool sLoadEnabled = true;
354 static bool sUnloadEnabled = true;
355
356 /*********************************************************************
357 * Stuff for the OSKext representing the kernel itself.
358 **********/
359 static OSKext * sKernelKext = NULL;
360
361 /* Set up a fake kmod_info struct for the kernel.
362 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
363 * before OSKext is initialized; that call only needs the name
364 * and address to be set correctly.
365 *
366 * We don't do much else with the kerne's kmod_info; we never
367 * put it into the kmod list, never adjust the reference count,
368 * and never have kernel components reference it.
369 * For that matter, we don't do much with kmod_info structs
370 * at all anymore! We just keep them filled in for gdb and
371 * binary compability.
372 */
373 kmod_info_t g_kernel_kmod_info = {
374 .next = NULL,
375 .info_version = KMOD_INFO_VERSION,
376 .id = 0, // loadTag: kernel is always 0
377 .name = kOSKextKernelIdentifier,// bundle identifier
378 .version = "0", // filled in in OSKext::initialize()
379 .reference_count = -1, // never adjusted; kernel never unloads
380 .reference_list = NULL,
381 .address = 0,
382 .size = 0, // filled in in OSKext::initialize()
383 .hdr_size = 0,
384 .start = NULL,
385 .stop = NULL
386 };
387
388 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
389
390 kmod_info_t invalid_kmod_info = {
391 .next = NULL,
392 .info_version = KMOD_INFO_VERSION,
393 .id = UINT32_MAX,
394 .name = "invalid",
395 .version = "0",
396 .reference_count = -1,
397 .reference_list = NULL,
398 .address = 0,
399 .size = 0,
400 .hdr_size = 0,
401 .start = NULL,
402 .stop = NULL
403 };
404
405 extern "C" {
406 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
407 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
408 // misc_protos.h, db_low_trace.c, kgmacros
409 // 'kmod' is a holdover from the old kmod system, we can't rename it.
410 kmod_info_t * kmod = NULL;
411
412 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
413
414
415 static char * loaded_kext_paniclist = NULL;
416 static uint32_t loaded_kext_paniclist_size = 0;
417
418 AbsoluteTime last_loaded_timestamp;
419 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
420 static u_long last_loaded_strlen = 0;
421 static void * last_loaded_address = NULL;
422 static u_long last_loaded_size = 0;
423
424 AbsoluteTime last_unloaded_timestamp;
425 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
426 static u_long last_unloaded_strlen = 0;
427 static void * last_unloaded_address = NULL;
428 static u_long last_unloaded_size = 0;
429
430 // Statically linked kmods described by several mach-o sections:
431 //
432 // kPrelinkInfoSegment:kBuiltinInfoSection
433 // Array of pointers to kmod_info_t structs.
434 //
435 // kPrelinkInfoSegment:kBuiltinInfoSection
436 // Array of pointers to an embedded mach-o header.
437 //
438 // __DATA:kBuiltinInitSection, kBuiltinTermSection
439 // Structors for all kmods. Has to be filtered by proc address.
440 //
441
442 static uint32_t gBuiltinKmodsCount;
443 static kernel_section_t * gBuiltinKmodsSectionInfo;
444 static kernel_section_t * gBuiltinKmodsSectionStart;
445
446 const OSSymbol * gIOSurfaceIdentifier;
447 vm_tag_t gIOSurfaceTag;
448
449 /*********************************************************************
450 * sKextInnerLock protects against cross-calls with IOService and
451 * IOCatalogue, and owns the variables declared immediately below.
452 *
453 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
454 *
455 * When both sKextLock and sKextInnerLock need to be taken,
456 * always lock sKextLock first and unlock it second. Never take both
457 * locks in an entry point to OSKext; if you need to do so, you must
458 * spawn an independent thread to avoid potential deadlocks for threads
459 * calling into OSKext.
460 **********/
461 static IORecursiveLock * sKextInnerLock = NULL;
462
463 #if XNU_TARGET_OS_OSX
464 static bool sAutounloadEnabled = true;
465 #endif
466 static bool sConsiderUnloadsCalled = false;
467 static bool sConsiderUnloadsPending = false;
468
469 static unsigned int sConsiderUnloadDelay = 60; // seconds
470 static thread_call_t sUnloadCallout = NULL;
471 #if CONFIG_KXLD
472 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
473 #endif // CONFIG_KXLD
474 static bool sSystemSleep = false; // true when system going to sleep
475 static AbsoluteTime sLastWakeTime; // last time we woke up
476
477 /*********************************************************************
478 * Backtraces can be printed at various times so we need a tight lock
479 * on data used for that. sKextSummariesLock protects the variables
480 * declared immediately below.
481 *
482 * gLoadedKextSummaries is accessed by other modules, but only during
483 * a panic so the lock isn't needed then.
484 *
485 * gLoadedKextSummaries has the "used" attribute in order to ensure
486 * that it remains visible even when we are performing extremely
487 * aggressive optimizations, as it is needed to allow the debugger
488 * to automatically parse the list of loaded kexts.
489 **********/
490 static IOLock * sKextSummariesLock = NULL;
491 extern "C" lck_ticket_t vm_allocation_sites_lock;
492 static lck_ticket_t * sKextAccountsLock = &vm_allocation_sites_lock;
493
494 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
495 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
496 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
497 static size_t sLoadedKextSummariesAllocSize = 0;
498
499 static OSKextActiveAccount * sKextAccounts;
500 static uint32_t sKextAccountsCount;
501 };
502
503 /*********************************************************************
504 * sKextLoggingLock protects the logging variables declared immediately below.
505 **********/
506 static IOLock * sKextLoggingLock = NULL;
507
508 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
509 kOSKextLogVerboseFlagsMask;
510 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
511 static bool sBootArgLogFilterFound = false;
512 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
513 0, "kernel kext logging");
514
515 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
516 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
517 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
518
519 /*********
520 * End scope for sKextInnerLock-protected variables.
521 *********************************************************************/
522
523 /*********************************************************************
524 * OSValueObject concrete type instantiations
525 **********/
526 OSDefineValueObjectForDependentType(void*)
527 OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
528
529
530 /**********************************************************************/
531
532 TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
533
534 /*********************************************************************
535 * helper function used for collecting PGO data upon unload of a kext
536 */
537
538 static int OSKextGrabPgoDataLocked(OSKext *kext,
539 bool metadata,
540 uuid_t instance_uuid,
541 uint64_t *pSize,
542 char *pBuffer,
543 uint64_t bufferSize);
544
545 /**********************************************************************/
546
547
548
549 #if PRAGMA_MARK
550 #pragma mark OSData callbacks (need to move to OSData)
551 #endif
552 /*********************************************************************
553 * C functions used for callbacks.
554 *********************************************************************/
555 extern "C" {
556 void
osdata_kmem_free(void * ptr,unsigned int length)557 osdata_kmem_free(void * ptr, unsigned int length)
558 {
559 kmem_free(kernel_map, (vm_address_t)ptr, length);
560 return;
561 }
562
563 void
osdata_phys_free(void * ptr,unsigned int length)564 osdata_phys_free(void * ptr, unsigned int length)
565 {
566 ml_static_mfree((vm_offset_t)ptr, length);
567 return;
568 }
569
570 void
osdata_vm_deallocate(void * ptr,unsigned int length)571 osdata_vm_deallocate(void * ptr, unsigned int length)
572 {
573 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
574 return;
575 }
576
577 void
osdata_kext_free(void * ptr,unsigned int length)578 osdata_kext_free(void * ptr, unsigned int length)
579 {
580 (void)kext_free((vm_offset_t)ptr, length);
581 }
582 };
583
584 #if PRAGMA_MARK
585 #pragma mark KXLD Allocation Callback
586 #endif
587 #if CONFIG_KXLD
588 /*********************************************************************
589 * KXLD Allocation Callback
590 *********************************************************************/
591 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)592 kern_allocate(
593 u_long size,
594 KXLDAllocateFlags * flags,
595 void * user_data)
596 {
597 vm_address_t result = 0; // returned
598 kern_return_t mach_result = KERN_FAILURE;
599 bool success = false;
600 OSKext * theKext = (OSKext *)user_data;
601 unsigned int roundSize = 0;
602 OSSharedPtr<OSData> linkBuffer;
603
604 if (round_page(size) > UINT_MAX) {
605 OSKextLog(theKext,
606 kOSKextLogErrorLevel |
607 kOSKextLogGeneralFlag,
608 "%s: Requested memory size is greater than UINT_MAX.",
609 theKext->getIdentifierCString());
610 goto finish;
611 }
612
613 roundSize = (unsigned int)round_page(size);
614
615 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
616 if (mach_result != KERN_SUCCESS) {
617 OSKextLog(theKext,
618 kOSKextLogErrorLevel |
619 kOSKextLogGeneralFlag,
620 "Can't allocate kernel memory to link %s.",
621 theKext->getIdentifierCString());
622 goto finish;
623 }
624
625 /* Create an OSData wrapper for the allocated buffer.
626 */
627 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
628 if (!linkBuffer) {
629 OSKextLog(theKext,
630 kOSKextLogErrorLevel |
631 kOSKextLogGeneralFlag,
632 "Can't allocate linked executable wrapper for %s.",
633 theKext->getIdentifierCString());
634 goto finish;
635 }
636 linkBuffer->setDeallocFunction(osdata_kext_free);
637 OSKextLog(theKext,
638 kOSKextLogProgressLevel |
639 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
640 "Allocated link buffer for kext %s at %p (%lu bytes).",
641 theKext->getIdentifierCString(),
642 (void *)result, (unsigned long)roundSize);
643
644 theKext->setLinkedExecutable(linkBuffer.get());
645
646 *flags = kKxldAllocateWritable;
647 success = true;
648
649 finish:
650 if (!success && result) {
651 kext_free(result, roundSize);
652 result = 0;
653 }
654
655 return (kxld_addr_t)result;
656 }
657
658 /*********************************************************************
659 *********************************************************************/
660 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)661 kxld_log_callback(
662 KXLDLogSubsystem subsystem,
663 KXLDLogLevel level,
664 const char * format,
665 va_list argList,
666 void * user_data)
667 {
668 OSKext *theKext = (OSKext *) user_data;
669 OSKextLogSpec logSpec = 0;
670
671 switch (subsystem) {
672 case kKxldLogLinking:
673 logSpec |= kOSKextLogLinkFlag;
674 break;
675 case kKxldLogPatching:
676 logSpec |= kOSKextLogPatchFlag;
677 break;
678 }
679
680 switch (level) {
681 case kKxldLogExplicit:
682 logSpec |= kOSKextLogExplicitLevel;
683 break;
684 case kKxldLogErr:
685 logSpec |= kOSKextLogErrorLevel;
686 break;
687 case kKxldLogWarn:
688 logSpec |= kOSKextLogWarningLevel;
689 break;
690 case kKxldLogBasic:
691 logSpec |= kOSKextLogProgressLevel;
692 break;
693 case kKxldLogDetail:
694 logSpec |= kOSKextLogDetailLevel;
695 break;
696 case kKxldLogDebug:
697 logSpec |= kOSKextLogDebugLevel;
698 break;
699 }
700
701 OSKextVLog(theKext, logSpec, format, argList);
702 }
703 #endif // CONFIG_KXLD
704
705 #if PRAGMA_MARK
706 #pragma mark IOStatistics defines
707 #endif
708
709 #if IOKITSTATS
710
711 #define notifyKextLoadObservers(kext, kmod_info) \
712 do { \
713 IOStatistics::onKextLoad(kext, kmod_info); \
714 } while (0)
715
716 #define notifyKextUnloadObservers(kext) \
717 do { \
718 IOStatistics::onKextUnload(kext); \
719 } while (0)
720
721 #define notifyAddClassObservers(kext, addedClass, flags) \
722 do { \
723 IOStatistics::onClassAdded(kext, addedClass); \
724 } while (0)
725
726 #define notifyRemoveClassObservers(kext, removedClass, flags) \
727 do { \
728 IOStatistics::onClassRemoved(kext, removedClass); \
729 } while (0)
730
731 #else
732
733 #define notifyKextLoadObservers(kext, kmod_info)
734 #define notifyKextUnloadObservers(kext)
735 #define notifyAddClassObservers(kext, addedClass, flags)
736 #define notifyRemoveClassObservers(kext, removedClass, flags)
737
738 #endif /* IOKITSTATS */
739
740 #if PRAGMA_MARK
741 #pragma mark Module Config (Startup & Shutdown)
742 #endif
743 /*********************************************************************
744 * Module Config (Class Definition & Class Methods)
745 *********************************************************************/
746 #define super OSObject
747 OSDefineMetaClassAndStructors(OSKext, OSObject)
748
749 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
750
751 OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
752
753 /*********************************************************************
754 *********************************************************************/
755 /* static */
756 void
initialize(void)757 OSKext::initialize(void)
758 {
759 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
760 u_char * kernelStart = NULL;// do not free
761 size_t kernelLength = 0;
762 IORegistryEntry * registryRoot = NULL;// do not release
763 OSSharedPtr<OSNumber> kernelCPUType;
764 OSSharedPtr<OSNumber> kernelCPUSubtype;
765 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
766 bool setResult = false;
767 uint64_t * timestamp = NULL;
768 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
769
770 /* This must be the first thing allocated. Everything else grabs this lock.
771 */
772 sKextLock = IORecursiveLockAlloc();
773 sKextInnerLock = IORecursiveLockAlloc();
774 sKextSummariesLock = IOLockAlloc();
775 sKextLoggingLock = IOLockAlloc();
776 assert(sKextLock);
777 assert(sKextInnerLock);
778 assert(sKextSummariesLock);
779 assert(sKextLoggingLock);
780
781 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
782 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
783 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
784 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
785 sKernelRequests = OSArray::withCapacity(0);
786 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
787 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
788 sRequestCallbackRecords = OSArray::withCapacity(0);
789 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
790
791 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
792 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
793 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
794
795 /* Read the log flag boot-args and set the log flags.
796 */
797 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
798 sBootArgLogFilterFound = true;
799 sKernelLogFilter = bootLogFilter;
800 // log this if any flags are set
801 OSKextLog(/* kext */ NULL,
802 kOSKextLogBasicLevel |
803 kOSKextLogFlagsMask,
804 "Kernel kext log filter 0x%x per kextlog boot arg.",
805 (unsigned)sKernelLogFilter);
806 }
807
808 #if !defined(__arm__) && !defined(__arm64__)
809 /*
810 * On our ARM targets, the kernelcache/boot kernel collection contains
811 * the set of kexts required to boot, as specified by KCB. Safeboot is
812 * either unsupported, or is supported by the bootloader only loading
813 * the boot kernel collection; as a result OSKext has no role to play
814 * in safeboot policy on ARM.
815 */
816 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
817 sizeof(bootArgBuffer)) ? true : false;
818 #endif /* defined(__arm__) && defined(__arm64__) */
819
820 if (sSafeBoot) {
821 OSKextLog(/* kext */ NULL,
822 kOSKextLogWarningLevel |
823 kOSKextLogGeneralFlag,
824 "SAFE BOOT DETECTED - "
825 "only valid OSBundleRequired kexts will be loaded.");
826 }
827
828 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
829 #if CONFIG_DTRACE
830 if (dtrace_keep_kernel_symbols()) {
831 sKeepSymbols = true;
832 }
833 #endif /* CONFIG_DTRACE */
834 #if KASAN_DYNAMIC_BLACKLIST
835 /* needed for function lookup */
836 sKeepSymbols = true;
837 #endif
838
839 /*
840 * Should we panic when the SystemKC is not linked against the
841 * BootKC that was loaded by the booter? By default: yes, if the
842 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
843 * on mis-match and instead just print an error and continue.
844 */
845 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
846 sizeof(bootArgBuffer)) ? false : true;
847
848 /* Set up an OSKext instance to represent the kernel itself.
849 */
850 sKernelKext = new OSKext;
851 assert(sKernelKext);
852
853 kernelStart = (u_char *)&_mh_execute_header;
854 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
855 assert(kernelLength <= UINT_MAX);
856 kernelExecutable = OSData::withBytesNoCopy(
857 kernelStart, (unsigned int)kernelLength);
858 assert(kernelExecutable);
859
860 #if KASLR_KEXT_DEBUG
861 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
862 (unsigned long)kernelStart,
863 (unsigned long)getlastaddr(),
864 kernelLength,
865 (unsigned long)vm_kernel_slide,
866 (unsigned long)vm_kernel_slide);
867 #endif
868
869 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
870 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
871
872 sKernelKext->version = OSKextParseVersionString(osrelease);
873 sKernelKext->compatibleVersion = sKernelKext->version;
874 sKernelKext->linkedExecutable = os::move(kernelExecutable);
875 sKernelKext->interfaceUUID = sKernelKext->copyUUID();
876
877 sKernelKext->flags.hasAllDependencies = 1;
878 sKernelKext->flags.kernelComponent = 1;
879 sKernelKext->flags.prelinked = 0;
880 sKernelKext->flags.loaded = 1;
881 sKernelKext->flags.started = 1;
882 sKernelKext->flags.CPPInitialized = 0;
883 sKernelKext->flags.jettisonLinkeditSeg = 0;
884
885 sKernelKext->kmod_info = &g_kernel_kmod_info;
886 strlcpy(g_kernel_kmod_info.version, osrelease,
887 sizeof(g_kernel_kmod_info.version));
888 g_kernel_kmod_info.size = kernelLength;
889 g_kernel_kmod_info.id = sKernelKext->loadTag;
890
891 /* Cons up an info dict, so we don't have to have special-case
892 * checking all over.
893 */
894 sKernelKext->infoDict = OSDictionary::withCapacity(5);
895 assert(sKernelKext->infoDict);
896 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
897 sKernelKext->bundleID.get());
898 assert(setResult);
899 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
900 kOSBooleanTrue);
901 assert(setResult);
902
903 {
904 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
905 assert(scratchString);
906 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
907 scratchString.get());
908 assert(setResult);
909 }
910
911 {
912 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy("mach_kernel"));
913 assert(scratchString);
914 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
915 scratchString.get());
916 assert(setResult);
917 }
918
919 /* Add the kernel kext to the bookkeeping dictionaries. Note that
920 * the kernel kext doesn't have a kmod_info struct. copyInfo()
921 * gathers info from other places anyhow.
922 */
923 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
924 assert(setResult);
925 setResult = sLoadedKexts->setObject(sKernelKext);
926 assert(setResult);
927
928 // XXX: better way with OSSharedPtr?
929 // sKernelKext remains a valid pointer even after the decref
930 sKernelKext->release();
931
932 registryRoot = IORegistryEntry::getRegistryRoot();
933 kernelCPUType = OSNumber::withNumber(
934 (long long unsigned int)_mh_execute_header.cputype,
935 8 * sizeof(_mh_execute_header.cputype));
936 kernelCPUSubtype = OSNumber::withNumber(
937 (long long unsigned int)_mh_execute_header.cpusubtype,
938 8 * sizeof(_mh_execute_header.cpusubtype));
939 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
940
941 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
942 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
943
944 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
945 if (gBuiltinKmodsSectionInfo) {
946 uint32_t count;
947
948 assert(gBuiltinKmodsSectionInfo->addr);
949 assert(gBuiltinKmodsSectionInfo->size);
950 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
951 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
952
953 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
954 assert(gBuiltinKmodsSectionStart);
955 assert(gBuiltinKmodsSectionStart->addr);
956 assert(gBuiltinKmodsSectionStart->size);
957 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
958 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
959 // one extra pointer for the end of last kmod
960 assert(count == (gBuiltinKmodsCount + 1));
961
962 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
963 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
964 }
965
966 // Don't track this object -- it's never released
967 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
968
969 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
970 *timestamp = 0;
971 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
972 *timestamp = 0;
973 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
974 *timestamp = 0;
975
976 OSKextLog(/* kext */ NULL,
977 kOSKextLogProgressLevel |
978 kOSKextLogGeneralFlag,
979 "Kext system initialized.");
980
981 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
982
983 return;
984 }
985
986 /*********************************************************************
987 * This is expected to be called exactly once, from exactly one thread
988 * context, during kernel bootstrap.
989 *********************************************************************/
990 /* static */
991 OSReturn
removeKextBootstrap(void)992 OSKext::removeKextBootstrap(void)
993 {
994 OSReturn result = kOSReturnError;
995
996 const char * dt_kernel_header_name = "Kernel-__HEADER";
997 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
998 kernel_mach_header_t * dt_mach_header = NULL;
999 int dt_mach_header_size = 0;
1000 struct symtab_command * dt_symtab = NULL;
1001 int dt_symtab_size = 0;
1002 int dt_result = 0;
1003
1004 kernel_segment_command_t * seg_kld = NULL;
1005 kernel_segment_command_t * seg_klddata = NULL;
1006 kernel_segment_command_t * seg_linkedit = NULL;
1007
1008 const char __unused * dt_segment_name = NULL;
1009 void __unused * segment_paddress = NULL;
1010 int __unused segment_size = 0;
1011
1012 OSKextLog(/* kext */ NULL,
1013 kOSKextLogProgressLevel |
1014 kOSKextLogGeneralFlag,
1015 "Jettisoning kext bootstrap segments.");
1016
1017 /*
1018 * keep the linkedit segment around when booted from a new MH_FILESET
1019 * KC because all the kexts shared a linkedit segment.
1020 */
1021 kc_format_t kc_format;
1022 if (!PE_get_primary_kc_format(&kc_format)) {
1023 OSKextLog(/* kext */ NULL,
1024 kOSKextLogErrorLevel |
1025 kOSKextLogGeneralFlag,
1026 "Unable to determine primary KC format");
1027 }
1028
1029 /*****
1030 * Dispose of unnecessary stuff that the booter didn't need to load.
1031 */
1032 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1033 (void **)&dt_mach_header, &dt_mach_header_size);
1034 if (dt_result == 0 && dt_mach_header) {
1035 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1036 round_page_32(dt_mach_header_size));
1037 }
1038 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1039 (void **)&dt_symtab, &dt_symtab_size);
1040 if (dt_result == 0 && dt_symtab) {
1041 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1042 round_page_32(dt_symtab_size));
1043 }
1044
1045 /*****
1046 * KLD & KLDDATA bootstrap segments.
1047 */
1048 // xxx - should rename KLD segment
1049 seg_kld = getsegbyname("__KLD");
1050 seg_klddata = getsegbyname("__KLDDATA");
1051 if (seg_klddata) {
1052 // __mod_term_func is part of __KLDDATA
1053 OSRuntimeUnloadCPPForSegment(seg_klddata);
1054 }
1055
1056 #if __arm__ || __arm64__
1057 /* Free the memory that was set up by iBoot.
1058 */
1059 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1060 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1061 * is covered by the contiguous rorgn.
1062 */
1063 dt_segment_name = "Kernel-__KLD";
1064 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1065 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1066 (int)segment_size); // calls ml_static_mfree
1067 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1068 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1069 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1070 seg_kld->vmsize);
1071 }
1072 #endif
1073 dt_segment_name = "Kernel-__KLDDATA";
1074 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1075 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1076 (int)segment_size); // calls ml_static_mfree
1077 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1078 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1079 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1080 seg_klddata->vmsize);
1081 }
1082 #elif __i386__ || __x86_64__
1083 /* On x86, use the mapping data from the segment load command to
1084 * unload KLD & KLDDATA directly.
1085 * This may invalidate any assumptions about "avail_start"
1086 * defining the lower bound for valid physical addresses.
1087 */
1088 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1089 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1090 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1091 }
1092 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1093 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1094 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1095 }
1096 #else
1097 #error arch
1098 #endif
1099
1100 /*****
1101 * Prelinked kernel's symtab (if there is one).
1102 */
1103 if (kc_format != KCFormatFileset) {
1104 kernel_section_t * sect;
1105 sect = getsectbyname("__PRELINK", "__symtab");
1106 if (sect && sect->addr && sect->size) {
1107 ml_static_mfree(sect->addr, sect->size);
1108 }
1109 }
1110
1111 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1112
1113 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1114 * pageable, unless keepsyms is set. To do that, we have to copy it from
1115 * its booter-allocated memory, free the booter memory, reallocate proper
1116 * managed memory, then copy the segment back in.
1117 *
1118 * NOTE: This optimization is not valid for fileset KCs because each
1119 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1120 * that points to one fileset-global LINKEDIT segment. This
1121 * optimization is also only valid for platforms that support vm
1122 * mapped kexts or mapped kext collections (pageable KCs)
1123 */
1124 #if VM_MAPPED_KEXTS
1125 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1126 kern_return_t mem_result;
1127 void *seg_copy = NULL;
1128 void *seg_data = NULL;
1129 vm_map_offset_t seg_offset = 0;
1130 vm_map_offset_t seg_copy_offset = 0;
1131 vm_map_size_t seg_length = 0;
1132
1133 seg_data = (void *) seg_linkedit->vmaddr;
1134 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1135 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1136
1137 /* Allocate space for the LINKEDIT copy.
1138 */
1139 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1140 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1141 if (mem_result != KERN_SUCCESS) {
1142 OSKextLog(/* kext */ NULL,
1143 kOSKextLogErrorLevel |
1144 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1145 "Can't copy __LINKEDIT segment for VM reassign.");
1146 return result;
1147 }
1148 seg_copy_offset = (vm_map_offset_t) seg_copy;
1149
1150 /* Copy it out.
1151 */
1152 memcpy(seg_copy, seg_data, seg_length);
1153
1154 /* Dump the booter memory.
1155 */
1156 ml_static_mfree(seg_offset, seg_length);
1157
1158 /* Set up the VM region.
1159 */
1160 mem_result = vm_map_enter_mem_object(
1161 kernel_map,
1162 &seg_offset,
1163 seg_length, /* mask */ 0,
1164 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1165 VM_MAP_KERNEL_FLAGS_NONE,
1166 VM_KERN_MEMORY_NONE,
1167 (ipc_port_t)NULL,
1168 (vm_object_offset_t) 0,
1169 /* copy */ FALSE,
1170 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1171 /* max_protection */ VM_PROT_ALL,
1172 /* inheritance */ VM_INHERIT_DEFAULT);
1173 if ((mem_result != KERN_SUCCESS) ||
1174 (seg_offset != (vm_map_offset_t) seg_data)) {
1175 OSKextLog(/* kext */ NULL,
1176 kOSKextLogErrorLevel |
1177 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1178 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1179 seg_data, seg_length, mem_result);
1180 return result;
1181 }
1182
1183 /* And copy it back.
1184 */
1185 memcpy(seg_data, seg_copy, seg_length);
1186
1187 /* Free the copy.
1188 */
1189 kmem_free(kernel_map, seg_copy_offset, seg_length);
1190 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1191 /* Remove the linkedit segment of the Boot KC */
1192 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1193 OSKext::jettisonFileSetLinkeditSegment(mh);
1194 }
1195 #else // !VM_MAPPED_KEXTS
1196 /*****
1197 * Dump the LINKEDIT segment, unless keepsyms is set.
1198 */
1199 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1200 dt_segment_name = "Kernel-__LINKEDIT";
1201 if (0 == IODTGetLoaderInfo(dt_segment_name,
1202 &segment_paddress, &segment_size)) {
1203 #ifdef SECURE_KERNEL
1204 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1205 bzero((void*)vmaddr, segment_size);
1206 #endif
1207 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1208 (int)segment_size);
1209 }
1210 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1211 /* Remove the linkedit segment of the Boot KC */
1212 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1213 OSKext::jettisonFileSetLinkeditSegment(mh);
1214 } else {
1215 OSKextLog(/* kext */ NULL,
1216 kOSKextLogBasicLevel |
1217 kOSKextLogGeneralFlag,
1218 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1219 }
1220 #endif // VM_MAPPED_KEXTS
1221
1222 result = kOSReturnSuccess;
1223
1224 return result;
1225 }
1226
1227 #if CONFIG_KXLD
1228 /*********************************************************************
1229 *********************************************************************/
1230 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1231 OSKext::flushNonloadedKexts(
1232 Boolean flushPrelinkedKexts)
1233 {
1234 OSSharedPtr<OSSet> keepKexts;
1235
1236 /* TODO: make this more efficient with MH_FILESET kexts */
1237
1238 // Do not unload prelinked kexts on arm because the kernelcache is not
1239 // structured in a way that allows them to be unmapped
1240 #if !defined(__x86_64__)
1241 flushPrelinkedKexts = false;
1242 #endif /* defined(__x86_64__) */
1243
1244 IORecursiveLockLock(sKextLock);
1245
1246 OSKextLog(/* kext */ NULL,
1247 kOSKextLogProgressLevel |
1248 kOSKextLogKextBookkeepingFlag,
1249 "Flushing nonloaded kexts and other unused data.");
1250
1251 OSKext::considerDestroyingLinkContext();
1252
1253 /* If we aren't flushing unused prelinked kexts, we have to put them
1254 * aside while we flush everything else so make a container for them.
1255 */
1256 keepKexts = OSSet::withCapacity(16);
1257 if (!keepKexts) {
1258 goto finish;
1259 }
1260
1261 /* Set aside prelinked kexts (in-use or not) and break
1262 * any lingering inter-kext references for nonloaded kexts
1263 * so they have min. retain counts.
1264 */
1265 {
1266 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1267 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1268 if (!thisKext) {
1269 return false;
1270 }
1271 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1272 keepKexts->setObject(thisKext);
1273 } else if (!thisKext->declaresExecutable()) {
1274 /*
1275 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1276 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1277 * flushNonloadedKexts().
1278 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1279 */
1280 keepKexts->setObject(thisKext);
1281 } else if (thisKext->isInFileset()) {
1282 /* keep all kexts in the new MH_FILESET KC */
1283 keepKexts->setObject(thisKext);
1284 }
1285
1286 thisKext->flushDependencies(/* forceIfLoaded */ false);
1287 return false;
1288 });
1289 }
1290 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1291 */
1292 sKextsByID->flushCollection();
1293
1294 /* Now put the loaded kexts back into the ID dictionary.
1295 */
1296 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1297 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1298 if (!thisKext) {
1299 return false;
1300 }
1301 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1302 return false;
1303 });
1304
1305 /* Finally, put back the kept kexts if we saved any.
1306 */
1307 keepKexts->iterateObjects(^bool (OSObject * obj) {
1308 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1309 if (!thisKext) {
1310 return false;
1311 }
1312 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1313 return false;
1314 });
1315
1316 finish:
1317 IORecursiveLockUnlock(sKextLock);
1318 return;
1319 }
1320 #else /* !CONFIG_KXLD */
1321
1322 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1323 OSKext::flushNonloadedKexts(
1324 Boolean flushPrelinkedKexts __unused)
1325 {
1326 IORecursiveLockLock(sKextLock);
1327
1328 OSKextLog(/* kext */ NULL,
1329 kOSKextLogProgressLevel |
1330 kOSKextLogKextBookkeepingFlag,
1331 "Flushing dependency info for non-loaded kexts.");
1332
1333 /*
1334 * In a world where we don't dynamically link kexts, they all come
1335 * from a kext collection that's either in wired memory, or
1336 * wire-on-demand. We don't need to mess around with moving kexts in
1337 * and out of the sKextsByID array - they can all just stay there.
1338 * Here we just flush the dependency list for kexts that are not
1339 * loaded.
1340 */
1341 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1342 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1343 if (!thisKext) {
1344 return false;
1345 }
1346 thisKext->flushDependencies(/* forceIfLoaded */ false);
1347 return false;
1348 });
1349
1350 IORecursiveLockUnlock(sKextLock);
1351 return;
1352 }
1353
1354 #endif /* CONFIG_KXLD */
1355
1356 /*********************************************************************
1357 *********************************************************************/
1358 /* static */
1359 void
setIOKitDaemonActive(bool active)1360 OSKext::setIOKitDaemonActive(bool active)
1361 {
1362 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1363 IORecursiveLockLock(sKextLock);
1364 sIOKitDaemonActive = active;
1365 if (sKernelRequests->getCount()) {
1366 OSKext::pingIOKitDaemon();
1367 }
1368 IORecursiveLockUnlock(sKextLock);
1369
1370 return;
1371 }
1372
1373 /*********************************************************************
1374 * OSKextLib.cpp might need access to this someday but for now it's
1375 * private.
1376 *********************************************************************/
1377 extern "C" {
1378 extern void ipc_port_release_send(ipc_port_t);
1379 };
1380
1381 /* static */
1382 OSReturn
pingIOKitDaemon(void)1383 OSKext::pingIOKitDaemon(void)
1384 {
1385 OSReturn result = kOSReturnError;
1386 #if !NO_KEXTD
1387 mach_port_t kextd_port = IPC_PORT_NULL;
1388
1389 if (!sIOKitDaemonActive) {
1390 result = kOSKextReturnDisabled; // basically unavailable
1391 goto finish;
1392 }
1393
1394 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1395 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1396 OSKextLog(/* kext */ NULL,
1397 kOSKextLogErrorLevel |
1398 kOSKextLogIPCFlag,
1399 "Can't get " kIOKitDaemonName " port.");
1400 goto finish;
1401 }
1402
1403 result = kextd_ping(kextd_port);
1404 if (result != KERN_SUCCESS) {
1405 OSKextLog(/* kext */ NULL,
1406 kOSKextLogErrorLevel |
1407 kOSKextLogIPCFlag,
1408 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1409 goto finish;
1410 }
1411
1412 finish:
1413 if (IPC_PORT_VALID(kextd_port)) {
1414 ipc_port_release_send(kextd_port);
1415 }
1416 #endif
1417
1418 return result;
1419 }
1420
1421 /*********************************************************************
1422 *********************************************************************/
1423 /* static */
1424 bool
iokitDaemonAvailable(void)1425 OSKext::iokitDaemonAvailable(void)
1426 {
1427 int notused;
1428 if (PE_parse_boot_argn("-restore", ¬used, sizeof(notused))) {
1429 return false;
1430 }
1431 return true;
1432 }
1433
1434 /*********************************************************************
1435 *********************************************************************/
1436 /* static */
1437 void
setDeferredLoadSucceeded(Boolean succeeded)1438 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1439 {
1440 IORecursiveLockLock(sKextLock);
1441 sDeferredLoadSucceeded = succeeded;
1442 IORecursiveLockUnlock(sKextLock);
1443
1444 return;
1445 }
1446
1447 /*********************************************************************
1448 * Called from IOSystemShutdownNotification.
1449 *********************************************************************/
1450 /* static */
1451 void
willShutdown(void)1452 OSKext::willShutdown(void)
1453 {
1454 #if !NO_KEXTD
1455 OSReturn checkResult = kOSReturnError;
1456 #endif
1457 OSSharedPtr<OSDictionary> exitRequest;
1458
1459 IORecursiveLockLock(sKextLock);
1460
1461 OSKext::setLoadEnabled(false);
1462 OSKext::setUnloadEnabled(false);
1463 OSKext::setAutounloadsEnabled(false);
1464 OSKext::setKernelRequestsEnabled(false);
1465
1466 #if defined(__x86_64__) || defined(__i386__)
1467 if (IOPMRootDomainGetWillShutdown()) {
1468 OSKext::freeKCFileSetcontrol();
1469 }
1470 #endif // (__x86_64__) || defined(__i386__)
1471
1472 #if !NO_KEXTD
1473 OSKextLog(/* kext */ NULL,
1474 kOSKextLogProgressLevel |
1475 kOSKextLogGeneralFlag,
1476 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1477
1478 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1479 exitRequest);
1480 if (checkResult != kOSReturnSuccess) {
1481 goto finish;
1482 }
1483 if (!sKernelRequests->setObject(exitRequest.get())) {
1484 goto finish;
1485 }
1486
1487 OSKext::pingIOKitDaemon();
1488
1489 finish:
1490 #endif
1491
1492 IORecursiveLockUnlock(sKextLock);
1493 return;
1494 }
1495
1496 void
willUserspaceReboot(void)1497 OSKext::willUserspaceReboot(void)
1498 {
1499 OSKext::willShutdown();
1500 IOService::userSpaceWillReboot();
1501 gIOCatalogue->terminateDriversForUserspaceReboot();
1502 }
1503
1504 void
resetAfterUserspaceReboot(void)1505 OSKext::resetAfterUserspaceReboot(void)
1506 {
1507 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1508 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1509
1510 IORecursiveLockLock(sKextLock);
1511 gIOCatalogue->resetAfterUserspaceReboot();
1512 IOService::userSpaceDidReboot();
1513 OSKext::removeDaemonExitRequests();
1514 OSKext::setLoadEnabled(true);
1515 OSKext::setUnloadEnabled(true);
1516 OSKext::setAutounloadsEnabled(true);
1517 OSKext::setKernelRequestsEnabled(true);
1518 sOSKextWasResetAfterUserspaceReboot = true;
1519 IORecursiveLockUnlock(sKextLock);
1520 }
1521
1522 extern "C" void
OSKextResetAfterUserspaceReboot(void)1523 OSKextResetAfterUserspaceReboot(void)
1524 {
1525 OSKext::resetAfterUserspaceReboot();
1526 }
1527
1528 /*
1529 * Remove daemon exit requests from sKernelRequests
1530 *
1531 * If we sent a daemon exit request during a userspace reboot and launchd
1532 * killed the IOKit daemon before it was able to dequeue the exit request, the
1533 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1534 *
1535 * This removes exit requests so that this does not happen.
1536 */
1537 void
removeDaemonExitRequests(void)1538 OSKext::removeDaemonExitRequests(void)
1539 {
1540 OSDictionary * current = NULL;
1541 OSString * predicate = NULL;
1542 size_t index = 0;
1543 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1544
1545 while (index < sKernelRequests->getCount()) {
1546 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1547 if (current) {
1548 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1549 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1550 sKernelRequests->removeObject(index);
1551 continue;
1552 }
1553 }
1554 index++;
1555 }
1556 }
1557
1558 /*********************************************************************
1559 *********************************************************************/
1560 /* static */
1561 bool
getLoadEnabled(void)1562 OSKext::getLoadEnabled(void)
1563 {
1564 bool result;
1565
1566 IORecursiveLockLock(sKextLock);
1567 result = sLoadEnabled;
1568 IORecursiveLockUnlock(sKextLock);
1569 return result;
1570 }
1571
1572 /*********************************************************************
1573 *********************************************************************/
1574 /* static */
1575 bool
setLoadEnabled(bool flag)1576 OSKext::setLoadEnabled(bool flag)
1577 {
1578 bool result;
1579
1580 IORecursiveLockLock(sKextLock);
1581 result = sLoadEnabled;
1582 sLoadEnabled = (flag ? true : false);
1583
1584 if (sLoadEnabled != result) {
1585 OSKextLog(/* kext */ NULL,
1586 kOSKextLogBasicLevel |
1587 kOSKextLogLoadFlag,
1588 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1589 }
1590
1591 IORecursiveLockUnlock(sKextLock);
1592
1593 return result;
1594 }
1595
1596 /*********************************************************************
1597 *********************************************************************/
1598 /* static */
1599 bool
getUnloadEnabled(void)1600 OSKext::getUnloadEnabled(void)
1601 {
1602 bool result;
1603
1604 IORecursiveLockLock(sKextLock);
1605 result = sUnloadEnabled;
1606 IORecursiveLockUnlock(sKextLock);
1607 return result;
1608 }
1609
1610 /*********************************************************************
1611 *********************************************************************/
1612 /* static */
1613 bool
setUnloadEnabled(bool flag)1614 OSKext::setUnloadEnabled(bool flag)
1615 {
1616 bool result;
1617
1618 IORecursiveLockLock(sKextLock);
1619 result = sUnloadEnabled;
1620 sUnloadEnabled = (flag ? true : false);
1621 IORecursiveLockUnlock(sKextLock);
1622
1623 if (sUnloadEnabled != result) {
1624 OSKextLog(/* kext */ NULL,
1625 kOSKextLogBasicLevel |
1626 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1627 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1628 }
1629
1630 return result;
1631 }
1632
1633 /*********************************************************************
1634 * Do not call any function that takes sKextLock here!
1635 *********************************************************************/
1636 /* static */
1637 bool
getAutounloadEnabled(void)1638 OSKext::getAutounloadEnabled(void)
1639 {
1640 #if XNU_TARGET_OS_OSX
1641 bool result;
1642
1643 IORecursiveLockLock(sKextInnerLock);
1644 result = sAutounloadEnabled ? true : false;
1645 IORecursiveLockUnlock(sKextInnerLock);
1646 return result;
1647 #else
1648 return false;
1649 #endif /* XNU_TARGET_OS_OSX */
1650 }
1651
1652 /*********************************************************************
1653 * Do not call any function that takes sKextLock here!
1654 *********************************************************************/
1655 /* static */
1656 bool
setAutounloadsEnabled(bool flag)1657 OSKext::setAutounloadsEnabled(bool flag)
1658 {
1659 #if XNU_TARGET_OS_OSX
1660 bool result;
1661
1662 IORecursiveLockLock(sKextInnerLock);
1663
1664 result = sAutounloadEnabled;
1665 sAutounloadEnabled = (flag ? true : false);
1666 if (!sAutounloadEnabled && sUnloadCallout) {
1667 thread_call_cancel(sUnloadCallout);
1668 }
1669
1670 if (sAutounloadEnabled != result) {
1671 OSKextLog(/* kext */ NULL,
1672 kOSKextLogBasicLevel |
1673 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1674 "Kext autounloading now %sabled.",
1675 sAutounloadEnabled ? "en" : "dis");
1676 }
1677
1678 IORecursiveLockUnlock(sKextInnerLock);
1679
1680 return result;
1681 #else
1682 (void)flag;
1683 return false;
1684 #endif /* XNU_TARGET_OS_OSX */
1685 }
1686
1687 /*********************************************************************
1688 *********************************************************************/
1689 /* instance method operating on OSKext field */
1690 bool
setAutounloadEnabled(bool flag)1691 OSKext::setAutounloadEnabled(bool flag)
1692 {
1693 bool result = flags.autounloadEnabled ? true : false;
1694 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1695
1696 if (result != (flag ? true : false)) {
1697 OSKextLog(this,
1698 kOSKextLogProgressLevel |
1699 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1700 "Autounloading for kext %s now %sabled.",
1701 getIdentifierCString(),
1702 flags.autounloadEnabled ? "en" : "dis");
1703 }
1704 return result;
1705 }
1706
1707 /*********************************************************************
1708 *********************************************************************/
1709 /* static */
1710 bool
setKernelRequestsEnabled(bool flag)1711 OSKext::setKernelRequestsEnabled(bool flag)
1712 {
1713 bool result;
1714
1715 IORecursiveLockLock(sKextLock);
1716 result = sKernelRequestsEnabled;
1717 sKernelRequestsEnabled = flag ? true : false;
1718
1719 if (sKernelRequestsEnabled != result) {
1720 OSKextLog(/* kext */ NULL,
1721 kOSKextLogBasicLevel |
1722 kOSKextLogGeneralFlag,
1723 "Kernel requests now %sabled.",
1724 sKernelRequestsEnabled ? "en" : "dis");
1725 }
1726 IORecursiveLockUnlock(sKextLock);
1727 return result;
1728 }
1729
1730 /*********************************************************************
1731 *********************************************************************/
1732 /* static */
1733 bool
getKernelRequestsEnabled(void)1734 OSKext::getKernelRequestsEnabled(void)
1735 {
1736 bool result;
1737
1738 IORecursiveLockLock(sKextLock);
1739 result = sKernelRequestsEnabled;
1740 IORecursiveLockUnlock(sKextLock);
1741 return result;
1742 }
1743
1744 static bool
segmentIsMutable(kernel_segment_command_t * seg)1745 segmentIsMutable(kernel_segment_command_t *seg)
1746 {
1747 /* Mutable segments have to have VM_PROT_WRITE */
1748 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1749 return false;
1750 }
1751 /* Exclude the __DATA_CONST segment */
1752 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1753 return false;
1754 }
1755 /* Exclude __LINKEDIT */
1756 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1757 return false;
1758 }
1759 return true;
1760 }
1761
1762 #if PRAGMA_MARK
1763 #pragma mark Kext Life Cycle
1764 #endif
1765 /*********************************************************************
1766 *********************************************************************/
1767 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1768 OSKext::withPrelinkedInfoDict(
1769 OSDictionary * anInfoDict,
1770 bool doCoalescedSlides,
1771 kc_kind_t type)
1772 {
1773 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1774
1775 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1776 return NULL;
1777 }
1778
1779 return newKext;
1780 }
1781
1782 OSData *
parseDextUniqueID(OSDictionary * anInfoDict,const char * dextIDCS)1783 OSKext::parseDextUniqueID(
1784 OSDictionary * anInfoDict,
1785 const char *dextIDCS)
1786 {
1787 OSData *ret = NULL;
1788 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1789 if (data_duid != NULL) {
1790 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1791 OSKextLog(NULL,
1792 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1793 "Dext %s DextUniqueIdentifier too long.",
1794 dextIDCS);
1795 } else {
1796 /*
1797 * If the DextUniqueID exists it should be
1798 * present also into the personalities.
1799 */
1800 setDextUniqueIDInPersonalities(anInfoDict, data_duid);
1801 ret = data_duid;
1802 }
1803 } else {
1804 OSKextLog(NULL,
1805 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1806 "Dext %s does not have a DextUniqueIdentifier",
1807 dextIDCS);
1808 }
1809 return ret;
1810 }
1811
1812 void
setDextUniqueIDInPersonalities(OSDictionary * anInfoDict,OSData * dextUniqueID)1813 OSKext::setDextUniqueIDInPersonalities(
1814 OSDictionary * anInfoDict,
1815 OSData * dextUniqueID)
1816 {
1817 OSDictionary * dextPersonalities = NULL;
1818 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
1819 OSString * personalityName = NULL;
1820
1821 dextPersonalities = OSDynamicCast(OSDictionary,
1822 anInfoDict->getObject(kIOKitPersonalitiesKey));
1823 if (!dextPersonalities || !dextPersonalities->getCount()) {
1824 return;
1825 }
1826
1827 personalitiesIterator =
1828 OSCollectionIterator::withCollection(dextPersonalities);
1829 if (!personalitiesIterator) {
1830 return;
1831 }
1832 while ((personalityName = OSDynamicCast(OSString,
1833 personalitiesIterator->getNextObject()))) {
1834 OSDictionary * personality = OSDynamicCast(OSDictionary,
1835 dextPersonalities->getObject(personalityName));
1836 if (personality) {
1837 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
1838 if (duid == NULL) {
1839 personality->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID);
1840 }
1841 }
1842 }
1843 }
1844 /*********************************************************************
1845 *********************************************************************/
1846 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1847 OSKext::initWithPrelinkedInfoDict(
1848 OSDictionary * anInfoDict,
1849 bool doCoalescedSlides,
1850 kc_kind_t type)
1851 {
1852 bool result = false;
1853 OSString * kextPath = NULL; // do not release
1854 OSNumber * addressNum = NULL; // reused; do not release
1855 OSNumber * lengthNum = NULL; // reused; do not release
1856 OSBoolean * scratchBool = NULL; // do not release
1857 void * data = NULL; // do not free
1858 void * srcData = NULL; // do not free
1859 OSSharedPtr<OSData> prelinkedExecutable;
1860 uint32_t length = 0; // reused
1861 uintptr_t kext_slide = PE_get_kc_slide(type);
1862 bool shouldSaveSegments = false;
1863 kc_format format = KCFormatUnknown;
1864
1865 if (!super::init()) {
1866 goto finish;
1867 }
1868
1869 /* Get the path. Don't look for an arch-specific path property.
1870 */
1871 kextPath = OSDynamicCast(OSString,
1872 anInfoDict->getObject(kPrelinkBundlePathKey));
1873
1874 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1875 goto finish;
1876 }
1877
1878 #if KASLR_KEXT_DEBUG
1879 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1880 #endif
1881
1882 /* Also get the executable's bundle-relative path if present.
1883 * Don't look for an arch-specific path property.
1884 */
1885 executableRelPath.reset(OSDynamicCast(OSString,
1886 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1887 userExecutableRelPath.reset(OSDynamicCast(OSString,
1888 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1889
1890 /* Don't need the paths to be in the info dictionary any more.
1891 */
1892 anInfoDict->removeObject(kPrelinkBundlePathKey);
1893 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1894
1895 scratchBool = OSDynamicCast(OSBoolean,
1896 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1897 if (scratchBool == kOSBooleanTrue) {
1898 flags.requireExplicitLoad = 1;
1899 }
1900
1901 /* Create an OSData wrapper around the linked executable.
1902 */
1903 addressNum = OSDynamicCast(OSNumber,
1904 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1905 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1906 lengthNum = OSDynamicCast(OSNumber,
1907 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1908 if (!lengthNum) {
1909 OSKextLog(this,
1910 kOSKextLogErrorLevel |
1911 kOSKextLogArchiveFlag,
1912 "Kext %s can't find prelinked kext executable size.",
1913 getIdentifierCString());
1914 return result;
1915 }
1916
1917 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1918 length = (uint32_t) (lengthNum->unsigned32BitValue());
1919
1920 #if KASLR_KEXT_DEBUG
1921 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1922 (unsigned long)ml_static_unslide((vm_offset_t)data),
1923 (unsigned long)data,
1924 length);
1925 #endif
1926
1927 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1928 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1929
1930 /* If the kext's load address differs from its source address, allocate
1931 * space in the kext map at the load address and copy the kext over.
1932 */
1933 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1934 if (addressNum) {
1935 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1936
1937 #if KASLR_KEXT_DEBUG
1938 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1939 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1940 (unsigned long)srcData);
1941 #endif
1942
1943 if (data != srcData) {
1944 #if __LP64__
1945 kern_return_t alloc_result;
1946
1947 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1948 if (alloc_result != KERN_SUCCESS) {
1949 OSKextLog(this,
1950 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1951 "Failed to allocate space for prelinked kext %s.",
1952 getIdentifierCString());
1953 goto finish;
1954 }
1955 memcpy(data, srcData, length);
1956 #else
1957 OSKextLog(this,
1958 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1959 "Error: prelinked kext %s - source and load addresses "
1960 "differ on ILP32 architecture.",
1961 getIdentifierCString());
1962 goto finish;
1963 #endif /* __LP64__ */
1964 }
1965
1966 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1967 }
1968
1969 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1970 if (!prelinkedExecutable) {
1971 OSKextLog(this,
1972 kOSKextLogErrorLevel |
1973 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1974 "Kext %s failed to create executable wrapper.",
1975 getIdentifierCString());
1976 goto finish;
1977 }
1978
1979 /*
1980 * Fileset KCs are mapped as a whole by iBoot.
1981 * Individual kext executables should not be unmapped
1982 * by xnu.
1983 * Doing so may result in panics like rdar://85419651
1984 */
1985 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
1986 prelinkedExecutable->setDeallocFunction(NULL);
1987 } else { // Not from a Fileset KC
1988 #if VM_MAPPED_KEXTS
1989 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1990 #else
1991 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1992 #endif
1993 }
1994 setLinkedExecutable(prelinkedExecutable.get());
1995 addressNum = OSDynamicCast(OSNumber,
1996 anInfoDict->getObject(kPrelinkKmodInfoKey));
1997 if (!addressNum) {
1998 OSKextLog(this,
1999 kOSKextLogErrorLevel |
2000 kOSKextLogArchiveFlag,
2001 "Kext %s can't find prelinked kext kmod_info address.",
2002 getIdentifierCString());
2003 goto finish;
2004 }
2005
2006 if (addressNum->unsigned64BitValue() != 0) {
2007 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2008 if (kmod_info->address) {
2009 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2010 } else {
2011 kmod_info->address = (uintptr_t)data;
2012 kmod_info->size = length;
2013 }
2014 #if KASLR_KEXT_DEBUG
2015 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2016 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2017 (unsigned long)kmod_info);
2018 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2019 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2020 (unsigned long)kmod_info->address);
2021 #endif
2022 }
2023
2024 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2025 }
2026
2027 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2028 uintptr_t builtinTextStart;
2029 uintptr_t builtinTextEnd;
2030
2031 flags.builtin = true;
2032 builtinKmodIdx = addressNum->unsigned32BitValue();
2033 assert(builtinKmodIdx < gBuiltinKmodsCount);
2034
2035 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2036 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2037
2038 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2039 kmod_info->address = builtinTextStart;
2040 kmod_info->size = builtinTextEnd - builtinTextStart;
2041 }
2042
2043 /* If the plist has a UUID for an interface, save that off.
2044 */
2045 if (isInterface()) {
2046 interfaceUUID.reset(OSDynamicCast(OSData,
2047 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2048 if (interfaceUUID) {
2049 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2050 }
2051 }
2052
2053 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
2054 if (!result) {
2055 goto finish;
2056 }
2057
2058 kc_type = type;
2059 /* Exclude builtin and codeless kexts */
2060 if (prelinkedExecutable && kmod_info) {
2061 switch (kc_type) {
2062 case KCKindPrimary:
2063 shouldSaveSegments = (
2064 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2065 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2066 if (shouldSaveSegments) {
2067 flags.resetSegmentsFromImmutableCopy = 1;
2068 } else {
2069 flags.unloadUnsupported = 1;
2070 }
2071 break;
2072 case KCKindPageable:
2073 flags.resetSegmentsFromVnode = 1;
2074 break;
2075 case KCKindAuxiliary:
2076 if (!pageableKCloaded) {
2077 flags.resetSegmentsFromImmutableCopy = 1;
2078 } else if (resetAuxKCSegmentOnUnload) {
2079 flags.resetSegmentsFromVnode = 1;
2080 } else {
2081 flags.unloadUnsupported = 1;
2082 }
2083 break;
2084 default:
2085 break;
2086 }
2087 }
2088
2089 if (flags.resetSegmentsFromImmutableCopy) {
2090 /* Save a pristine copy of the mutable segments */
2091 kernel_segment_command_t *seg = NULL;
2092 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2093
2094 savedMutableSegments = OSArray::withCapacity(0);
2095
2096 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
2097 if (!segmentIsMutable(seg)) {
2098 continue;
2099 }
2100 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2101 uint64_t vmsize = seg->vmsize;
2102 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2103 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2104 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2105 if (!savedSegment) {
2106 OSKextLog(this,
2107 kOSKextLogErrorLevel |
2108 kOSKextLogGeneralFlag,
2109 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2110 result = false;
2111 goto finish;
2112 }
2113 savedMutableSegments->setObject(savedSegment);
2114 }
2115 }
2116
2117 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2118 /*
2119 * set VM protections now, wire pages for the old style Aux KC now,
2120 * wire pages for the rest of the KC types at load time.
2121 */
2122 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2123 if (!result) {
2124 goto finish;
2125 }
2126 }
2127
2128 flags.prelinked = true;
2129
2130 if (isDriverKit()) {
2131 dextStatistics = OSDextStatistics::create();
2132 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2133 dextLaunchedCount = 0;
2134 }
2135
2136 /* If we created a kext from prelink info,
2137 * we must be booting from a prelinked kernel.
2138 */
2139 sPrelinkBoot = true;
2140
2141 result = (registerIdentifier() == kOSKextInitialized);
2142 finish:
2143 return result;
2144 }
2145
2146 /*********************************************************************
2147 *********************************************************************/
2148 /* static */
2149 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict,OSKextInitResult * result)2150 OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2151 {
2152 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2153 if (!newKext) {
2154 return NULL;
2155 }
2156
2157 OSKextInitResult ret = newKext->initWithCodelessInfo(anInfoDict);
2158 if (result != NULL) {
2159 *result = ret;
2160 }
2161 if (ret != kOSKextInitialized) {
2162 return NULL;
2163 }
2164
2165 return newKext;
2166 }
2167
2168 /*********************************************************************
2169 *********************************************************************/
2170 OSKextInitResult
initWithCodelessInfo(OSDictionary * anInfoDict)2171 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2172 {
2173 OSKextInitResult result = kOSKextInitFailure;
2174 OSString * kextPath = NULL; // do not release
2175 OSBoolean * scratchBool = NULL; // do not release
2176
2177 if (anInfoDict == NULL || !super::init()) {
2178 goto finish;
2179 }
2180
2181 /*
2182 * Get the path. Don't look for an arch-specific path property.
2183 */
2184 kextPath = OSDynamicCast(OSString,
2185 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2186 if (!kextPath) {
2187 OSKextLog(NULL,
2188 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2189 "Requested codeless kext dictionary does not contain the '%s' key",
2190 kKextRequestArgumentCodelessInfoBundlePathKey);
2191 goto finish;
2192 }
2193
2194 uniquePersonalityProperties(anInfoDict);
2195
2196 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2197 goto finish;
2198 }
2199
2200 /*
2201 * This path is meant to initialize codeless kexts only. Refuse
2202 * anything that looks like it has an executable and/or declares
2203 * itself as a kernel component.
2204 */
2205 if (declaresExecutable() || isKernelComponent()) {
2206 OSKextLog(NULL,
2207 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2208 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2209 getIdentifierCString());
2210 goto finish;
2211 }
2212
2213 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2214 boolean_t updated = updateExcludeList(infoDict.get());
2215 if (updated) {
2216 OSKextLog(this,
2217 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2218 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2219 }
2220 }
2221
2222 kc_type = KCKindNone;
2223
2224 scratchBool = OSDynamicCast(OSBoolean,
2225 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2226 if (scratchBool == kOSBooleanTrue) {
2227 flags.requireExplicitLoad = 1;
2228 }
2229
2230 /* Also get the executable's bundle-relative path if present.
2231 * Don't look for an arch-specific path property.
2232 */
2233 userExecutableRelPath.reset(OSDynamicCast(OSString,
2234 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2235
2236 /* remove unnecessary paths from the info dict */
2237 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2238
2239 if (isDriverKit()) {
2240 dextStatistics = OSDextStatistics::create();
2241 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2242 dextLaunchedCount = 0;
2243 }
2244
2245 result = registerIdentifier();
2246
2247 finish:
2248 return result;
2249 }
2250
2251 /*********************************************************************
2252 *********************************************************************/
2253 /* static */
2254 void
setAllVMAttributes(void)2255 OSKext::setAllVMAttributes(void)
2256 {
2257 OSSharedPtr<OSCollectionIterator> kextIterator;
2258 const OSSymbol * thisID = NULL; // do not release
2259
2260 IORecursiveLockLock(sKextLock);
2261
2262 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2263 if (!kextIterator) {
2264 goto finish;
2265 }
2266
2267 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2268 OSKext * thisKext; // do not release
2269
2270 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2271 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2272 continue;
2273 }
2274
2275 if (!thisKext->flags.resetSegmentsFromVnode) {
2276 /*
2277 * set VM protections now, wire pages for the old style Aux KC now,
2278 * wire pages for the rest of the KC types at load time.
2279 */
2280 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2281 }
2282 }
2283
2284 finish:
2285 IORecursiveLockUnlock(sKextLock);
2286
2287 return;
2288 }
2289
2290 /*********************************************************************
2291 *********************************************************************/
2292 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2293 OSKext::withBooterData(
2294 OSString * deviceTreeName,
2295 OSData * booterData)
2296 {
2297 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2298
2299 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2300 return NULL;
2301 }
2302
2303 return newKext;
2304 }
2305
2306 /*********************************************************************
2307 *********************************************************************/
2308 typedef struct _BooterKextFileInfo {
2309 uint32_t infoDictPhysAddr;
2310 uint32_t infoDictLength;
2311 uint32_t executablePhysAddr;
2312 uint32_t executableLength;
2313 uint32_t bundlePathPhysAddr;
2314 uint32_t bundlePathLength;
2315 } _BooterKextFileInfo;
2316
2317 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2318 OSKext::initWithBooterData(
2319 OSString * deviceTreeName,
2320 OSData * booterData)
2321 {
2322 bool result = false;
2323 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2324 char * infoDictAddr = NULL; // do not free
2325 void * executableAddr = NULL; // do not free
2326 char * bundlePathAddr = NULL; // do not free
2327
2328 OSDictionary * theInfoDict = NULL; // do not release
2329 OSSharedPtr<OSObject> parsedXML;
2330 OSSharedPtr<OSString> kextPath;
2331
2332 OSSharedPtr<OSString> errorString;
2333 OSSharedPtr<OSData> executable;
2334
2335 if (!super::init()) {
2336 goto finish;
2337 }
2338
2339 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2340 if (!kextFileInfo) {
2341 OSKextLog(this,
2342 kOSKextLogErrorLevel |
2343 kOSKextLogGeneralFlag,
2344 "No booter-provided data for kext device tree entry %s.",
2345 deviceTreeName->getCStringNoCopy());
2346 goto finish;
2347 }
2348
2349 /* The info plist must exist or we can't read the kext.
2350 */
2351 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2352 OSKextLog(this,
2353 kOSKextLogErrorLevel |
2354 kOSKextLogGeneralFlag,
2355 "No kext info dictionary for booter device tree entry %s.",
2356 deviceTreeName->getCStringNoCopy());
2357 goto finish;
2358 }
2359
2360 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2361 if (!infoDictAddr) {
2362 OSKextLog(this,
2363 kOSKextLogErrorLevel |
2364 kOSKextLogGeneralFlag,
2365 "Can't translate physical address 0x%x of kext info dictionary "
2366 "for device tree entry %s.",
2367 (int)kextFileInfo->infoDictPhysAddr,
2368 deviceTreeName->getCStringNoCopy());
2369 goto finish;
2370 }
2371
2372 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2373 if (parsedXML) {
2374 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2375 }
2376 if (!theInfoDict) {
2377 const char * errorCString = "(unknown error)";
2378
2379 if (errorString && errorString->getCStringNoCopy()) {
2380 errorCString = errorString->getCStringNoCopy();
2381 } else if (parsedXML) {
2382 errorCString = "not a dictionary";
2383 }
2384 OSKextLog(this,
2385 kOSKextLogErrorLevel |
2386 kOSKextLogGeneralFlag,
2387 "Error unserializing info dictionary for device tree entry %s: %s.",
2388 deviceTreeName->getCStringNoCopy(), errorCString);
2389 goto finish;
2390 }
2391
2392 /* A bundle path is not mandatory.
2393 */
2394 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2395 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2396 if (!bundlePathAddr) {
2397 OSKextLog(this,
2398 kOSKextLogErrorLevel |
2399 kOSKextLogGeneralFlag,
2400 "Can't translate physical address 0x%x of kext bundle path "
2401 "for device tree entry %s.",
2402 (int)kextFileInfo->bundlePathPhysAddr,
2403 deviceTreeName->getCStringNoCopy());
2404 goto finish;
2405 }
2406 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2407
2408 kextPath = OSString::withCString(bundlePathAddr);
2409 if (!kextPath) {
2410 OSKextLog(this,
2411 kOSKextLogErrorLevel |
2412 kOSKextLogGeneralFlag,
2413 "Failed to create wrapper for device tree entry %s kext path %s.",
2414 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2415 goto finish;
2416 }
2417 }
2418
2419 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2420 goto finish;
2421 }
2422
2423 /* An executable is not mandatory.
2424 */
2425 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2426 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2427 if (!executableAddr) {
2428 OSKextLog(this,
2429 kOSKextLogErrorLevel |
2430 kOSKextLogGeneralFlag,
2431 "Can't translate physical address 0x%x of kext executable "
2432 "for device tree entry %s.",
2433 (int)kextFileInfo->executablePhysAddr,
2434 deviceTreeName->getCStringNoCopy());
2435 goto finish;
2436 }
2437
2438 executable = OSData::withBytesNoCopy(executableAddr,
2439 kextFileInfo->executableLength);
2440 if (!executable) {
2441 OSKextLog(this,
2442 kOSKextLogErrorLevel |
2443 kOSKextLogGeneralFlag,
2444 "Failed to create executable wrapper for device tree entry %s.",
2445 deviceTreeName->getCStringNoCopy());
2446 goto finish;
2447 }
2448
2449 /* A kext with an executable needs to retain the whole booterData
2450 * object to keep the executable in memory.
2451 */
2452 if (!setExecutable(executable.get(), booterData)) {
2453 OSKextLog(this,
2454 kOSKextLogErrorLevel |
2455 kOSKextLogGeneralFlag,
2456 "Failed to set kext executable for device tree entry %s.",
2457 deviceTreeName->getCStringNoCopy());
2458 goto finish;
2459 }
2460 }
2461
2462 if (isDriverKit()) {
2463 dextStatistics = OSDextStatistics::create();
2464 dextUniqueID.reset(parseDextUniqueID(theInfoDict, getIdentifierCString()), OSRetain);
2465 dextLaunchedCount = 0;
2466 }
2467
2468 result = (registerIdentifier() == kOSKextInitialized);
2469
2470 finish:
2471 return result;
2472 }
2473
2474 /*********************************************************************
2475 *********************************************************************/
2476 OSKextInitResult
registerIdentifier(void)2477 OSKext::registerIdentifier(void)
2478 {
2479 OSKextInitResult result = kOSKextInitFailure;
2480 OSKext * existingKext = NULL; // do not release
2481 bool existingIsLoaded = false;
2482 bool existingIsPrelinked = false;
2483 bool existingIsCodeless = false;
2484 bool existingIsDext = false;
2485 OSKextVersion newVersion = -1;
2486 OSKextVersion existingVersion = -1;
2487 char newVersionCString[kOSKextVersionMaxLength];
2488 char existingVersionCString[kOSKextVersionMaxLength];
2489 OSSharedPtr<OSData> newUUID;
2490 OSSharedPtr<OSData> existingUUID;
2491 const char *newDextUniqueIDCString = NULL;
2492 const char *existingDextUniqueIDCString = NULL;
2493 unsigned int newDextUniqueIDCStringSize = 0;
2494 unsigned int existingDextUniqueIDCStringSize = 0;
2495
2496 IORecursiveLockLock(sKextLock);
2497
2498 /* Get the new kext's version for checks & log messages.
2499 */
2500 newVersion = getVersion();
2501 OSKextVersionGetString(newVersion, newVersionCString,
2502 kOSKextVersionMaxLength);
2503
2504 /* If we don't have an existing kext with this identifier,
2505 * just record the new kext and we're done!
2506 */
2507 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2508 if (!existingKext) {
2509 sKextsByID->setObject(bundleID.get(), this);
2510 result = kOSKextInitialized;
2511 goto finish;
2512 }
2513
2514 /* Get the existing kext's version for checks & log messages.
2515 */
2516 existingVersion = existingKext->getVersion();
2517 OSKextVersionGetString(existingVersion,
2518 existingVersionCString, kOSKextVersionMaxLength);
2519
2520 existingIsLoaded = existingKext->isLoaded();
2521 existingIsPrelinked = existingKext->isPrelinked();
2522 existingIsDext = existingKext->isDriverKit();
2523 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2524
2525 /*
2526 * Check if we are trying to upgrade a dext
2527 * with another dext.
2528 */
2529 if (isDriverKit() && existingIsDext) {
2530 OSData *newDextUID = getDextUniqueID();
2531 if (!newDextUID) {
2532 OSKextLog(this,
2533 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2534 "New dext %s, v%s requested does not have a unique dext identifier\n",
2535 getIdentifierCString(), newVersionCString);
2536 goto finish;
2537 }
2538 newDextUniqueIDCString = getDextUniqueIDCString(newDextUID, &newDextUniqueIDCStringSize);
2539 assert(newDextUniqueIDCString != NULL);
2540
2541 OSData *existingDextUID = existingKext->getDextUniqueID();
2542 if (!existingDextUID) {
2543 OSKextLog(this,
2544 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2545 "Found a dext %s, v%s: with no unique dext identifier\n",
2546 existingKext->getIdentifierCString(), existingVersionCString);
2547 goto finish;
2548 }
2549 existingDextUniqueIDCString = getDextUniqueIDCString(existingDextUID, &existingDextUniqueIDCStringSize);
2550 assert(existingDextUniqueIDCString != NULL);
2551
2552 /*
2553 * We might get multiple requests to save the same dext.
2554 * Check if we already have saved it or if this is an upgrade
2555 * for a dext with the same BundleID.
2556 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2557 * is requested for a BundleID we are going to upgrade to the newest
2558 * received irrespective from the dext version.
2559 */
2560 if (newDextUID->isEqualTo(existingDextUID) && existingKext->flags.dextToReplace == 0) {
2561 OSKextLog(this,
2562 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2563 "Refusing new dext %s, v%s:"
2564 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2565 getIdentifierCString(), newVersionCString,
2566 existingVersionCString, newDextUniqueIDCString);
2567 result = kOSKextAlreadyExist;
2568 goto finish;
2569 }
2570
2571 bool upgraded = upgradeDext(existingKext, this);
2572 if (upgraded) {
2573 /* If the dext was upgraded existingKext might have been deallocated */
2574 existingKext = NULL;
2575 OSKextLog(this,
2576 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2577 "Dext %s, v%s , unique dext identifier %s "
2578 "Upgraded to v%s, unique dext identifier %s \n",
2579 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2580 newVersionCString, newDextUniqueIDCString);
2581 result = kOSKextInitialized;
2582 } else {
2583 OSKextLog(this,
2584 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2585 "Upgrade delayed for %s v%s, unique dext identifier %s "
2586 "with v%s, unique dext identifier %s.\n",
2587 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2588 newVersionCString, newDextUniqueIDCString);
2589 result = kOSKextAlreadyExist;
2590 }
2591
2592 goto finish;
2593 }
2594
2595 /* If we have a non-codeless kext with this identifier that's already
2596 * loaded/prelinked, we can't use the new one, but let's be really
2597 * thorough and check how the two are related for a precise diagnostic
2598 * log message.
2599 *
2600 * This check is valid for kexts that declare an executable and for
2601 * dexts, but not for codeless kexts - we can just replace those.
2602 */
2603 if ((!existingIsCodeless || existingIsDext) &&
2604 (existingIsLoaded || existingIsPrelinked)) {
2605 bool sameVersion = (newVersion == existingVersion);
2606 bool sameExecutable = true; // assume true unless we have UUIDs
2607
2608 /* Only get the UUID if the existing kext is loaded. Doing so
2609 * might have to uncompress an mkext executable and we shouldn't
2610 * take that hit when neither kext is loaded.
2611 *
2612 * Note: there is no decompression that happens when all kexts
2613 * are loaded from kext collecitons.
2614 */
2615 newUUID = copyUUID();
2616 existingUUID = existingKext->copyUUID();
2617
2618 if (existingIsDext && !isDriverKit()) {
2619 OSKextLog(this,
2620 kOSKextLogWarningLevel |
2621 kOSKextLogKextBookkeepingFlag,
2622 "Notice - new kext %s, v%s matches a %s dext"
2623 "with the same bundle ID, v%s.",
2624 getIdentifierCString(), newVersionCString,
2625 (existingIsLoaded ? "loaded" : "prelinked"),
2626 existingVersionCString);
2627 goto finish;
2628 }
2629
2630 /* I'm entirely too paranoid about checking equivalence of executables,
2631 * but I remember nasty problems with it in the past.
2632 *
2633 * - If we have UUIDs for both kexts, compare them.
2634 * - If only one kext has a UUID, they're definitely different.
2635 */
2636 if (newUUID && existingUUID) {
2637 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2638 } else if (newUUID || existingUUID) {
2639 sameExecutable = false;
2640 }
2641
2642 if (!newUUID && !existingUUID) {
2643 /* If there are no UUIDs, we can't really tell that the executables
2644 * are *different* without a lot of work; the loaded kext's
2645 * unrelocated executable is no longer around (and we never had it
2646 * in-kernel for a prelinked kext). We certainly don't want to do
2647 * a whole fake link for the new kext just to compare, either.
2648 */
2649 OSKextLog(this,
2650 kOSKextLogWarningLevel |
2651 kOSKextLogKextBookkeepingFlag,
2652 "Notice - new kext %s, v%s matches %s kext "
2653 "but can't determine if executables are the same (no UUIDs).",
2654 getIdentifierCString(),
2655 newVersionCString,
2656 (existingIsLoaded ? "loaded" : "prelinked"));
2657 }
2658
2659 if (sameVersion && sameExecutable) {
2660 OSKextLog(this,
2661 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2662 kOSKextLogKextBookkeepingFlag,
2663 "Refusing new kext %s, v%s: a %s copy is already present "
2664 "(same version and executable).",
2665 getIdentifierCString(), newVersionCString,
2666 (existingIsLoaded ? "loaded" : "prelinked"));
2667 } else {
2668 if (!sameVersion) {
2669 /* This condition is significant so log it under warnings.
2670 */
2671 OSKextLog(this,
2672 kOSKextLogWarningLevel |
2673 kOSKextLogKextBookkeepingFlag,
2674 "Refusing new kext %s, v%s: already have %s v%s.",
2675 getIdentifierCString(),
2676 newVersionCString,
2677 (existingIsLoaded ? "loaded" : "prelinked"),
2678 existingVersionCString);
2679 } else {
2680 /* This condition is significant so log it under warnings.
2681 */
2682 OSKextLog(this,
2683 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2684 "Refusing new kext %s, v%s: a %s copy with a different "
2685 "executable UUID is already present.",
2686 getIdentifierCString(), newVersionCString,
2687 (existingIsLoaded ? "loaded" : "prelinked"));
2688 }
2689 }
2690 goto finish;
2691 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2692
2693 /* Refuse to allow an existing loaded codeless kext be replaced by a
2694 * normal kext with the same bundle ID.
2695 */
2696 if (existingIsCodeless && declaresExecutable()) {
2697 OSKextLog(this,
2698 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2699 "Refusing new kext %s, v%s: a codeless copy is already %s",
2700 getIdentifierCString(), newVersionCString,
2701 (existingIsLoaded ? "loaded" : "prelinked"));
2702 goto finish;
2703 }
2704
2705 /* Dexts packaged in the BootKC will be protected against replacement
2706 * by non-dexts by the logic above which checks if they are prelinked.
2707 * Dexts which are prelinked into the System KC will be registered
2708 * before any other kexts in the AuxKC are registered, and we never
2709 * put dexts in the AuxKC. Therefore, there is no need to check if an
2710 * existing object is a dext and is being replaced by a non-dext.
2711 * The scenario cannot happen by construction.
2712 *
2713 * See: OSKext::loadFileSetKexts()
2714 */
2715
2716
2717 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2718 * user loads are happening or if we're still in early boot. User agents are
2719 * supposed to resolve dependencies topside and include only the exact
2720 * kexts needed; so we always accept the new kext (in fact we should never
2721 * see an older unloaded copy hanging around).
2722 */
2723 if (sUserLoadsActive) {
2724 sKextsByID->setObject(bundleID.get(), this);
2725 result = kOSKextInitialized;
2726
2727 OSKextLog(this,
2728 kOSKextLogStepLevel |
2729 kOSKextLogKextBookkeepingFlag,
2730 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2731 getIdentifierCString(),
2732 existingVersionCString,
2733 newVersionCString);
2734
2735 goto finish;
2736 }
2737
2738 /* During early boot, the kext with the highest version always wins out.
2739 * Prelinked kernels will never hit this, but mkexts and booter-read
2740 * kexts might have duplicates.
2741 */
2742 if (newVersion > existingVersion) {
2743 sKextsByID->setObject(bundleID.get(), this);
2744 result = kOSKextInitialized;
2745
2746 OSKextLog(this,
2747 kOSKextLogStepLevel |
2748 kOSKextLogKextBookkeepingFlag,
2749 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2750 existingVersionCString,
2751 getIdentifierCString(),
2752 newVersionCString);
2753 } else {
2754 OSKextLog(this,
2755 kOSKextLogStepLevel |
2756 kOSKextLogKextBookkeepingFlag,
2757 "Kext %s is already registered with a higher/same version (v%s); "
2758 "dropping newly-added (v%s).",
2759 getIdentifierCString(),
2760 existingVersionCString,
2761 newVersionCString);
2762 }
2763
2764 /* result has been set appropriately by now. */
2765
2766 finish:
2767
2768 IORecursiveLockUnlock(sKextLock);
2769
2770 if (newDextUniqueIDCString != NULL) {
2771 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2772 }
2773 if (existingDextUniqueIDCString != NULL) {
2774 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2775 }
2776
2777 if (result == kOSKextInitialized) {
2778 OSKextLog(this,
2779 kOSKextLogStepLevel |
2780 kOSKextLogKextBookkeepingFlag,
2781 "Kext %s, v%s registered and available for loading.",
2782 getIdentifierCString(), newVersionCString);
2783 }
2784
2785 return result;
2786 }
2787
2788 /*********************************************************************
2789 * Does the bare minimum validation to look up a kext.
2790 * All other validation is done on the spot as needed.
2791 **********************************************************************/
2792 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2793 OSKext::setInfoDictionaryAndPath(
2794 OSDictionary * aDictionary,
2795 OSString * aPath)
2796 {
2797 bool result = false;
2798 OSString * bundleIDString = NULL; // do not release
2799 OSString * versionString = NULL; // do not release
2800 OSString * compatibleVersionString = NULL; // do not release
2801 const char * versionCString = NULL; // do not free
2802 const char * compatibleVersionCString = NULL; // do not free
2803 OSBoolean * scratchBool = NULL; // do not release
2804 OSDictionary * scratchDict = NULL; // do not release
2805
2806 if (infoDict) {
2807 panic("Attempt to set info dictionary on a kext "
2808 "that already has one (%s).",
2809 getIdentifierCString());
2810 }
2811
2812 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2813 goto finish;
2814 }
2815
2816 infoDict.reset(aDictionary, OSRetain);
2817
2818 /* Check right away if the info dictionary has any log flags.
2819 */
2820 scratchBool = OSDynamicCast(OSBoolean,
2821 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2822 if (scratchBool == kOSBooleanTrue) {
2823 flags.loggingEnabled = 1;
2824 }
2825
2826 /* The very next thing to get is the bundle identifier. Unlike
2827 * in user space, a kext with no bundle identifier gets axed
2828 * immediately.
2829 */
2830 bundleIDString = OSDynamicCast(OSString,
2831 getPropertyForHostArch(kCFBundleIdentifierKey));
2832 if (!bundleIDString) {
2833 OSKextLog(this,
2834 kOSKextLogErrorLevel |
2835 kOSKextLogValidationFlag,
2836 "CFBundleIdentifier missing/invalid type in kext %s.",
2837 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2838 goto finish;
2839 }
2840 bundleID = OSSymbol::withString(bundleIDString);
2841 if (!bundleID) {
2842 OSKextLog(this,
2843 kOSKextLogErrorLevel |
2844 kOSKextLogValidationFlag,
2845 "Can't copy bundle identifier as symbol for kext %s.",
2846 bundleIDString->getCStringNoCopy());
2847 goto finish;
2848 }
2849
2850 /* Save the path if we got one (it should always be available but it's
2851 * just something nice to have for bookkeeping).
2852 */
2853 if (aPath) {
2854 path.reset(aPath, OSRetain);
2855 }
2856
2857 /*****
2858 * Minimal validation to initialize. We'll do other validation on the spot.
2859 */
2860 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2861 OSKextLog(this,
2862 kOSKextLogErrorLevel |
2863 kOSKextLogValidationFlag,
2864 "Kext %s error - CFBundleIdentifier over max length %d.",
2865 getIdentifierCString(), KMOD_MAX_NAME - 1);
2866 goto finish;
2867 }
2868
2869 version = compatibleVersion = -1;
2870
2871 versionString = OSDynamicCast(OSString,
2872 getPropertyForHostArch(kCFBundleVersionKey));
2873 if (!versionString) {
2874 OSKextLog(this,
2875 kOSKextLogErrorLevel |
2876 kOSKextLogValidationFlag,
2877 "Kext %s error - CFBundleVersion missing/invalid type.",
2878 getIdentifierCString());
2879 goto finish;
2880 }
2881 versionCString = versionString->getCStringNoCopy();
2882 version = OSKextParseVersionString(versionCString);
2883 if (version < 0) {
2884 OSKextLog(this,
2885 kOSKextLogErrorLevel |
2886 kOSKextLogValidationFlag,
2887 "Kext %s error - CFBundleVersion bad value '%s'.",
2888 getIdentifierCString(), versionCString);
2889 goto finish;
2890 }
2891
2892 compatibleVersion = -1; // set to illegal value for kexts that don't have
2893
2894 compatibleVersionString = OSDynamicCast(OSString,
2895 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2896 if (compatibleVersionString) {
2897 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2898 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2899 if (compatibleVersion < 0) {
2900 OSKextLog(this,
2901 kOSKextLogErrorLevel |
2902 kOSKextLogValidationFlag,
2903 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2904 getIdentifierCString(), compatibleVersionCString);
2905 goto finish;
2906 }
2907
2908 if (compatibleVersion > version) {
2909 OSKextLog(this,
2910 kOSKextLogErrorLevel |
2911 kOSKextLogValidationFlag,
2912 "Kext %s error - %s %s > %s %s (must be <=).",
2913 getIdentifierCString(),
2914 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2915 kCFBundleVersionKey, versionCString);
2916 goto finish;
2917 }
2918 }
2919
2920 /* Check to see if this kext is in exclude list */
2921 if (isInExcludeList()) {
2922 OSKextLog(this,
2923 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2924 "Kext %s is in exclude list, not loadable",
2925 getIdentifierCString());
2926 goto finish;
2927 }
2928
2929 /* Set flags for later use if the infoDict gets flushed. We only
2930 * check for true values, not false ones(!)
2931 */
2932 scratchBool = OSDynamicCast(OSBoolean,
2933 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2934 if (scratchBool == kOSBooleanTrue) {
2935 flags.interface = 1;
2936 }
2937
2938 scratchBool = OSDynamicCast(OSBoolean,
2939 getPropertyForHostArch(kOSKernelResourceKey));
2940 if (scratchBool == kOSBooleanTrue) {
2941 flags.kernelComponent = 1;
2942 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2943 flags.started = 1;
2944
2945 /* A kernel component has one implicit dependency on the kernel.
2946 */
2947 flags.hasAllDependencies = 1;
2948 }
2949
2950 /* Make sure common string values in personalities are uniqued to OSSymbols.
2951 */
2952 scratchDict = OSDynamicCast(OSDictionary,
2953 getPropertyForHostArch(kIOKitPersonalitiesKey));
2954 if (scratchDict) {
2955 uniquePersonalityProperties(scratchDict);
2956 }
2957
2958 result = true;
2959
2960 finish:
2961
2962 return result;
2963 }
2964
2965 /*********************************************************************
2966 * Not used for prelinked kernel boot as there is no unrelocated
2967 * executable.
2968 *********************************************************************/
2969 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)2970 OSKext::setExecutable(
2971 OSData * anExecutable,
2972 OSData * externalData,
2973 bool externalDataIsMkext)
2974 {
2975 bool result = false;
2976 const char * executableKey = NULL; // do not free
2977
2978 if (!anExecutable) {
2979 infoDict->removeObject(_kOSKextExecutableKey);
2980 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2981 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2982 result = true;
2983 goto finish;
2984 }
2985
2986 if (infoDict->getObject(_kOSKextExecutableKey) ||
2987 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2988 panic("Attempt to set an executable on a kext "
2989 "that already has one (%s).",
2990 getIdentifierCString());
2991 goto finish;
2992 }
2993
2994 if (externalDataIsMkext) {
2995 executableKey = _kOSKextMkextExecutableReferenceKey;
2996 } else {
2997 executableKey = _kOSKextExecutableKey;
2998 }
2999
3000 if (anExecutable) {
3001 infoDict->setObject(executableKey, anExecutable);
3002 if (externalData) {
3003 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
3004 }
3005 }
3006
3007 result = true;
3008
3009 finish:
3010 return result;
3011 }
3012
3013 /*********************************************************************
3014 *********************************************************************/
3015 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)3016 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3017 {
3018 OSObject * value = NULL; // do not release
3019 OSString * stringValue = NULL; // do not release
3020 OSSharedPtr<const OSSymbol> symbolValue;
3021
3022 value = dict->getObject(key);
3023 if (!value) {
3024 goto finish;
3025 }
3026 if (OSDynamicCast(OSSymbol, value)) {
3027 /* this is already an OSSymbol: we're good */
3028 goto finish;
3029 }
3030
3031 stringValue = OSDynamicCast(OSString, value);
3032 if (!stringValue) {
3033 goto finish;
3034 }
3035
3036 symbolValue = OSSymbol::withString(stringValue);
3037 if (!symbolValue) {
3038 goto finish;
3039 }
3040
3041 dict->setObject(key, symbolValue.get());
3042
3043 finish:
3044 return;
3045 }
3046
3047 /*********************************************************************
3048 *********************************************************************/
3049 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)3050 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3051 {
3052 OSObject * value = NULL; // do not release
3053 OSString * stringValue = NULL; // do not release
3054 OSSharedPtr<const OSSymbol> symbolValue;
3055
3056 value = dict->getObject(key);
3057 if (!value) {
3058 goto finish;
3059 }
3060 if (OSDynamicCast(OSSymbol, value)) {
3061 /* this is already an OSSymbol: we're good */
3062 goto finish;
3063 }
3064
3065 stringValue = OSDynamicCast(OSString, value);
3066 if (!stringValue) {
3067 goto finish;
3068 }
3069
3070 symbolValue = OSSymbol::withString(stringValue);
3071 if (!symbolValue) {
3072 goto finish;
3073 }
3074
3075 dict->setObject(key, symbolValue.get());
3076
3077 finish:
3078 return;
3079 }
3080
3081 void
uniquePersonalityProperties(OSDictionary * personalityDict)3082 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3083 {
3084 OSKext::uniquePersonalityProperties(personalityDict, true);
3085 }
3086
3087 /*********************************************************************
3088 * Replace common personality property values with uniqued instances
3089 * to save on wired memory.
3090 *********************************************************************/
3091 /* static */
3092 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)3093 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3094 {
3095 /* Properties every personality has.
3096 */
3097 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
3098 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
3099 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
3100 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3101 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
3102 } else if (defaultAddKernelBundleIdentifier) {
3103 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
3104 }
3105
3106 /* Other commonly used properties.
3107 */
3108 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
3109 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
3110 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
3111
3112 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
3113 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
3114 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
3115 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
3116 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
3117 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
3118 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
3119 uniqueStringPlistProperty(personalityDict, "Vendor");
3120 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
3121 uniqueStringPlistProperty(personalityDict, "Vendor Name");
3122 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
3123 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
3124 uniqueStringPlistProperty(personalityDict, "idProduct");
3125
3126 return;
3127 }
3128
3129 /*********************************************************************
3130 *********************************************************************/
3131 void
free(void)3132 OSKext::free(void)
3133 {
3134 if (isLoaded()) {
3135 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3136 }
3137
3138 if (isDriverKit()) {
3139 if (dextLaunchedCount > 0) {
3140 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3141 }
3142 }
3143
3144 infoDict.reset();
3145 bundleID.reset();
3146 path.reset();
3147 executableRelPath.reset();
3148 userExecutableRelPath.reset();
3149 dependencies.reset();
3150 linkedExecutable.reset();
3151 metaClasses.reset();
3152 interfaceUUID.reset();
3153 driverKitUUID.reset();
3154 dextStatistics.reset();
3155 dextUniqueID.reset();
3156
3157 if (isInterface() && kmod_info) {
3158 kfree_type(kmod_info_t, kmod_info);
3159 }
3160
3161 super::free();
3162 return;
3163 }
3164
3165 #if PRAGMA_MARK
3166 #pragma mark Mkext files
3167 #endif
3168
3169 #if CONFIG_KXLD
3170 /*
3171 * mkext archives are really only relevant on kxld-enabled kernels.
3172 * Without a dynamic kernel linker, we don't need to support any mkexts.
3173 */
3174
3175 /*********************************************************************
3176 *********************************************************************/
3177 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)3178 OSKext::readMkextArchive(OSData * mkextData,
3179 uint32_t * checksumPtr)
3180 {
3181 OSReturn result = kOSKextReturnBadData;
3182 uint32_t mkextLength = 0;
3183 mkext_header * mkextHeader = NULL; // do not free
3184 uint32_t mkextVersion = 0;
3185
3186 /* Note default return of kOSKextReturnBadData above.
3187 */
3188 mkextLength = mkextData->getLength();
3189 if (mkextLength < sizeof(mkext_basic_header)) {
3190 OSKextLog(/* kext */ NULL,
3191 kOSKextLogErrorLevel |
3192 kOSKextLogArchiveFlag,
3193 "Mkext archive too small to be valid.");
3194 goto finish;
3195 }
3196
3197 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3198
3199 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3200 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3201 OSKextLog(/* kext */ NULL,
3202 kOSKextLogErrorLevel |
3203 kOSKextLogArchiveFlag,
3204 "Mkext archive has invalid magic or signature.");
3205 goto finish;
3206 }
3207
3208 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3209 OSKextLog(/* kext */ NULL,
3210 kOSKextLogErrorLevel |
3211 kOSKextLogArchiveFlag,
3212 "Mkext archive recorded length doesn't match actual file length.");
3213 goto finish;
3214 }
3215
3216 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3217
3218 if (mkextVersion == MKEXT_VERS_2) {
3219 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3220 } else {
3221 OSKextLog(/* kext */ NULL,
3222 kOSKextLogErrorLevel |
3223 kOSKextLogArchiveFlag,
3224 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3225 result = kOSKextReturnUnsupported;
3226 }
3227
3228 finish:
3229 return result;
3230 }
3231
3232 /*********************************************************************
3233 * Assumes magic, signature, version, length have been checked.
3234 * xxx - need to add further bounds checking for each file entry
3235 *
3236 * Should keep track of all kexts created so far, and if we hit a
3237 * fatal error halfway through, remove those kexts. If we've dropped
3238 * an older version that had already been read, whoops! Might want to
3239 * add a level of buffering?
3240 *********************************************************************/
3241 /* static */
3242 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3243 OSKext::readMkext2Archive(
3244 OSData * mkextData,
3245 OSDictionary ** mkextPlistOut,
3246 uint32_t * checksumPtr)
3247 {
3248 OSReturn result = kOSReturnError;
3249 uint32_t mkextLength;
3250 mkext2_header * mkextHeader = NULL; // do not free
3251 void * mkextEnd = NULL; // do not free
3252 uint32_t mkextVersion;
3253 uint8_t * crc_address = NULL;
3254 size_t crc_buffer_size = 0;
3255 uint32_t checksum;
3256 uint32_t mkextPlistOffset;
3257 uint32_t mkextPlistCompressedSize;
3258 char * mkextPlistEnd = NULL; // do not free
3259 uint32_t mkextPlistFullSize;
3260 OSSharedPtr<OSString> errorString;
3261 OSSharedPtr<OSData> mkextPlistUncompressedData;
3262 const char * mkextPlistDataBuffer = NULL; // do not free
3263 OSSharedPtr<OSObject> parsedXML;
3264 OSDictionary * mkextPlist = NULL; // do not release
3265 OSArray * mkextInfoDictArray = NULL; // do not release
3266 uint32_t count, i;
3267 kc_format_t kc_format;
3268
3269 if (!PE_get_primary_kc_format(&kc_format)) {
3270 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3271 "Unable to determine primary KC format");
3272 goto finish;
3273 }
3274
3275 mkextLength = mkextData->getLength();
3276 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3277 mkextEnd = (char *)mkextHeader + mkextLength;
3278 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3279
3280 crc_address = (u_int8_t *)&mkextHeader->version;
3281 crc_buffer_size = (uintptr_t)mkextHeader +
3282 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3283 if (crc_buffer_size > INT32_MAX) {
3284 OSKextLog(/* kext */ NULL,
3285 kOSKextLogErrorLevel |
3286 kOSKextLogArchiveFlag,
3287 "Mkext archive size is too large (%lu > INT32_MAX).",
3288 crc_buffer_size);
3289 result = kOSKextReturnBadData;
3290 goto finish;
3291 }
3292 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3293
3294 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3295 OSKextLog(/* kext */ NULL,
3296 kOSKextLogErrorLevel |
3297 kOSKextLogArchiveFlag,
3298 "Mkext archive has bad checksum.");
3299 result = kOSKextReturnBadData;
3300 goto finish;
3301 }
3302
3303 if (checksumPtr) {
3304 *checksumPtr = checksum;
3305 }
3306
3307 /* Check that the CPU type & subtype match that of the running kernel. */
3308 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3309 OSKextLog(/* kext */ NULL,
3310 kOSKextLogErrorLevel |
3311 kOSKextLogArchiveFlag,
3312 "Mkext archive must have a specific CPU type.");
3313 result = kOSKextReturnBadData;
3314 goto finish;
3315 } else {
3316 if ((UInt32)_mh_execute_header.cputype !=
3317 MKEXT_GET_CPUTYPE(mkextHeader)) {
3318 OSKextLog(/* kext */ NULL,
3319 kOSKextLogErrorLevel |
3320 kOSKextLogArchiveFlag,
3321 "Mkext archive does not match the running kernel's CPU type.");
3322 result = kOSKextReturnArchNotFound;
3323 goto finish;
3324 }
3325 }
3326
3327 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3328 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3329 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3330 mkextPlistCompressedSize;
3331 if (mkextPlistEnd > mkextEnd) {
3332 OSKextLog(/* kext */ NULL,
3333 kOSKextLogErrorLevel |
3334 kOSKextLogArchiveFlag,
3335 "Mkext archive file overrun.");
3336 result = kOSKextReturnBadData;
3337 }
3338
3339 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3340 if (mkextPlistCompressedSize) {
3341 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3342 (UInt8 *)mkextHeader + mkextPlistOffset,
3343 "plist",
3344 mkextPlistCompressedSize, mkextPlistFullSize);
3345 if (!mkextPlistUncompressedData) {
3346 goto finish;
3347 }
3348 mkextPlistDataBuffer = (const char *)
3349 mkextPlistUncompressedData->getBytesNoCopy();
3350 } else {
3351 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3352 }
3353
3354 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3355 */
3356 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3357 if (parsedXML) {
3358 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3359 }
3360 if (!mkextPlist) {
3361 const char * errorCString = "(unknown error)";
3362
3363 if (errorString && errorString->getCStringNoCopy()) {
3364 errorCString = errorString->getCStringNoCopy();
3365 } else if (parsedXML) {
3366 errorCString = "not a dictionary";
3367 }
3368 OSKextLog(/* kext */ NULL,
3369 kOSKextLogErrorLevel |
3370 kOSKextLogArchiveFlag,
3371 "Error unserializing mkext plist: %s.", errorCString);
3372 goto finish;
3373 }
3374
3375 mkextInfoDictArray = OSDynamicCast(OSArray,
3376 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3377 if (!mkextInfoDictArray) {
3378 OSKextLog(/* kext */ NULL,
3379 kOSKextLogErrorLevel |
3380 kOSKextLogArchiveFlag,
3381 "Mkext archive contains no kext info dictionaries.");
3382 goto finish;
3383 }
3384
3385 count = mkextInfoDictArray->getCount();
3386 for (i = 0; i < count; i++) {
3387 OSDictionary * infoDict;
3388
3389
3390 infoDict = OSDynamicCast(OSDictionary,
3391 mkextInfoDictArray->getObject(i));
3392
3393 /* Create the kext for the entry, then release it, because the
3394 * kext system keeps them around until explicitly removed.
3395 * Any creation/registration failures are already logged for us.
3396 */
3397 if (infoDict) {
3398 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3399
3400 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3401 if (kc_format == KCFormatFileset &&
3402 newKext &&
3403 !(newKext->isPrelinked()) &&
3404 newKext->declaresExecutable()) {
3405 result = kOSReturnError;
3406 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3407 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3408
3409 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3410 "Dynamic loading of kext denied for kext %s\n",
3411 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3412 goto finish;
3413 }
3414 }
3415 }
3416
3417 /* If the caller needs the plist, hand them back our copy
3418 */
3419 if (mkextPlistOut) {
3420 *mkextPlistOut = mkextPlist;
3421 parsedXML.detach();
3422 }
3423
3424 /* Even if we didn't keep any kexts from the mkext, we may have a load
3425 * request to process, so we are successful (no errors occurred).
3426 */
3427 result = kOSReturnSuccess;
3428
3429 finish:
3430 return result;
3431 }
3432
3433 /* static */
3434 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3435 OSKext::readMkext2Archive(
3436 OSData * mkextData,
3437 OSSharedPtr<OSDictionary> &mkextPlistOut,
3438 uint32_t * checksumPtr)
3439 {
3440 OSDictionary * mkextPlist = NULL;
3441 OSReturn ret;
3442
3443 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3444 &mkextPlist,
3445 checksumPtr))) {
3446 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3447 }
3448 return ret;
3449 }
3450
3451 /*********************************************************************
3452 *********************************************************************/
3453 /* static */
3454 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3455 OSKext::withMkext2Info(
3456 OSDictionary * anInfoDict,
3457 OSData * mkextData)
3458 {
3459 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3460
3461 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3462 return NULL;
3463 }
3464
3465 return newKext;
3466 }
3467
3468 /*********************************************************************
3469 *********************************************************************/
3470 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3471 OSKext::initWithMkext2Info(
3472 OSDictionary * anInfoDict,
3473 OSData * mkextData)
3474 {
3475 bool result = false;
3476 OSString * kextPath = NULL; // do not release
3477 OSNumber * executableOffsetNum = NULL; // do not release
3478 OSSharedPtr<OSData> executable;
3479
3480 if (anInfoDict == NULL || !super::init()) {
3481 goto finish;
3482 }
3483
3484 /* Get the path. Don't look for an arch-specific path property.
3485 */
3486 kextPath = OSDynamicCast(OSString,
3487 anInfoDict->getObject(kMKEXTBundlePathKey));
3488
3489 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3490 goto finish;
3491 }
3492
3493 /* If we have a path to the executable, save it.
3494 */
3495 executableRelPath.reset(OSDynamicCast(OSString,
3496 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3497
3498 /* Don't need the paths to be in the info dictionary any more.
3499 */
3500 anInfoDict->removeObject(kMKEXTBundlePathKey);
3501 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3502
3503 executableOffsetNum = OSDynamicCast(OSNumber,
3504 infoDict->getObject(kMKEXTExecutableKey));
3505 if (executableOffsetNum) {
3506 executable = createMkext2FileEntry(mkextData,
3507 executableOffsetNum, "executable");
3508 infoDict->removeObject(kMKEXTExecutableKey);
3509 if (!executable) {
3510 goto finish;
3511 }
3512 if (!setExecutable(executable.get(), mkextData, true)) {
3513 goto finish;
3514 }
3515 }
3516
3517 result = (registerIdentifier() == kOSKextInitialized);
3518 finish:
3519 return result;
3520 }
3521
3522 /*********************************************************************
3523 *********************************************************************/
3524 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3525 OSKext::createMkext2FileEntry(
3526 OSData * mkextData,
3527 OSNumber * offsetNum,
3528 const char * name)
3529 {
3530 OSSharedPtr<OSData> result;
3531 MkextEntryRef entryRef;
3532 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3533 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3534
3535 result = OSData::withCapacity(sizeof(entryRef));
3536 if (!result) {
3537 goto finish;
3538 }
3539
3540 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3541 entryRef.fileinfo = mkextBuffer + entryOffset;
3542 if (!result->appendValue(entryRef)) {
3543 result.reset();
3544 goto finish;
3545 }
3546
3547 finish:
3548 if (!result) {
3549 OSKextLog(this,
3550 kOSKextLogErrorLevel |
3551 kOSKextLogArchiveFlag,
3552 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3553 name, getIdentifierCString());
3554 }
3555 return result;
3556 }
3557
3558 /*********************************************************************
3559 *********************************************************************/
3560 extern "C" {
3561 static void * z_alloc(void *, u_int items, u_int size);
3562 static void z_free(void *, void *ptr);
3563
3564 typedef struct z_mem {
3565 uint32_t alloc_size;
3566 uint8_t data[0];
3567 } z_mem;
3568
3569 /*
3570 * Space allocation and freeing routines for use by zlib routines.
3571 */
3572 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3573 z_alloc(void * notused __unused, u_int num_items, u_int size)
3574 {
3575 void * result = NULL;
3576 z_mem * zmem = NULL;
3577
3578 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3579 //Check for overflow due to multiplication
3580 if (total > UINT32_MAX) {
3581 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3582 notused, num_items, size, num_items, size);
3583 }
3584
3585 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3586 //Check for overflow due to addition
3587 if (allocSize64 > UINT32_MAX) {
3588 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3589 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3590 }
3591 uint32_t allocSize = (uint32_t)allocSize64;
3592
3593 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3594 VM_KERN_MEMORY_OSKEXT);
3595 if (!zmem) {
3596 goto finish;
3597 }
3598 zmem->alloc_size = allocSize;
3599 result = (void *)&(zmem->data);
3600 finish:
3601 return result;
3602 }
3603
3604 void
z_free(void * notused __unused,void * ptr)3605 z_free(void * notused __unused, void * ptr)
3606 {
3607 uint32_t * skipper = (uint32_t *)ptr - 1;
3608 z_mem * zmem = (z_mem *)skipper;
3609 kfree_data(zmem, zmem->alloc_size);
3610 }
3611 };
3612
3613 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3614 OSKext::extractMkext2FileData(
3615 UInt8 * data,
3616 const char * name,
3617 uint32_t compressedSize,
3618 uint32_t fullSize)
3619 {
3620 OSSharedPtr<OSData> result;
3621 OSSharedPtr<OSData> uncompressedData; // release on error
3622
3623 uint8_t * uncompressedDataBuffer = NULL; // do not free
3624 unsigned long uncompressedSize;
3625 z_stream zstream;
3626 bool zstream_inited = false;
3627 int zlib_result;
3628
3629 /* If the file isn't compressed, we want to make a copy
3630 * so that we don't have the tie to the larger mkext file buffer any more.
3631 */
3632 if (!compressedSize) {
3633 uncompressedData = OSData::withBytes(data, fullSize);
3634 // xxx - no check for failure?
3635 result = uncompressedData;
3636 goto finish;
3637 }
3638
3639 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3640 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3641 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3642 /* How's this for cheesy? The kernel is only asked to extract
3643 * kext plists so we tailor the log messages.
3644 */
3645 if (isKernel()) {
3646 OSKextLog(this,
3647 kOSKextLogErrorLevel |
3648 kOSKextLogArchiveFlag,
3649 "Allocation failure extracting %s from mkext.", name);
3650 } else {
3651 OSKextLog(this,
3652 kOSKextLogErrorLevel |
3653 kOSKextLogArchiveFlag,
3654 "Allocation failure extracting %s from mkext for kext %s.",
3655 name, getIdentifierCString());
3656 }
3657
3658 goto finish;
3659 }
3660 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3661 if (!uncompressedData) {
3662 if (isKernel()) {
3663 OSKextLog(this,
3664 kOSKextLogErrorLevel |
3665 kOSKextLogArchiveFlag,
3666 "Allocation failure extracting %s from mkext.", name);
3667 } else {
3668 OSKextLog(this,
3669 kOSKextLogErrorLevel |
3670 kOSKextLogArchiveFlag,
3671 "Allocation failure extracting %s from mkext for kext %s.",
3672 name, getIdentifierCString());
3673 }
3674 goto finish;
3675 }
3676 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3677
3678 if (isKernel()) {
3679 OSKextLog(this,
3680 kOSKextLogDetailLevel |
3681 kOSKextLogArchiveFlag,
3682 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3683 name, compressedSize, fullSize);
3684 } else {
3685 OSKextLog(this,
3686 kOSKextLogDetailLevel |
3687 kOSKextLogArchiveFlag,
3688 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3689 getIdentifierCString(), name, compressedSize, fullSize);
3690 }
3691
3692 bzero(&zstream, sizeof(zstream));
3693 zstream.next_in = (UInt8 *)data;
3694 zstream.avail_in = compressedSize;
3695
3696 zstream.next_out = uncompressedDataBuffer;
3697 zstream.avail_out = fullSize;
3698
3699 zstream.zalloc = z_alloc;
3700 zstream.zfree = z_free;
3701
3702 zlib_result = inflateInit(&zstream);
3703 if (Z_OK != zlib_result) {
3704 if (isKernel()) {
3705 OSKextLog(this,
3706 kOSKextLogErrorLevel |
3707 kOSKextLogArchiveFlag,
3708 "Mkext error; zlib inflateInit failed (%d) for %s.",
3709 zlib_result, name);
3710 } else {
3711 OSKextLog(this,
3712 kOSKextLogErrorLevel |
3713 kOSKextLogArchiveFlag,
3714 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3715 getIdentifierCString(), zlib_result, name);
3716 }
3717 goto finish;
3718 } else {
3719 zstream_inited = true;
3720 }
3721
3722 zlib_result = inflate(&zstream, Z_FINISH);
3723
3724 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3725 uncompressedSize = zstream.total_out;
3726 } else {
3727 if (isKernel()) {
3728 OSKextLog(this,
3729 kOSKextLogErrorLevel |
3730 kOSKextLogArchiveFlag,
3731 "Mkext error; zlib inflate failed (%d) for %s.",
3732 zlib_result, name);
3733 } else {
3734 OSKextLog(this,
3735 kOSKextLogErrorLevel |
3736 kOSKextLogArchiveFlag,
3737 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3738 getIdentifierCString(), zlib_result, name);
3739 }
3740 if (zstream.msg) {
3741 OSKextLog(this,
3742 kOSKextLogErrorLevel |
3743 kOSKextLogArchiveFlag,
3744 "zlib error: %s.", zstream.msg);
3745 }
3746 goto finish;
3747 }
3748
3749 if (uncompressedSize != fullSize) {
3750 if (isKernel()) {
3751 OSKextLog(this,
3752 kOSKextLogErrorLevel |
3753 kOSKextLogArchiveFlag,
3754 "Mkext error; zlib inflate discrepancy for %s, "
3755 "uncompressed size != original size.", name);
3756 } else {
3757 OSKextLog(this,
3758 kOSKextLogErrorLevel |
3759 kOSKextLogArchiveFlag,
3760 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3761 "uncompressed size != original size.",
3762 getIdentifierCString(), name);
3763 }
3764 goto finish;
3765 }
3766
3767 result = os::move(uncompressedData);
3768
3769 finish:
3770 /* Don't bother checking return, nothing we can do on fail.
3771 */
3772 if (zstream_inited) {
3773 inflateEnd(&zstream);
3774 }
3775
3776 return result;
3777 }
3778
3779 /*********************************************************************
3780 *********************************************************************/
3781 /* static */
3782 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3783 OSKext::loadFromMkext(
3784 OSKextLogSpec clientLogFilter,
3785 char * mkextBuffer,
3786 uint32_t mkextBufferLength,
3787 char ** logInfoOut,
3788 uint32_t * logInfoLengthOut)
3789 {
3790 OSReturn result = kOSReturnError;
3791 OSReturn tempResult = kOSReturnError;
3792
3793 OSSharedPtr<OSData> mkextData;
3794 OSSharedPtr<OSDictionary> mkextPlist;
3795
3796 OSSharedPtr<OSArray> logInfoArray;
3797 OSSharedPtr<OSSerialize> serializer;
3798
3799 OSString * predicate = NULL; // do not release
3800 OSDictionary * requestArgs = NULL; // do not release
3801
3802 OSString * kextIdentifier = NULL; // do not release
3803 OSNumber * startKextExcludeNum = NULL; // do not release
3804 OSNumber * startMatchingExcludeNum = NULL; // do not release
3805 OSBoolean * delayAutounloadBool = NULL; // do not release
3806 OSArray * personalityNames = NULL; // do not release
3807
3808 /* Default values for these two options: regular autounload behavior,
3809 * load all kexts, send no personalities.
3810 */
3811 Boolean delayAutounload = false;
3812 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3813 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3814
3815 IORecursiveLockLock(sKextLock);
3816
3817 if (logInfoOut) {
3818 *logInfoOut = NULL;
3819 *logInfoLengthOut = 0;
3820 }
3821
3822 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3823
3824 OSKextLog(/* kext */ NULL,
3825 kOSKextLogDebugLevel |
3826 kOSKextLogIPCFlag,
3827 "Received kext load request from user space.");
3828
3829 /* Regardless of processing, the fact that we have gotten here means some
3830 * user-space program is up and talking to us, so we'll switch our kext
3831 * registration to reflect that.
3832 */
3833 if (!sUserLoadsActive) {
3834 OSKextLog(/* kext */ NULL,
3835 kOSKextLogProgressLevel |
3836 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3837 "Switching to late startup (user-space) kext loading policy.");
3838
3839 sUserLoadsActive = true;
3840 }
3841
3842 if (!sLoadEnabled) {
3843 OSKextLog(/* kext */ NULL,
3844 kOSKextLogErrorLevel |
3845 kOSKextLogLoadFlag,
3846 "Kext loading is disabled.");
3847 result = kOSKextReturnDisabled;
3848 goto finish;
3849 }
3850
3851 /* Note that we do not set a dealloc function on this OSData
3852 * object! No references to it can remain after the loadFromMkext()
3853 * call since we are in a MIG function, and will vm_deallocate()
3854 * the buffer.
3855 */
3856 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3857 mkextBufferLength);
3858 if (!mkextData) {
3859 OSKextLog(/* kext */ NULL,
3860 kOSKextLogErrorLevel |
3861 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3862 "Failed to create wrapper for kext load request.");
3863 result = kOSKextReturnNoMemory;
3864 goto finish;
3865 }
3866
3867 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3868 if (result != kOSReturnSuccess) {
3869 OSKextLog(/* kext */ NULL,
3870 kOSKextLogErrorLevel |
3871 kOSKextLogLoadFlag,
3872 "Failed to read kext load request.");
3873 goto finish;
3874 }
3875
3876 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3877 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3878 OSKextLog(/* kext */ NULL,
3879 kOSKextLogErrorLevel |
3880 kOSKextLogLoadFlag,
3881 "Received kext load request with no predicate; skipping.");
3882 result = kOSKextReturnInvalidArgument;
3883 goto finish;
3884 }
3885
3886 requestArgs = OSDynamicCast(OSDictionary,
3887 mkextPlist->getObject(kKextRequestArgumentsKey));
3888 if (!requestArgs || !requestArgs->getCount()) {
3889 OSKextLog(/* kext */ NULL,
3890 kOSKextLogErrorLevel |
3891 kOSKextLogLoadFlag,
3892 "Received kext load request with no arguments.");
3893 result = kOSKextReturnInvalidArgument;
3894 goto finish;
3895 }
3896
3897 kextIdentifier = OSDynamicCast(OSString,
3898 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3899
3900 if (!kextIdentifier) {
3901 OSKextLog(/* kext */ NULL,
3902 kOSKextLogErrorLevel |
3903 kOSKextLogLoadFlag,
3904 "Received kext load request with no kext identifier.");
3905 result = kOSKextReturnInvalidArgument;
3906 goto finish;
3907 }
3908
3909 startKextExcludeNum = OSDynamicCast(OSNumber,
3910 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3911 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3912 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3913 delayAutounloadBool = OSDynamicCast(OSBoolean,
3914 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3915 personalityNames = OSDynamicCast(OSArray,
3916 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3917
3918 if (delayAutounloadBool) {
3919 delayAutounload = delayAutounloadBool->getValue();
3920 }
3921 if (startKextExcludeNum) {
3922 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3923 }
3924 if (startMatchingExcludeNum) {
3925 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3926 }
3927
3928 OSKextLog(/* kext */ NULL,
3929 kOSKextLogProgressLevel |
3930 kOSKextLogIPCFlag,
3931 "Received request from user space to load kext %s.",
3932 kextIdentifier->getCStringNoCopy());
3933
3934 /* Load the kext, with no deferral, since this is a load from outside
3935 * the kernel.
3936 * xxx - Would like a better way to handle the default values for the
3937 * xxx - start/match opt args.
3938 */
3939 result = OSKext::loadKextWithIdentifier(
3940 kextIdentifier,
3941 /* kextRef */ NULL,
3942 /* allowDefer */ false,
3943 delayAutounload,
3944 startKextExcludeLevel,
3945 startMatchingExcludeLevel,
3946 personalityNames);
3947 if (result != kOSReturnSuccess) {
3948 goto finish;
3949 }
3950 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3951 * for matching via a separate IOKit calldown.
3952 */
3953
3954 finish:
3955
3956 /* Gather up the collected log messages for user space. Any
3957 * error messages past this call will not make it up as log messages
3958 * but will be in the system log.
3959 */
3960 logInfoArray = OSKext::clearUserSpaceLogFilter();
3961
3962 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3963 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3964 logInfoOut, logInfoLengthOut);
3965 if (tempResult != kOSReturnSuccess) {
3966 result = tempResult;
3967 }
3968 }
3969
3970 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3971
3972 IORecursiveLockUnlock(sKextLock);
3973
3974 /* Note: mkextDataObject will have been retained by every kext w/an
3975 * executable in it. That should all have been flushed out at the
3976 * and of the load operation, but you never know....
3977 */
3978 if (mkextData && mkextData->getRetainCount() > 1) {
3979 OSKextLog(/* kext */ NULL,
3980 kOSKextLogErrorLevel |
3981 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3982 "Kext load request buffer from user space still retained by a kext; "
3983 "probable memory leak.");
3984 }
3985
3986 return result;
3987 }
3988
3989 #endif // CONFIG_KXLD
3990
3991 /*********************************************************************
3992 *********************************************************************/
3993 /* static */
3994 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)3995 OSKext::serializeLogInfo(
3996 OSArray * logInfoArray,
3997 char ** logInfoOut,
3998 uint32_t * logInfoLengthOut)
3999 {
4000 OSReturn result = kOSReturnError;
4001 char * buffer = NULL;
4002 kern_return_t kmem_result = KERN_FAILURE;
4003 OSSharedPtr<OSSerialize> serializer;
4004 char * logInfo = NULL; // returned by reference
4005 uint32_t logInfoLength = 0;
4006
4007 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4008 OSKextLog(/* kext */ NULL,
4009 kOSKextLogErrorLevel |
4010 kOSKextLogIPCFlag,
4011 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4012 /* Bad programmer. */
4013 result = kOSKextReturnInvalidArgument;
4014 goto finish;
4015 }
4016
4017 serializer = OSSerialize::withCapacity(0);
4018 if (!serializer) {
4019 OSKextLog(/* kext */ NULL,
4020 kOSKextLogErrorLevel |
4021 kOSKextLogIPCFlag,
4022 "Failed to create serializer on log info for request from user space.");
4023 /* Incidental error; we're going to (try to) allow the request
4024 * itself to succeed. */
4025 }
4026
4027 if (!logInfoArray->serialize(serializer.get())) {
4028 OSKextLog(/* kext */ NULL,
4029 kOSKextLogErrorLevel |
4030 kOSKextLogIPCFlag,
4031 "Failed to serialize log info for request from user space.");
4032 /* Incidental error; we're going to (try to) allow the request
4033 * itself to succeed. */
4034 } else {
4035 logInfo = serializer->text();
4036 logInfoLength = serializer->getLength();
4037
4038 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
4039 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
4040 if (kmem_result != KERN_SUCCESS) {
4041 OSKextLog(/* kext */ NULL,
4042 kOSKextLogErrorLevel |
4043 kOSKextLogIPCFlag,
4044 "Failed to copy log info for request from user space.");
4045 /* Incidental error; we're going to (try to) allow the request
4046 * to succeed. */
4047 } else {
4048 /* 11981737 - clear uninitialized data in last page */
4049 bzero((void *)(buffer + logInfoLength),
4050 (round_page(logInfoLength) - logInfoLength));
4051 memcpy(buffer, logInfo, logInfoLength);
4052 *logInfoOut = buffer;
4053 *logInfoLengthOut = logInfoLength;
4054 }
4055 }
4056
4057 result = kOSReturnSuccess;
4058 finish:
4059 return result;
4060 }
4061
4062 #if PRAGMA_MARK
4063 #pragma mark Instance Management Methods
4064 #endif
4065 /*********************************************************************
4066 *********************************************************************/
4067 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)4068 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4069 {
4070 OSSharedPtr<OSKext> foundKext;
4071
4072 IORecursiveLockLock(sKextLock);
4073 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4074 IORecursiveLockUnlock(sKextLock);
4075
4076 return foundKext;
4077 }
4078
4079 /*********************************************************************
4080 *********************************************************************/
4081 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)4082 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4083 {
4084 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
4085 }
4086
4087 /*********************************************************************
4088 *********************************************************************/
4089 OSSharedPtr<OSKext>
lookupDextWithIdentifier(OSString * dextIdentifier,OSData * dextUniqueIdentifier)4090 OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4091 {
4092 OSSharedPtr<OSKext> foundDext;
4093 foundDext.reset();
4094
4095 IORecursiveLockLock(sKextLock);
4096 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4097 if (dext != NULL && dext->isDriverKit()) {
4098 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(dextUniqueIdentifier)) {
4099 foundDext.reset(dext, OSRetain);
4100 }
4101 }
4102 IORecursiveLockUnlock(sKextLock);
4103
4104 return foundDext;
4105 }
4106
4107 /*********************************************************************
4108 *********************************************************************/
4109 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)4110 OSKext::lookupKextWithLoadTag(uint32_t aTag)
4111 {
4112 OSSharedPtr<OSKext> foundKext; // returned
4113 uint32_t i, j;
4114 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4115 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4116
4117 IORecursiveLockLock(sKextLock);
4118
4119 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4120 for (i = 0; i < count[j]; i++) {
4121 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4122 if (thisKext->getLoadTag() == aTag) {
4123 foundKext.reset(thisKext, OSRetain);
4124 goto finish;
4125 }
4126 }
4127 }
4128
4129 finish:
4130 IORecursiveLockUnlock(sKextLock);
4131
4132 return foundKext;
4133 }
4134
4135 /*********************************************************************
4136 *********************************************************************/
4137 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)4138 OSKext::lookupKextWithAddress(vm_address_t address)
4139 {
4140 OSSharedPtr<OSKext> foundKext; // returned
4141 uint32_t count, i;
4142 kmod_info_t *kmod_info;
4143 vm_address_t originalAddress;
4144 #if defined(__arm64__)
4145 uint64_t textExecBase;
4146 size_t textExecSize;
4147 #endif /* defined(__arm64__) */
4148
4149 originalAddress = address;
4150 #if __has_feature(ptrauth_calls)
4151 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4152 #endif /* __has_feature(ptrauth_calls) */
4153
4154 IORecursiveLockLock(sKextLock);
4155
4156 count = sLoadedKexts->getCount();
4157 for (i = 0; i < count; i++) {
4158 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4159 if (thisKext == sKernelKext) {
4160 continue;
4161 }
4162 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4163 kmod_info = thisKext->kmod_info;
4164 vm_address_t kext_start = kmod_info->address;
4165 vm_address_t kext_end = kext_start + kmod_info->size;
4166 if ((kext_start <= address) && (address < kext_end)) {
4167 foundKext.reset(thisKext, OSRetain);
4168 goto finish;
4169 }
4170 #if defined(__arm64__)
4171 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4172 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4173 foundKext.reset(thisKext, OSRetain);
4174 goto finish;
4175 }
4176 #endif /* defined (__arm64__) */
4177 }
4178 }
4179 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4180 foundKext.reset(sKernelKext, OSRetain);
4181 goto finish;
4182 }
4183 /*
4184 * DriverKit userspace executables do not have a kernel linkedExecutable,
4185 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4186 * here, so use the original address passed to this method.
4187 *
4188 * This is supposed to be used for logging reasons only. When logd
4189 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4190 * remove it here before checking it against the LoadTag.
4191 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4192 */
4193
4194 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4195 count = sLoadedDriverKitKexts->getCount();
4196 for (i = 0; i < count; i++) {
4197 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4198 if (thisKext->getLoadTag() == address) {
4199 foundKext.reset(thisKext, OSRetain);
4200 }
4201 }
4202
4203 finish:
4204 IORecursiveLockUnlock(sKextLock);
4205
4206 return foundKext;
4207 }
4208
4209 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4210 OSKext::copyKextUUIDForAddress(OSNumber *address)
4211 {
4212 OSSharedPtr<OSData> uuid;
4213 OSSharedPtr<OSKext> kext;
4214
4215 if (!address) {
4216 return NULL;
4217 }
4218
4219 #if CONFIG_MACF
4220 /* Is the calling process allowed to query kext info? */
4221 if (current_task() != kernel_task) {
4222 int macCheckResult = 0;
4223 kauth_cred_t cred = NULL;
4224
4225 cred = kauth_cred_get_with_ref();
4226 macCheckResult = mac_kext_check_query(cred);
4227 kauth_cred_unref(&cred);
4228
4229 if (macCheckResult != 0) {
4230 OSKextLog(/* kext */ NULL,
4231 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4232 "Failed to query kext UUID (MAC policy error 0x%x).",
4233 macCheckResult);
4234 return NULL;
4235 }
4236 }
4237 #endif
4238
4239 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4240 if (slidAddress != 0) {
4241 kext = lookupKextWithAddress(slidAddress);
4242 if (kext) {
4243 uuid = kext->copyTextUUID();
4244 }
4245 }
4246
4247 if (!uuid) {
4248 /*
4249 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4250 * a kext. This might have happened because the log message came from a dext.
4251 *
4252 * Try again with the original address.
4253 */
4254 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4255 if (kext && kext->isDriverKit()) {
4256 uuid = kext->copyTextUUID();
4257 }
4258 }
4259
4260 return uuid;
4261 }
4262
4263 /*********************************************************************
4264 *********************************************************************/
4265 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4266 OSKext::lookupKextWithUUID(uuid_t wanted)
4267 {
4268 OSSharedPtr<OSKext> foundKext; // returned
4269 uint32_t j, i;
4270 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4271 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4272
4273
4274 IORecursiveLockLock(sKextLock);
4275
4276 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4277 for (i = 0; i < count[j]; i++) {
4278 OSKext * thisKext = NULL;
4279
4280 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4281 if (!thisKext) {
4282 continue;
4283 }
4284
4285 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4286 if (!uuid_data) {
4287 continue;
4288 }
4289
4290 uuid_t uuid;
4291 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4292
4293 if (0 == uuid_compare(wanted, uuid)) {
4294 foundKext.reset(thisKext, OSRetain);
4295 goto finish;
4296 }
4297 }
4298 }
4299 finish:
4300 IORecursiveLockUnlock(sKextLock);
4301
4302 return foundKext;
4303 }
4304
4305
4306
4307
4308 /*********************************************************************
4309 *********************************************************************/
4310 /* static */
4311 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4312 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4313 {
4314 bool result = false;
4315 OSKext * foundKext = NULL; // returned
4316
4317 IORecursiveLockLock(sKextLock);
4318
4319 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4320 if (foundKext && foundKext->isLoaded()) {
4321 result = true;
4322 }
4323
4324 IORecursiveLockUnlock(sKextLock);
4325
4326 return result;
4327 }
4328
4329 /*********************************************************************
4330 * xxx - should spawn a separate thread so a kext can safely have
4331 * xxx - itself unloaded.
4332 *********************************************************************/
4333 /* static */
4334 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4335 OSKext::removeKext(
4336 OSKext * aKext,
4337 #if CONFIG_EMBEDDED
4338 __unused
4339 #endif
4340 bool terminateServicesAndRemovePersonalitiesFlag)
4341 {
4342 #if CONFIG_EMBEDDED
4343 if (!aKext->isDriverKit()) {
4344 OSKextLog(aKext,
4345 kOSKextLogErrorLevel |
4346 kOSKextLogKextBookkeepingFlag,
4347 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4348 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4349
4350 return kOSReturnSuccess;
4351 }
4352 #endif /* CONFIG_EMBEDDED */
4353 OSReturn result = kOSKextReturnInUse;
4354 OSKext * checkKext = NULL; // do not release
4355 #if CONFIG_MACF
4356 int macCheckResult = 0;
4357 kauth_cred_t cred = NULL;
4358 #endif
4359
4360 IORecursiveLockLock(sKextLock);
4361
4362 /* If the kext has no identifier, it failed to init
4363 * so isn't in sKextsByID and it isn't loaded.
4364 */
4365 if (!aKext->getIdentifier()) {
4366 result = kOSReturnSuccess;
4367 goto finish;
4368 }
4369
4370 checkKext = OSDynamicCast(OSKext,
4371 sKextsByID->getObject(aKext->getIdentifier()));
4372 if (checkKext != aKext) {
4373 result = kOSKextReturnNotFound;
4374 goto finish;
4375 }
4376
4377 if (aKext->isLoaded() || aKext->isDriverKit()) {
4378 #if CONFIG_MACF
4379 if (current_task() != kernel_task) {
4380 cred = kauth_cred_get_with_ref();
4381 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4382 kauth_cred_unref(&cred);
4383 }
4384
4385 if (macCheckResult != 0) {
4386 result = kOSReturnError;
4387 OSKextLog(aKext,
4388 kOSKextLogErrorLevel |
4389 kOSKextLogKextBookkeepingFlag,
4390 "Failed to remove kext %s (MAC policy error 0x%x).",
4391 aKext->getIdentifierCString(), macCheckResult);
4392 goto finish;
4393 }
4394 #endif
4395
4396 /* make sure there are no resource requests in flight - 17187548 */
4397 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4398 goto finish;
4399 }
4400 if (aKext->flags.unloadUnsupported) {
4401 result = kOSKextReturnInUse;
4402 OSKextLog(aKext,
4403 kOSKextLogErrorLevel |
4404 kOSKextLogKextBookkeepingFlag,
4405 "Can't remove kext %s; unsupported by cache.",
4406 aKext->getIdentifierCString());
4407 goto finish;
4408 }
4409
4410 /* If we are terminating, send the request to the IOCatalogue
4411 * (which will actually call us right back but that's ok we have
4412 * a recursive lock don't you know) but do not ask the IOCatalogue
4413 * to call back with an unload, we'll do that right here.
4414 */
4415 if (terminateServicesAndRemovePersonalitiesFlag) {
4416 result = gIOCatalogue->terminateDriversForModule(
4417 aKext->getIdentifierCString(), /* unload */ false);
4418 if (result != kOSReturnSuccess) {
4419 OSKextLog(aKext,
4420 kOSKextLogErrorLevel |
4421 kOSKextLogKextBookkeepingFlag,
4422 "Can't remove kext %s; services failed to terminate - 0x%x.",
4423 aKext->getIdentifierCString(), result);
4424 goto finish;
4425 }
4426 }
4427
4428 result = aKext->unload();
4429 if (result != kOSReturnSuccess) {
4430 OSKextLog(aKext,
4431 kOSKextLogErrorLevel |
4432 kOSKextLogKextBookkeepingFlag,
4433 "Can't remove kext %s; kext failed to unload - 0x%x.",
4434 aKext->getIdentifierCString(), result);
4435 goto finish;
4436 }
4437 }
4438
4439 /* Remove personalities as requested. This is a bit redundant for a loaded
4440 * kext as IOCatalogue::terminateDriversForModule() removes driver
4441 * personalities, but it doesn't restart matching, which we always want
4442 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4443 * that happens.
4444 */
4445 if (terminateServicesAndRemovePersonalitiesFlag) {
4446 aKext->removePersonalitiesFromCatalog();
4447 }
4448
4449 if (aKext->isInFileset()) {
4450 OSKextLog(aKext,
4451 kOSKextLogProgressLevel |
4452 kOSKextLogKextBookkeepingFlag,
4453 "Fileset kext %s unloaded.",
4454 aKext->getIdentifierCString());
4455 } else {
4456 OSKextLog(aKext,
4457 kOSKextLogProgressLevel |
4458 kOSKextLogKextBookkeepingFlag,
4459 "Removing kext %s.",
4460 aKext->getIdentifierCString());
4461
4462 sKextsByID->removeObject(aKext->getIdentifier());
4463 }
4464 result = kOSReturnSuccess;
4465
4466 finish:
4467 IORecursiveLockUnlock(sKextLock);
4468 return result;
4469 }
4470
4471 /*********************************************************************
4472 *********************************************************************/
4473 /* static */
4474 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4475 OSKext::removeKextWithIdentifier(
4476 const char * kextIdentifier,
4477 bool terminateServicesAndRemovePersonalitiesFlag)
4478 {
4479 OSReturn result = kOSReturnError;
4480
4481 IORecursiveLockLock(sKextLock);
4482
4483 OSKext * aKext = OSDynamicCast(OSKext,
4484 sKextsByID->getObject(kextIdentifier));
4485 if (!aKext) {
4486 result = kOSKextReturnNotFound;
4487 OSKextLog(/* kext */ NULL,
4488 kOSKextLogErrorLevel |
4489 kOSKextLogKextBookkeepingFlag,
4490 "Can't remove kext %s - not found.",
4491 kextIdentifier);
4492 goto finish;
4493 }
4494
4495 result = OSKext::removeKext(aKext,
4496 terminateServicesAndRemovePersonalitiesFlag);
4497
4498 finish:
4499 IORecursiveLockUnlock(sKextLock);
4500
4501 return result;
4502 }
4503
4504 /*********************************************************************
4505 *********************************************************************/
4506 /* static */
4507 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4508 OSKext::removeKextWithLoadTag(
4509 OSKextLoadTag loadTag,
4510 bool terminateServicesAndRemovePersonalitiesFlag)
4511 {
4512 OSReturn result = kOSReturnError;
4513 OSKext * foundKext = NULL;
4514 uint32_t i, j;
4515 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4516 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4517
4518
4519 IORecursiveLockLock(sKextLock);
4520
4521 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4522 for (i = 0; i < count[j]; i++) {
4523 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4524 if (thisKext->loadTag == loadTag) {
4525 foundKext = thisKext;
4526 break;
4527 }
4528 }
4529 }
4530
4531 if (!foundKext) {
4532 result = kOSKextReturnNotFound;
4533 OSKextLog(/* kext */ NULL,
4534 kOSKextLogErrorLevel |
4535 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4536 "Can't remove kext with load tag %d - not found.",
4537 loadTag);
4538 goto finish;
4539 }
4540
4541 result = OSKext::removeKext(foundKext,
4542 terminateServicesAndRemovePersonalitiesFlag);
4543
4544 finish:
4545 IORecursiveLockUnlock(sKextLock);
4546
4547 return result;
4548 }
4549
4550 /*********************************************************************
4551 *********************************************************************/
4552 OSSharedPtr<OSDictionary>
copyKexts(void)4553 OSKext::copyKexts(void)
4554 {
4555 OSSharedPtr<OSDictionary> result;
4556
4557 IORecursiveLockLock(sKextLock);
4558 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4559 IORecursiveLockUnlock(sKextLock);
4560
4561 return result;
4562 }
4563
4564 /*********************************************************************
4565 *********************************************************************/
4566 #define BOOTER_KEXT_PREFIX "Driver-"
4567
4568 typedef struct _DeviceTreeBuffer {
4569 uint32_t paddr;
4570 uint32_t length;
4571 } _DeviceTreeBuffer;
4572
4573 /*********************************************************************
4574 * Create a dictionary of excluded kexts from the given booter data.
4575 *********************************************************************/
4576 /* static */
4577 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4578 OSKext::createExcludeListFromBooterData(
4579 OSDictionary * theDictionary,
4580 OSCollectionIterator * theIterator )
4581 {
4582 OSString * deviceTreeName = NULL; // do not release
4583 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4584 char * booterDataPtr = NULL; // do not release
4585 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4586 char * infoDictAddr = NULL; // do not release
4587 OSSharedPtr<OSObject> parsedXML;
4588 OSDictionary * theInfoDict = NULL; // do not release
4589
4590 theIterator->reset();
4591
4592 /* look for AppleKextExcludeList.kext */
4593 while ((deviceTreeName =
4594 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4595 const char * devTreeNameCString;
4596 OSData * deviceTreeEntry; // do not release
4597 OSString * myBundleID; // do not release
4598
4599 deviceTreeEntry =
4600 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4601 if (!deviceTreeEntry) {
4602 continue;
4603 }
4604
4605 /* Make sure it is a kext */
4606 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4607 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4608 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4609 OSKextLog(NULL,
4610 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4611 "\"%s\" not a kext",
4612 devTreeNameCString);
4613 continue;
4614 }
4615
4616 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4617 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4618 if (!deviceTreeBuffer) {
4619 continue;
4620 }
4621
4622 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4623 if (!booterDataPtr) {
4624 continue;
4625 }
4626
4627 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4628 if (!kextFileInfo->infoDictPhysAddr ||
4629 !kextFileInfo->infoDictLength) {
4630 continue;
4631 }
4632
4633 infoDictAddr = (char *)
4634 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4635 if (!infoDictAddr) {
4636 continue;
4637 }
4638
4639 parsedXML = OSUnserializeXML(infoDictAddr);
4640 if (!parsedXML) {
4641 continue;
4642 }
4643
4644 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4645 if (!theInfoDict) {
4646 continue;
4647 }
4648
4649 myBundleID =
4650 OSDynamicCast(OSString,
4651 theInfoDict->getObject(kCFBundleIdentifierKey));
4652 if (myBundleID &&
4653 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4654 boolean_t updated = updateExcludeList(theInfoDict);
4655 if (!updated) {
4656 /* 25322874 */
4657 panic("Missing OSKextExcludeList dictionary");
4658 }
4659 break;
4660 }
4661 } // while ( (deviceTreeName = ...) )
4662
4663 return;
4664 }
4665
4666 /*********************************************************************
4667 * Create a dictionary of excluded kexts from the given prelink
4668 * info (kernelcache).
4669 *********************************************************************/
4670 /* static */
4671 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4672 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4673 {
4674 OSDictionary * myInfoDict = NULL; // do not release
4675 OSString * myBundleID; // do not release
4676 u_int i;
4677
4678 /* Find the Apple Kext Exclude List. */
4679 for (i = 0; i < theInfoArray->getCount(); i++) {
4680 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4681 if (!myInfoDict) {
4682 continue;
4683 }
4684 myBundleID =
4685 OSDynamicCast(OSString,
4686 myInfoDict->getObject(kCFBundleIdentifierKey));
4687 if (myBundleID &&
4688 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4689 boolean_t updated = updateExcludeList(myInfoDict);
4690 if (!updated) {
4691 /* 25322874 */
4692 panic("Missing OSKextExcludeList dictionary");
4693 }
4694 break;
4695 }
4696 } // for (i = 0; i < theInfoArray->getCount()...
4697
4698 return;
4699 }
4700
4701 /* static */
4702 boolean_t
updateExcludeList(OSDictionary * infoDict)4703 OSKext::updateExcludeList(OSDictionary *infoDict)
4704 {
4705 OSDictionary *myTempDict = NULL; // do not free
4706 OSString *myTempString = NULL; // do not free
4707 OSKextVersion newVersion = 0;
4708 boolean_t updated = false;
4709
4710 if (!infoDict) {
4711 return false;
4712 }
4713
4714 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4715 if (!myTempDict) {
4716 return false;
4717 }
4718
4719 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4720 if (!myTempString) {
4721 return false;
4722 }
4723
4724 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4725 if (newVersion == 0) {
4726 return false;
4727 }
4728
4729 IORecursiveLockLock(sKextLock);
4730
4731 if (newVersion > sExcludeListVersion) {
4732 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4733 sExcludeListVersion = newVersion;
4734 updated = true;
4735 }
4736
4737 IORecursiveLockUnlock(sKextLock);
4738 return updated;
4739 }
4740
4741 #if PRAGMA_MARK
4742 #pragma mark Accessors
4743 #endif
4744 /*********************************************************************
4745 *********************************************************************/
4746 const OSSymbol *
getIdentifier(void)4747 OSKext::getIdentifier(void)
4748 {
4749 return bundleID.get();
4750 }
4751
4752 /*********************************************************************
4753 * A kext must have a bundle identifier to even survive initialization;
4754 * this is guaranteed to exist past then.
4755 *********************************************************************/
4756 const char *
getIdentifierCString(void)4757 OSKext::getIdentifierCString(void)
4758 {
4759 return bundleID->getCStringNoCopy();
4760 }
4761
4762 /*********************************************************************
4763 *********************************************************************/
4764 OSKextVersion
getVersion(void)4765 OSKext::getVersion(void)
4766 {
4767 return version;
4768 }
4769
4770 /*********************************************************************
4771 *********************************************************************/
4772 OSKextVersion
getCompatibleVersion(void)4773 OSKext::getCompatibleVersion(void)
4774 {
4775 return compatibleVersion;
4776 }
4777
4778 /*********************************************************************
4779 *********************************************************************/
4780 bool
isLibrary(void)4781 OSKext::isLibrary(void)
4782 {
4783 return getCompatibleVersion() > 0;
4784 }
4785
4786 /*********************************************************************
4787 *********************************************************************/
4788 bool
isCompatibleWithVersion(OSKextVersion aVersion)4789 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4790 {
4791 if ((compatibleVersion > -1 && version > -1) &&
4792 (compatibleVersion <= version && aVersion <= version)) {
4793 return true;
4794 }
4795 return false;
4796 }
4797
4798 /*********************************************************************
4799 *********************************************************************/
4800 bool
declaresExecutable(void)4801 OSKext::declaresExecutable(void)
4802 {
4803 if (isDriverKit()) {
4804 return false;
4805 }
4806 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4807 }
4808
4809 /*********************************************************************
4810 *********************************************************************/
4811 OSData *
getExecutable(void)4812 OSKext::getExecutable(void)
4813 {
4814 OSData * result = NULL;
4815 OSSharedPtr<OSData> extractedExecutable;
4816
4817 if (flags.builtin) {
4818 return sKernelKext->linkedExecutable.get();
4819 }
4820
4821 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4822 if (result) {
4823 return result;
4824 }
4825
4826 #if CONFIG_KXLD
4827 OSData * mkextExecutableRef = NULL; // do not release
4828 mkextExecutableRef = OSDynamicCast(OSData,
4829 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4830
4831 if (mkextExecutableRef) {
4832 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4833 mkextExecutableRef->getBytesNoCopy();
4834 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4835 if (mkextVersion == MKEXT_VERS_2) {
4836 mkext2_file_entry * fileinfo =
4837 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4838 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4839 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4840 extractedExecutable = extractMkext2FileData(
4841 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4842 compressedSize, fullSize);
4843 } else {
4844 OSKextLog(this, kOSKextLogErrorLevel |
4845 kOSKextLogArchiveFlag,
4846 "Kext %s - unknown mkext version 0x%x for executable.",
4847 getIdentifierCString(), mkextVersion);
4848 }
4849
4850 /* Regardless of success, remove the mkext executable,
4851 * and drop one reference on the mkext. (setExecutable() does not
4852 * replace, it removes, or panics if asked to replace.)
4853 */
4854 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4855 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4856
4857 if (extractedExecutable && extractedExecutable->getLength()) {
4858 if (!setExecutable(extractedExecutable.get())) {
4859 goto finish;
4860 }
4861 result = extractedExecutable.get();
4862 } else {
4863 goto finish;
4864 }
4865 }
4866
4867 finish:
4868 #endif // CONFIG_KXLD
4869 return result;
4870 }
4871
4872 /*********************************************************************
4873 *********************************************************************/
4874 bool
isInterface(void)4875 OSKext::isInterface(void)
4876 {
4877 return flags.interface;
4878 }
4879
4880 /*********************************************************************
4881 *********************************************************************/
4882 bool
isKernel(void)4883 OSKext::isKernel(void)
4884 {
4885 return this == sKernelKext;
4886 }
4887
4888 /*********************************************************************
4889 *********************************************************************/
4890 bool
isKernelComponent(void)4891 OSKext::isKernelComponent(void)
4892 {
4893 return flags.kernelComponent ? true : false;
4894 }
4895
4896 /*********************************************************************
4897 *********************************************************************/
4898 bool
isExecutable(void)4899 OSKext::isExecutable(void)
4900 {
4901 return !isKernel() && !isInterface() && declaresExecutable();
4902 }
4903
4904 /*********************************************************************
4905 * We might want to check this recursively for all dependencies,
4906 * since a subtree of dependencies could get loaded before we hit
4907 * a dependency that isn't safe-boot-loadable.
4908 *
4909 * xxx - Might want to return false if OSBundleEnableKextLogging or
4910 * OSBundleDebugLevel
4911 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4912 * the point except it's usually development drivers, which might
4913 * cause panics on startup, that have those properties). Heh; could
4914 * use a "kx" boot-arg!
4915 *********************************************************************/
4916 bool
isLoadableInSafeBoot(void)4917 OSKext::isLoadableInSafeBoot(void)
4918 {
4919 bool result = false;
4920 OSString * required = NULL; // do not release
4921
4922 if (isKernel()) {
4923 result = true;
4924 goto finish;
4925 }
4926
4927 if (isDriverKit()) {
4928 result = true;
4929 goto finish;
4930 }
4931
4932 required = OSDynamicCast(OSString,
4933 getPropertyForHostArch(kOSBundleRequiredKey));
4934 if (!required) {
4935 goto finish;
4936 }
4937 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4938 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4939 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4940 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4941 required->isEqualTo(kOSBundleRequiredConsole)) {
4942 result = true;
4943 }
4944
4945 finish:
4946 return result;
4947 }
4948
4949 /*********************************************************************
4950 *********************************************************************/
4951 bool
isPrelinked(void)4952 OSKext::isPrelinked(void)
4953 {
4954 return flags.prelinked ? true : false;
4955 }
4956
4957 /*********************************************************************
4958 *********************************************************************/
4959 bool
isLoaded(void)4960 OSKext::isLoaded(void)
4961 {
4962 return flags.loaded ? true : false;
4963 }
4964
4965 /*********************************************************************
4966 *********************************************************************/
4967 bool
isStarted(void)4968 OSKext::isStarted(void)
4969 {
4970 return flags.started ? true : false;
4971 }
4972
4973 /*********************************************************************
4974 *********************************************************************/
4975 bool
isCPPInitialized(void)4976 OSKext::isCPPInitialized(void)
4977 {
4978 return flags.CPPInitialized;
4979 }
4980
4981 /*********************************************************************
4982 *********************************************************************/
4983 void
setCPPInitialized(bool initialized)4984 OSKext::setCPPInitialized(bool initialized)
4985 {
4986 flags.CPPInitialized = initialized;
4987 }
4988
4989 /*********************************************************************
4990 *********************************************************************/
4991 uint32_t
getLoadTag(void)4992 OSKext::getLoadTag(void)
4993 {
4994 return loadTag;
4995 }
4996
4997 /*********************************************************************
4998 *********************************************************************/
4999 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5000 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5001 {
5002 if (linkedExecutable) {
5003 *loadSize = linkedExecutable->getLength();
5004
5005 /* If we have a kmod_info struct, calculated the wired size
5006 * from that. Otherwise it's the full load size.
5007 */
5008 if (kmod_info) {
5009 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5010 } else {
5011 *wiredSize = *loadSize;
5012 }
5013 } else {
5014 *wiredSize = 0;
5015 *loadSize = 0;
5016 }
5017 }
5018
5019 /*********************************************************************
5020 *********************************************************************/
5021 OSSharedPtr<OSData>
copyUUID(void)5022 OSKext::copyUUID(void)
5023 {
5024 OSSharedPtr<OSData> result;
5025 OSData * theExecutable = NULL; // do not release
5026 const kernel_mach_header_t * header;
5027
5028 /* An interface kext doesn't have a linked executable with an LC_UUID,
5029 * we create one when it's linked.
5030 */
5031 if (interfaceUUID) {
5032 result = interfaceUUID;
5033 goto finish;
5034 }
5035
5036 if (flags.builtin || isInterface()) {
5037 return sKernelKext->copyUUID();
5038 }
5039
5040 if (isDriverKit() && infoDict) {
5041 return driverKitUUID;
5042 }
5043
5044 /* For real kexts, try to get the UUID from the linked executable,
5045 * or if is hasn't been linked yet, the unrelocated executable.
5046 */
5047 theExecutable = linkedExecutable.get();
5048 if (!theExecutable) {
5049 theExecutable = getExecutable();
5050 }
5051
5052 if (!theExecutable) {
5053 goto finish;
5054 }
5055
5056 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5057 result = copyMachoUUID(header);
5058
5059 finish:
5060 return result;
5061 }
5062
5063 /*********************************************************************
5064 *********************************************************************/
5065 OSSharedPtr<OSData>
copyTextUUID(void)5066 OSKext::copyTextUUID(void)
5067 {
5068 if (flags.builtin) {
5069 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5070 }
5071 return copyUUID();
5072 }
5073
5074 /*********************************************************************
5075 *********************************************************************/
5076 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5077 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5078 {
5079 OSSharedPtr<OSData> result;
5080 const struct load_command * load_cmd = NULL;
5081 const struct uuid_command * uuid_cmd = NULL;
5082 uint32_t i;
5083
5084 load_cmd = (const struct load_command *)&header[1];
5085
5086 if (header->magic != MH_MAGIC_KERNEL) {
5087 OSKextLog(NULL,
5088 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5089 "%s: bad header %p",
5090 __func__,
5091 header);
5092 goto finish;
5093 }
5094
5095 for (i = 0; i < header->ncmds; i++) {
5096 if (load_cmd->cmd == LC_UUID) {
5097 uuid_cmd = (struct uuid_command *)load_cmd;
5098 result = OSData::withValue(uuid_cmd->uuid);
5099 goto finish;
5100 }
5101 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5102 }
5103
5104 finish:
5105 return result;
5106 }
5107
5108 void
setDriverKitUUID(OSData * uuid)5109 OSKext::setDriverKitUUID(OSData *uuid)
5110 {
5111 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5112 OSSafeReleaseNULL(uuid);
5113 }
5114 }
5115
5116 OSData *
getDextUniqueID(void)5117 OSKext::getDextUniqueID(void)
5118 {
5119 if (isDriverKit() && dextUniqueID != NULL) {
5120 return dextUniqueID.get();
5121 }
5122
5123 return NULL;
5124 }
5125
5126 /*
5127 * In case a DextUniqueID exists this function returns
5128 * an allocated char* with the hexadecimal represantition of
5129 * DextUniqueID.
5130 * The returned pinter needs to be freed with kfree_data, the
5131 * size of the allocated buffer is returned in size.
5132 */
5133 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5134 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5135 {
5136 if (dextUniqueID != NULL) {
5137 char *s_buffer = NULL;
5138 unsigned int d_length = dextUniqueID->getLength();
5139 /*
5140 * We are converting in hex, so for every byte we will have
5141 * 2 hex chars and one last \0.
5142 */
5143 unsigned int s_length = d_length * 2 + 1;
5144 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5145
5146 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5147 int cpos = 0;
5148 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5149 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5150 if (ret <= 0) {
5151 break;
5152 }
5153 cpos += ret;
5154 }
5155 *size = s_length;
5156
5157 return s_buffer;
5158 }
5159
5160 return NULL;
5161 }
5162
5163 /*
5164 * Atomically swaps the olddext with newdext.
5165 * olddext will be unloaded, so it might be freed
5166 * after this call unless it was previously retained.
5167 *
5168 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5169 */
5170 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5171 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5172 {
5173 OSReturn result;
5174 const OSSymbol * dextID = olddext->getIdentifier();
5175 OSSharedPtr<OSArray> new_personalities;
5176 OSSharedPtr<OSString> kextIdentifier;
5177 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5178 assert(lock_held);
5179
5180 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5181 dextID->retain();
5182
5183 if (newdext != NULL) {
5184 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5185 assert(eq);
5186 }
5187
5188 if (newdext != NULL) {
5189 /*
5190 * Swap the catalog personalities.
5191 */
5192 new_personalities = newdext->copyPersonalitiesArray();
5193 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5194 }
5195
5196 /*
5197 * Unload the dext.
5198 */
5199 result = olddext->unload();
5200 if (result != kOSReturnSuccess) {
5201 OSKextLog(NULL,
5202 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5203 "Cannot unload dext for upgrade %s: %d\n",
5204 dextID->getCStringNoCopy(), result);
5205 }
5206
5207 if (newdext != NULL) {
5208 /*
5209 * Swap the dexts on the OSKext dictionary.
5210 * This might free the dext.
5211 */
5212 sKextsByID->setObject(dextID, newdext);
5213 } else {
5214 /*
5215 * Remove the old dext
5216 */
5217 removeKext(olddext, true);
5218 }
5219
5220 /*
5221 * Inform userspace.
5222 */
5223 if (newdext != NULL) {
5224 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5225 if (result != kOSReturnSuccess) {
5226 OSKextLog(NULL,
5227 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5228 "Cannot send upgrade notification for %s\n",
5229 dextID->getCStringNoCopy());
5230 }
5231 } else {
5232 // notify dext removal
5233 queueKextNotification(kKextRequestPredicateUnloadNotification, OSDynamicCast(OSString, dextID));
5234 }
5235
5236 OSSafeReleaseNULL(dextID);
5237 }
5238
5239 /*
5240 * To be called with sKextLock held.
5241 * NOTE: this could unload the olddext.
5242 */
5243 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5244 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5245 {
5246 const char * dextIDCS = newdext->getIdentifierCString();
5247 __assert_only bool old_isDext = olddext->isDriverKit();
5248 __assert_only bool new_isDext = newdext->isDriverKit();
5249 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5250
5251 assert(old_isDext && new_isDext);
5252 assert(lock_held);
5253
5254 /*
5255 * New dext and old dext have the same ID.
5256 * We use this ID as key on the OSKext
5257 * dictionarys/arrays.
5258 */
5259 const OSSymbol * dextID = newdext->getIdentifier();
5260 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5261 assert(eq);
5262
5263 /*
5264 * Set this OSKect as to update.
5265 * Note that this flags will never be removed once set.
5266 * When a OSKext is marked, it will be substitued by a new
5267 * OSKext, and every subsystem having a reference on this
5268 * OSKext need to know they have check if they can use
5269 * this OSKext or look for a new one.
5270 */
5271 olddext->flags.dextToReplace = 1;
5272
5273 /*
5274 * Check if the current OSKext has any
5275 * userspace processes launched.
5276 * In this case we cannot upgrade and we have to
5277 * delay the upgrade until all processes
5278 * are done.
5279 */
5280 if (olddext->dextLaunchedCount == 0) {
5281 /*
5282 * Be sure that if there are no launched dexts, no
5283 * pending upgrades exist.
5284 * This is an error if it happens, as the decrement
5285 * should have removed the dext from sDriverKitToUpgradeByID
5286 * in case it reached 0.
5287 */
5288 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5289 if (pending_upgdare != NULL) {
5290 OSKextLog(NULL,
5291 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5292 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5293 dextIDCS);
5294 goto out;
5295 }
5296
5297 replaceDextInternal(olddext, newdext);
5298 return true;
5299 }
5300
5301 out:
5302
5303 /*
5304 * Delay the upgrade.
5305 * Make the new dext available in sDriverKitToUpgradeByID.
5306 * In case there was already a pending upgrade, this will
5307 * overwrite it.
5308 */
5309 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5310 return false;
5311 }
5312
5313 /*
5314 * To be called with sKextLock held.
5315 * NOTE: this could unload the dext.
5316 */
5317 bool
removeDext(OSKext * dext)5318 OSKext::removeDext(OSKext *dext)
5319 {
5320 __assert_only bool dext_isDext = dext->isDriverKit();
5321 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5322 IOReturn result;
5323
5324 assert(dext_isDext);
5325 assert(lock_held);
5326
5327 /*
5328 * Set this OSKext to be unloaded when all running instances exit.
5329 */
5330 dext->flags.dextToReplace = 1;
5331
5332 result = gIOCatalogue->terminateDriversForModule(
5333 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5334 if (result != kOSReturnSuccess) {
5335 OSKextLog(dext,
5336 kOSKextLogErrorLevel |
5337 kOSKextLogKextBookkeepingFlag,
5338 "%s services failed to terminate - 0x%x.",
5339 dext->getIdentifierCString(), result);
5340 }
5341
5342 dext->removePersonalitiesFromCatalog();
5343 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5344
5345 /*
5346 * Check if the current OSKext has any
5347 * userspace processes launched.
5348 * In this case we cannot unload and we have to
5349 * delay the unload until all processes
5350 * are done.
5351 */
5352 if (dext->dextLaunchedCount == 0) {
5353 replaceDextInternal(dext, NULL);
5354 return true;
5355 }
5356
5357 return false;
5358 }
5359
5360 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5361 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5362 {
5363 bool ret = false;
5364 __assert_only bool isDext = dext->isDriverKit();
5365 assert(isDext);
5366
5367 const char * dextIDCS = dext->getIdentifierCString();
5368 OSData *myDextUniqueID = dext->getDextUniqueID();
5369
5370 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5371 OSKextLog(dext,
5372 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5373 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5374 dextIDCS);
5375 return ret;
5376 }
5377
5378 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5379 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5380 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5381 assert(dextUniqueIDCString != NULL);
5382 assert(dextUniqueIDToMatchCString != NULL);
5383
5384 IORecursiveLockLock(sKextLock);
5385
5386 /*
5387 * Check that the dext we are referencing is the same
5388 * looked for the match.
5389 */
5390 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5391 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5392 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5393 OSKextLog(dext,
5394 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5395 "Too many dexts launched for %s UniqueID %s\n",
5396 dextIDCS, dextUniqueIDCString);
5397 } else {
5398 dext->dextLaunchedCount++;
5399 ret = true;
5400
5401 OSKextLog(dext,
5402 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5403 "New dext launched for %s UniqueID %s",
5404 dextIDCS, dextUniqueIDCString);
5405 }
5406 } else {
5407 OSKextLog(dext,
5408 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5409 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5410 dextIDCS, dextUniqueIDCString);
5411 }
5412 } else {
5413 OSKextLog(dext,
5414 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5415 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5416 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5417 }
5418
5419 IORecursiveLockUnlock(sKextLock);
5420
5421 if (dextUniqueIDCString != NULL) {
5422 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5423 }
5424 if (dextUniqueIDToMatchCString != NULL) {
5425 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5426 }
5427 return ret;
5428 }
5429
5430 bool
decrementDextLaunchCount(OSString * bundleID)5431 OSKext::decrementDextLaunchCount(OSString *bundleID)
5432 {
5433 bool ret = false;
5434 const char * dextIDCS;
5435 OSData *myDextUniqueID;
5436 unsigned int dextUniqueIDCStringSize = 0;
5437 const char * dextUniqueIDCString = NULL;
5438 OSKext* dext = NULL;
5439
5440 if (!bundleID) {
5441 return ret;
5442 }
5443 dextIDCS = bundleID->getCStringNoCopy();
5444
5445 IORecursiveLockLock(sKextLock);
5446
5447 /*
5448 * Look for the dext with the bundle it. This
5449 * call is triggered only if a previous increment was
5450 * performed. It means that the dext could have not
5451 * been upgraded as its dextLaunchedCount was at least 1.
5452 * Because of this it still needs to be available
5453 * in sKextsByID.
5454 */
5455 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5456 if (!dext || !dext->isDriverKit()) {
5457 OSKextLog(NULL,
5458 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5459 "Cannot find dext for %s, cannot decrement dext launches\n",
5460 dextIDCS);
5461
5462 goto out_locked;
5463 }
5464
5465 myDextUniqueID = dext->getDextUniqueID();
5466 if (!myDextUniqueID) {
5467 OSKextLog(dext,
5468 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5469 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5470 dextIDCS);
5471
5472 goto out_locked;
5473 }
5474 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5475 assert(dextUniqueIDCString != NULL);
5476
5477 if (dext->dextLaunchedCount == 0) {
5478 OSKextLog(dext,
5479 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5480 "Over decrementing dext launch for %s UniqueID %s\n",
5481 dextIDCS, dextUniqueIDCString);
5482
5483 goto out_locked;
5484 }
5485
5486 dext->dextLaunchedCount--;
5487
5488 OSKextLog(dext,
5489 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5490 "Dext terminated for %s UniqueID %s",
5491 dextIDCS, dextUniqueIDCString);
5492
5493 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5494 /*
5495 * Find the upgraded dext.
5496 */
5497 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5498 if (newdext) {
5499 OSKextLog(dext,
5500 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5501 "Dext upgrade for %s UniqueID %s",
5502 dextIDCS, dextUniqueIDCString);
5503 replaceDextInternal(dext, newdext);
5504 /* NOTE dext could have been freed past this point */
5505
5506 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5507 } else {
5508 OSKextLog(dext,
5509 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5510 "Dext unload for %s UniqueID %s",
5511 dextIDCS, dextUniqueIDCString);
5512 replaceDextInternal(dext, NULL);
5513 }
5514
5515 ret = true;
5516 }
5517 out_locked:
5518 IORecursiveLockUnlock(sKextLock);
5519
5520 if (dextUniqueIDCString != NULL) {
5521 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5522 }
5523
5524 return ret;
5525 }
5526
5527 /*********************************************************************
5528 *********************************************************************/
5529 #if defined (__arm__)
5530 #include <arm/arch.h>
5531 #endif
5532
5533 #if defined (__x86_64__)
5534 #define ARCHNAME "x86_64"
5535 #elif defined (__arm64__)
5536 #define ARCHNAME "arm64"
5537 #elif defined (__arm__)
5538
5539 #if defined (__ARM_ARCH_7S__)
5540 #define ARCHNAME "armv7s"
5541 #elif defined (__ARM_ARCH_7F__)
5542 #define ARCHNAME "armv7f"
5543 #elif defined (__ARM_ARCH_7K__)
5544 #define ARCHNAME "armv7k"
5545 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5546 #define ARCHNAME "armv7"
5547 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5548 #define ARCHNAME "armv6"
5549 #endif
5550
5551 #elif defined (__arm64__)
5552 #define ARCHNAME "arm64"
5553 #else
5554 #error architecture not supported
5555 #endif
5556
5557 #define ARCH_SEPARATOR_CHAR '_'
5558
5559 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5560 makeHostArchKey(const char * key, size_t * keySizeOut)
5561 {
5562 char * result = NULL;
5563 size_t keyLength = strlen(key);
5564 size_t keySize;
5565
5566 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5567 */
5568 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5569 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5570
5571 if (!result) {
5572 goto finish;
5573 }
5574 strlcpy(result, key, keySize);
5575 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5576 result[keyLength] = '\0';
5577 strlcat(result, ARCHNAME, keySize);
5578 *keySizeOut = keySize;
5579
5580 finish:
5581 return result;
5582 }
5583
5584 /*********************************************************************
5585 *********************************************************************/
5586 OSObject *
getPropertyForHostArch(const char * key)5587 OSKext::getPropertyForHostArch(const char * key)
5588 {
5589 OSObject * result = NULL;// do not release
5590 size_t hostArchKeySize = 0;
5591 char * hostArchKey = NULL;// must kfree
5592
5593 if (!key || !infoDict) {
5594 goto finish;
5595 }
5596
5597 /* Some properties are not allowed to be arch-variant:
5598 * - Any CFBundle... property.
5599 * - OSBundleIsInterface.
5600 * - OSKernelResource.
5601 */
5602 if (STRING_HAS_PREFIX(key, "OS") ||
5603 STRING_HAS_PREFIX(key, "IO")) {
5604 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5605 if (!hostArchKey) {
5606 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5607 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5608 "Allocation failure.");
5609 goto finish;
5610 }
5611 result = infoDict->getObject(hostArchKey);
5612 }
5613
5614 if (!result) {
5615 result = infoDict->getObject(key);
5616 }
5617
5618 finish:
5619 if (hostArchKey) {
5620 kfree_data(hostArchKey, hostArchKeySize);
5621 }
5622 return result;
5623 }
5624
5625 #if PRAGMA_MARK
5626 #pragma mark Load/Start/Stop/Unload
5627 #endif
5628
5629 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5630
5631 /*********************************************************************
5632 * sExcludeListByID is a dictionary with keys / values of:
5633 * key = bundleID string of kext we will not allow to load
5634 * value = version string(s) of the kext that is to be denied loading.
5635 * The version strings can be comma delimited. For example if kext
5636 * com.foocompany.fookext has two versions that we want to deny
5637 * loading then the version strings might look like:
5638 * 1.0.0, 1.0.1
5639 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5640 * not load the kext.
5641 *
5642 * Value may also be in the form of "LE 2.0.0" (version numbers
5643 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5644 * number less than 2.0.0 will not load)
5645 *
5646 * NOTE - we cannot use the characters "<=" or "<" because we have code
5647 * that serializes plists and treats '<' as a special character.
5648 *********************************************************************/
5649 bool
isInExcludeList(void)5650 OSKext::isInExcludeList(void)
5651 {
5652 OSString * versionString = NULL; // do not release
5653 char * versionCString = NULL; // do not free
5654 size_t i;
5655 boolean_t wantLessThan = false;
5656 boolean_t wantLessThanEqualTo = false;
5657 boolean_t isInExcludeList = true;
5658 char myBuffer[32];
5659
5660 IORecursiveLockLock(sKextLock);
5661
5662 if (!sExcludeListByID) {
5663 isInExcludeList = false;
5664 } else {
5665 /* look up by bundleID in our exclude list and if found get version
5666 * string (or strings) that we will not allow to load
5667 */
5668 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5669 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5670 isInExcludeList = false;
5671 }
5672 }
5673
5674 IORecursiveLockUnlock(sKextLock);
5675
5676 if (!isInExcludeList) {
5677 return false;
5678 }
5679
5680 /* parse version strings */
5681 versionCString = (char *) versionString->getCStringNoCopy();
5682
5683 /* look for "LT" or "LE" form of version string, must be in first two
5684 * positions.
5685 */
5686 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5687 wantLessThan = true;
5688 versionCString += 2;
5689 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5690 wantLessThanEqualTo = true;
5691 versionCString += 2;
5692 }
5693
5694 for (i = 0; *versionCString != 0x00; versionCString++) {
5695 /* skip whitespace */
5696 if (isWhiteSpace(*versionCString)) {
5697 continue;
5698 }
5699
5700 /* peek ahead for version string separator or null terminator */
5701 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5702 /* OK, we have a version string */
5703 myBuffer[i++] = *versionCString;
5704 myBuffer[i] = 0x00;
5705
5706 OSKextVersion excludeVers;
5707 excludeVers = OSKextParseVersionString(myBuffer);
5708
5709 if (wantLessThanEqualTo) {
5710 if (version <= excludeVers) {
5711 return true;
5712 }
5713 } else if (wantLessThan) {
5714 if (version < excludeVers) {
5715 return true;
5716 }
5717 } else if (version == excludeVers) {
5718 return true;
5719 }
5720
5721 /* reset for the next (if any) version string */
5722 i = 0;
5723 wantLessThan = false;
5724 wantLessThanEqualTo = false;
5725 } else {
5726 /* save valid version character */
5727 myBuffer[i++] = *versionCString;
5728
5729 /* make sure bogus version string doesn't overrun local buffer */
5730 if (i >= sizeof(myBuffer)) {
5731 break;
5732 }
5733 }
5734 }
5735
5736 return false;
5737 }
5738
5739 /*********************************************************************
5740 * sNonLoadableKextsByID is a dictionary with keys / values of:
5741 * key = bundleID string of kext we will not allow to load
5742 * value = boolean (true == loadable, false == not loadable)
5743 *
5744 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5745 * i.e., the value for the kext's bundleID will be false. All kexts in
5746 * the primary and system KCs will always be marked as "loadable."
5747 *
5748 * This list ultimately comes from kexts which have been uninstalled
5749 * in user space by deleting the kext from disk, but which have not
5750 * yet been removed from the AuxKC. Because the user could choose to
5751 * re-install the exact same version of the kext, we need to keep
5752 * a dictionary of boolean values so that user space only needs to
5753 * keep a simple list of "uninstalled" or "missing" bundles. When
5754 * a bundle is re-installed, the iokit daemon can use the
5755 * AucKCBundleAvailable predicate to set the individual kext's
5756 * availability to true.
5757 *********************************************************************/
5758 bool
isLoadable(void)5759 OSKext::isLoadable(void)
5760 {
5761 bool isLoadable = true;
5762
5763 if (kc_type != KCKindAuxiliary) {
5764 /* this filtering only applies to kexts in the auxkc */
5765 return true;
5766 }
5767
5768 IORecursiveLockLock(sKextLock);
5769
5770 if (sNonLoadableKextsByID) {
5771 /* look up by bundleID in our exclude list and if found get version
5772 * string (or strings) that we will not allow to load
5773 */
5774 OSBoolean *loadableVal;
5775 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5776 if (loadableVal && !loadableVal->getValue()) {
5777 isLoadable = false;
5778 }
5779 }
5780 IORecursiveLockUnlock(sKextLock);
5781
5782 return isLoadable;
5783 }
5784
5785 /*********************************************************************
5786 *********************************************************************/
5787 /* static */
5788 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5789 OSKext::loadKextWithIdentifier(
5790 const char * kextIdentifierCString,
5791 Boolean allowDeferFlag,
5792 Boolean delayAutounloadFlag,
5793 OSKextExcludeLevel startOpt,
5794 OSKextExcludeLevel startMatchingOpt,
5795 OSArray * personalityNames)
5796 {
5797 OSReturn result = kOSReturnError;
5798 OSSharedPtr<OSString> kextIdentifier;
5799
5800 kextIdentifier = OSString::withCString(kextIdentifierCString);
5801 if (!kextIdentifier) {
5802 result = kOSKextReturnNoMemory;
5803 goto finish;
5804 }
5805 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5806 NULL /* kextRef */,
5807 allowDeferFlag, delayAutounloadFlag,
5808 startOpt, startMatchingOpt, personalityNames);
5809
5810 finish:
5811 return result;
5812 }
5813
5814 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5815 OSKext::loadKextWithIdentifier(
5816 OSString * kextIdentifier,
5817 OSSharedPtr<OSObject> &kextRef,
5818 Boolean allowDeferFlag,
5819 Boolean delayAutounloadFlag,
5820 OSKextExcludeLevel startOpt,
5821 OSKextExcludeLevel startMatchingOpt,
5822 OSArray * personalityNames)
5823 {
5824 OSObject * kextRefRaw = NULL;
5825 OSReturn result;
5826
5827 result = loadKextWithIdentifier(kextIdentifier,
5828 &kextRefRaw,
5829 allowDeferFlag,
5830 delayAutounloadFlag,
5831 startOpt,
5832 startMatchingOpt,
5833 personalityNames);
5834 if ((kOSReturnSuccess == result) && kextRefRaw) {
5835 kextRef.reset(kextRefRaw, OSNoRetain);
5836 }
5837 return result;
5838 }
5839
5840 /*********************************************************************
5841 *********************************************************************/
5842 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5843 OSKext::loadKextWithIdentifier(
5844 OSString * kextIdentifier,
5845 OSObject ** kextRef,
5846 Boolean allowDeferFlag,
5847 Boolean delayAutounloadFlag,
5848 OSKextExcludeLevel startOpt,
5849 OSKextExcludeLevel startMatchingOpt,
5850 OSArray * personalityNames)
5851 {
5852 OSReturn result = kOSReturnError;
5853 OSReturn pingResult = kOSReturnError;
5854 OSKext * theKext = NULL; // do not release
5855 OSSharedPtr<OSDictionary> loadRequest;
5856 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5857
5858 if (kextRef) {
5859 *kextRef = NULL;
5860 }
5861
5862 IORecursiveLockLock(sKextLock);
5863
5864 if (!kextIdentifier) {
5865 result = kOSKextReturnInvalidArgument;
5866 goto finish;
5867 }
5868
5869 OSKext::recordIdentifierRequest(kextIdentifier);
5870
5871 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5872 if (!theKext) {
5873 if (!allowDeferFlag) {
5874 OSKextLog(/* kext */ NULL,
5875 kOSKextLogErrorLevel |
5876 kOSKextLogLoadFlag,
5877 "Can't load kext %s - not found.",
5878 kextIdentifier->getCStringNoCopy());
5879 goto finish;
5880 }
5881
5882 if (!sKernelRequestsEnabled) {
5883 OSKextLog(theKext,
5884 kOSKextLogErrorLevel |
5885 kOSKextLogLoadFlag,
5886 "Can't load kext %s - requests to user space are disabled.",
5887 kextIdentifier->getCStringNoCopy());
5888 result = kOSKextReturnDisabled;
5889 goto finish;
5890 }
5891
5892 /* Create a new request unless one is already sitting
5893 * in sKernelRequests for this bundle identifier
5894 */
5895 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5896 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5897 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5898 loadRequest);
5899 if (result != kOSReturnSuccess) {
5900 goto finish;
5901 }
5902 if (!_OSKextSetRequestArgument(loadRequest.get(),
5903 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5904 result = kOSKextReturnNoMemory;
5905 goto finish;
5906 }
5907 if (!sKernelRequests->setObject(loadRequest.get())) {
5908 result = kOSKextReturnNoMemory;
5909 goto finish;
5910 }
5911
5912 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5913 result = kOSKextReturnNoMemory;
5914 goto finish;
5915 }
5916
5917 OSKextLog(theKext,
5918 kOSKextLogDebugLevel |
5919 kOSKextLogLoadFlag,
5920 "Kext %s not found; queued load request to user space.",
5921 kextIdentifier->getCStringNoCopy());
5922 }
5923
5924 pingResult = OSKext::pingIOKitDaemon();
5925 if (pingResult == kOSKextReturnDisabled) {
5926 OSKextLog(/* kext */ NULL,
5927 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5928 kOSKextLogLoadFlag,
5929 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5930 kextIdentifier->getCStringNoCopy());
5931 }
5932
5933 result = kOSKextReturnDeferred;
5934 goto finish;
5935 }
5936
5937 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5938
5939 if (result != kOSReturnSuccess) {
5940 OSKextLog(theKext,
5941 kOSKextLogErrorLevel |
5942 kOSKextLogLoadFlag,
5943 "Failed to load kext %s (error 0x%x).",
5944 kextIdentifier->getCStringNoCopy(), (int)result);
5945
5946 if (theKext->kc_type == KCKindUnknown) {
5947 OSKext::removeKext(theKext,
5948 /* terminateService/removePersonalities */ true);
5949 }
5950 goto finish;
5951 }
5952
5953 if (delayAutounloadFlag) {
5954 OSKextLog(theKext,
5955 kOSKextLogProgressLevel |
5956 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5957 "Setting delayed autounload for %s.",
5958 kextIdentifier->getCStringNoCopy());
5959 theKext->flags.delayAutounload = 1;
5960 }
5961
5962 finish:
5963 if ((kOSReturnSuccess == result) && kextRef) {
5964 *kextRef = theKext;
5965 theKext->matchingRefCount++;
5966 theKext->retain();
5967 }
5968
5969 IORecursiveLockUnlock(sKextLock);
5970
5971 return result;
5972 }
5973
5974 /*********************************************************************
5975 *********************************************************************/
5976 /* static */
5977 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)5978 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5979 {
5980 OSReturn result = kOSReturnError;
5981
5982 OSBoolean *delayAutounloadBool = NULL; // do not release
5983 OSNumber *startKextExcludeNum = NULL; // do not release
5984 OSNumber *startMatchingExcludeNum = NULL; // do not release
5985 OSArray *personalityNames = NULL; // do not release
5986
5987 /*
5988 * Default values for these options:
5989 * regular autounload behavior
5990 * start the kext
5991 * send all personalities to the catalog
5992 */
5993 Boolean delayAutounload = false;
5994 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5995 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5996
5997 IORecursiveLockLock(sKextLock);
5998
5999 OSKextLog(/* kext */ NULL,
6000 kOSKextLogDebugLevel |
6001 kOSKextLogIPCFlag,
6002 "Received kext KC load request from user space.");
6003
6004 /* Regardless of processing, the fact that we have gotten here means some
6005 * user-space program is up and talking to us, so we'll switch our kext
6006 * registration to reflect that.
6007 */
6008 if (!sUserLoadsActive) {
6009 OSKextLog(/* kext */ NULL,
6010 kOSKextLogProgressLevel |
6011 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6012 "Switching to late startup (user-space) kext loading policy.");
6013 sUserLoadsActive = true;
6014 }
6015
6016 delayAutounloadBool = OSDynamicCast(OSBoolean,
6017 _OSKextGetRequestArgument(requestDict,
6018 kKextRequestArgumentDelayAutounloadKey));
6019 startKextExcludeNum = OSDynamicCast(OSNumber,
6020 _OSKextGetRequestArgument(requestDict,
6021 kKextRequestArgumentStartExcludeKey));
6022 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6023 _OSKextGetRequestArgument(requestDict,
6024 kKextRequestArgumentStartMatchingExcludeKey));
6025 personalityNames = OSDynamicCast(OSArray,
6026 _OSKextGetRequestArgument(requestDict,
6027 kKextRequestArgumentPersonalityNamesKey));
6028
6029 if (delayAutounloadBool) {
6030 delayAutounload = delayAutounloadBool->getValue();
6031 }
6032 if (startKextExcludeNum) {
6033 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6034 }
6035 if (startMatchingExcludeNum) {
6036 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6037 }
6038
6039 OSKextLog(/* kext */ NULL,
6040 kOSKextLogProgressLevel |
6041 kOSKextLogIPCFlag,
6042 "Received request from user space to load KC kext %s.",
6043 theKext->getIdentifierCString());
6044
6045 /* this could be in the Auxiliary KC, so record the load request */
6046 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6047
6048 /*
6049 * Load the kext
6050 */
6051 result = theKext->load(startKextExcludeLevel,
6052 startMatchingExcludeLevel, personalityNames);
6053
6054 if (result != kOSReturnSuccess) {
6055 OSKextLog(theKext,
6056 kOSKextLogErrorLevel |
6057 kOSKextLogLoadFlag,
6058 "Failed to load kext %s (error 0x%x).",
6059 theKext->getIdentifierCString(), (int)result);
6060
6061 OSKext::removeKext(theKext,
6062 /* terminateService/removePersonalities */ true);
6063 goto finish;
6064 } else {
6065 OSKextLog(theKext,
6066 kOSKextLogProgressLevel |
6067 kOSKextLogLoadFlag,
6068 "Kext %s Loaded successfully from %s KC",
6069 theKext->getIdentifierCString(), theKext->getKCTypeString());
6070 }
6071
6072 if (delayAutounload) {
6073 OSKextLog(theKext,
6074 kOSKextLogProgressLevel |
6075 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6076 "Setting delayed autounload for %s.",
6077 theKext->getIdentifierCString());
6078 theKext->flags.delayAutounload = 1;
6079 }
6080
6081 finish:
6082 IORecursiveLockUnlock(sKextLock);
6083
6084 return result;
6085 }
6086
6087 /*********************************************************************
6088 *********************************************************************/
6089 /* static */
6090 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6091 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6092 {
6093 OSReturn result = kOSReturnError;
6094 OSDictionary *anInfoDict = NULL; // do not release
6095
6096 anInfoDict = OSDynamicCast(OSDictionary,
6097 _OSKextGetRequestArgument(requestDict,
6098 kKextRequestArgumentCodelessInfoKey));
6099 if (anInfoDict == NULL) {
6100 OSKextLog(/* kext */ NULL,
6101 kOSKextLogErrorLevel |
6102 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6103 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6104 kextIdentifier->getCStringNoCopy());
6105 return kOSKextReturnInvalidArgument;
6106 }
6107
6108 IORecursiveLockLock(sKextLock);
6109
6110 OSKextLog(/* kext */ NULL,
6111 kOSKextLogProgressLevel |
6112 kOSKextLogIPCFlag,
6113 "Received request from user space to load codeless kext %s.",
6114 kextIdentifier->getCStringNoCopy());
6115
6116 {
6117 // instantiate a new kext, and don't hold a reference
6118 // (the kext subsystem will hold one implicitly)
6119 OSKextInitResult ret;
6120 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6121 if (!newKext) {
6122 /*
6123 * We might have failed to create a new OSKext
6124 * because the old one should still be used.
6125 * Check if that is the case.
6126 */
6127 if (ret != kOSKextInitFailure) {
6128 result = kOSReturnSuccess;
6129 goto finish;
6130 }
6131 OSKextLog(/* kext */ NULL,
6132 kOSKextLogErrorLevel |
6133 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6134 "Could not instantiate codeless kext.");
6135 result = kOSKextReturnNotLoadable;
6136 goto finish;
6137 }
6138 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6139 OSKextLog(/* kext */ NULL,
6140 kOSKextLogErrorLevel |
6141 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6142 "Codeless kext identifiers don't match '%s' != '%s'",
6143 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6144
6145 OSKext::removeKext(newKext.get(), false);
6146 result = kOSKextReturnInvalidArgument;
6147 goto finish;
6148 }
6149
6150 /* Record the request for the codeless kext */
6151 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6152
6153 result = kOSReturnSuccess;
6154 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6155 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6156 }
6157
6158 finish:
6159 IORecursiveLockUnlock(sKextLock);
6160
6161 return result;
6162 }
6163
6164 /*********************************************************************
6165 *********************************************************************/
6166 /* static */
6167 void
dropMatchingReferences(OSSet * kexts)6168 OSKext::dropMatchingReferences(
6169 OSSet * kexts)
6170 {
6171 IORecursiveLockLock(sKextLock);
6172 kexts->iterateObjects(^bool (OSObject * obj) {
6173 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6174 if (!thisKext) {
6175 return false;
6176 }
6177 thisKext->matchingRefCount--;
6178 return false;
6179 });
6180 IORecursiveLockUnlock(sKextLock);
6181 }
6182
6183 /*********************************************************************
6184 *********************************************************************/
6185 /* static */
6186 void
recordIdentifierRequest(OSString * kextIdentifier)6187 OSKext::recordIdentifierRequest(
6188 OSString * kextIdentifier)
6189 {
6190 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6191 bool fail = false;
6192
6193 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6194 goto finish;
6195 }
6196
6197 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6198 if (!kextIdentifierSymbol) {
6199 // xxx - this is really a basic alloc failure
6200 fail = true;
6201 goto finish;
6202 }
6203
6204 IORecursiveLockLock(sKextLock);
6205 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6206 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6207 fail = true;
6208 } else {
6209 // xxx - need to find a way to associate this whole func w/the kext
6210 OSKextLog(/* kext */ NULL,
6211 // xxx - check level
6212 kOSKextLogStepLevel |
6213 kOSKextLogArchiveFlag,
6214 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6215 kextIdentifier->getCStringNoCopy());
6216 }
6217 }
6218 IORecursiveLockUnlock(sKextLock);
6219
6220 finish:
6221
6222 if (fail) {
6223 OSKextLog(/* kext */ NULL,
6224 kOSKextLogErrorLevel |
6225 kOSKextLogArchiveFlag,
6226 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6227 kextIdentifier->getCStringNoCopy());
6228 }
6229 return;
6230 }
6231
6232 /*********************************************************************
6233 *********************************************************************/
6234 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6235 OSKext::load(
6236 OSKextExcludeLevel startOpt,
6237 OSKextExcludeLevel startMatchingOpt,
6238 OSArray * personalityNames)
6239 {
6240 OSReturn result = kOSReturnError;
6241 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6242 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6243 unsigned int i, count;
6244 Boolean alreadyLoaded = false;
6245 OSKext * lastLoadedKext = NULL; // do not release
6246
6247 if (isInExcludeList()) {
6248 OSKextLog(this,
6249 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6250 kOSKextLogLoadFlag,
6251 "Kext %s is in exclude list, not loadable",
6252 getIdentifierCString());
6253
6254 result = kOSKextReturnNotLoadable;
6255 goto finish;
6256 }
6257 if (!isLoadable()) {
6258 OSKextLog(this,
6259 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6260 kOSKextLogLoadFlag,
6261 "Kext %s is not loadable",
6262 getIdentifierCString());
6263
6264 result = kOSKextReturnNotLoadable;
6265 goto finish;
6266 }
6267
6268 if (isLoaded()) {
6269 alreadyLoaded = true;
6270 result = kOSReturnSuccess;
6271
6272 OSKextLog(this,
6273 kOSKextLogDebugLevel |
6274 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6275 "Kext %s is already loaded.",
6276 getIdentifierCString());
6277 goto loaded;
6278 }
6279
6280 #if CONFIG_MACF
6281 /*
6282 * On kxld and on embedded, only call into the MAC hook when on a
6283 * user thread, for access control over userspace kextloads.
6284 *
6285 * On non-kxld systems, additionally check the MAC hook for kexts in
6286 * the Pageable and Aux KCs, regardless of whether we are on a user
6287 * thread or not. This means on Apple silicon devices that the MAC
6288 * hook will only be useful to block 3rd party kexts loaded via
6289 * matching, and any kexts loaded from userspace kextloads.
6290 *
6291 * Note that this should _not_ be called on kexts loaded from the
6292 * kernel bootstrap thread as the kernel proc's cred struct is not
6293 * yet initialized! This won't happen on macOS because all the kexts
6294 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6295 */
6296 if (current_task() != kernel_task
6297 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6298 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6299 #endif
6300 ) {
6301 int macCheckResult = 0;
6302 kauth_cred_t cred = NULL;
6303
6304 cred = kauth_cred_get_with_ref();
6305 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6306 kauth_cred_unref(&cred);
6307
6308 if (macCheckResult != 0) {
6309 result = kOSReturnError;
6310 OSKextLog(this,
6311 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6312 "Failed to load kext %s (MAC policy error 0x%x).",
6313 getIdentifierCString(), macCheckResult);
6314 goto finish;
6315 }
6316 }
6317 #endif /* CONFIG_MACF */
6318
6319 if (!sLoadEnabled) {
6320 OSKextLog(this,
6321 kOSKextLogErrorLevel |
6322 kOSKextLogLoadFlag,
6323 "Kext loading is disabled (attempt to load kext %s).",
6324 getIdentifierCString());
6325 result = kOSKextReturnDisabled;
6326 goto finish;
6327 }
6328
6329 /* If we've pushed the next available load tag to the invalid value,
6330 * we can't load any more kexts.
6331 */
6332 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6333 OSKextLog(this,
6334 kOSKextLogErrorLevel |
6335 kOSKextLogLoadFlag,
6336 "Can't load kext %s - no more load tags to assign.",
6337 getIdentifierCString());
6338 result = kOSKextReturnNoResources;
6339 goto finish;
6340 }
6341
6342 /* This is a bit of a hack, because we shouldn't be handling
6343 * personalities within the load function.
6344 */
6345 if (!declaresExecutable()) {
6346 /* There is a special case where a non-executable kext can be loaded: the
6347 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6348 * load its metadata into the global data structures, if appropriate
6349 */
6350 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6351 boolean_t updated = updateExcludeList(infoDict.get());
6352 if (updated) {
6353 OSKextLog(this,
6354 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6355 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6356 }
6357 }
6358
6359 if (isDriverKit()) {
6360 if (loadTag == 0) {
6361 sLoadedDriverKitKexts->setObject(this);
6362 loadTag = sNextLoadTag++;
6363 }
6364 }
6365 result = kOSReturnSuccess;
6366 goto loaded;
6367 }
6368
6369 /* Are we in safe boot?
6370 */
6371 if (sSafeBoot && !isLoadableInSafeBoot()) {
6372 OSKextLog(this,
6373 kOSKextLogErrorLevel |
6374 kOSKextLogLoadFlag,
6375 "Can't load kext %s - not loadable during safe boot.",
6376 getIdentifierCString());
6377 result = kOSKextReturnBootLevel;
6378 goto finish;
6379 }
6380
6381 OSKextLog(this,
6382 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6383 "Loading kext %s.",
6384 getIdentifierCString());
6385
6386 #if !VM_MAPPED_KEXTS
6387 if (isPrelinked() == false) {
6388 OSKextLog(this,
6389 kOSKextLogErrorLevel |
6390 kOSKextLogLoadFlag,
6391 "Can't load kext %s - not in a kext collection.",
6392 getIdentifierCString());
6393 result = kOSKextReturnDisabled;
6394 goto finish;
6395 }
6396 #endif /* defined(__x86_64__) */
6397
6398 #if CONFIG_KXLD
6399 if (!sKxldContext) {
6400 kern_return_t kxldResult;
6401 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6402 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6403 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6404 if (kxldResult) {
6405 OSKextLog(this,
6406 kOSKextLogErrorLevel |
6407 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6408 "Can't load kext %s - failed to create link context.",
6409 getIdentifierCString());
6410 result = kOSKextReturnNoMemory;
6411 goto finish;
6412 }
6413 }
6414 #endif // CONFIG_KXLD
6415
6416 /* We only need to resolve dependencies once for the whole graph, but
6417 * resolveDependencies will just return if there's no work to do, so it's
6418 * safe to call it more than once.
6419 */
6420 if (!resolveDependencies()) {
6421 // xxx - check resolveDependencies() for log msg
6422 OSKextLog(this,
6423 kOSKextLogErrorLevel |
6424 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6425 "Can't load kext %s - failed to resolve library dependencies.",
6426 getIdentifierCString());
6427 result = kOSKextReturnDependencies;
6428 goto finish;
6429 }
6430
6431 /* If we are excluding just the kext being loaded now (and not its
6432 * dependencies), drop the exclusion level to none so dependencies
6433 * start and/or add their personalities.
6434 */
6435 if (dependenciesStartOpt == kOSKextExcludeKext) {
6436 dependenciesStartOpt = kOSKextExcludeNone;
6437 }
6438
6439 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6440 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6441 }
6442
6443 /* Load the dependencies, recursively.
6444 */
6445 count = getNumDependencies();
6446 for (i = 0; i < count; i++) {
6447 OSKext * dependency = OSDynamicCast(OSKext,
6448 dependencies->getObject(i));
6449 if (dependency == NULL) {
6450 OSKextLog(this,
6451 kOSKextLogErrorLevel |
6452 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6453 "Internal error loading kext %s; dependency disappeared.",
6454 getIdentifierCString());
6455 result = kOSKextReturnInternalError;
6456 goto finish;
6457 }
6458
6459 /* Dependencies must be started accorting to the opt,
6460 * but not given the personality names of the main kext.
6461 */
6462 result = dependency->load(dependenciesStartOpt,
6463 dependenciesStartMatchingOpt,
6464 /* personalityNames */ NULL);
6465 if (result != KERN_SUCCESS) {
6466 OSKextLog(this,
6467 kOSKextLogErrorLevel |
6468 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6469 "Dependency %s of kext %s failed to load.",
6470 dependency->getIdentifierCString(),
6471 getIdentifierCString());
6472
6473 OSKext::removeKext(dependency,
6474 /* terminateService/removePersonalities */ true);
6475 result = kOSKextReturnDependencyLoadError;
6476
6477 goto finish;
6478 }
6479 }
6480
6481 result = loadExecutable();
6482 if (result != KERN_SUCCESS) {
6483 goto finish;
6484 }
6485
6486 pendingPgoHead.next = &pendingPgoHead;
6487 pendingPgoHead.prev = &pendingPgoHead;
6488
6489 // The kernel PRNG is not initialized when the first kext is
6490 // loaded, so use early random
6491 uuid_generate_early_random(instance_uuid);
6492 account = IOMallocType(OSKextAccount);
6493
6494 account->loadTag = kmod_info->id;
6495 account->site.refcount = 0;
6496 account->site.flags = VM_TAG_KMOD;
6497
6498 #if DEVELOPMENT || DEBUG
6499 /* Setup the task reference group. */
6500 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6501 "task_%s", getIdentifierCString());
6502 account->task_refgrp.grp_name = account->task_refgrp_name;
6503 account->task_refgrp.grp_parent = &task_external_refgrp;
6504 os_ref_log_init(&account->task_refgrp);
6505 #endif /* DEVELOPMENT || DEBUG */
6506
6507 account->kext = this;
6508 if (gIOSurfaceIdentifier == bundleID) {
6509 vm_tag_alloc(&account->site);
6510 gIOSurfaceTag = account->site.tag;
6511 }
6512
6513 flags.loaded = true;
6514
6515 /* Add the kext to the list of loaded kexts and update the kmod_info
6516 * struct to point to that of the last loaded kext (which is the way
6517 * it's always been done, though I'd rather do them in order now).
6518 */
6519 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6520 sLoadedKexts->setObject(this);
6521
6522 /* Keep the kernel itself out of the kmod list.
6523 */
6524 if (lastLoadedKext->isKernel()) {
6525 lastLoadedKext = NULL;
6526 }
6527
6528 if (lastLoadedKext) {
6529 kmod_info->next = lastLoadedKext->kmod_info;
6530 }
6531
6532 notifyKextLoadObservers(this, kmod_info);
6533
6534 /* Make the global kmod list point at the just-loaded kext. Note that the
6535 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6536 * although we do report it in kextstat these days by using the newer
6537 * OSArray of loaded kexts, which does contain it.
6538 *
6539 * (The OSKext object representing the kernel doesn't even have a kmod_info
6540 * struct, though I suppose we could stick a pointer to it from the
6541 * static struct in OSRuntime.cpp.)
6542 */
6543 kmod = kmod_info;
6544
6545 /* Save the list of loaded kexts in case we panic.
6546 */
6547 OSKext::saveLoadedKextPanicList();
6548
6549 if (isExecutable()) {
6550 OSKext::updateLoadedKextSummaries();
6551 savePanicString(/* isLoading */ true);
6552
6553 #if CONFIG_DTRACE
6554 registerWithDTrace();
6555 #else
6556 jettisonLinkeditSegment();
6557 #endif /* CONFIG_DTRACE */
6558
6559 #if !VM_MAPPED_KEXTS
6560 /* If there is a page (or more) worth of padding after the end
6561 * of the last data section but before the end of the data segment
6562 * then free it in the same manner the LinkeditSegment is freed
6563 */
6564 jettisonDATASegmentPadding();
6565 #endif
6566 }
6567
6568 loaded:
6569 if (isExecutable() && !flags.started) {
6570 if (startOpt == kOSKextExcludeNone) {
6571 result = start();
6572 if (result != kOSReturnSuccess) {
6573 OSKextLog(this,
6574 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6575 "Kext %s start failed (result 0x%x).",
6576 getIdentifierCString(), result);
6577 result = kOSKextReturnStartStopError;
6578 }
6579 }
6580 }
6581
6582 /* If not excluding matching, send the personalities to the kernel.
6583 * This never affects the result of the load operation.
6584 * This is a bit of a hack, because we shouldn't be handling
6585 * personalities within the load function.
6586 */
6587 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6588 result = sendPersonalitiesToCatalog(true, personalityNames);
6589 }
6590
6591 finish:
6592
6593 if (result != kOSReturnSuccess) {
6594 OSKextLog(this,
6595 kOSKextLogErrorLevel |
6596 kOSKextLogLoadFlag,
6597 "Kext %s failed to load (0x%x).",
6598 getIdentifierCString(), (int)result);
6599 } else if (!alreadyLoaded) {
6600 OSKextLog(this,
6601 kOSKextLogProgressLevel |
6602 kOSKextLogLoadFlag,
6603 "Kext %s loaded.",
6604 getIdentifierCString());
6605
6606 queueKextNotification(kKextRequestPredicateLoadNotification,
6607 OSDynamicCast(OSString, bundleID.get()));
6608 }
6609 return result;
6610 }
6611
6612 #if CONFIG_KXLD
6613 /*********************************************************************
6614 *
6615 *********************************************************************/
6616 static char *
strdup(const char * string)6617 strdup(const char * string)
6618 {
6619 char * result = NULL;
6620 size_t size;
6621
6622 if (!string) {
6623 goto finish;
6624 }
6625
6626 size = 1 + strlen(string);
6627 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6628 if (!result) {
6629 goto finish;
6630 }
6631
6632 memcpy(result, string, size);
6633
6634 finish:
6635 return result;
6636 }
6637 #endif // CONFIG_KXLD
6638
6639 /*********************************************************************
6640 *
6641 *********************************************************************/
6642
6643 kernel_section_t *
lookupSection(const char * segname,const char * secname)6644 OSKext::lookupSection(const char *segname, const char *secname)
6645 {
6646 kernel_section_t * found_section = NULL;
6647 kernel_mach_header_t * mh = NULL;
6648 kernel_segment_command_t * seg = NULL;
6649 kernel_section_t * sec = NULL;
6650
6651 if (!linkedExecutable) {
6652 return NULL;
6653 }
6654
6655 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6656
6657 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6658 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6659 continue;
6660 }
6661
6662 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6663 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6664 found_section = sec;
6665 goto out;
6666 }
6667 }
6668 }
6669
6670 out:
6671 return found_section;
6672 }
6673
6674 /*********************************************************************
6675 *
6676 *********************************************************************/
6677
6678 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6679 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6680 {
6681 OSReturn result = kOSKextReturnBadData;
6682 kernel_mach_header_t * mh = NULL;
6683 kernel_segment_command_t * seg = NULL;
6684 kernel_segment_command_t * linkeditSeg = NULL;
6685 kernel_section_t * sec = NULL;
6686 char * linkeditBase = NULL;
6687 bool haveLinkeditBase = false;
6688 char * relocBase = NULL;
6689 bool haveRelocBase = false;
6690 struct dysymtab_command * dysymtab = NULL;
6691 struct linkedit_data_command * segmentSplitInfo = NULL;
6692 struct symtab_command * symtab = NULL;
6693 kernel_nlist_t * sym = NULL;
6694 struct relocation_info * reloc = NULL;
6695 uint32_t i = 0;
6696 int reloc_size;
6697 vm_offset_t new_kextsize;
6698 kc_format format = KCFormatUnknown;
6699
6700 if (linkedExecutable == NULL || flags.builtin) {
6701 result = kOSReturnSuccess;
6702 goto finish;
6703 }
6704
6705 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6706 if (kernel_mach_header_is_in_fileset(mh)) {
6707 // kexts in filesets are slid as part of collection sliding
6708 result = kOSReturnSuccess;
6709 goto finish;
6710 }
6711
6712 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6713
6714 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6715 if (!seg->vmaddr) {
6716 continue;
6717 }
6718
6719 seg->vmaddr = ml_static_slide(seg->vmaddr);
6720
6721 #if KASLR_KEXT_DEBUG
6722 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6723 seg->segname,
6724 (unsigned long)ml_static_unslide(seg->vmaddr),
6725 (unsigned long)seg->vmaddr);
6726 #endif
6727
6728 if (!haveRelocBase) {
6729 relocBase = (char *) seg->vmaddr;
6730 haveRelocBase = true;
6731 }
6732 if (!strcmp(seg->segname, "__LINKEDIT")) {
6733 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6734 haveLinkeditBase = true;
6735 linkeditSeg = seg;
6736 }
6737 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6738 sec->addr = ml_static_slide(sec->addr);
6739
6740 #if KASLR_KEXT_DEBUG
6741 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6742 sec->sectname,
6743 (unsigned long)ml_static_unslide(sec->addr),
6744 (unsigned long)sec->addr);
6745 #endif
6746 }
6747 }
6748
6749 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6750
6751 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6752
6753 if (symtab != NULL && doCoalescedSlides == false) {
6754 /* Some pseudo-kexts have symbol tables without segments.
6755 * Ignore them. */
6756 if (symtab->nsyms > 0 && haveLinkeditBase) {
6757 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6758 for (i = 0; i < symtab->nsyms; i++) {
6759 if (sym[i].n_type & N_STAB) {
6760 continue;
6761 }
6762 sym[i].n_value = ml_static_slide(sym[i].n_value);
6763
6764 #if KASLR_KEXT_DEBUG
6765 #define MAX_SYMS_TO_LOG 5
6766 if (i < MAX_SYMS_TO_LOG) {
6767 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6768 (unsigned long)ml_static_unslide(sym[i].n_value),
6769 (unsigned long)sym[i].n_value);
6770 }
6771 #endif
6772 }
6773 }
6774 }
6775
6776 if (dysymtab != NULL && doCoalescedSlides == false) {
6777 if (dysymtab->nextrel > 0) {
6778 OSKextLog(this,
6779 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6780 kOSKextLogLinkFlag,
6781 "Sliding kext %s: External relocations found.",
6782 getIdentifierCString());
6783 goto finish;
6784 }
6785
6786 if (dysymtab->nlocrel > 0) {
6787 if (!haveLinkeditBase) {
6788 OSKextLog(this,
6789 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6790 kOSKextLogLinkFlag,
6791 "Sliding kext %s: No linkedit segment.",
6792 getIdentifierCString());
6793 goto finish;
6794 }
6795
6796 if (!haveRelocBase) {
6797 OSKextLog(this,
6798 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6799 kOSKextLogLinkFlag,
6800 #if __x86_64__
6801 "Sliding kext %s: No writable segments.",
6802 #else
6803 "Sliding kext %s: No segments.",
6804 #endif
6805 getIdentifierCString());
6806 goto finish;
6807 }
6808
6809 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6810 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6811
6812 for (i = 0; i < dysymtab->nlocrel; i++) {
6813 if (reloc[i].r_extern != 0
6814 || reloc[i].r_type != 0
6815 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6816 ) {
6817 OSKextLog(this,
6818 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6819 kOSKextLogLinkFlag,
6820 "Sliding kext %s: Unexpected relocation found.",
6821 getIdentifierCString());
6822 goto finish;
6823 }
6824 if (reloc[i].r_pcrel != 0) {
6825 continue;
6826 }
6827 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6828 *relocAddr = ml_static_slide(*relocAddr);
6829
6830 #if KASLR_KEXT_DEBUG
6831 #define MAX_DYSYMS_TO_LOG 5
6832 if (i < MAX_DYSYMS_TO_LOG) {
6833 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6834 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6835 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6836 }
6837 #endif
6838 }
6839
6840 /* We should free these relocations, not just delete the reference to them.
6841 * <rdar://problem/10535549> Free relocations from PIE kexts.
6842 *
6843 * For now, we do not free LINKEDIT for kexts with split segments.
6844 */
6845 new_kextsize = round_page(kmod_info->size - reloc_size);
6846 if (new_kextsize > UINT_MAX) {
6847 OSKextLog(this,
6848 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6849 kOSKextLogLinkFlag,
6850 "Kext %s: new kext size is too large.",
6851 getIdentifierCString());
6852 goto finish;
6853 }
6854 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6855 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6856 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6857 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6858 size_t bytes_remaining = endofkext - endofrelocInfo;
6859 OSSharedPtr<OSData> new_osdata;
6860
6861 /* fix up symbol offsets if they are after the dsymtab local relocs */
6862 if (symtab) {
6863 if (dysymtab->locreloff < symtab->symoff) {
6864 symtab->symoff -= reloc_size;
6865 }
6866 if (dysymtab->locreloff < symtab->stroff) {
6867 symtab->stroff -= reloc_size;
6868 }
6869 }
6870 if (dysymtab->locreloff < dysymtab->extreloff) {
6871 dysymtab->extreloff -= reloc_size;
6872 }
6873
6874 /* move data behind reloc info down to new offset */
6875 if (endofrelocInfo < endofkext) {
6876 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6877 }
6878
6879 /* Create a new OSData for the smaller kext object and reflect
6880 * new linkedit segment size.
6881 */
6882 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6883 linkeditSeg->filesize = linkeditSeg->vmsize;
6884
6885 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6886 if (new_osdata) {
6887 /* Fix up kmod info and linkedExecutable.
6888 */
6889 kmod_info->size = new_kextsize;
6890 /*
6891 * Fileset KCs are mapped as a whole by iBoot.
6892 * Individual kext executables should not be unmapped
6893 * by xnu.
6894 * Doing so may result in panics like rdar://85419651
6895 */
6896 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
6897 new_osdata->setDeallocFunction(NULL);
6898 } else { // Not from a Fileset KC
6899 #if VM_MAPPED_KEXTS
6900 new_osdata->setDeallocFunction(osdata_kext_free);
6901 #else
6902 new_osdata->setDeallocFunction(osdata_phys_free);
6903 #endif
6904 }
6905 linkedExecutable->setDeallocFunction(NULL);
6906 linkedExecutable = os::move(new_osdata);
6907
6908 #if VM_MAPPED_KEXTS
6909 kext_free(new_endofkext, (endofkext - new_endofkext));
6910 #else
6911 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6912 #endif
6913 }
6914 }
6915 dysymtab->nlocrel = 0;
6916 dysymtab->locreloff = 0;
6917 }
6918 }
6919
6920 result = kOSReturnSuccess;
6921 finish:
6922 return result;
6923 }
6924
6925 /*********************************************************************
6926 * called only by load()
6927 *********************************************************************/
6928 OSReturn
loadExecutable()6929 OSKext::loadExecutable()
6930 {
6931 OSReturn result = kOSReturnError;
6932 OSSharedPtr<OSArray> linkDependencies;
6933 uint32_t num_kmod_refs = 0;
6934 OSData * theExecutable = NULL; // do not release
6935 OSString * versString = NULL; // do not release
6936 const char * versCString = NULL; // do not free
6937 const char * string = NULL; // do not free
6938
6939 #if CONFIG_KXLD
6940 unsigned int i;
6941 uint32_t numDirectDependencies = 0;
6942 kern_return_t kxldResult;
6943 KXLDDependency * kxlddeps = NULL; // must kfree
6944 uint32_t num_kxlddeps = 0;
6945 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6946 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6947 #endif // CONFIG_KXLD
6948
6949 /* We need the version string for a variety of bits below.
6950 */
6951 versString = OSDynamicCast(OSString,
6952 getPropertyForHostArch(kCFBundleVersionKey));
6953 if (!versString) {
6954 goto finish;
6955 }
6956 versCString = versString->getCStringNoCopy();
6957
6958 if (isKernelComponent()) {
6959 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6960 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6961 OSKextLog(this,
6962 kOSKextLogErrorLevel |
6963 kOSKextLogLoadFlag,
6964 "Kernel component %s has incorrect version %s; "
6965 "expected %s.",
6966 getIdentifierCString(),
6967 versCString, KERNEL6_VERSION);
6968 result = kOSKextReturnInternalError;
6969 goto finish;
6970 } else if (strcmp(versCString, osrelease)) {
6971 OSKextLog(this,
6972 kOSKextLogErrorLevel |
6973 kOSKextLogLoadFlag,
6974 "Kernel component %s has incorrect version %s; "
6975 "expected %s.",
6976 getIdentifierCString(),
6977 versCString, osrelease);
6978 result = kOSKextReturnInternalError;
6979 goto finish;
6980 }
6981 }
6982 }
6983
6984 #if defined(__x86_64__) || defined(__i386__)
6985 if (flags.resetSegmentsFromVnode) {
6986 /* Fixup the chains and slide the mach headers */
6987 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6988
6989 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6990 result = kOSKextReturnValidation;
6991 goto finish;
6992 }
6993 }
6994 #endif //(__x86_64__) || defined(__i386__)
6995
6996 if (isPrelinked()) {
6997 goto register_kmod;
6998 }
6999
7000 /* <rdar://problem/21444003> all callers must be entitled */
7001 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7002 OSKextLog(this,
7003 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7004 "Not entitled to link kext '%s'",
7005 getIdentifierCString());
7006 result = kOSKextReturnNotPrivileged;
7007 goto finish;
7008 }
7009
7010 theExecutable = getExecutable();
7011 if (!theExecutable) {
7012 if (declaresExecutable()) {
7013 OSKextLog(this,
7014 kOSKextLogErrorLevel |
7015 kOSKextLogLoadFlag,
7016 "Can't load kext %s - executable is missing.",
7017 getIdentifierCString());
7018 result = kOSKextReturnValidation;
7019 goto finish;
7020 }
7021 goto register_kmod;
7022 }
7023
7024 if (isInterface()) {
7025 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7026 if (executableCopy) {
7027 setLinkedExecutable(executableCopy.get());
7028 }
7029 goto register_kmod;
7030 }
7031
7032 #if CONFIG_KXLD
7033 numDirectDependencies = getNumDependencies();
7034
7035 if (flags.hasBleedthrough) {
7036 linkDependencies = dependencies;
7037 } else {
7038 linkDependencies = OSArray::withArray(dependencies.get());
7039 if (!linkDependencies) {
7040 OSKextLog(this,
7041 kOSKextLogErrorLevel |
7042 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7043 "Can't allocate link dependencies to load kext %s.",
7044 getIdentifierCString());
7045 goto finish;
7046 }
7047
7048 for (i = 0; i < numDirectDependencies; ++i) {
7049 OSKext * dependencyKext = OSDynamicCast(OSKext,
7050 dependencies->getObject(i));
7051 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7052 }
7053 }
7054
7055 num_kxlddeps = linkDependencies->getCount();
7056 if (!num_kxlddeps) {
7057 OSKextLog(this,
7058 kOSKextLogErrorLevel |
7059 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7060 "Can't load kext %s - it has no library dependencies.",
7061 getIdentifierCString());
7062 goto finish;
7063 }
7064
7065 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7066 if (!kxlddeps) {
7067 OSKextLog(this,
7068 kOSKextLogErrorLevel |
7069 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7070 "Can't allocate link context to load kext %s.",
7071 getIdentifierCString());
7072 goto finish;
7073 }
7074 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7075
7076 for (i = 0; i < num_kxlddeps; ++i) {
7077 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7078
7079 if (dependency->isInterface()) {
7080 OSKext *interfaceTargetKext = NULL; //do not release
7081 OSData * interfaceTarget = NULL; //do not release
7082
7083 if (dependency->isKernelComponent()) {
7084 interfaceTargetKext = sKernelKext;
7085 interfaceTarget = sKernelKext->linkedExecutable.get();
7086 } else {
7087 interfaceTargetKext = OSDynamicCast(OSKext,
7088 dependency->dependencies->getObject(0));
7089
7090 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7091 }
7092
7093 if (!interfaceTarget) {
7094 // panic?
7095 goto finish;
7096 }
7097
7098 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7099 * it will be useful to have them in the debugger.
7100 * strdup() failing isn't critical right here so we don't check that.
7101 */
7102 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7103 kxlddeps[i].kext_size = interfaceTarget->getLength();
7104 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7105
7106 if (dependency->linkedExecutable != NULL) {
7107 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7108 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7109 } else {
7110 kxlddeps[i].interface = (u_char *) NULL;
7111 kxlddeps[i].interface_size = 0;
7112 }
7113 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7114 } else {
7115 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7116 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7117 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7118 }
7119
7120 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7121 }
7122
7123 kxldHeaderPtr = &kxld_header;
7124
7125 #if DEBUG
7126 OSKextLog(this,
7127 kOSKextLogExplicitLevel |
7128 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7129 "Kext %s - calling kxld_link_file:\n"
7130 " kxld_context: %p\n"
7131 " executable: %p executable_length: %d\n"
7132 " user_data: %p\n"
7133 " kxld_dependencies: %p num_dependencies: %d\n"
7134 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7135 getIdentifierCString(), sKxldContext,
7136 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7137 this, kxlddeps, num_kxlddeps,
7138 kxldHeaderPtr, &kmod_info);
7139 #endif
7140
7141 /* After this call, the linkedExecutable instance variable
7142 * should exist.
7143 */
7144 kxldResult = kxld_link_file(sKxldContext,
7145 (u_char *)theExecutable->getBytesNoCopy(),
7146 theExecutable->getLength(),
7147 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7148 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7149
7150 if (kxldResult != KERN_SUCCESS) {
7151 // xxx - add kxldResult here?
7152 OSKextLog(this,
7153 kOSKextLogErrorLevel |
7154 kOSKextLogLoadFlag,
7155 "Can't load kext %s - link failed.",
7156 getIdentifierCString());
7157 result = kOSKextReturnLinkError;
7158 goto finish;
7159 }
7160
7161 /* We've written data & instructions into kernel memory, so flush the data
7162 * cache and invalidate the instruction cache.
7163 * I/D caches are coherent on x86
7164 */
7165 #if !defined(__i386__) && !defined(__x86_64__)
7166 flush_dcache(kmod_info->address, kmod_info->size, false);
7167 invalidate_icache(kmod_info->address, kmod_info->size, false);
7168 #endif
7169
7170 #else // !CONFIG_KXLD
7171 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7172 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7173 result = kOSKextReturnLinkError;
7174 goto finish;
7175 #endif // CONFIG_KXLD
7176
7177 register_kmod:
7178
7179 if (isInterface()) {
7180 /* Whip up a fake kmod_info entry for the interface kext.
7181 */
7182 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7183 if (!kmod_info) {
7184 result = KERN_MEMORY_ERROR;
7185 goto finish;
7186 }
7187
7188 /* A pseudokext has almost nothing in its kmod_info struct.
7189 */
7190 kmod_info->info_version = KMOD_INFO_VERSION;
7191
7192 /* An interface kext doesn't have a linkedExecutable, so save a
7193 * copy of the UUID out of the original executable via copyUUID()
7194 * while we still have the original executable.
7195 */
7196 interfaceUUID = copyUUID();
7197 }
7198
7199 kmod_info->id = loadTag = sNextLoadTag++;
7200 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7201
7202 /* Stamp the bundle ID and version from the OSKext over anything
7203 * resident inside the kmod_info.
7204 */
7205 string = getIdentifierCString();
7206 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7207
7208 string = versCString;
7209 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7210
7211 /* Add the dependencies' kmod_info structs as kmod_references.
7212 */
7213 num_kmod_refs = getNumDependencies();
7214 if (num_kmod_refs) {
7215 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7216 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7217 if (!kmod_info->reference_list) {
7218 result = KERN_MEMORY_ERROR;
7219 goto finish;
7220 }
7221 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7222 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7223 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7224 ref->info = refKext->kmod_info;
7225 ref->info->reference_count++;
7226
7227 if (refIndex + 1 < num_kmod_refs) {
7228 ref->next = kmod_info->reference_list + refIndex + 1;
7229 }
7230 }
7231 }
7232
7233 if (kmod_info->hdr_size > UINT32_MAX) {
7234 OSKextLog(this,
7235 kOSKextLogErrorLevel |
7236 kOSKextLogLoadFlag,
7237 #if __LP64__
7238 "Kext %s header size is too large (%lu > UINT32_MAX).",
7239 #else
7240 "Kext %s header size is too large (%u > UINT32_MAX).",
7241 #endif
7242 kmod_info->name,
7243 kmod_info->hdr_size);
7244 result = KERN_FAILURE;
7245 goto finish;
7246 }
7247
7248 if (kmod_info->size > UINT32_MAX) {
7249 OSKextLog(this,
7250 kOSKextLogErrorLevel |
7251 kOSKextLogLoadFlag,
7252 #if __LP64__
7253 "Kext %s size is too large (%lu > UINT32_MAX).",
7254 #else
7255 "Kext %s size is too large (%u > UINT32_MAX).",
7256 #endif
7257 kmod_info->name,
7258 kmod_info->size);
7259 result = KERN_FAILURE;
7260 goto finish;
7261 }
7262
7263 if (!isInterface() && linkedExecutable) {
7264 OSKextLog(this,
7265 kOSKextLogProgressLevel |
7266 kOSKextLogLoadFlag,
7267 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7268 kmod_info->name,
7269 (unsigned)kmod_info->size / PAGE_SIZE,
7270 (unsigned long)ml_static_unslide(kmod_info->address),
7271 (unsigned)kmod_info->id);
7272 }
7273
7274 /* VM protections and wiring for the Aux KC are done at collection loading time */
7275 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7276 /* if prelinked and primary KC, VM protections are already set */
7277 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7278 if (result != KERN_SUCCESS) {
7279 goto finish;
7280 }
7281 }
7282
7283 #if KASAN
7284 if (linkedExecutable) {
7285 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7286 linkedExecutable->getLength(), getIdentifierCString());
7287 }
7288 #else
7289 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7290 OSKextLog(this,
7291 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7292 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7293 getIdentifierCString()
7294 );
7295 result = KERN_FAILURE;
7296 goto finish;
7297 }
7298 #endif
7299
7300 result = kOSReturnSuccess;
7301
7302 finish:
7303
7304 #if CONFIG_KXLD
7305 /* Clear up locally allocated dependency info.
7306 */
7307 for (i = 0; i < num_kxlddeps; ++i) {
7308 size_t size;
7309
7310 if (kxlddeps[i].kext_name) {
7311 size = 1 + strlen(kxlddeps[i].kext_name);
7312 kfree_data(kxlddeps[i].kext_name, size);
7313 }
7314 if (kxlddeps[i].interface_name) {
7315 size = 1 + strlen(kxlddeps[i].interface_name);
7316 kfree_data(kxlddeps[i].interface_name, size);
7317 }
7318 }
7319 if (kxlddeps) {
7320 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7321 }
7322 #endif // CONFIG_KXLD
7323
7324 /* We no longer need the unrelocated executable (which the linker
7325 * has altered anyhow).
7326 */
7327 setExecutable(NULL);
7328
7329 if (result != kOSReturnSuccess) {
7330 OSKextLog(this,
7331 kOSKextLogErrorLevel |
7332 kOSKextLogLoadFlag,
7333 "Failed to load executable for kext %s.",
7334 getIdentifierCString());
7335
7336 if (kmod_info && kmod_info->reference_list) {
7337 kfree_type(kmod_reference_t, num_kmod_refs,
7338 kmod_info->reference_list);
7339 }
7340 if (isInterface()) {
7341 kfree_type(kmod_info_t, kmod_info);
7342 kmod_info = NULL;
7343 }
7344 if (kc_type == KCKindUnknown) {
7345 kmod_info = NULL;
7346 if (linkedExecutable) {
7347 linkedExecutable.reset();
7348 }
7349 }
7350 }
7351
7352 return result;
7353 }
7354
7355 /* static */
7356 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7357 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7358 {
7359 kernel_segment_command_t *linkeditseg = NULL;
7360
7361 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7362 if (linkeditseg == NULL) {
7363 panic("FileSet booted with no Linkedit segment");
7364 }
7365
7366 #if VM_MAPPED_KEXTS
7367 /* BootKC on x86_64 is not vm mapped */
7368 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7369
7370 OSKextLog(/* kext */ NULL,
7371 kOSKextLogProgressLevel |
7372 kOSKextLogGeneralFlag,
7373 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7374 linkeditseg->vmaddr, linkeditseg->vmsize);
7375 #else
7376 /* BootKC on arm64 is not vm mapped, but is slid */
7377 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7378
7379 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7380
7381 OSKextLog(/* kext */ NULL,
7382 kOSKextLogProgressLevel |
7383 kOSKextLogGeneralFlag,
7384 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7385 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7386 #endif /* VM_MAPPED_KEXTS */
7387 }
7388
7389 /*********************************************************************
7390 * The linkedit segment is used by the kext linker for dependency
7391 * resolution, and by dtrace for probe initialization. We can free it
7392 * for non-library kexts, since no kexts depend on non-library kexts
7393 * by definition, once dtrace has been initialized.
7394 *********************************************************************/
7395 void
jettisonLinkeditSegment(void)7396 OSKext::jettisonLinkeditSegment(void)
7397 {
7398 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7399 kernel_segment_command_t * linkedit = NULL;
7400 vm_offset_t start;
7401 vm_size_t linkeditsize, kextsize;
7402 OSSharedPtr<OSData> data;
7403 kc_format format = KCFormatUnknown;
7404
7405 if (isInFileset()) {
7406 return;
7407 }
7408
7409 #if NO_KEXTD
7410 /* We can free symbol tables for all embedded kexts because we don't
7411 * support runtime kext linking.
7412 */
7413 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7414 #else
7415 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7416 #endif
7417 goto finish;
7418 }
7419
7420 /* Find the linkedit segment. If it's not the last segment, then freeing
7421 * it will fragment the kext into multiple VM regions, which OSKext is not
7422 * designed to handle, so we'll have to skip it.
7423 */
7424 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7425 if (!linkedit) {
7426 goto finish;
7427 }
7428
7429 if (round_page(kmod_info->address + kmod_info->size) !=
7430 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7431 goto finish;
7432 }
7433
7434 /* Create a new OSData for the smaller kext object.
7435 */
7436 linkeditsize = round_page(linkedit->vmsize);
7437 kextsize = kmod_info->size - linkeditsize;
7438 start = linkedit->vmaddr;
7439
7440 if (kextsize > UINT_MAX) {
7441 goto finish;
7442 }
7443 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7444 if (!data) {
7445 goto finish;
7446 }
7447
7448 /* Fix the kmod info and linkedExecutable.
7449 */
7450 kmod_info->size = kextsize;
7451
7452 /*
7453 * Fileset KCs are mapped as a whole by iBoot.
7454 * Individual kext executables should not be unmapped by xnu
7455 * Doing so may result in panics like rdar://85419651
7456 */
7457 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7458 data->setDeallocFunction(NULL);
7459 } else { // Not from a Fileset KC
7460 #if VM_MAPPED_KEXTS
7461 data->setDeallocFunction(osdata_kext_free);
7462 #else
7463 data->setDeallocFunction(osdata_phys_free);
7464 #endif
7465 }
7466 linkedExecutable->setDeallocFunction(NULL);
7467 linkedExecutable = os::move(data);
7468 flags.jettisonLinkeditSeg = 1;
7469
7470 /* Free the linkedit segment.
7471 */
7472 #if VM_MAPPED_KEXTS
7473 kext_free(start, linkeditsize);
7474 #else
7475 ml_static_mfree(start, linkeditsize);
7476 #endif
7477
7478 finish:
7479 return;
7480 }
7481
7482 /*********************************************************************
7483 * If there are whole pages that are unused betweem the last section
7484 * of the DATA segment and the end of the DATA segment then we can free
7485 * them
7486 *********************************************************************/
7487 void
7488 OSKext::jettisonDATASegmentPadding(void)
7489 {
7490 kernel_mach_header_t * mh;
7491 kernel_segment_command_t * dataSeg;
7492 kernel_section_t * sec, * lastSec;
7493 vm_offset_t dataSegEnd, lastSecEnd;
7494 vm_size_t padSize;
7495
7496 if (flags.builtin) {
7497 return;
7498 }
7499 mh = (kernel_mach_header_t *)kmod_info->address;
7500
7501 if (isInFileset()) {
7502 return;
7503 }
7504
7505 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7506 if (dataSeg == NULL) {
7507 return;
7508 }
7509
7510 lastSec = NULL;
7511 sec = firstsect(dataSeg);
7512 while (sec != NULL) {
7513 lastSec = sec;
7514 sec = nextsect(dataSeg, sec);
7515 }
7516
7517 if (lastSec == NULL) {
7518 return;
7519 }
7520
7521 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7522 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7523 return;
7524 }
7525
7526 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7527 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7528
7529 if (dataSegEnd <= lastSecEnd) {
7530 return;
7531 }
7532
7533 padSize = dataSegEnd - lastSecEnd;
7534
7535 if (padSize >= PAGE_SIZE) {
7536 #if VM_MAPPED_KEXTS
7537 kext_free(lastSecEnd, padSize);
7538 #else
7539 ml_static_mfree(lastSecEnd, padSize);
7540 #endif
7541 }
7542 }
7543
7544 /*********************************************************************
7545 *********************************************************************/
7546 void
7547 OSKext::setLinkedExecutable(OSData * anExecutable)
7548 {
7549 if (linkedExecutable) {
7550 panic("Attempt to set linked executable on kext "
7551 "that already has one (%s).\n",
7552 getIdentifierCString());
7553 }
7554 linkedExecutable.reset(anExecutable, OSRetain);
7555 return;
7556 }
7557
7558 #if CONFIG_DTRACE
7559 /*********************************************************************
7560 * Go through all loaded kexts and tell them to register with dtrace.
7561 * The instance method only registers if necessary.
7562 *********************************************************************/
7563 /* static */
7564 void
7565 OSKext::registerKextsWithDTrace(void)
7566 {
7567 uint32_t count = sLoadedKexts->getCount();
7568 uint32_t i;
7569
7570 IORecursiveLockLock(sKextLock);
7571
7572 for (i = 0; i < count; i++) {
7573 OSKext * thisKext = NULL; // do not release
7574
7575 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7576 if (!thisKext || !thisKext->isExecutable()) {
7577 continue;
7578 }
7579
7580 thisKext->registerWithDTrace();
7581 }
7582
7583 IORecursiveLockUnlock(sKextLock);
7584
7585 return;
7586 }
7587
7588 extern "C" {
7589 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7590 extern int (*dtrace_modunload)(struct kmod_info *);
7591 };
7592
7593 /*********************************************************************
7594 *********************************************************************/
7595 void
7596 OSKext::registerWithDTrace(void)
7597 {
7598 /* Register kext with dtrace. A dtrace_modload failure should not
7599 * prevent a kext from loading, so we ignore the return code.
7600 */
7601 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7602 uint32_t modflag = 0;
7603 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7604
7605 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7606 if (forceInit == kOSBooleanTrue) {
7607 OSKextLog(this,
7608 kOSKextLogBasicLevel |
7609 kOSKextLogGeneralFlag,
7610 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7611 getIdentifierCString());
7612 forceInit = kOSBooleanFalse;
7613 }
7614 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7615 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7616 }
7617
7618 if (forceInit == kOSBooleanTrue) {
7619 modflag |= KMOD_DTRACE_FORCE_INIT;
7620 }
7621 if (flags.builtin) {
7622 modflag |= KMOD_DTRACE_STATIC_KEXT;
7623 }
7624
7625 (void)(*dtrace_modload)(kmod_info, modflag);
7626 flags.dtraceInitialized = true;
7627 jettisonLinkeditSegment();
7628 }
7629 return;
7630 }
7631 /*********************************************************************
7632 *********************************************************************/
7633 void
7634 OSKext::unregisterWithDTrace(void)
7635 {
7636 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7637 * prevent a kext from loading, so we ignore the return code.
7638 */
7639 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7640 (void)(*dtrace_modunload)(kmod_info);
7641 flags.dtraceInitialized = false;
7642 }
7643 return;
7644 }
7645 #endif /* CONFIG_DTRACE */
7646
7647
7648 /*********************************************************************
7649 * called only by loadExecutable()
7650 *********************************************************************/
7651 #if !VM_MAPPED_KEXTS
7652 #if defined(__arm__) || defined(__arm64__)
7653 static inline kern_return_t
7654 OSKext_protect(
7655 kernel_mach_header_t *kext_mh,
7656 vm_map_t map,
7657 vm_map_offset_t start,
7658 vm_map_offset_t end,
7659 vm_prot_t new_prot,
7660 boolean_t set_max,
7661 kc_kind_t kc_type)
7662 {
7663 #pragma unused(kext_mh,map,kc_type)
7664 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7665 assert(start <= end);
7666 if (start >= end) {
7667 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7668 } else if (set_max) {
7669 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7670 } else {
7671 return ml_static_protect(start, end - start, new_prot);
7672 }
7673 }
7674
7675 static inline kern_return_t
7676 OSKext_wire(
7677 kernel_mach_header_t *kext_mh,
7678 vm_map_t map,
7679 vm_map_offset_t start,
7680 vm_map_offset_t end,
7681 vm_prot_t access_type,
7682 boolean_t user_wire,
7683 kc_kind_t kc_type)
7684 {
7685 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7686 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7687 }
7688 #else
7689 #error Unrecognized architecture
7690 #endif
7691 #else
7692 static inline kern_return_t
7693 OSKext_protect(
7694 kernel_mach_header_t *kext_mh,
7695 vm_map_t map,
7696 vm_map_offset_t start,
7697 vm_map_offset_t end,
7698 vm_prot_t new_prot,
7699 boolean_t set_max,
7700 kc_kind_t kc_type)
7701 {
7702 if (start == end) { // 10538581
7703 return KERN_SUCCESS;
7704 }
7705 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7706 /*
7707 * XXX: This will probably need to be different for AuxKC and
7708 * pageableKC!
7709 */
7710 return ml_static_protect(start, end - start, new_prot);
7711 }
7712 return vm_map_protect(map, start, end, new_prot, set_max);
7713 }
7714
7715 static inline kern_return_t
7716 OSKext_wire(
7717 kernel_mach_header_t *kext_mh,
7718 vm_map_t map,
7719 vm_map_offset_t start,
7720 vm_map_offset_t end,
7721 vm_prot_t access_type,
7722 boolean_t user_wire,
7723 kc_kind_t kc_type)
7724 {
7725 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7726 /* TODO: we may need to hook this for the pageableKC */
7727 return KERN_SUCCESS;
7728 }
7729 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7730 }
7731 #endif
7732
7733 OSReturn
7734 OSKext::setVMAttributes(bool protect, bool wire)
7735 {
7736 vm_map_t kext_map = NULL;
7737 kernel_segment_command_t * seg = NULL;
7738 vm_map_offset_t start_protect = 0;
7739 vm_map_offset_t start_wire = 0;
7740 vm_map_offset_t end_protect = 0;
7741 vm_map_offset_t end_wire = 0;
7742 OSReturn result = kOSReturnError;
7743
7744 if (isInterface() || !declaresExecutable() || flags.builtin) {
7745 result = kOSReturnSuccess;
7746 goto finish;
7747 }
7748
7749 /* Get the kext's vm map */
7750 kext_map = kext_get_vm_map(kmod_info);
7751 if (!kext_map) {
7752 result = KERN_MEMORY_ERROR;
7753 goto finish;
7754 }
7755
7756 #if !VM_MAPPED_KEXTS
7757 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7758 /* This is a split kext in a prelinked kernelcache; we'll let the
7759 * platform code take care of protecting it. It is already wired.
7760 */
7761 /* TODO: Should this still allow protections for the first segment
7762 * to go through, in the event that we have a mix of split and
7763 * unsplit kexts?
7764 */
7765 result = KERN_SUCCESS;
7766 goto finish;
7767 }
7768
7769 if (isInFileset() && kc_type != KCKindPageable) {
7770 // kexts in filesets have protections setup as part of collection loading
7771 result = KERN_SUCCESS;
7772 goto finish;
7773 }
7774 #endif
7775
7776 /* Protect the headers as read-only; they do not need to be wired */
7777 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7778 kext_map, kmod_info->address,
7779 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7780 : KERN_SUCCESS;
7781 if (result != KERN_SUCCESS) {
7782 goto finish;
7783 }
7784
7785 /* Set the VM protections and wire down each of the segments */
7786 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7787 while (seg) {
7788 #if __arm__
7789 /* We build all ARM kexts, so we can ensure they are aligned */
7790 assert((seg->vmaddr & PAGE_MASK) == 0);
7791 assert((seg->vmsize & PAGE_MASK) == 0);
7792 #endif
7793
7794 /*
7795 * For the non page aligned segments, the range calculation for protection
7796 * and wiring differ as follows:
7797 *
7798 * Protection: The non page aligned data at the start or at the end of the
7799 * segment is excluded from the protection. This exclusion is needed to make
7800 * sure OSKext_protect is not called twice on same page, if the page is shared
7801 * between two segments.
7802 *
7803 * Wiring: The non page aligned data at the start or at the end of the
7804 * segment is included in the wiring range, this inclusion is needed to make sure
7805 * all the data of the segment is wired.
7806 */
7807 start_protect = round_page(seg->vmaddr);
7808 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7809
7810 start_wire = trunc_page(seg->vmaddr);
7811 end_wire = round_page(seg->vmaddr + seg->vmsize);
7812
7813 /*
7814 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7815 * across kexts and data from kexts is not page aligned
7816 */
7817 if (protect && (end_protect > start_protect) &&
7818 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7819 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7820 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7821 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7822 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7823 if (result != KERN_SUCCESS) {
7824 OSKextLog(this,
7825 kOSKextLogErrorLevel |
7826 kOSKextLogLoadFlag,
7827 "Kext %s failed to set maximum VM protections "
7828 "for segment %s - 0x%x.",
7829 getIdentifierCString(), seg->segname, (int)result);
7830 goto finish;
7831 }
7832
7833 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7834 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7835 if (result != KERN_SUCCESS) {
7836 OSKextLog(this,
7837 kOSKextLogErrorLevel |
7838 kOSKextLogLoadFlag,
7839 "Kext %s failed to set initial VM protections "
7840 "for segment %s - 0x%x.",
7841 getIdentifierCString(), seg->segname, (int)result);
7842 goto finish;
7843 }
7844 }
7845
7846 if (segmentShouldBeWired(seg) && wire) {
7847 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7848 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7849 if (result != KERN_SUCCESS) {
7850 goto finish;
7851 }
7852 }
7853
7854 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7855 }
7856
7857 finish:
7858 return result;
7859 }
7860
7861 /*********************************************************************
7862 *********************************************************************/
7863 boolean_t
7864 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7865 {
7866 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7867 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7868 }
7869
7870 /*********************************************************************
7871 *********************************************************************/
7872 OSReturn
7873 OSKext::validateKextMapping(bool startFlag)
7874 {
7875 OSReturn result = kOSReturnError;
7876 const char * whichOp = startFlag ? "start" : "stop";
7877 kern_return_t kern_result = 0;
7878 vm_map_t kext_map = NULL;
7879 kernel_segment_command_t * seg = NULL;
7880 mach_vm_address_t address = 0;
7881 mach_vm_size_t size = 0;
7882 uint32_t depth = 0;
7883 uint64_t kext_segbase = 0;
7884 uint64_t kext_segsize = 0;
7885 mach_msg_type_number_t count;
7886 vm_region_submap_short_info_data_64_t info;
7887 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7888
7889 if (flags.builtin) {
7890 return kOSReturnSuccess;
7891 }
7892
7893 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7894 bzero(&info, sizeof(info));
7895
7896 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7897 // xxx - sufficient?
7898
7899 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7900 */
7901 if (!kmod_info) {
7902 OSKextLog(this,
7903 kOSKextLogErrorLevel |
7904 kOSKextLogLoadFlag,
7905 "Kext %s - NULL kmod_info pointer.",
7906 getIdentifierCString());
7907 result = kOSKextReturnBadData;
7908 goto finish;
7909 }
7910
7911 if (startFlag) {
7912 address = (mach_vm_address_t)kmod_info->start;
7913 } else {
7914 address = (mach_vm_address_t)kmod_info->stop;
7915 }
7916
7917 if (!address) {
7918 OSKextLog(this,
7919 kOSKextLogErrorLevel |
7920 kOSKextLogLoadFlag,
7921 "Kext %s - NULL module %s pointer.",
7922 getIdentifierCString(), whichOp);
7923 result = kOSKextReturnBadData;
7924 goto finish;
7925 }
7926
7927 kext_map = kext_get_vm_map(kmod_info);
7928 depth = (kernel_map == kext_map) ? 1 : 2;
7929 if (isInFileset()) {
7930 #if defined(HAS_APPLE_PAC)
7931 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7932 #endif /* defined(HAS_APPLE_PAC) */
7933 }
7934
7935 /* Verify that the start/stop function lies within the kext's address range.
7936 */
7937 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7938 isInFileset()) {
7939 /* This will likely be how we deal with split kexts; walk the segments to
7940 * check that the function lies inside one of the segments of this kext.
7941 */
7942 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7943 seg != NULL;
7944 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7945 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7946 kext_segbase = seg->vmaddr;
7947 kext_segsize = seg->vmsize;
7948 break;
7949 }
7950 }
7951
7952 if (!seg) {
7953 OSKextLog(this,
7954 kOSKextLogErrorLevel |
7955 kOSKextLogLoadFlag,
7956 "Kext %s module %s pointer is outside of kext range "
7957 "(%s %p - kext starts at %p).",
7958 getIdentifierCString(),
7959 whichOp,
7960 whichOp,
7961 (void *)(((uintptr_t)address) - kext_slide),
7962 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7963 result = kOSKextReturnBadData;
7964 goto finish;
7965 }
7966
7967 seg = NULL;
7968 } else {
7969 if (address < kmod_info->address + kmod_info->hdr_size ||
7970 kmod_info->address + kmod_info->size <= address) {
7971 OSKextLog(this,
7972 kOSKextLogErrorLevel |
7973 kOSKextLogLoadFlag,
7974 "Kext %s module %s pointer is outside of kext range "
7975 "(%s %p - kext at %p-%p).",
7976 getIdentifierCString(),
7977 whichOp,
7978 whichOp,
7979 (void *)(((uintptr_t)address) - kext_slide),
7980 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7981 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7982 result = kOSKextReturnBadData;
7983 goto finish;
7984 }
7985 }
7986
7987 /* Only do these checks before calling the start function;
7988 * If anything goes wrong with the mapping while the kext is running,
7989 * we'll likely have panicked well before any attempt to stop the kext.
7990 */
7991 if (startFlag) {
7992 if (!isInFileset() || kc_type != KCKindPrimary) {
7993 /*
7994 * Verify that the start/stop function is executable.
7995 */
7996 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7997 (vm_region_recurse_info_t)&info, &count);
7998 if (kern_result != KERN_SUCCESS) {
7999 OSKextLog(this,
8000 kOSKextLogErrorLevel |
8001 kOSKextLogLoadFlag,
8002 "Kext %s - bad %s pointer %p.",
8003 getIdentifierCString(),
8004 whichOp, (void *)ml_static_unslide(address));
8005 result = kOSKextReturnBadData;
8006 goto finish;
8007 }
8008 } else {
8009 /*
8010 * Since kexts loaded from the primary KC are held in memory
8011 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8012 * discover that memory's protection flags. Instead, we need to
8013 * get that information from the kernel pmap itself. Above, we
8014 * (potentially) saved the size of the segment in which the address
8015 * in question was located. If we have a non-zero size, verify
8016 * that all pages in the (address, address + kext_segsize) range
8017 * are marked executable. If we somehow did not record the size
8018 * (or the base) just verify the single page that includes the address.
8019 */
8020 if (kext_segbase == 0 || kext_segsize == 0) {
8021 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8022 kext_segsize = PAGE_SIZE;
8023 }
8024 }
8025
8026 #if VM_MAPPED_KEXTS
8027 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8028 ((isInFileset() && kc_type == KCKindPrimary) &&
8029 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8030 OSKextLog(this,
8031 kOSKextLogErrorLevel |
8032 kOSKextLogLoadFlag,
8033 "Kext %s - memory region containing module %s function "
8034 "is not executable.",
8035 getIdentifierCString(), whichOp);
8036 result = kOSKextReturnBadData;
8037 goto finish;
8038 }
8039 #endif
8040
8041 /* Verify that the kext's segments are backed by physical memory.
8042 */
8043 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8044 while (seg) {
8045 if (!verifySegmentMapping(seg)) {
8046 result = kOSKextReturnBadData;
8047 goto finish;
8048 }
8049
8050 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8051 }
8052 }
8053
8054 result = kOSReturnSuccess;
8055 finish:
8056 return result;
8057 }
8058
8059 /*********************************************************************
8060 *********************************************************************/
8061 boolean_t
8062 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8063 {
8064 mach_vm_address_t address = 0;
8065
8066 if (seg->vmsize > UINT32_MAX) {
8067 return false;
8068 }
8069
8070 if (!segmentShouldBeWired(seg)) {
8071 return true;
8072 }
8073
8074 for (address = seg->vmaddr;
8075 address < round_page(seg->vmaddr + seg->vmsize);
8076 address += PAGE_SIZE) {
8077 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8078 OSKextLog(this,
8079 kOSKextLogErrorLevel |
8080 kOSKextLogLoadFlag,
8081 "Kext %s - page %p is not backed by physical memory.",
8082 getIdentifierCString(),
8083 (void *)address);
8084 return false;
8085 }
8086 }
8087
8088 return true;
8089 }
8090
8091 /*********************************************************************
8092 *********************************************************************/
8093 static void
8094 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8095 {
8096 uint64_t stamp = 0;
8097 firehose_tracepoint_id_u trace_id;
8098 struct firehose_trace_uuid_info_s uuid_info_s;
8099 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8100 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8101 OSSharedPtr<OSData> uuid_data;
8102
8103 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8104 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8105
8106 uuid_data = aKext->copyTextUUID();
8107 if (uuid_data) {
8108 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8109 }
8110
8111 uuid_info->ftui_size = size;
8112 if (aKext->isDriverKit()) {
8113 uuid_info->ftui_address = address;
8114 } else {
8115 uuid_info->ftui_address = ml_static_unslide(address);
8116 }
8117 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
8118 return;
8119 }
8120
8121 void
8122 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8123 {
8124 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8125 }
8126
8127 /*********************************************************************
8128 *********************************************************************/
8129 OSReturn
8130 OSKext::start(bool startDependenciesFlag)
8131 {
8132 OSReturn result = kOSReturnError;
8133 kern_return_t (* startfunc)(kmod_info_t *, void *);
8134 unsigned int i, count;
8135 void * kmodStartData = NULL;
8136
8137 if (isStarted() || isInterface() || isKernelComponent()) {
8138 result = kOSReturnSuccess;
8139 goto finish;
8140 }
8141
8142 if (!isLoaded()) {
8143 OSKextLog(this,
8144 kOSKextLogErrorLevel |
8145 kOSKextLogLoadFlag,
8146 "Attempt to start nonloaded kext %s.",
8147 getIdentifierCString());
8148 result = kOSKextReturnInvalidArgument;
8149 goto finish;
8150 }
8151
8152 if (!sLoadEnabled) {
8153 OSKextLog(this,
8154 kOSKextLogErrorLevel |
8155 kOSKextLogLoadFlag,
8156 "Kext loading is disabled (attempt to start kext %s).",
8157 getIdentifierCString());
8158 result = kOSKextReturnDisabled;
8159 goto finish;
8160 }
8161
8162 result = validateKextMapping(/* start? */ true);
8163 if (result != kOSReturnSuccess) {
8164 goto finish;
8165 }
8166
8167 startfunc = kmod_info->start;
8168
8169 count = getNumDependencies();
8170 for (i = 0; i < count; i++) {
8171 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8172 if (dependency == NULL) {
8173 OSKextLog(this,
8174 kOSKextLogErrorLevel |
8175 kOSKextLogLoadFlag,
8176 "Kext %s start - internal error, dependency disappeared.",
8177 getIdentifierCString());
8178 goto finish;
8179 }
8180 if (!dependency->isStarted()) {
8181 if (startDependenciesFlag) {
8182 OSReturn dependencyResult =
8183 dependency->start(startDependenciesFlag);
8184 if (dependencyResult != KERN_SUCCESS) {
8185 OSKextLog(this,
8186 kOSKextLogErrorLevel |
8187 kOSKextLogLoadFlag,
8188 "Kext %s start - dependency %s failed to start (error 0x%x).",
8189 getIdentifierCString(),
8190 dependency->getIdentifierCString(),
8191 dependencyResult);
8192 goto finish;
8193 }
8194 } else {
8195 OSKextLog(this,
8196 kOSKextLogErrorLevel |
8197 kOSKextLogLoadFlag,
8198 "Not starting %s - dependency %s not started yet.",
8199 getIdentifierCString(),
8200 dependency->getIdentifierCString());
8201 result = kOSKextReturnStartStopError; // xxx - make new return?
8202 goto finish;
8203 }
8204 }
8205 }
8206
8207 OSKextLog(this,
8208 kOSKextLogDetailLevel |
8209 kOSKextLogLoadFlag,
8210 "Kext %s calling module start function.",
8211 getIdentifierCString());
8212
8213 flags.starting = 1;
8214
8215 // Drop a log message so logd can grab the needed information to decode this kext
8216 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8217 result = OSRuntimeInitializeCPP(this);
8218 if (result == KERN_SUCCESS) {
8219 result = startfunc(kmod_info, kmodStartData);
8220 }
8221
8222 flags.starting = 0;
8223
8224 /* On success overlap the setting of started/starting. On failure just
8225 * clear starting.
8226 */
8227 if (result == KERN_SUCCESS) {
8228 flags.started = 1;
8229
8230 // xxx - log start error from kernel?
8231 OSKextLog(this,
8232 kOSKextLogProgressLevel |
8233 kOSKextLogLoadFlag,
8234 "Kext %s is now started.",
8235 getIdentifierCString());
8236 } else {
8237 invokeOrCancelRequestCallbacks(
8238 /* result not actually used */ kOSKextReturnStartStopError,
8239 /* invokeFlag */ false);
8240 OSKextLog(this,
8241 kOSKextLogWarningLevel |
8242 kOSKextLogLoadFlag,
8243 "Kext %s did not start (return code 0x%x).",
8244 getIdentifierCString(), result);
8245 }
8246
8247 finish:
8248 return result;
8249 }
8250
8251 /*********************************************************************
8252 *********************************************************************/
8253 /* static */
8254 bool
8255 OSKext::canUnloadKextWithIdentifier(
8256 OSString * kextIdentifier,
8257 bool checkClassesFlag)
8258 {
8259 bool result = false;
8260 OSKext * aKext = NULL; // do not release
8261
8262 IORecursiveLockLock(sKextLock);
8263
8264 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8265
8266 if (!aKext) {
8267 goto finish; // can't unload what's not loaded
8268 }
8269
8270 if (aKext->isLoaded()) {
8271 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8272 goto finish;
8273 }
8274 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8275 goto finish;
8276 }
8277 }
8278
8279 result = true;
8280
8281 finish:
8282 IORecursiveLockUnlock(sKextLock);
8283 return result;
8284 }
8285
8286 /*********************************************************************
8287 *********************************************************************/
8288 OSReturn
8289 OSKext::stop(void)
8290 {
8291 OSReturn result = kOSReturnError;
8292 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8293
8294 if (!isStarted() || isInterface()) {
8295 result = kOSReturnSuccess;
8296 goto finish;
8297 }
8298
8299 if (!isLoaded()) {
8300 OSKextLog(this,
8301 kOSKextLogErrorLevel |
8302 kOSKextLogLoadFlag,
8303 "Attempt to stop nonloaded kext %s.",
8304 getIdentifierCString());
8305 result = kOSKextReturnInvalidArgument;
8306 goto finish;
8307 }
8308
8309 /* Refuse to stop if we have clients or instances. It is up to
8310 * the caller to make sure those aren't true.
8311 */
8312 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8313 OSKextLog(this,
8314 kOSKextLogErrorLevel |
8315 kOSKextLogLoadFlag,
8316 "Kext %s - C++ instances; can't stop.",
8317 getIdentifierCString());
8318 result = kOSKextReturnInUse;
8319 goto finish;
8320 }
8321
8322 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8323 OSKextLog(this,
8324 kOSKextLogErrorLevel |
8325 kOSKextLogLoadFlag,
8326 "Kext %s - has references (linkage or tracking object); "
8327 "can't stop.",
8328 getIdentifierCString());
8329 result = kOSKextReturnInUse;
8330 goto finish;
8331 }
8332
8333 /* Note: If validateKextMapping fails on the stop & unload path,
8334 * we are in serious trouble and a kernel panic is likely whether
8335 * we stop & unload the kext or not.
8336 */
8337 result = validateKextMapping(/* start? */ false);
8338 if (result != kOSReturnSuccess) {
8339 goto finish;
8340 }
8341
8342 stopfunc = kmod_info->stop;
8343 if (stopfunc) {
8344 OSKextLog(this,
8345 kOSKextLogDetailLevel |
8346 kOSKextLogLoadFlag,
8347 "Kext %s calling module stop function.",
8348 getIdentifierCString());
8349
8350 flags.stopping = 1;
8351
8352 result = stopfunc(kmod_info, /* userData */ NULL);
8353 if (result == KERN_SUCCESS) {
8354 result = OSRuntimeFinalizeCPP(this);
8355 }
8356
8357 flags.stopping = 0;
8358
8359 if (result == KERN_SUCCESS) {
8360 flags.started = 0;
8361
8362 OSKextLog(this,
8363 kOSKextLogDetailLevel |
8364 kOSKextLogLoadFlag,
8365 "Kext %s is now stopped and ready to unload.",
8366 getIdentifierCString());
8367 } else {
8368 OSKextLog(this,
8369 kOSKextLogErrorLevel |
8370 kOSKextLogLoadFlag,
8371 "Kext %s did not stop (return code 0x%x).",
8372 getIdentifierCString(), result);
8373 result = kOSKextReturnStartStopError;
8374 }
8375 }
8376
8377 finish:
8378 // Drop a log message so logd can update this kext's metadata
8379 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8380 return result;
8381 }
8382
8383 /*********************************************************************
8384 *********************************************************************/
8385 OSReturn
8386 OSKext::unload(void)
8387 {
8388 OSReturn result = kOSReturnError;
8389 unsigned int index;
8390 uint32_t num_kmod_refs = 0;
8391 OSKextAccount * freeAccount;
8392 bool in_fileset = false;
8393
8394 if (!sUnloadEnabled) {
8395 OSKextLog(this,
8396 kOSKextLogErrorLevel |
8397 kOSKextLogLoadFlag,
8398 "Kext unloading is disabled (%s).",
8399 this->getIdentifierCString());
8400
8401 result = kOSKextReturnDisabled;
8402 goto finish;
8403 }
8404
8405 // cache this result so we don't need to access the kmod_info after
8406 // it's been potentially free'd
8407 in_fileset = isInFileset();
8408
8409 /* Refuse to unload if we have clients or instances. It is up to
8410 * the caller to make sure those aren't true.
8411 */
8412 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8413 // xxx - Don't log under errors? this is more of an info thing
8414 OSKextLog(this,
8415 kOSKextLogErrorLevel |
8416 kOSKextLogKextBookkeepingFlag,
8417 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8418 getIdentifierCString(), getRetainCount());
8419 result = kOSKextReturnInUse;
8420 goto finish;
8421 }
8422
8423 if (isDriverKit()) {
8424 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8425 if (index != (unsigned int)-1) {
8426 sLoadedDriverKitKexts->removeObject(index);
8427 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8428 loadTag = 0;
8429 }
8430 }
8431
8432 if (!isLoaded()) {
8433 result = kOSReturnSuccess;
8434 goto finish;
8435 }
8436
8437 if (isKernelComponent()) {
8438 result = kOSKextReturnInvalidArgument;
8439 goto finish;
8440 }
8441
8442 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8443 OSKextLog(this,
8444 kOSKextLogErrorLevel |
8445 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8446 "Can't unload kext %s; classes have instances:",
8447 getIdentifierCString());
8448 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8449 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8450 result = kOSKextReturnInUse;
8451 goto finish;
8452 }
8453
8454 /* Note that the kext is unloading before running any code that
8455 * might be in the kext (request callbacks, module stop function).
8456 * We will deny certain requests made against a kext in the process
8457 * of unloading.
8458 */
8459 flags.unloading = 1;
8460
8461 /* Update the string describing the last kext to unload in case we panic.
8462 */
8463 savePanicString(/* isLoading */ false);
8464
8465 if (isStarted()) {
8466 result = stop();
8467 if (result != KERN_SUCCESS) {
8468 OSKextLog(this,
8469 kOSKextLogErrorLevel |
8470 kOSKextLogLoadFlag,
8471 "Kext %s can't unload - module stop returned 0x%x.",
8472 getIdentifierCString(), (unsigned)result);
8473 result = kOSKextReturnStartStopError;
8474 goto finish;
8475 }
8476 }
8477
8478 OSKextLog(this,
8479 kOSKextLogProgressLevel |
8480 kOSKextLogLoadFlag,
8481 "Kext %s unloading.",
8482 getIdentifierCString());
8483
8484 {
8485 struct list_head *p;
8486 struct list_head *prev;
8487 struct list_head *next;
8488 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8489 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8490 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8491 prev = p->prev;
8492 next = p->next;
8493 prev->next = next;
8494 next->prev = prev;
8495 p->prev = p;
8496 p->next = p;
8497 IORecursiveLockWakeup(sKextLock, s, false);
8498 }
8499 }
8500
8501
8502 /* Even if we don't call the stop function, we want to be sure we
8503 * have no OSMetaClass references before unloading the kext executable
8504 * from memory. OSMetaClasses may have pointers into the kext executable
8505 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8506 */
8507 if (metaClasses) {
8508 metaClasses->flushCollection();
8509 }
8510 (void) OSRuntimeFinalizeCPP(this);
8511
8512 /* Remove the kext from the list of loaded kexts, patch the gap
8513 * in the kmod_info_t linked list, and reset "kmod" to point to the
8514 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8515 */
8516 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8517 if (index != (unsigned int)-1) {
8518 sLoadedKexts->removeObject(index);
8519
8520 OSKext * nextKext = OSDynamicCast(OSKext,
8521 sLoadedKexts->getObject(index));
8522
8523 if (nextKext) {
8524 if (index > 0) {
8525 OSKext * gapKext = OSDynamicCast(OSKext,
8526 sLoadedKexts->getObject(index - 1));
8527
8528 nextKext->kmod_info->next = gapKext->kmod_info;
8529 } else { /* index == 0 */
8530 nextKext->kmod_info->next = NULL;
8531 }
8532 }
8533
8534 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8535 if (lastKext && !lastKext->isKernel()) {
8536 kmod = lastKext->kmod_info;
8537 } else {
8538 kmod = NULL; // clear the global kmod variable
8539 }
8540 }
8541
8542 /* Clear out the kmod references that we're keeping for compatibility
8543 * with current panic backtrace code & kgmacros.
8544 * xxx - will want to update those bits sometime and remove this.
8545 */
8546 num_kmod_refs = getNumDependencies();
8547 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8548 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8549 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8550 ref->info->reference_count--;
8551 }
8552 kfree_type(kmod_reference_t, num_kmod_refs,
8553 kmod_info->reference_list);
8554 }
8555
8556 #if CONFIG_DTRACE
8557 unregisterWithDTrace();
8558 #endif /* CONFIG_DTRACE */
8559
8560 notifyKextUnloadObservers(this);
8561
8562 freeAccount = NULL;
8563 lck_ticket_lock(sKextAccountsLock, LCK_GRP_NULL);
8564 account->kext = NULL;
8565 if (account->site.tag) {
8566 account->site.flags |= VM_TAG_UNLOAD;
8567 } else {
8568 freeAccount = account;
8569 }
8570
8571 #if DEVELOPMENT || DEBUG
8572 assertf(account->task_refgrp.grp_count == 0,
8573 "unloading a kext with active task references");
8574 #endif /* DEVELOPMENT || DEBUG */
8575
8576 lck_ticket_unlock(sKextAccountsLock);
8577 if (freeAccount) {
8578 IOFreeType(freeAccount, OSKextAccount);
8579 }
8580
8581 /* Unwire and free the linked executable.
8582 */
8583 if (linkedExecutable) {
8584 #if KASAN
8585 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8586 #endif
8587
8588 #if VM_MAPPED_KEXTS
8589 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8590 kernel_segment_command_t *seg = NULL;
8591 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8592
8593 if (!kext_map) {
8594 OSKextLog(this,
8595 kOSKextLogErrorLevel |
8596 kOSKextLogLoadFlag,
8597 "Failed to free kext %s; couldn't find the kext map.",
8598 getIdentifierCString());
8599 result = kOSKextReturnInternalError;
8600 goto finish;
8601 }
8602
8603 OSKextLog(this,
8604 kOSKextLogProgressLevel |
8605 kOSKextLogLoadFlag,
8606 "Kext %s unwiring and unmapping linked executable.",
8607 getIdentifierCString());
8608
8609 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8610 while (seg) {
8611 if (segmentShouldBeWired(seg)) {
8612 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8613 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8614
8615 result = vm_map_unwire(kext_map, start_wire,
8616 end_wire, FALSE);
8617 if (result != KERN_SUCCESS) {
8618 OSKextLog(this,
8619 kOSKextLogErrorLevel |
8620 kOSKextLogLoadFlag,
8621 "Failed to unwire kext %s.",
8622 getIdentifierCString());
8623 result = kOSKextReturnInternalError;
8624 goto finish;
8625 }
8626 }
8627
8628 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8629 }
8630 #if defined(__x86_64__) || defined(__i386__)
8631 if (in_fileset && flags.resetSegmentsFromVnode) {
8632 IORecursiveLockLock(sKextLock);
8633 resetKCFileSetSegments();
8634 IORecursiveLockUnlock(sKextLock);
8635 }
8636 #endif // (__x86_64__) || defined(__i386__)
8637 }
8638 #endif /* VM_MAPPED_KEXTS */
8639 if (flags.resetSegmentsFromImmutableCopy) {
8640 result = resetMutableSegments();
8641 if (result != kOSReturnSuccess) {
8642 OSKextLog(this,
8643 kOSKextLogErrorLevel |
8644 kOSKextLogLoadFlag,
8645 "Failed to reset kext %s.",
8646 getIdentifierCString());
8647 result = kOSKextReturnInternalError;
8648 goto finish;
8649 }
8650 }
8651 if (kc_type == KCKindUnknown) {
8652 linkedExecutable.reset();
8653 }
8654 }
8655
8656 /* An interface kext has a fake kmod_info that was allocated,
8657 * so we have to free it.
8658 */
8659 if (isInterface()) {
8660 kfree_type(kmod_info_t, kmod_info);
8661 kmod_info = NULL;
8662 }
8663
8664 if (!in_fileset) {
8665 kmod_info = NULL;
8666 }
8667
8668 flags.loaded = false;
8669 flushDependencies();
8670
8671 /* save a copy of the bundle ID for us to check when deciding to
8672 * rebuild the kernel cache file. If a kext was already in the kernel
8673 * cache and unloaded then later loaded we do not need to rebuild the
8674 * kernel cache. 9055303
8675 */
8676 if (isPrelinked()) {
8677 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8678 IORecursiveLockLock(sKextLock);
8679 if (sUnloadedPrelinkedKexts) {
8680 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8681 }
8682 IORecursiveLockUnlock(sKextLock);
8683 }
8684 }
8685
8686 OSKextLog(this,
8687 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8688 "Kext %s unloaded.", getIdentifierCString());
8689
8690 queueKextNotification(kKextRequestPredicateUnloadNotification,
8691 OSDynamicCast(OSString, bundleID.get()));
8692
8693 finish:
8694 OSKext::saveLoadedKextPanicList();
8695 OSKext::updateLoadedKextSummaries();
8696
8697 flags.unloading = 0;
8698 return result;
8699 }
8700
8701 /*********************************************************************
8702 * Assumes sKextLock is held.
8703 *********************************************************************/
8704 /* static */
8705 OSReturn
8706 OSKext::queueKextNotification(
8707 const char * notificationName,
8708 OSString * kextIdentifier)
8709 {
8710 OSReturn result = kOSReturnError;
8711 OSSharedPtr<OSDictionary> loadRequest;
8712
8713 if (!kextIdentifier) {
8714 result = kOSKextReturnInvalidArgument;
8715 goto finish;
8716 }
8717
8718 /* Create a new request unless one is already sitting
8719 * in sKernelRequests for this bundle identifier
8720 */
8721 result = _OSKextCreateRequest(notificationName, loadRequest);
8722 if (result != kOSReturnSuccess) {
8723 goto finish;
8724 }
8725 if (!_OSKextSetRequestArgument(loadRequest.get(),
8726 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8727 result = kOSKextReturnNoMemory;
8728 goto finish;
8729 }
8730 if (!sKernelRequests->setObject(loadRequest.get())) {
8731 result = kOSKextReturnNoMemory;
8732 goto finish;
8733 }
8734
8735 /* We might want to only queue the notification if the IOKit daemon is active,
8736 * but that wouldn't work for embedded. Note that we don't care if
8737 * the ping immediately succeeds here so don't do anything with the
8738 * result of this call.
8739 */
8740 OSKext::pingIOKitDaemon();
8741
8742 result = kOSReturnSuccess;
8743
8744 finish:
8745 return result;
8746 }
8747
8748
8749 #if CONFIG_KXLD
8750 /*********************************************************************
8751 *********************************************************************/
8752 static void
8753 _OSKextConsiderDestroyingLinkContext(
8754 __unused thread_call_param_t p0,
8755 __unused thread_call_param_t p1)
8756 {
8757 /* Take multiple locks in the correct order.
8758 */
8759 IORecursiveLockLock(sKextLock);
8760 IORecursiveLockLock(sKextInnerLock);
8761
8762 /* The first time we destroy the kxldContext is in the first
8763 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8764 * before calling this function. Thereafter any call to this function
8765 * will actually destroy the context.
8766 */
8767 if (sConsiderUnloadsCalled && sKxldContext) {
8768 kxld_destroy_context(sKxldContext);
8769 sKxldContext = NULL;
8770 }
8771
8772 /* Free the thread_call that was allocated to execute this function.
8773 */
8774 if (sDestroyLinkContextThread) {
8775 if (!thread_call_free(sDestroyLinkContextThread)) {
8776 OSKextLog(/* kext */ NULL,
8777 kOSKextLogErrorLevel |
8778 kOSKextLogGeneralFlag,
8779 "thread_call_free() failed for kext link context.");
8780 }
8781 sDestroyLinkContextThread = NULL;
8782 }
8783
8784 IORecursiveLockUnlock(sKextInnerLock);
8785 IORecursiveLockUnlock(sKextLock);
8786
8787 return;
8788 }
8789
8790 /*********************************************************************
8791 * Destroying the kxldContext requires checking variables under both
8792 * sKextInnerLock and sKextLock, so we do it on a separate thread
8793 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8794 * call relationship.
8795 *
8796 * This function must be invoked with sKextInnerLock held.
8797 * Do not call any function that takes sKextLock here!
8798 *********************************************************************/
8799 /* static */
8800 void
8801 OSKext::considerDestroyingLinkContext(void)
8802 {
8803 IORecursiveLockLock(sKextInnerLock);
8804
8805 /* If we have already queued a thread to destroy the link context,
8806 * don't bother resetting; that thread will take care of it.
8807 */
8808 if (sDestroyLinkContextThread) {
8809 goto finish;
8810 }
8811
8812 /* The function to be invoked in the thread will deallocate
8813 * this thread_call, so don't share it around.
8814 */
8815 sDestroyLinkContextThread = thread_call_allocate(
8816 &_OSKextConsiderDestroyingLinkContext, NULL);
8817 if (!sDestroyLinkContextThread) {
8818 OSKextLog(/* kext */ NULL,
8819 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8820 "Can't create thread to destroy kext link context.");
8821 goto finish;
8822 }
8823
8824 thread_call_enter(sDestroyLinkContextThread);
8825
8826 finish:
8827 IORecursiveLockUnlock(sKextInnerLock);
8828 return;
8829 }
8830
8831 #else // !CONFIG_KXLD
8832
8833 /* static */
8834 void
8835 OSKext::considerDestroyingLinkContext(void)
8836 {
8837 return;
8838 }
8839
8840 #endif // CONFIG_KXLD
8841
8842 #if PRAGMA_MARK
8843 #pragma mark Autounload
8844 #endif
8845 /*********************************************************************
8846 * This is a static method because the kext will be deallocated if it
8847 * does unload!
8848 *********************************************************************/
8849 /* static */
8850 OSReturn
8851 OSKext::autounloadKext(OSKext * aKext)
8852 {
8853 OSReturn result = kOSKextReturnInUse;
8854
8855 #if NO_KEXTD
8856 /*
8857 * Do not unload prelinked kexts on platforms that do not have an
8858 * IOKit daemon as there is no way to reload the kext or restart
8859 * matching.
8860 */
8861 if (aKext->isPrelinked()) {
8862 goto finish;
8863 }
8864 #endif /* defined(__x86_64__) */
8865
8866 /* Check for external references to this kext (usu. dependents),
8867 * instances of defined classes (or classes derived from them),
8868 * outstanding requests.
8869 */
8870 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8871 !aKext->flags.autounloadEnabled ||
8872 aKext->isKernelComponent()) {
8873 goto finish;
8874 }
8875
8876 /* Skip a delay-autounload kext, once.
8877 */
8878 if (aKext->flags.delayAutounload) {
8879 OSKextLog(aKext,
8880 kOSKextLogProgressLevel |
8881 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8882 "Kext %s has delayed autounload set; skipping and clearing flag.",
8883 aKext->getIdentifierCString());
8884 aKext->flags.delayAutounload = 0;
8885 goto finish;
8886 }
8887
8888 if (aKext->hasOSMetaClassInstances() ||
8889 aKext->countRequestCallbacks()) {
8890 goto finish;
8891 }
8892
8893 result = OSKext::removeKext(aKext);
8894
8895 finish:
8896 return result;
8897 }
8898
8899 /*********************************************************************
8900 *********************************************************************/
8901 void
8902 _OSKextConsiderUnloads(
8903 __unused thread_call_param_t p0,
8904 __unused thread_call_param_t p1)
8905 {
8906 bool didUnload = false;
8907 unsigned int count, i;
8908
8909 /* Take multiple locks in the correct order
8910 * (note also sKextSummaries lock further down).
8911 */
8912 IORecursiveLockLock(sKextLock);
8913 IORecursiveLockLock(sKextInnerLock);
8914
8915 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8916
8917 /* If the system is powering down, don't try to unload anything.
8918 */
8919 if (sSystemSleep) {
8920 goto finish;
8921 }
8922
8923 OSKextLog(/* kext */ NULL,
8924 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8925 "Checking for unused kexts to autounload.");
8926
8927 /*****
8928 * Remove any request callbacks marked as stale,
8929 * and mark as stale any currently in flight.
8930 */
8931 count = sRequestCallbackRecords->getCount();
8932 if (count) {
8933 i = count - 1;
8934 do {
8935 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8936 sRequestCallbackRecords->getObject(i));
8937 if (callbackRecord) {
8938 OSBoolean * stale = OSDynamicCast(OSBoolean,
8939 callbackRecord->getObject(kKextRequestStaleKey));
8940
8941 if (stale == kOSBooleanTrue) {
8942 OSKext::invokeRequestCallback(callbackRecord,
8943 kOSKextReturnTimeout);
8944 } else {
8945 callbackRecord->setObject(kKextRequestStaleKey,
8946 kOSBooleanTrue);
8947 }
8948 }
8949 } while (i--);
8950 }
8951
8952 /*****
8953 * Make multiple passes through the array of loaded kexts until
8954 * we don't unload any. This handles unwinding of dependency
8955 * chains. We have to go *backwards* through the array because
8956 * kexts are removed from it when unloaded, and we cannot make
8957 * a copy or we'll mess up the retain counts we rely on to
8958 * check whether a kext will unload. If only we could have
8959 * nonretaining collections like CF has....
8960 */
8961 do {
8962 didUnload = false;
8963
8964 count = sLoadedKexts->getCount();
8965 if (count) {
8966 i = count - 1;
8967 do {
8968 OSKext * thisKext = OSDynamicCast(OSKext,
8969 sLoadedKexts->getObject(i));
8970 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8971 } while (i--);
8972 }
8973 } while (didUnload);
8974
8975 finish:
8976 sConsiderUnloadsPending = false;
8977 sConsiderUnloadsExecuted = true;
8978
8979 (void) OSKext::considerRebuildOfPrelinkedKernel();
8980
8981 IORecursiveLockUnlock(sKextInnerLock);
8982 IORecursiveLockUnlock(sKextLock);
8983
8984 return;
8985 }
8986
8987 /*********************************************************************
8988 * Do not call any function that takes sKextLock here!
8989 *********************************************************************/
8990 void
8991 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8992 {
8993 AbsoluteTime when;
8994
8995 IORecursiveLockLock(sKextInnerLock);
8996
8997 if (!sUnloadCallout) {
8998 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8999 }
9000
9001 /* we only reset delay value for unloading if we already have something
9002 * pending. rescheduleOnlyFlag should not start the count down.
9003 */
9004 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9005 goto finish;
9006 }
9007
9008 thread_call_cancel(sUnloadCallout);
9009 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9010 #if !NO_KEXTD
9011 && sIOKitDaemonActive
9012 #endif
9013 ) {
9014 clock_interval_to_deadline(sConsiderUnloadDelay,
9015 1000 * 1000 * 1000, &when);
9016
9017 OSKextLog(/* kext */ NULL,
9018 kOSKextLogProgressLevel |
9019 kOSKextLogLoadFlag,
9020 "%scheduling %sscan for unused kexts in %lu seconds.",
9021 sConsiderUnloadsPending ? "Res" : "S",
9022 sConsiderUnloadsCalled ? "" : "initial ",
9023 (unsigned long)sConsiderUnloadDelay);
9024
9025 sConsiderUnloadsPending = true;
9026 thread_call_enter_delayed(sUnloadCallout, when);
9027 }
9028
9029 finish:
9030 /* The kxld context should be reused throughout boot. We mark the end of
9031 * period as the first time considerUnloads() is called, and we destroy
9032 * the first kxld context in that function. Afterwards, it will be
9033 * destroyed in flushNonloadedKexts.
9034 */
9035 if (!sConsiderUnloadsCalled) {
9036 sConsiderUnloadsCalled = true;
9037 OSKext::considerDestroyingLinkContext();
9038 }
9039
9040 IORecursiveLockUnlock(sKextInnerLock);
9041 return;
9042 }
9043
9044 /*********************************************************************
9045 * Do not call any function that takes sKextLock here!
9046 *********************************************************************/
9047 extern "C" {
9048 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9049 IOReturn
9050 OSKextSystemSleepOrWake(UInt32 messageType)
9051 {
9052 IORecursiveLockLock(sKextInnerLock);
9053
9054 /* If the system is going to sleep, cancel the reaper thread timer,
9055 * and note that we're in a sleep state in case it just fired but hasn't
9056 * taken the lock yet. If we are coming back from sleep, just
9057 * clear the sleep flag; IOService's normal operation will cause
9058 * unloads to be considered soon enough.
9059 */
9060 if (messageType == kIOMessageSystemWillSleep) {
9061 if (sUnloadCallout) {
9062 thread_call_cancel(sUnloadCallout);
9063 }
9064 sSystemSleep = true;
9065 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9066 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9067 sSystemSleep = false;
9068 clock_get_uptime(&sLastWakeTime);
9069 }
9070 IORecursiveLockUnlock(sKextInnerLock);
9071
9072 return kIOReturnSuccess;
9073 }
9074 };
9075
9076
9077 #if PRAGMA_MARK
9078 #pragma mark Prelinked Kernel
9079 #endif
9080
9081 #ifdef CONFIG_KXLD
9082 /*********************************************************************
9083 * Do not access sConsiderUnloads... variables other than
9084 * sConsiderUnloadsExecuted in this function. They are guarded by a
9085 * different lock.
9086 *********************************************************************/
9087 /* static */
9088 void
9089 OSKext::considerRebuildOfPrelinkedKernel(void)
9090 {
9091 static bool requestedPrelink = false;
9092 OSReturn checkResult = kOSReturnError;
9093 OSSharedPtr<OSDictionary> prelinkRequest;
9094 OSSharedPtr<OSCollectionIterator> kextIterator;
9095 const OSSymbol * thisID = NULL; // do not release
9096 bool doRebuild = false;
9097 AbsoluteTime my_abstime;
9098 UInt64 my_ns;
9099 SInt32 delta_secs;
9100
9101 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9102 if (requestedPrelink || !sPrelinkBoot) {
9103 return;
9104 }
9105
9106 /* no direct return from this point */
9107 IORecursiveLockLock(sKextLock);
9108
9109 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9110 * and any new startup kexts loaded.
9111 */
9112 if (!sConsiderUnloadsExecuted ||
9113 !sDeferredLoadSucceeded) {
9114 goto finish;
9115 }
9116
9117 /* we really only care about boot / system start up related kexts so bail
9118 * if we're here after REBUILD_MAX_TIME.
9119 */
9120 if (!_OSKextInPrelinkRebuildWindow()) {
9121 OSKextLog(/* kext */ NULL,
9122 kOSKextLogArchiveFlag,
9123 "%s prebuild rebuild has expired",
9124 __FUNCTION__);
9125 requestedPrelink = true;
9126 goto finish;
9127 }
9128
9129 /* we do not want to trigger a rebuild if we get here too close to waking
9130 * up. (see radar 10233768)
9131 */
9132 IORecursiveLockLock(sKextInnerLock);
9133
9134 clock_get_uptime(&my_abstime);
9135 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9136 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9137 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9138 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9139 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9140 }
9141 IORecursiveLockUnlock(sKextInnerLock);
9142
9143 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9144 /* too close to time of last wake from sleep */
9145 goto finish;
9146 }
9147 requestedPrelink = true;
9148
9149 /* Now it's time to see if we have a reason to rebuild. We may have done
9150 * some loads and unloads but the kernel cache didn't actually change.
9151 * We will rebuild if any kext is not marked prelinked AND is not in our
9152 * list of prelinked kexts that got unloaded. (see radar 9055303)
9153 */
9154 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9155 if (!kextIterator) {
9156 goto finish;
9157 }
9158
9159 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9160 OSKext * thisKext; // do not release
9161
9162 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9163 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9164 continue;
9165 }
9166
9167 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9168 continue;
9169 }
9170 /* kext is loaded and was not in current kernel cache so let's rebuild
9171 */
9172 doRebuild = true;
9173 OSKextLog(/* kext */ NULL,
9174 kOSKextLogArchiveFlag,
9175 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9176 thisKext->bundleID->getCStringNoCopy());
9177 break;
9178 }
9179 sUnloadedPrelinkedKexts->flushCollection();
9180
9181 if (!doRebuild) {
9182 goto finish;
9183 }
9184
9185 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9186 prelinkRequest);
9187 if (checkResult != kOSReturnSuccess) {
9188 goto finish;
9189 }
9190
9191 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9192 goto finish;
9193 }
9194
9195 OSKext::pingIOKitDaemon();
9196
9197 finish:
9198 IORecursiveLockUnlock(sKextLock);
9199
9200 return;
9201 }
9202
9203 #else /* !CONFIG_KXLD */
9204
9205 void
9206 OSKext::considerRebuildOfPrelinkedKernel(void)
9207 {
9208 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9209 return;
9210 }
9211
9212 #endif /* CONFIG_KXLD */
9213
9214 #if PRAGMA_MARK
9215 #pragma mark Dependencies
9216 #endif
9217 /*********************************************************************
9218 *********************************************************************/
9219 bool
9220 OSKext::resolveDependencies(
9221 OSArray * loopStack)
9222 {
9223 bool result = false;
9224 OSSharedPtr<OSArray> localLoopStack;
9225 bool addedToLoopStack = false;
9226 OSDictionary * libraries = NULL; // do not release
9227 OSSharedPtr<OSCollectionIterator> libraryIterator;
9228 OSString * libraryID = NULL; // do not release
9229 OSKext * libraryKext = NULL; // do not release
9230 bool hasRawKernelDependency = false;
9231 bool hasKernelDependency = false;
9232 bool hasKPIDependency = false;
9233 bool hasPrivateKPIDependency = false;
9234 unsigned int count;
9235
9236 #if CONFIG_KXLD
9237 OSString * infoString = NULL; // do not release
9238 OSString * readableString = NULL; // do not release
9239 #endif // CONFIG_KXLD
9240
9241 /* A kernel component will automatically have this flag set,
9242 * and a loaded kext should also have it set (as should all its
9243 * loaded dependencies).
9244 */
9245 if (flags.hasAllDependencies) {
9246 result = true;
9247 goto finish;
9248 }
9249
9250 /* Check for loops in the dependency graph.
9251 */
9252 if (loopStack) {
9253 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9254 OSKextLog(this,
9255 kOSKextLogErrorLevel |
9256 kOSKextLogDependenciesFlag,
9257 "Kext %s has a dependency loop; can't resolve dependencies.",
9258 getIdentifierCString());
9259 goto finish;
9260 }
9261 } else {
9262 OSKextLog(this,
9263 kOSKextLogStepLevel |
9264 kOSKextLogDependenciesFlag,
9265 "Kext %s resolving dependencies.",
9266 getIdentifierCString());
9267
9268 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9269 if (!localLoopStack) {
9270 OSKextLog(this,
9271 kOSKextLogErrorLevel |
9272 kOSKextLogDependenciesFlag,
9273 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9274 getIdentifierCString());
9275 goto finish;
9276 }
9277 loopStack = localLoopStack.get();
9278 }
9279 if (!loopStack->setObject(this)) {
9280 OSKextLog(this,
9281 kOSKextLogErrorLevel |
9282 kOSKextLogDependenciesFlag,
9283 "Kext %s - internal error resolving dependencies.",
9284 getIdentifierCString());
9285 goto finish;
9286 }
9287 addedToLoopStack = true;
9288
9289 /* Purge any existing kexts in the dependency list and start over.
9290 */
9291 flushDependencies();
9292 if (dependencies) {
9293 OSKextLog(this,
9294 kOSKextLogErrorLevel |
9295 kOSKextLogDependenciesFlag,
9296 "Kext %s - internal error resolving dependencies.",
9297 getIdentifierCString());
9298 }
9299
9300 libraries = OSDynamicCast(OSDictionary,
9301 getPropertyForHostArch(kOSBundleLibrariesKey));
9302 if (libraries == NULL || libraries->getCount() == 0) {
9303 OSKextLog(this,
9304 kOSKextLogErrorLevel |
9305 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9306 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9307 getIdentifierCString(), kOSBundleLibrariesKey);
9308 goto finish;
9309 }
9310
9311 /* Make a new array to hold the dependencies (flush freed the old one).
9312 */
9313 dependencies = OSArray::withCapacity(libraries->getCount());
9314 if (!dependencies) {
9315 OSKextLog(this,
9316 kOSKextLogErrorLevel |
9317 kOSKextLogDependenciesFlag,
9318 "Kext %s - can't allocate dependencies array.",
9319 getIdentifierCString());
9320 goto finish;
9321 }
9322
9323 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9324 // xxx - compat: if none were declared.
9325
9326 libraryIterator = OSCollectionIterator::withCollection(libraries);
9327 if (!libraryIterator) {
9328 OSKextLog(this,
9329 kOSKextLogErrorLevel |
9330 kOSKextLogDependenciesFlag,
9331 "Kext %s - can't allocate dependencies iterator.",
9332 getIdentifierCString());
9333 goto finish;
9334 }
9335
9336 while ((libraryID = OSDynamicCast(OSString,
9337 libraryIterator->getNextObject()))) {
9338 const char * library_id = libraryID->getCStringNoCopy();
9339
9340 OSString * libraryVersion = OSDynamicCast(OSString,
9341 libraries->getObject(libraryID));
9342 if (libraryVersion == NULL) {
9343 OSKextLog(this,
9344 kOSKextLogErrorLevel |
9345 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9346 "Kext %s - illegal type in OSBundleLibraries.",
9347 getIdentifierCString());
9348 goto finish;
9349 }
9350
9351 OSKextVersion libraryVers =
9352 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9353 if (libraryVers == -1) {
9354 OSKextLog(this,
9355 kOSKextLogErrorLevel |
9356 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9357 "Kext %s - invalid library version %s.",
9358 getIdentifierCString(),
9359 libraryVersion->getCStringNoCopy());
9360 goto finish;
9361 }
9362
9363 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9364 if (libraryKext == NULL) {
9365 OSKextLog(this,
9366 kOSKextLogErrorLevel |
9367 kOSKextLogDependenciesFlag,
9368 "Kext %s - library kext %s not found.",
9369 getIdentifierCString(), library_id);
9370 goto finish;
9371 }
9372
9373 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9374 OSKextLog(this,
9375 kOSKextLogErrorLevel |
9376 kOSKextLogDependenciesFlag,
9377 "Kext %s - library kext %s not compatible "
9378 "with requested version %s.",
9379 getIdentifierCString(), library_id,
9380 libraryVersion->getCStringNoCopy());
9381 goto finish;
9382 }
9383
9384 /* If a nonprelinked library somehow got into the mix for a
9385 * prelinked kext, at any point in the chain, we must fail
9386 * because the prelinked relocs for the library will be all wrong.
9387 */
9388 if (this->isPrelinked() &&
9389 libraryKext->declaresExecutable() &&
9390 !libraryKext->isPrelinked()) {
9391 OSKextLog(this,
9392 kOSKextLogErrorLevel |
9393 kOSKextLogDependenciesFlag,
9394 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9395 getIdentifierCString(), library_id,
9396 libraryVersion->getCStringNoCopy());
9397 goto finish;
9398 }
9399
9400 if (!libraryKext->resolveDependencies(loopStack)) {
9401 goto finish;
9402 }
9403
9404 /* Add the library directly only if it has an executable to link.
9405 * Otherwise it's just used to collect other dependencies, so put
9406 * *its* dependencies on the list for this kext.
9407 */
9408 // xxx - We are losing info here; would like to make fake entries or
9409 // xxx - keep these in the dependency graph for loaded kexts.
9410 // xxx - I really want to make kernel components not a special case!
9411 if (libraryKext->declaresExecutable() ||
9412 libraryKext->isInterface()) {
9413 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9414 dependencies->setObject(libraryKext);
9415
9416 OSKextLog(this,
9417 kOSKextLogDetailLevel |
9418 kOSKextLogDependenciesFlag,
9419 "Kext %s added dependency %s.",
9420 getIdentifierCString(),
9421 libraryKext->getIdentifierCString());
9422 }
9423 } else {
9424 int numLibDependencies = libraryKext->getNumDependencies();
9425 OSArray * libraryDependencies = libraryKext->getDependencies();
9426 int index;
9427
9428 if (numLibDependencies) {
9429 // xxx - this msg level should be 1 lower than the per-kext one
9430 OSKextLog(this,
9431 kOSKextLogDetailLevel |
9432 kOSKextLogDependenciesFlag,
9433 "Kext %s pulling %d dependencies from codeless library %s.",
9434 getIdentifierCString(),
9435 numLibDependencies,
9436 libraryKext->getIdentifierCString());
9437 }
9438 for (index = 0; index < numLibDependencies; index++) {
9439 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9440 libraryDependencies->getObject(index));
9441 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9442 dependencies->setObject(thisLibDependency);
9443 OSKextLog(this,
9444 kOSKextLogDetailLevel |
9445 kOSKextLogDependenciesFlag,
9446 "Kext %s added dependency %s from codeless library %s.",
9447 getIdentifierCString(),
9448 thisLibDependency->getIdentifierCString(),
9449 libraryKext->getIdentifierCString());
9450 }
9451 }
9452 }
9453
9454 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9455 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9456 hasRawKernelDependency = true;
9457 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9458 hasKernelDependency = true;
9459 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9460 hasKPIDependency = true;
9461 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9462 hasPrivateKPIDependency = true;
9463 }
9464 }
9465 }
9466
9467 if (hasRawKernelDependency) {
9468 OSKextLog(this,
9469 kOSKextLogErrorLevel |
9470 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9471 "Error - kext %s declares a dependency on %s, which is not permitted.",
9472 getIdentifierCString(), KERNEL_LIB);
9473 goto finish;
9474 }
9475 #if __LP64__
9476 if (hasKernelDependency) {
9477 OSKextLog(this,
9478 kOSKextLogErrorLevel |
9479 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9480 "Error - kext %s declares %s dependencies. "
9481 "Only %s* dependencies are supported for 64-bit kexts.",
9482 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9483 goto finish;
9484 }
9485 if (!hasKPIDependency) {
9486 OSKextLog(this,
9487 kOSKextLogWarningLevel |
9488 kOSKextLogDependenciesFlag,
9489 "Warning - kext %s declares no %s* dependencies. "
9490 "If it uses any KPIs, the link may fail with undefined symbols.",
9491 getIdentifierCString(), KPI_LIB_PREFIX);
9492 }
9493 #else /* __LP64__ */
9494 // xxx - will change to flatly disallow "kernel" dependencies at some point
9495 // xxx - is it invalid to do both "com.apple.kernel" and any
9496 // xxx - "com.apple.kernel.*"?
9497
9498 if (hasKernelDependency && hasKPIDependency) {
9499 OSKextLog(this,
9500 kOSKextLogWarningLevel |
9501 kOSKextLogDependenciesFlag,
9502 "Warning - kext %s has immediate dependencies on both "
9503 "%s* and %s* components; use only one style.",
9504 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9505 }
9506
9507 if (!hasKernelDependency && !hasKPIDependency) {
9508 // xxx - do we want to use validation flag for these too?
9509 OSKextLog(this,
9510 kOSKextLogWarningLevel |
9511 kOSKextLogDependenciesFlag,
9512 "Warning - %s declares no kernel dependencies; using %s.",
9513 getIdentifierCString(), KERNEL6_LIB);
9514 OSKext * kernelKext = OSDynamicCast(OSKext,
9515 sKextsByID->getObject(KERNEL6_LIB));
9516 if (kernelKext) {
9517 dependencies->setObject(kernelKext);
9518 } else {
9519 OSKextLog(this,
9520 kOSKextLogErrorLevel |
9521 kOSKextLogDependenciesFlag,
9522 "Error - Library %s not found for %s.",
9523 KERNEL6_LIB, getIdentifierCString());
9524 }
9525 }
9526
9527 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9528 * its indirect dependencies to simulate old-style linking. XXX - Should
9529 * check for duplicates.
9530 */
9531 if (!hasKPIDependency) {
9532 unsigned int i;
9533
9534 flags.hasBleedthrough = true;
9535
9536 count = getNumDependencies();
9537
9538 /* We add to the dependencies array in this loop, but do not iterate
9539 * past its original count.
9540 */
9541 for (i = 0; i < count; i++) {
9542 OSKext * dependencyKext = OSDynamicCast(OSKext,
9543 dependencies->getObject(i));
9544 dependencyKext->addBleedthroughDependencies(dependencies.get());
9545 }
9546 }
9547 #endif /* __LP64__ */
9548
9549 #if CONFIG_KXLD
9550 /*
9551 * If we're not dynamically linking kexts, then we don't need to check
9552 * copyright strings. The linker in user space has already done this.
9553 */
9554 if (hasPrivateKPIDependency) {
9555 bool hasApplePrefix = false;
9556 bool infoCopyrightIsValid = false;
9557 bool readableCopyrightIsValid = false;
9558
9559 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9560 APPLE_KEXT_PREFIX);
9561
9562 infoString = OSDynamicCast(OSString,
9563 getPropertyForHostArch("CFBundleGetInfoString"));
9564 if (infoString) {
9565 infoCopyrightIsValid =
9566 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9567 }
9568
9569 readableString = OSDynamicCast(OSString,
9570 getPropertyForHostArch("NSHumanReadableCopyright"));
9571 if (readableString) {
9572 readableCopyrightIsValid =
9573 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9574 }
9575
9576 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9577 OSKextLog(this,
9578 kOSKextLogErrorLevel |
9579 kOSKextLogDependenciesFlag,
9580 "Error - kext %s declares a dependency on %s. "
9581 "Only Apple kexts may declare a dependency on %s.",
9582 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9583 goto finish;
9584 }
9585 }
9586 #endif // CONFIG_KXLD
9587
9588 result = true;
9589 flags.hasAllDependencies = 1;
9590
9591 finish:
9592
9593 if (addedToLoopStack) {
9594 count = loopStack->getCount();
9595 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9596 loopStack->removeObject(count - 1);
9597 } else {
9598 OSKextLog(this,
9599 kOSKextLogErrorLevel |
9600 kOSKextLogDependenciesFlag,
9601 "Kext %s - internal error resolving dependencies.",
9602 getIdentifierCString());
9603 }
9604 }
9605
9606 if (result && localLoopStack) {
9607 OSKextLog(this,
9608 kOSKextLogStepLevel |
9609 kOSKextLogDependenciesFlag,
9610 "Kext %s successfully resolved dependencies.",
9611 getIdentifierCString());
9612 }
9613
9614 return result;
9615 }
9616
9617 /*********************************************************************
9618 *********************************************************************/
9619 bool
9620 OSKext::addBleedthroughDependencies(OSArray * anArray)
9621 {
9622 bool result = false;
9623 unsigned int dependencyIndex, dependencyCount;
9624
9625 dependencyCount = getNumDependencies();
9626
9627 for (dependencyIndex = 0;
9628 dependencyIndex < dependencyCount;
9629 dependencyIndex++) {
9630 OSKext * dependency = OSDynamicCast(OSKext,
9631 dependencies->getObject(dependencyIndex));
9632 if (!dependency) {
9633 OSKextLog(this,
9634 kOSKextLogErrorLevel |
9635 kOSKextLogDependenciesFlag,
9636 "Kext %s - internal error propagating compatibility dependencies.",
9637 getIdentifierCString());
9638 goto finish;
9639 }
9640 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9641 anArray->setObject(dependency);
9642 }
9643 dependency->addBleedthroughDependencies(anArray);
9644 }
9645
9646 result = true;
9647
9648 finish:
9649 return result;
9650 }
9651
9652 /*********************************************************************
9653 *********************************************************************/
9654 bool
9655 OSKext::flushDependencies(bool forceFlag)
9656 {
9657 bool result = false;
9658
9659 /* Only clear the dependencies if the kext isn't loaded;
9660 * we need the info for loaded kexts to track references.
9661 */
9662 if (!isLoaded() || forceFlag) {
9663 if (dependencies) {
9664 // xxx - check level
9665 OSKextLog(this,
9666 kOSKextLogProgressLevel |
9667 kOSKextLogDependenciesFlag,
9668 "Kext %s flushing dependencies.",
9669 getIdentifierCString());
9670 dependencies.reset();
9671 }
9672 if (!isKernelComponent()) {
9673 flags.hasAllDependencies = 0;
9674 }
9675 result = true;
9676 }
9677
9678 return result;
9679 }
9680
9681 /*********************************************************************
9682 *********************************************************************/
9683 uint32_t
9684 OSKext::getNumDependencies(void)
9685 {
9686 if (!dependencies) {
9687 return 0;
9688 }
9689 return dependencies->getCount();
9690 }
9691
9692 /*********************************************************************
9693 *********************************************************************/
9694 OSArray *
9695 OSKext::getDependencies(void)
9696 {
9697 return dependencies.get();
9698 }
9699
9700 bool
9701 OSKext::hasDependency(const OSSymbol * depID)
9702 {
9703 bool result __block;
9704
9705 if (depID == getIdentifier()) {
9706 return true;
9707 }
9708 if (!dependencies) {
9709 return false;
9710 }
9711 result = false;
9712 dependencies->iterateObjects(^bool (OSObject * obj) {
9713 OSKext * kext;
9714 kext = OSDynamicCast(OSKext, obj);
9715 if (!kext) {
9716 return false;
9717 }
9718 result = (depID == kext->getIdentifier());
9719 return result;
9720 });
9721 return result;
9722 }
9723
9724 #if PRAGMA_MARK
9725 #pragma mark OSMetaClass Support
9726 #endif
9727 /*********************************************************************
9728 *********************************************************************/
9729 OSReturn
9730 OSKext::addClass(
9731 OSMetaClass * aClass,
9732 uint32_t numClasses)
9733 {
9734 OSReturn result = kOSMetaClassNoInsKModSet;
9735
9736 if (!metaClasses) {
9737 metaClasses = OSSet::withCapacity(numClasses);
9738 if (!metaClasses) {
9739 goto finish;
9740 }
9741 }
9742
9743 if (metaClasses->containsObject(aClass)) {
9744 OSKextLog(this,
9745 kOSKextLogWarningLevel |
9746 kOSKextLogLoadFlag,
9747 "Notice - kext %s has already registered class %s.",
9748 getIdentifierCString(),
9749 aClass->getClassName());
9750 result = kOSReturnSuccess;
9751 goto finish;
9752 }
9753
9754 if (!metaClasses->setObject(aClass)) {
9755 goto finish;
9756 } else {
9757 OSKextLog(this,
9758 kOSKextLogDetailLevel |
9759 kOSKextLogLoadFlag,
9760 "Kext %s registered class %s.",
9761 getIdentifierCString(),
9762 aClass->getClassName());
9763 }
9764
9765 if (!flags.autounloadEnabled) {
9766 const OSMetaClass * metaScan = NULL; // do not release
9767
9768 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9769 if (metaScan == OSTypeID(IOService)) {
9770 OSKextLog(this,
9771 kOSKextLogProgressLevel |
9772 kOSKextLogLoadFlag,
9773 "Kext %s has IOService subclass %s; enabling autounload.",
9774 getIdentifierCString(),
9775 aClass->getClassName());
9776
9777 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9778 break;
9779 }
9780 }
9781 }
9782
9783 notifyAddClassObservers(this, aClass, flags);
9784
9785 result = kOSReturnSuccess;
9786
9787 finish:
9788 if (result != kOSReturnSuccess) {
9789 OSKextLog(this,
9790 kOSKextLogErrorLevel |
9791 kOSKextLogLoadFlag,
9792 "Kext %s failed to register class %s.",
9793 getIdentifierCString(),
9794 aClass->getClassName());
9795 }
9796
9797 return result;
9798 }
9799
9800 /*********************************************************************
9801 *********************************************************************/
9802 OSReturn
9803 OSKext::removeClass(
9804 OSMetaClass * aClass)
9805 {
9806 OSReturn result = kOSMetaClassNoKModSet;
9807
9808 if (!metaClasses) {
9809 goto finish;
9810 }
9811
9812 if (!metaClasses->containsObject(aClass)) {
9813 OSKextLog(this,
9814 kOSKextLogWarningLevel |
9815 kOSKextLogLoadFlag,
9816 "Notice - kext %s asked to unregister unknown class %s.",
9817 getIdentifierCString(),
9818 aClass->getClassName());
9819 result = kOSReturnSuccess;
9820 goto finish;
9821 }
9822
9823 OSKextLog(this,
9824 kOSKextLogDetailLevel |
9825 kOSKextLogLoadFlag,
9826 "Kext %s unregistering class %s.",
9827 getIdentifierCString(),
9828 aClass->getClassName());
9829
9830 metaClasses->removeObject(aClass);
9831
9832 notifyRemoveClassObservers(this, aClass, flags);
9833
9834 result = kOSReturnSuccess;
9835
9836 finish:
9837 if (result != kOSReturnSuccess) {
9838 OSKextLog(this,
9839 kOSKextLogErrorLevel |
9840 kOSKextLogLoadFlag,
9841 "Failed to unregister kext %s class %s.",
9842 getIdentifierCString(),
9843 aClass->getClassName());
9844 }
9845 return result;
9846 }
9847
9848 /*********************************************************************
9849 *********************************************************************/
9850 OSSet *
9851 OSKext::getMetaClasses(void)
9852 {
9853 return metaClasses.get();
9854 }
9855
9856 /*********************************************************************
9857 *********************************************************************/
9858 bool
9859 OSKext::hasOSMetaClassInstances(void)
9860 {
9861 bool result = false;
9862 OSSharedPtr<OSCollectionIterator> classIterator;
9863 OSMetaClass * checkClass = NULL; // do not release
9864
9865 if (!metaClasses) {
9866 goto finish;
9867 }
9868
9869 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9870 if (!classIterator) {
9871 // xxx - log alloc failure?
9872 goto finish;
9873 }
9874 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9875 if (checkClass->getInstanceCount()) {
9876 result = true;
9877 goto finish;
9878 }
9879 }
9880
9881 finish:
9882 return result;
9883 }
9884
9885 /*********************************************************************
9886 *********************************************************************/
9887 /* static */
9888 void
9889 OSKext::reportOSMetaClassInstances(
9890 const char * kextIdentifier,
9891 OSKextLogSpec msgLogSpec)
9892 {
9893 OSSharedPtr<OSKext> theKext;
9894
9895 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9896 if (!theKext) {
9897 goto finish;
9898 }
9899
9900 theKext->reportOSMetaClassInstances(msgLogSpec);
9901 finish:
9902 return;
9903 }
9904
9905 /*********************************************************************
9906 *********************************************************************/
9907 void
9908 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9909 {
9910 OSSharedPtr<OSCollectionIterator> classIterator;
9911 OSMetaClass * checkClass = NULL; // do not release
9912
9913 if (!metaClasses) {
9914 goto finish;
9915 }
9916
9917 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9918 if (!classIterator) {
9919 goto finish;
9920 }
9921 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9922 if (checkClass->getInstanceCount()) {
9923 OSKextLog(this,
9924 msgLogSpec,
9925 " Kext %s class %s has %d instance%s.",
9926 getIdentifierCString(),
9927 checkClass->getClassName(),
9928 checkClass->getInstanceCount(),
9929 checkClass->getInstanceCount() == 1 ? "" : "s");
9930 }
9931 }
9932
9933 finish:
9934 return;
9935 }
9936
9937 #if PRAGMA_MARK
9938 #pragma mark User-Space Requests
9939 #endif
9940
9941 static kern_return_t
9942 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9943 {
9944 OSReturn result = kOSReturnSuccess;
9945 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9946 OSDictionary * request = NULL; //do not release
9947 IOUserServerCheckInToken * token = NULL; //do not release
9948 OSString * requestPredicate = NULL; //do not release
9949 OSSharedPtr<OSNumber> portNameNumber;
9950 mach_port_name_t portName = 0;
9951 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9952 if (!request) {
9953 OSKextLog(/* kext */ NULL,
9954 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9955 "Elements of request should be of type OSDictionary");
9956 result = kOSKextReturnInternalError;
9957 goto finish;
9958 }
9959 requestPredicate = _OSKextGetRequestPredicate(request);
9960 if (!requestPredicate) {
9961 OSKextLog(/* kext */ NULL,
9962 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9963 "Failed to get request predicate");
9964 result = kOSKextReturnInternalError;
9965 goto finish;
9966 }
9967 // is this a dext launch?
9968 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9969 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9970 if (!token) {
9971 OSKextLog(/* kext */ NULL,
9972 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9973 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9974 result = kOSKextReturnInternalError;
9975 goto finish;
9976 }
9977 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9978 if (portName == 0 || portName == MACH_PORT_DEAD) {
9979 OSKextLog(/* kext */ NULL,
9980 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9981 "Could not create send right for object.");
9982 result = kOSKextReturnInternalError;
9983 goto finish;
9984 }
9985 // Store the mach port name as a OSNumber
9986 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9987 if (!portNameNumber) {
9988 OSKextLog(/* kext */ NULL,
9989 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9990 "Could not create OSNumber object.");
9991 result = kOSKextReturnNoMemory;
9992 goto finish;
9993 }
9994 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9995 OSKextLog(/* kext */ NULL,
9996 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9997 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9998 result = kOSKextReturnNoMemory;
9999 goto finish;
10000 }
10001 }
10002 finish:
10003 if (result != kOSReturnSuccess) {
10004 break;
10005 }
10006 }
10007 return result;
10008 }
10009
10010 bool
10011 OSKext::iokitDaemonActive()
10012 {
10013 bool result;
10014 IORecursiveLockLock(sKextLock);
10015 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10016 IORecursiveLockUnlock(sKextLock);
10017 return result;
10018 }
10019
10020 /*********************************************************************
10021 * XXX - this function is a big ugly mess
10022 *********************************************************************/
10023 /* static */
10024 OSReturn
10025 OSKext::handleRequest(
10026 host_priv_t hostPriv,
10027 OSKextLogSpec clientLogFilter,
10028 char * requestBuffer,
10029 uint32_t requestLength,
10030 char ** responseOut,
10031 uint32_t * responseLengthOut,
10032 char ** logInfoOut,
10033 uint32_t * logInfoLengthOut)
10034 {
10035 OSReturn result = kOSReturnError;
10036 kern_return_t kmem_result = KERN_FAILURE;
10037
10038 char * response = NULL; // returned by reference
10039 uint32_t responseLength = 0;
10040
10041 bool taskCanManageAllKCs = false;
10042 bool taskOnlyManagesBootKC = false;
10043
10044 OSSharedPtr<OSObject> parsedXML;
10045 OSDictionary * requestDict = NULL; // do not release
10046 OSSharedPtr<OSString> errorString;
10047
10048 OSSharedPtr<OSObject> responseObject;
10049
10050 OSSharedPtr<OSSerialize> serializer;
10051
10052 OSSharedPtr<OSArray> logInfoArray;
10053
10054 OSString * predicate = NULL; // do not release
10055 OSString * kextIdentifier = NULL; // do not release
10056 OSArray * kextIdentifiers = NULL; // do not release
10057 OSKext * theKext = NULL; // do not release
10058 OSBoolean * boolArg = NULL; // do not release
10059
10060
10061 IORecursiveLockLock(sKextLock);
10062
10063 if (responseOut) {
10064 *responseOut = NULL;
10065 *responseLengthOut = 0;
10066 }
10067 if (logInfoOut) {
10068 *logInfoOut = NULL;
10069 *logInfoLengthOut = 0;
10070 }
10071
10072 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10073
10074 /* XML must be nul-terminated.
10075 */
10076 if (requestBuffer[requestLength - 1] != '\0') {
10077 OSKextLog(/* kext */ NULL,
10078 kOSKextLogErrorLevel |
10079 kOSKextLogIPCFlag,
10080 "Invalid request from user space (not nul-terminated).");
10081 result = kOSKextReturnBadData;
10082 goto finish;
10083 }
10084 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10085 if (parsedXML) {
10086 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10087 }
10088 if (!requestDict) {
10089 const char * errorCString = "(unknown error)";
10090
10091 if (errorString && errorString->getCStringNoCopy()) {
10092 errorCString = errorString->getCStringNoCopy();
10093 } else if (parsedXML) {
10094 errorCString = "not a dictionary";
10095 }
10096 OSKextLog(/* kext */ NULL,
10097 kOSKextLogErrorLevel |
10098 kOSKextLogIPCFlag,
10099 "Error unserializing request from user space: %s.",
10100 errorCString);
10101 result = kOSKextReturnSerialization;
10102 goto finish;
10103 }
10104
10105 predicate = _OSKextGetRequestPredicate(requestDict);
10106 if (!predicate) {
10107 OSKextLog(/* kext */ NULL,
10108 kOSKextLogErrorLevel |
10109 kOSKextLogIPCFlag,
10110 "Recieved kext request from user space with no predicate.");
10111 result = kOSKextReturnInvalidArgument;
10112 goto finish;
10113 }
10114 OSKextLog(/* kext */ NULL,
10115 kOSKextLogDebugLevel |
10116 kOSKextLogIPCFlag,
10117 "Received '%s' request from user space.",
10118 predicate->getCStringNoCopy());
10119
10120 /*
10121 * All management of file sets requires an entitlement
10122 */
10123 result = kOSKextReturnNotPrivileged;
10124 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10125 predicate->isEqualTo(kKextRequestPredicateStart) ||
10126 predicate->isEqualTo(kKextRequestPredicateStop) ||
10127 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10128 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10129 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10130 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10131 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10132 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10133 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10134 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10135 if (!iokitDaemonAvailable()) {
10136 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10137 }
10138 if (hostPriv == HOST_PRIV_NULL) {
10139 OSKextLog(/* kext */ NULL,
10140 kOSKextLogErrorLevel |
10141 kOSKextLogIPCFlag,
10142 "Access Failure - must be root user.");
10143 goto finish;
10144 }
10145 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10146 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10147
10148 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10149 OSKextLog(/* kext */ NULL,
10150 kOSKextLogErrorLevel |
10151 kOSKextLogIPCFlag,
10152 "Access Failure - client not entitled to manage file sets.");
10153 goto finish;
10154 }
10155
10156 /*
10157 * The OnlyBootKC entitlement restricts the
10158 * collection-management entitlement to only managing kexts in
10159 * the BootKC. All other predicates that alter global state or
10160 * add new KCs are disallowed.
10161 */
10162 if (taskOnlyManagesBootKC &&
10163 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10164 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10165 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10166 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10167 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10168 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10169 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10170 OSKextLog(/* kext */ NULL,
10171 kOSKextLogErrorLevel |
10172 kOSKextLogIPCFlag,
10173 "Access Failure - client not entitled to manage non-primary KCs");
10174 goto finish;
10175 }
10176
10177 /*
10178 * If we get here, then the process either has the full KC
10179 * management entitlement, or it has the BootKC-only
10180 * entitlement and the request is about the BootKC.
10181 */
10182 }
10183
10184 /* Get common args in anticipation of use.
10185 */
10186 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10187 requestDict, kKextRequestArgumentBundleIdentifierKey));
10188 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10189 requestDict, kKextRequestArgumentBundleIdentifierKey));
10190 if (kextIdentifier) {
10191 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10192 }
10193 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10194 requestDict, kKextRequestArgumentValueKey));
10195
10196 if (taskOnlyManagesBootKC &&
10197 theKext &&
10198 theKext->isInFileset() &&
10199 theKext->kc_type != KCKindPrimary) {
10200 OSKextLog(/* kext */ NULL,
10201 kOSKextLogErrorLevel |
10202 kOSKextLogIPCFlag,
10203 "Access Failure - client not entitled to manage kext in non-primary KC");
10204 result = kOSKextReturnNotPrivileged;
10205 goto finish;
10206 }
10207 result = kOSKextReturnInvalidArgument;
10208
10209 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10210 if (!kextIdentifier) {
10211 OSKextLog(/* kext */ NULL,
10212 kOSKextLogErrorLevel |
10213 kOSKextLogIPCFlag,
10214 "Invalid arguments to kext start request.");
10215 } else if (!theKext) {
10216 OSKextLog(/* kext */ NULL,
10217 kOSKextLogErrorLevel |
10218 kOSKextLogIPCFlag,
10219 "Kext %s not found for start request.",
10220 kextIdentifier->getCStringNoCopy());
10221 result = kOSKextReturnNotFound;
10222 } else {
10223 result = theKext->start();
10224 }
10225 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10226 if (!kextIdentifier) {
10227 OSKextLog(/* kext */ NULL,
10228 kOSKextLogErrorLevel |
10229 kOSKextLogIPCFlag,
10230 "Invalid arguments to kext stop request.");
10231 } else if (!theKext) {
10232 OSKextLog(/* kext */ NULL,
10233 kOSKextLogErrorLevel |
10234 kOSKextLogIPCFlag,
10235 "Kext %s not found for stop request.",
10236 kextIdentifier->getCStringNoCopy());
10237 result = kOSKextReturnNotFound;
10238 } else {
10239 result = theKext->stop();
10240 }
10241 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10242 result = OSKext::setMissingAuxKCBundles(requestDict);
10243 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10244 if (!kextIdentifier) {
10245 OSKextLog(/* kext */ NULL,
10246 kOSKextLogErrorLevel |
10247 kOSKextLogIPCFlag,
10248 "Invalid arguments to AuxKC Bundle Available request.");
10249 } else {
10250 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10251 }
10252 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10253 if (!kextIdentifier) {
10254 OSKextLog(/* kext */ NULL,
10255 kOSKextLogErrorLevel |
10256 kOSKextLogIPCFlag,
10257 "Invalid arguments to kext load from KC request.");
10258 } else if (!theKext) {
10259 OSKextLog(/* kext */ NULL,
10260 kOSKextLogErrorLevel |
10261 kOSKextLogIPCFlag,
10262 "Kext %s not found for load from KC request.",
10263 kextIdentifier->getCStringNoCopy());
10264 result = kOSKextReturnNotFound;
10265 } else if (!theKext->isInFileset()) {
10266 OSKextLog(/* kext */ NULL,
10267 kOSKextLogErrorLevel |
10268 kOSKextLogIPCFlag,
10269 "Kext %s does not exist in a KC: refusing to load.",
10270 kextIdentifier->getCStringNoCopy());
10271 result = kOSKextReturnNotLoadable;
10272 } else {
10273 result = OSKext::loadKextFromKC(theKext, requestDict);
10274 }
10275 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10276 if (!kextIdentifier) {
10277 OSKextLog(/* kext */ NULL,
10278 kOSKextLogErrorLevel |
10279 kOSKextLogIPCFlag,
10280 "Invalid arguments to codeless kext load interface (missing identifier).");
10281 } else {
10282 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10283 }
10284 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10285 if (!kextIdentifier) {
10286 OSKextLog(/* kext */ NULL,
10287 kOSKextLogErrorLevel |
10288 kOSKextLogIPCFlag,
10289 "Invalid arguments to kext unload request.");
10290 } else if (!theKext) {
10291 OSKextLog(/* kext */ NULL,
10292 kOSKextLogErrorLevel |
10293 kOSKextLogIPCFlag,
10294 "Kext %s not found for unload request.",
10295 kextIdentifier->getCStringNoCopy());
10296 result = kOSKextReturnNotFound;
10297 } else {
10298 if (theKext->isDriverKit()) {
10299 result = OSKext::removeDext(theKext);
10300 } else {
10301 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10302 _OSKextGetRequestArgument(requestDict,
10303 kKextRequestArgumentTerminateIOServicesKey));
10304 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10305 }
10306 }
10307 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10308 result = OSKext::dispatchResource(requestDict);
10309 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10310 OSNumber *lookupNum = NULL;
10311 lookupNum = OSDynamicCast(OSNumber,
10312 _OSKextGetRequestArgument(requestDict,
10313 kKextRequestArgumentLookupAddressKey));
10314
10315 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10316 if (responseObject) {
10317 result = kOSReturnSuccess;
10318 } else {
10319 goto finish;
10320 }
10321 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10322 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10323 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10324 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10325 OSBoolean * delayAutounloadBool = NULL;
10326 OSObject * infoKeysRaw = NULL;
10327 OSArray * infoKeys = NULL;
10328 uint32_t infoKeysCount = 0;
10329
10330 delayAutounloadBool = OSDynamicCast(OSBoolean,
10331 _OSKextGetRequestArgument(requestDict,
10332 kKextRequestArgumentDelayAutounloadKey));
10333
10334 /* If asked to delay autounload, reset the timer if it's currently set.
10335 * (That is, don't schedule an unload if one isn't already pending.
10336 */
10337 if (delayAutounloadBool == kOSBooleanTrue) {
10338 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10339 }
10340
10341 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10342 kKextRequestArgumentInfoKeysKey);
10343 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10344 if (infoKeysRaw && !infoKeys) {
10345 OSKextLog(/* kext */ NULL,
10346 kOSKextLogErrorLevel |
10347 kOSKextLogIPCFlag,
10348 "Invalid arguments to kext info request.");
10349 goto finish;
10350 }
10351
10352 if (infoKeys) {
10353 infoKeysCount = infoKeys->getCount();
10354 for (uint32_t i = 0; i < infoKeysCount; i++) {
10355 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10356 OSKextLog(/* kext */ NULL,
10357 kOSKextLogErrorLevel |
10358 kOSKextLogIPCFlag,
10359 "Invalid arguments to kext info request.");
10360 goto finish;
10361 }
10362 }
10363 }
10364
10365 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10366 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10367 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10368 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10369 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10370 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10371 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10372 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10373 }
10374
10375 if (!responseObject) {
10376 result = kOSKextReturnInternalError;
10377 } else {
10378 OSKextLog(/* kext */ NULL,
10379 kOSKextLogDebugLevel |
10380 kOSKextLogIPCFlag,
10381 "Returning loaded kext info.");
10382 result = kOSReturnSuccess;
10383 }
10384 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10385 /* Hand the current sKernelRequests array to the caller
10386 * (who must release it), and make a new one.
10387 */
10388 responseObject = os::move(sKernelRequests);
10389 sKernelRequests = OSArray::withCapacity(0);
10390 sPostedKextLoadIdentifiers->flushCollection();
10391 OSKextLog(/* kext */ NULL,
10392 kOSKextLogDebugLevel |
10393 kOSKextLogIPCFlag,
10394 "Returning kernel requests.");
10395 result = kOSReturnSuccess;
10396 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10397 /* Return the set of all requested bundle identifiers */
10398 responseObject = sAllKextLoadIdentifiers;
10399 OSKextLog(/* kext */ NULL,
10400 kOSKextLogDebugLevel |
10401 kOSKextLogIPCFlag,
10402 "Returning load requests.");
10403 result = kOSReturnSuccess;
10404 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10405 printf("KextLog: Loading FileSet KC(s)\n");
10406 result = OSKext::loadFileSetKexts(requestDict);
10407 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10408 bool active = iokitDaemonActive();
10409 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10410 if (sOSKextWasResetAfterUserspaceReboot) {
10411 printf("KextLog: was reset after userspace reboot\n");
10412 }
10413 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10414 } else {
10415 OSKextLog(/* kext */ NULL,
10416 kOSKextLogDebugLevel |
10417 kOSKextLogIPCFlag,
10418 "Received '%s' invalid request from user space.",
10419 predicate->getCStringNoCopy());
10420 goto finish;
10421 }
10422
10423 /**********
10424 * Now we have handle the request, or not. Gather up the response & logging
10425 * info to ship to user space.
10426 *********/
10427
10428 /* Note: Nothing in OSKext is supposed to retain requestDict,
10429 * but you never know....
10430 */
10431 if (requestDict->getRetainCount() > 1) {
10432 OSKextLog(/* kext */ NULL,
10433 kOSKextLogWarningLevel |
10434 kOSKextLogIPCFlag,
10435 "Request from user space still retained by a kext; "
10436 "probable memory leak.");
10437 }
10438
10439 if (responseOut && responseObject) {
10440 serializer = OSSerialize::withCapacity(0);
10441 if (!serializer) {
10442 result = kOSKextReturnNoMemory;
10443 goto finish;
10444 }
10445 /*
10446 * Before serializing the kernel requests, patch the dext launch requests so
10447 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10448 * IOUserServerCheckInToken kernel object.
10449 */
10450 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10451 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10452 task_t calling_task = current_task();
10453 if (!requests) {
10454 OSKextLog(/* kext */ NULL,
10455 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10456 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10457 result = kOSKextReturnInternalError;
10458 goto finish;
10459 }
10460 result = patchDextLaunchRequests(calling_task, requests);
10461 if (result != kOSReturnSuccess) {
10462 OSKextLog(/* kext */ NULL,
10463 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10464 "Failed to patch dext launch requests.");
10465 goto finish;
10466 }
10467 }
10468
10469 if (!responseObject->serialize(serializer.get())) {
10470 OSKextLog(/* kext */ NULL,
10471 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10472 "Failed to serialize response to request from user space.");
10473 result = kOSKextReturnSerialization;
10474 goto finish;
10475 }
10476
10477 response = (char *)serializer->text();
10478 responseLength = serializer->getLength();
10479 }
10480
10481 if (responseOut && response) {
10482 char * buffer;
10483
10484 /* This kmem_alloc sets the return value of the function.
10485 */
10486 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10487 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10488 if (kmem_result != KERN_SUCCESS) {
10489 OSKextLog(/* kext */ NULL,
10490 kOSKextLogErrorLevel |
10491 kOSKextLogIPCFlag,
10492 "Failed to copy response to request from user space.");
10493 result = kmem_result;
10494 goto finish;
10495 } else {
10496 /* 11981737 - clear uninitialized data in last page */
10497 bzero((void *)(buffer + responseLength),
10498 (round_page(responseLength) - responseLength));
10499 memcpy(buffer, response, responseLength);
10500 *responseOut = buffer;
10501 *responseLengthOut = responseLength;
10502 }
10503 }
10504
10505 finish:
10506
10507 /* Gather up the collected log messages for user space. Any messages
10508 * messages past this call will not make it up as log messages but
10509 * will be in the system log. Note that we ignore the return of the
10510 * serialize; it has no bearing on the operation at hand even if we
10511 * fail to get the log messages.
10512 */
10513 logInfoArray = OSKext::clearUserSpaceLogFilter();
10514
10515 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10516 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10517 logInfoOut, logInfoLengthOut);
10518 }
10519
10520 IORecursiveLockUnlock(sKextLock);
10521
10522 return result;
10523 }
10524
10525 #if PRAGMA_MARK
10526 #pragma mark Linked Kext Collection Support
10527 #endif
10528
10529 static int
10530 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10531 {
10532 for (int i = 0; i < segCount; i++) {
10533 vm_offset_t segStart = segAddrs[i];
10534 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10535
10536 if (theAddr >= segStart && theAddr < segEnd) {
10537 return i;
10538 }
10539 }
10540 return -1;
10541 }
10542
10543 static void
10544 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10545 kernel_segment_command_t *kextTextSeg,
10546 OSData *kaslrOffsets)
10547 {
10548 static const char *plk_segNames[] = {
10549 "__TEXT",
10550 "__TEXT_EXEC",
10551 "__DATA",
10552 "__DATA_CONST",
10553 "__LINKEDIT",
10554 "__PRELINK_TEXT",
10555 "__PLK_TEXT_EXEC",
10556 "__PRELINK_DATA",
10557 "__PLK_DATA_CONST",
10558 "__PLK_LLVM_COV",
10559 "__PLK_LINKEDIT",
10560 "__PRELINK_INFO"
10561 };
10562 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10563
10564 unsigned long plk_segSizes[num_plk_seg];
10565 vm_offset_t plk_segAddrs[num_plk_seg];
10566
10567 for (size_t i = 0; i < num_plk_seg; i++) {
10568 plk_segSizes[i] = 0;
10569 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10570 }
10571
10572 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10573
10574 int slidKextAddrCount = 0;
10575 int badSlideAddr = 0;
10576 int badSlideTarget = 0;
10577
10578 struct kaslrPackedOffsets {
10579 uint32_t count; /* number of offsets */
10580 uint32_t offsetsArray[]; /* offsets to slide */
10581 };
10582 const struct kaslrPackedOffsets *myOffsets = NULL;
10583 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10584
10585 for (uint32_t j = 0; j < myOffsets->count; j++) {
10586 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10587 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10588 int slideAddrSegIndex = -1;
10589 int addrToSlideSegIndex = -1;
10590
10591 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10592 if (slideAddrSegIndex >= 0) {
10593 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10594 if (addrToSlideSegIndex < 0) {
10595 badSlideTarget++;
10596 continue;
10597 }
10598 } else {
10599 badSlideAddr++;
10600 continue;
10601 }
10602
10603 slidKextAddrCount++;
10604 *slideAddr = ml_static_slide(*slideAddr);
10605 } // for ...
10606 }
10607
10608
10609
10610 /********************************************************************
10611 * addKextsFromKextCollection
10612 *
10613 * Input: MachO header of kext collection. The MachO is assumed to
10614 * have a section named 'info_seg_name,info_sect_name' that
10615 * contains a serialized XML info dictionary. This dictionary
10616 * contains a UUID, possibly a set of relocations (for older
10617 * kxld-built binaries), and an array of kext personalities.
10618 *
10619 ********************************************************************/
10620 bool
10621 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10622 OSDictionary *infoDict, const char *text_seg_name,
10623 OSData **kcUUID, kc_kind_t type)
10624 {
10625 bool result = false;
10626
10627 OSArray *kextArray = NULL; // do not release
10628 OSData *infoDictKCUUID = NULL; // do not release
10629 OSData *kaslrOffsets = NULL; // do not release
10630
10631 IORegistryEntry *registryRoot = NULL; // do not release
10632 OSSharedPtr<OSNumber> kcKextCount;
10633
10634 /* extract the KC UUID from the dictionary */
10635 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10636 if (infoDictKCUUID) {
10637 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10638 panic("kcUUID length is %d, expected %lu",
10639 infoDictKCUUID->getLength(), sizeof(uuid_t));
10640 }
10641 }
10642
10643 /* locate the array of kext dictionaries */
10644 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10645 if (!kextArray) {
10646 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10647 "The given KC has no kext info dictionaries");
10648 goto finish;
10649 }
10650
10651 /*
10652 * old-style KASLR offsets may be present in the info dictionary. If
10653 * we find them, use them and eventually slide them.
10654 */
10655 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10656
10657 /*
10658 * Before processing any kexts, locate the special kext bundle which
10659 * contains a list of kexts that we are to prevent from loading.
10660 */
10661 createExcludeListFromPrelinkInfo(kextArray);
10662
10663 /*
10664 * Create OSKext objects for each kext we find in the array of kext
10665 * info plist dictionaries.
10666 */
10667 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10668 OSDictionary *kextDict = NULL;
10669 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10670 if (!kextDict) {
10671 OSKextLog(/* kext */ NULL,
10672 kOSKextLogErrorLevel |
10673 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10674 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10675 continue;
10676 }
10677
10678 /*
10679 * Create the kext for the entry, then release it, because the
10680 * kext system keeps a reference around until the kext is
10681 * explicitly removed. Any creation/registration failures are
10682 * already logged for us.
10683 */
10684 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10685 }
10686
10687 /*
10688 * slide old-style kxld relocations
10689 * NOTE: this is still used on embedded KCs built with kcgen
10690 * TODO: Remove this once we use the new kext linker everywhere!
10691 */
10692 if (kaslrOffsets && vm_kernel_slide > 0) {
10693 kernel_segment_command_t *text_segment = NULL;
10694 text_segment = getsegbynamefromheader(mh, text_seg_name);
10695 if (!text_segment) {
10696 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10697 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10698 goto finish;
10699 }
10700
10701 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10702 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10703 setAllVMAttributes();
10704 }
10705
10706 /* Store the number of prelinked kexts in the registry so we can tell
10707 * when the system has been started from a prelinked kernel.
10708 */
10709 registryRoot = IORegistryEntry::getRegistryRoot();
10710 assert(registryRoot);
10711
10712 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10713 assert(kcKextCount);
10714 if (kcKextCount) {
10715 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10716 OSNumber *num;
10717 num = OSDynamicCast(OSNumber, prop.get());
10718 if (num) {
10719 kcKextCount->addValue(num->unsigned64BitValue());
10720 }
10721 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10722 }
10723
10724 OSKextLog(/* kext */ NULL,
10725 kOSKextLogProgressLevel |
10726 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10727 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10728 "%u prelinked kexts", infoDict->getCount());
10729
10730
10731 if (kcUUID && infoDictKCUUID) {
10732 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10733 }
10734
10735 result = true;
10736
10737 finish:
10738 return result;
10739 }
10740
10741 bool
10742 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10743 OSDictionary *infoDict, const char *text_seg_name,
10744 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10745 {
10746 OSData *result = NULL;
10747 bool success = addKextsFromKextCollection(mh,
10748 infoDict,
10749 text_seg_name,
10750 &result,
10751 type);
10752 if (success) {
10753 kcUUID.reset(result, OSNoRetain);
10754 }
10755 return success;
10756 }
10757
10758 static OSSharedPtr<OSObject> deferredAuxKCXML;
10759 bool
10760 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10761 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10762 {
10763 if (type != KCKindAuxiliary) {
10764 return false;
10765 }
10766
10767 kernel_mach_header_t *_mh;
10768 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10769 if (!_mh || _mh != mh) {
10770 return false;
10771 }
10772
10773 if (deferredAuxKCXML) {
10774 /* only allow this to be called once */
10775 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10776 "An Aux KC has already been registered for deferred processing.");
10777 return false;
10778 }
10779
10780 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10781 if (!infoDict) {
10782 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10783 "The Aux KC has info dictionary");
10784 return false;
10785 }
10786
10787 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10788 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10789 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10790 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10791 return false;
10792 }
10793
10794 /*
10795 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10796 * sysctl can return the UUID to user space which will check this
10797 * value for errors.
10798 */
10799 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10800 kcUUID->getLength());
10801 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10802 auxkc_uuid_valid = TRUE;
10803
10804 deferredAuxKCXML = parsedXML;
10805
10806 return true;
10807 }
10808
10809 OSSharedPtr<OSObject>
10810 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10811 {
10812 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10813 return NULL;
10814 }
10815
10816 return os::move(deferredAuxKCXML);
10817 }
10818
10819 #if PRAGMA_MARK
10820 #pragma mark Profile-Guided-Optimization Support
10821 #endif
10822
10823 // #include <InstrProfiling.h>
10824 extern "C" {
10825 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10826 const char *DataEnd,
10827 const char *CountersBegin,
10828 const char *CountersEnd,
10829 const char *NamesBegin,
10830 const char *NamesEnd);
10831 int __llvm_profile_write_buffer_internal(char *Buffer,
10832 const char *DataBegin,
10833 const char *DataEnd,
10834 const char *CountersBegin,
10835 const char *CountersEnd,
10836 const char *NamesBegin,
10837 const char *NamesEnd);
10838 }
10839
10840
10841 static
10842 void
10843 OSKextPgoMetadataPut(char *pBuffer,
10844 size_t *position,
10845 size_t bufferSize,
10846 uint32_t *num_pairs,
10847 const char *key,
10848 const char *value)
10849 {
10850 size_t strlen_key = strlen(key);
10851 size_t strlen_value = strlen(value);
10852 size_t len = strlen(key) + 1 + strlen(value) + 1;
10853 char *pos = pBuffer + *position;
10854 *position += len;
10855 if (pBuffer && bufferSize && *position <= bufferSize) {
10856 memcpy(pos, key, strlen_key); pos += strlen_key;
10857 *(pos++) = '=';
10858 memcpy(pos, value, strlen_value); pos += strlen_value;
10859 *(pos++) = 0;
10860 if (num_pairs) {
10861 (*num_pairs)++;
10862 }
10863 }
10864 }
10865
10866
10867 static
10868 void
10869 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10870 {
10871 *position += strlen(key) + 1 + value_max + 1;
10872 }
10873
10874
10875 static
10876 void
10877 OSKextPgoMetadataPutAll(OSKext *kext,
10878 uuid_t instance_uuid,
10879 char *pBuffer,
10880 size_t *position,
10881 size_t bufferSize,
10882 uint32_t *num_pairs)
10883 {
10884 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10885 //log_10 2^16 ≈ 4.82
10886 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10887 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10888
10889 if (!pBuffer) {
10890 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10891 OSKextPgoMetadataPutMax(position, "UUID", 36);
10892 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10893 } else {
10894 uuid_string_t instance_uuid_string;
10895 uuid_unparse(instance_uuid, instance_uuid_string);
10896 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10897 "INSTANCE", instance_uuid_string);
10898
10899 OSSharedPtr<OSData> uuid_data;
10900 uuid_t uuid;
10901 uuid_string_t uuid_string;
10902 uuid_data = kext->copyUUID();
10903 if (uuid_data) {
10904 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10905 uuid_unparse(uuid, uuid_string);
10906 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10907 "UUID", uuid_string);
10908 }
10909
10910 clock_sec_t secs;
10911 clock_usec_t usecs;
10912 clock_get_calendar_microtime(&secs, &usecs);
10913 assert(usecs < 1000000);
10914 char timestamp[max_timestamp_string_size + 1];
10915 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10916 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10917 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10918 "TIMESTAMP", timestamp);
10919 }
10920
10921 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10922 "NAME", kext->getIdentifierCString());
10923
10924 char versionCString[kOSKextVersionMaxLength];
10925 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10926 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10927 "VERSION", versionCString);
10928 }
10929
10930 static
10931 size_t
10932 OSKextPgoMetadataSize(OSKext *kext)
10933 {
10934 size_t position = 0;
10935 uuid_t fakeuuid = {};
10936 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10937 return position;
10938 }
10939
10940 int
10941 OSKextGrabPgoDataLocked(OSKext *kext,
10942 bool metadata,
10943 uuid_t instance_uuid,
10944 uint64_t *pSize,
10945 char *pBuffer,
10946 uint64_t bufferSize)
10947 {
10948 int err = 0;
10949
10950 kernel_section_t *sect_prf_data = NULL;
10951 kernel_section_t *sect_prf_name = NULL;
10952 kernel_section_t *sect_prf_cnts = NULL;
10953 uint64_t size;
10954 size_t metadata_size = 0;
10955 size_t offset_to_pairs = 0;
10956
10957 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10958 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10959 if (!sect_prf_name) {
10960 // kextcache sometimes truncates the section name to 15 chars
10961 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10962 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10963 }
10964 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10965
10966 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10967 err = ENOTSUP;
10968 goto out;
10969 }
10970
10971 size = __llvm_profile_get_size_for_buffer_internal(
10972 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10973 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10974 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10975
10976 if (metadata) {
10977 metadata_size = OSKextPgoMetadataSize(kext);
10978 size += metadata_size;
10979 size += sizeof(pgo_metadata_footer);
10980 }
10981
10982
10983 if (pSize) {
10984 *pSize = size;
10985 }
10986
10987 if (pBuffer && bufferSize) {
10988 if (bufferSize < size) {
10989 err = ERANGE;
10990 goto out;
10991 }
10992
10993 err = __llvm_profile_write_buffer_internal(
10994 pBuffer,
10995 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10996 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10997 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10998
10999 if (err) {
11000 err = EIO;
11001 goto out;
11002 }
11003
11004 if (metadata) {
11005 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11006 if (offset_to_pairs > UINT32_MAX) {
11007 err = E2BIG;
11008 goto out;
11009 }
11010
11011 char *end_of_buffer = pBuffer + size;
11012 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11013 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11014
11015 size_t metadata_position = 0;
11016 uint32_t num_pairs = 0;
11017 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11018 while (metadata_position < metadata_size) {
11019 metadata_buffer[metadata_position++] = 0;
11020 }
11021
11022 struct pgo_metadata_footer footer;
11023 footer.magic = htonl(0x6d657461);
11024 footer.number_of_pairs = htonl( num_pairs );
11025 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11026 memcpy(footerp, &footer, sizeof(footer));
11027 }
11028 }
11029
11030 out:
11031 return err;
11032 }
11033
11034
11035 int
11036 OSKextGrabPgoData(uuid_t uuid,
11037 uint64_t *pSize,
11038 char *pBuffer,
11039 uint64_t bufferSize,
11040 int wait_for_unload,
11041 int metadata)
11042 {
11043 int err = 0;
11044 OSSharedPtr<OSKext> kext;
11045
11046
11047 IORecursiveLockLock(sKextLock);
11048
11049 kext = OSKext::lookupKextWithUUID(uuid);
11050 if (!kext) {
11051 err = ENOENT;
11052 goto out;
11053 }
11054
11055 if (wait_for_unload) {
11056 OSKextGrabPgoStruct s;
11057
11058 s.metadata = metadata;
11059 s.pSize = pSize;
11060 s.pBuffer = pBuffer;
11061 s.bufferSize = bufferSize;
11062 s.err = EINTR;
11063
11064 struct list_head *prev = &kext->pendingPgoHead;
11065 struct list_head *next = kext->pendingPgoHead.next;
11066
11067 s.list_head.prev = prev;
11068 s.list_head.next = next;
11069
11070 prev->next = &s.list_head;
11071 next->prev = &s.list_head;
11072
11073 kext.reset();
11074
11075 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11076
11077 prev = s.list_head.prev;
11078 next = s.list_head.next;
11079
11080 prev->next = next;
11081 next->prev = prev;
11082
11083 err = s.err;
11084 } else {
11085 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11086 }
11087
11088 out:
11089
11090 IORecursiveLockUnlock(sKextLock);
11091
11092 return err;
11093 }
11094
11095 void
11096 OSKextResetPgoCountersLock()
11097 {
11098 IORecursiveLockLock(sKextLock);
11099 }
11100
11101 void
11102 OSKextResetPgoCountersUnlock()
11103 {
11104 IORecursiveLockUnlock(sKextLock);
11105 }
11106
11107
11108 extern unsigned int not_in_kdp;
11109
11110 void
11111 OSKextResetPgoCounters()
11112 {
11113 assert(!not_in_kdp);
11114 uint32_t count = sLoadedKexts->getCount();
11115 for (uint32_t i = 0; i < count; i++) {
11116 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11117 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11118 if (!sect_prf_cnts) {
11119 continue;
11120 }
11121 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11122 }
11123 }
11124
11125 OSSharedPtr<OSDictionary>
11126 OSKext::copyLoadedKextInfoByUUID(
11127 OSArray * kextIdentifiers,
11128 OSArray * infoKeys)
11129 {
11130 OSSharedPtr<OSDictionary> result;
11131 OSSharedPtr<OSDictionary> kextInfo;
11132 uint32_t max_count, i, j;
11133 uint32_t idCount = 0;
11134 uint32_t idIndex = 0;
11135 IORecursiveLockLock(sKextLock);
11136 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11137 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11138
11139 #if CONFIG_MACF
11140 /* Is the calling process allowed to query kext info? */
11141 if (current_task() != kernel_task) {
11142 int macCheckResult = 0;
11143 kauth_cred_t cred = NULL;
11144
11145 cred = kauth_cred_get_with_ref();
11146 macCheckResult = mac_kext_check_query(cred);
11147 kauth_cred_unref(&cred);
11148
11149 if (macCheckResult != 0) {
11150 OSKextLog(/* kext */ NULL,
11151 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11152 "Failed to query kext info (MAC policy error 0x%x).",
11153 macCheckResult);
11154 goto finish;
11155 }
11156 }
11157 #endif
11158
11159 /* Empty list of UUIDs is equivalent to no list (get all).
11160 */
11161 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11162 kextIdentifiers = NULL;
11163 } else if (kextIdentifiers) {
11164 idCount = kextIdentifiers->getCount();
11165 }
11166
11167 /* Same for keys.
11168 */
11169 if (infoKeys && !infoKeys->getCount()) {
11170 infoKeys = NULL;
11171 }
11172
11173 max_count = count[0] + count[1];
11174 result = OSDictionary::withCapacity(max_count);
11175 if (!result) {
11176 goto finish;
11177 }
11178
11179 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11180 for (i = 0; i < count[j]; i++) {
11181 OSKext *thisKext = NULL; // do not release
11182 Boolean includeThis = true;
11183 uuid_t thisKextUUID;
11184 uuid_t thisKextTextUUID;
11185 OSSharedPtr<OSData> uuid_data;
11186 uuid_string_t uuid_key;
11187
11188 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11189 if (!thisKext) {
11190 continue;
11191 }
11192
11193 uuid_data = thisKext->copyUUID();
11194 if (!uuid_data) {
11195 continue;
11196 }
11197
11198 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11199
11200 uuid_unparse(thisKextUUID, uuid_key);
11201
11202 uuid_data = thisKext->copyTextUUID();
11203 if (!uuid_data) {
11204 continue;
11205 }
11206 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11207
11208 /* Skip current kext if we have a list of UUIDs and
11209 * it isn't in the list.
11210 */
11211 if (kextIdentifiers) {
11212 includeThis = false;
11213
11214 for (idIndex = 0; idIndex < idCount; idIndex++) {
11215 const OSString* wantedUUID = OSDynamicCast(OSString,
11216 kextIdentifiers->getObject(idIndex));
11217
11218 uuid_t uuid;
11219 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11220
11221 if ((0 == uuid_compare(uuid, thisKextUUID))
11222 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11223 includeThis = true;
11224 /* Only need to find the first kext if multiple match,
11225 * ie. asking for the kernel uuid does not need to find
11226 * interface kexts or builtin static kexts.
11227 */
11228 kextIdentifiers->removeObject(idIndex);
11229 uuid_unparse(uuid, uuid_key);
11230 break;
11231 }
11232 }
11233 }
11234
11235 if (!includeThis) {
11236 continue;
11237 }
11238
11239 kextInfo = thisKext->copyInfo(infoKeys);
11240 if (kextInfo) {
11241 result->setObject(uuid_key, kextInfo.get());
11242 }
11243
11244 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11245 goto finish;
11246 }
11247 }
11248 }
11249
11250 finish:
11251 IORecursiveLockUnlock(sKextLock);
11252
11253 return result;
11254 }
11255
11256 /*********************************************************************
11257 *********************************************************************/
11258 /* static */
11259 OSSharedPtr<OSDictionary>
11260 OSKext::copyKextCollectionInfo(
11261 OSDictionary *requestDict,
11262 OSArray *infoKeys)
11263 {
11264 OSSharedPtr<OSDictionary> result;
11265 OSString *collectionType = NULL;
11266 OSObject *rawLoadedState = NULL;
11267 OSString *loadedState = NULL;
11268
11269 kc_kind_t kc_request_kind = KCKindUnknown;
11270 bool onlyLoaded = false;
11271 bool onlyUnloaded = false;
11272
11273 #if CONFIG_MACF
11274 /* Is the calling process allowed to query kext info? */
11275 if (current_task() != kernel_task) {
11276 int macCheckResult = 0;
11277 kauth_cred_t cred = NULL;
11278
11279 cred = kauth_cred_get_with_ref();
11280 macCheckResult = mac_kext_check_query(cred);
11281 kauth_cred_unref(&cred);
11282
11283 if (macCheckResult != 0) {
11284 OSKextLog(/* kext */ NULL,
11285 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11286 "Failed to query kext info (MAC policy error 0x%x).",
11287 macCheckResult);
11288 goto finish;
11289 }
11290 }
11291 #endif
11292
11293 if (infoKeys && !infoKeys->getCount()) {
11294 infoKeys = NULL;
11295 }
11296
11297 collectionType = OSDynamicCast(OSString,
11298 _OSKextGetRequestArgument(requestDict,
11299 kKextRequestArgumentCollectionTypeKey));
11300 if (!collectionType) {
11301 OSKextLog(/* kext */ NULL,
11302 kOSKextLogErrorLevel |
11303 kOSKextLogIPCFlag,
11304 "Invalid '%s' argument to kext collection info request.",
11305 kKextRequestArgumentCollectionTypeKey);
11306 goto finish;
11307 }
11308 if (collectionType->isEqualTo(kKCTypePrimary)) {
11309 kc_request_kind = KCKindPrimary;
11310 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11311 kc_request_kind = KCKindPageable;
11312 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11313 kc_request_kind = KCKindAuxiliary;
11314 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11315 kc_request_kind = KCKindNone;
11316 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11317 OSKextLog(/* kext */ NULL,
11318 kOSKextLogErrorLevel |
11319 kOSKextLogIPCFlag,
11320 "Invalid '%s' argument value '%s' to kext collection info request.",
11321 kKextRequestArgumentCollectionTypeKey,
11322 collectionType->getCStringNoCopy());
11323 goto finish;
11324 }
11325
11326 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11327 kKextRequestArgumentLoadedStateKey);
11328 if (rawLoadedState) {
11329 loadedState = OSDynamicCast(OSString, rawLoadedState);
11330 if (!loadedState) {
11331 OSKextLog(/* kext */ NULL,
11332 kOSKextLogErrorLevel |
11333 kOSKextLogIPCFlag,
11334 "Invalid '%s' argument to kext collection info request.",
11335 kKextRequestArgumentLoadedStateKey);
11336 goto finish;
11337 }
11338 }
11339 if (loadedState) {
11340 if (loadedState->isEqualTo("Loaded")) {
11341 onlyLoaded = true;
11342 } else if (loadedState->isEqualTo("Unloaded")) {
11343 onlyUnloaded = true;
11344 } else if (!loadedState->isEqualTo("Any")) {
11345 OSKextLog(/* kext */ NULL,
11346 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11347 "Invalid '%s' argument value '%s' for '%s' collection info",
11348 kKextRequestArgumentLoadedStateKey,
11349 loadedState->getCStringNoCopy(),
11350 collectionType->getCStringNoCopy());
11351 goto finish;
11352 }
11353 }
11354
11355 result = OSDictionary::withCapacity(sKextsByID->getCount());
11356 if (!result) {
11357 goto finish;
11358 }
11359
11360 IORecursiveLockLock(sKextLock);
11361 { // start block scope
11362 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11363 {
11364 OSKext *thisKext = NULL; // do not release
11365 OSSharedPtr<OSDictionary> kextInfo;
11366
11367 (void)thisKextID;
11368
11369 thisKext = OSDynamicCast(OSKext, obj);
11370 if (!thisKext) {
11371 return false;
11372 }
11373
11374 /*
11375 * skip the kext if it came from the wrong collection type
11376 * (and the caller requested a specific type)
11377 */
11378 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11379 return false;
11380 }
11381
11382 /*
11383 * respect the caller's desire to find only loaded or
11384 * unloaded kexts
11385 */
11386 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11387 return false;
11388 }
11389 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11390 return false;
11391 }
11392
11393 kextInfo = thisKext->copyInfo(infoKeys);
11394 if (kextInfo) {
11395 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11396 }
11397 return false;
11398 });
11399 } // end block scope
11400 IORecursiveLockUnlock(sKextLock);
11401
11402 finish:
11403 return result;
11404 }
11405
11406 /* static */
11407 OSSharedPtr<OSArray>
11408 OSKext::copyDextsInfo(
11409 OSArray *kextIdentifiers,
11410 OSArray *infoKeys)
11411 {
11412 OSSharedPtr<OSArray> result = NULL;
11413 uint32_t idCount = 0;
11414 bool getActive = false;
11415 bool getLoaded = false;
11416 bool getUnloaded = false;
11417 bool getPendingUpgrade = false;
11418 unsigned int avgDextCount = 0;
11419
11420 #if CONFIG_MACF
11421 /* Is the calling process allowed to query dext info? */
11422 if (current_task() != kernel_task) {
11423 int macCheckResult = 0;
11424 kauth_cred_t cred = NULL;
11425
11426 cred = kauth_cred_get_with_ref();
11427 macCheckResult = mac_kext_check_query(cred);
11428 kauth_cred_unref(&cred);
11429
11430 if (macCheckResult != 0) {
11431 OSKextLog(/* kext */ NULL,
11432 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11433 "Failed to query kext info (MAC policy error 0x%x).",
11434 macCheckResult);
11435 goto finish;
11436 }
11437 }
11438 #endif
11439 /*
11440 * No infoKeys means return everything we
11441 * know about the dexts.
11442 */
11443 if (infoKeys && !infoKeys->getCount()) {
11444 infoKeys = NULL;
11445 }
11446
11447 /*
11448 * Empty list of bundle ids is equivalent to
11449 * no list (get all).
11450 */
11451 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11452 kextIdentifiers = NULL;
11453 } else if (kextIdentifiers) {
11454 idCount = kextIdentifiers->getCount();
11455 }
11456
11457 /*
11458 * Caller can specify which state of dexts to query.
11459 */
11460 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11461 getActive = true;
11462 }
11463 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11464 getLoaded = true;
11465 }
11466 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11467 getUnloaded = true;
11468 }
11469 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11470 getPendingUpgrade = true;
11471 }
11472
11473 /*
11474 * By default we are going to return all active and pendingUpgrade dexts
11475 * only.
11476 */
11477 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11478 getActive = true;
11479 getPendingUpgrade = true;
11480 }
11481
11482 /*
11483 * We return a dictionary of dexts
11484 * for every group requested.
11485 */
11486 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11487 result = OSArray::withCapacity(avgDextCount);
11488 if (!result) {
11489 goto finish;
11490 }
11491
11492 IORecursiveLockLock(sKextLock);
11493 { // start block scope
11494 if (getActive || getLoaded || getUnloaded) {
11495 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11496 {
11497 OSKext *thisKext = NULL; // do not release
11498 OSSharedPtr<OSDictionary> kextInfo;
11499 Boolean includeThis = true;
11500 (void)thisKextID;
11501
11502 thisKext = OSDynamicCast(OSKext, obj);
11503 if (!thisKext || !thisKext->isDriverKit()) {
11504 return false;
11505 }
11506
11507 /*
11508 * Skip current dext if we have a list of bundle IDs and
11509 * it isn't in the list.
11510 */
11511 if (kextIdentifiers) {
11512 includeThis = false;
11513
11514 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11515 const OSString * thisRequestID = OSDynamicCast(OSString,
11516 kextIdentifiers->getObject(idIndex));
11517 if (thisKextID->isEqualTo(thisRequestID)) {
11518 includeThis = true;
11519 break;
11520 }
11521 }
11522 }
11523
11524 if (!includeThis) {
11525 return false;
11526 }
11527
11528 OSSharedPtr<OSString> state;
11529 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11530 if (!(getActive || getUnloaded)) {
11531 return false;
11532 }
11533 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11534 } else {
11535 if (!(getActive || getLoaded)) {
11536 return false;
11537 }
11538 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11539 }
11540
11541 kextInfo = thisKext->copyInfo(infoKeys);
11542 if (kextInfo) {
11543 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11544 result->setObject(kextInfo.get());
11545 }
11546
11547 return false;
11548 });
11549 }
11550
11551 if (getPendingUpgrade) {
11552 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11553 {
11554 OSKext *thisKext = NULL; // do not release
11555 OSSharedPtr<OSDictionary> kextInfo;
11556 Boolean includeThis = true;
11557 (void)thisKextID;
11558
11559 thisKext = OSDynamicCast(OSKext, obj);
11560 if (!thisKext) {
11561 return false;
11562 }
11563 __assert_only bool isDext = thisKext->isDriverKit();
11564 assert(isDext == true);
11565
11566 /*
11567 * Skip current dext if we have a list of bundle IDs and
11568 * it isn't in the list.
11569 */
11570 if (kextIdentifiers) {
11571 includeThis = false;
11572
11573 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11574 const OSString * thisRequestID = OSDynamicCast(OSString,
11575 kextIdentifiers->getObject(idIndex));
11576 if (thisKextID->isEqualTo(thisRequestID)) {
11577 includeThis = true;
11578 break;
11579 }
11580 }
11581 }
11582
11583 if (!includeThis) {
11584 return false;
11585 }
11586
11587 kextInfo = thisKext->copyInfo(infoKeys);
11588 if (kextInfo) {
11589 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11590 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11591 result->setObject(kextInfo.get());
11592 }
11593 return false;
11594 });
11595 }
11596 } // end block scope
11597 IORecursiveLockUnlock(sKextLock);
11598 finish:
11599 return result;
11600 }
11601
11602 /*********************************************************************
11603 *********************************************************************/
11604 /* static */
11605 OSSharedPtr<OSDictionary>
11606 OSKext::copyLoadedKextInfo(
11607 OSArray * kextIdentifiers,
11608 OSArray * infoKeys)
11609 {
11610 OSSharedPtr<OSDictionary> result;
11611 uint32_t idCount = 0;
11612 bool onlyLoaded;
11613
11614 IORecursiveLockLock(sKextLock);
11615
11616 #if CONFIG_MACF
11617 /* Is the calling process allowed to query kext info? */
11618 if (current_task() != kernel_task) {
11619 int macCheckResult = 0;
11620 kauth_cred_t cred = NULL;
11621
11622 cred = kauth_cred_get_with_ref();
11623 macCheckResult = mac_kext_check_query(cred);
11624 kauth_cred_unref(&cred);
11625
11626 if (macCheckResult != 0) {
11627 OSKextLog(/* kext */ NULL,
11628 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11629 "Failed to query kext info (MAC policy error 0x%x).",
11630 macCheckResult);
11631 goto finish;
11632 }
11633 }
11634 #endif
11635
11636 /* Empty list of bundle ids is equivalent to no list (get all).
11637 */
11638 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11639 kextIdentifiers = NULL;
11640 } else if (kextIdentifiers) {
11641 idCount = kextIdentifiers->getCount();
11642 }
11643
11644 /* Same for keys.
11645 */
11646 if (infoKeys && !infoKeys->getCount()) {
11647 infoKeys = NULL;
11648 }
11649
11650 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11651
11652 result = OSDictionary::withCapacity(128);
11653 if (!result) {
11654 goto finish;
11655 }
11656
11657 #if 0
11658 OSKextLog(/* kext */ NULL,
11659 kOSKextLogErrorLevel |
11660 kOSKextLogGeneralFlag,
11661 "kaslr: vm_kernel_slide 0x%lx \n",
11662 vm_kernel_slide);
11663 OSKextLog(/* kext */ NULL,
11664 kOSKextLogErrorLevel |
11665 kOSKextLogGeneralFlag,
11666 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11667 vm_kernel_stext, vm_kernel_etext);
11668 OSKextLog(/* kext */ NULL,
11669 kOSKextLogErrorLevel |
11670 kOSKextLogGeneralFlag,
11671 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11672 vm_kernel_base, vm_kernel_top);
11673 OSKextLog(/* kext */ NULL,
11674 kOSKextLogErrorLevel |
11675 kOSKextLogGeneralFlag,
11676 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11677 vm_kext_base, vm_kext_top);
11678 OSKextLog(/* kext */ NULL,
11679 kOSKextLogErrorLevel |
11680 kOSKextLogGeneralFlag,
11681 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11682 vm_prelink_stext, vm_prelink_etext);
11683 OSKextLog(/* kext */ NULL,
11684 kOSKextLogErrorLevel |
11685 kOSKextLogGeneralFlag,
11686 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11687 vm_prelink_sinfo, vm_prelink_einfo);
11688 OSKextLog(/* kext */ NULL,
11689 kOSKextLogErrorLevel |
11690 kOSKextLogGeneralFlag,
11691 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11692 vm_slinkedit, vm_elinkedit);
11693 #endif
11694 { // start block scope
11695 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11696 {
11697 OSKext * thisKext = NULL; // do not release
11698 Boolean includeThis = true;
11699 OSSharedPtr<OSDictionary> kextInfo;
11700
11701 thisKext = OSDynamicCast(OSKext, obj);
11702 if (!thisKext) {
11703 return false;
11704 }
11705
11706 /* Skip current kext if not yet started and caller didn't request all.
11707 */
11708 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11709 return false;
11710 }
11711
11712 /* Skip current kext if we have a list of bundle IDs and
11713 * it isn't in the list.
11714 */
11715 if (kextIdentifiers) {
11716 includeThis = false;
11717
11718 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11719 const OSString * thisRequestID = OSDynamicCast(OSString,
11720 kextIdentifiers->getObject(idIndex));
11721 if (thisKextID->isEqualTo(thisRequestID)) {
11722 includeThis = true;
11723 break;
11724 }
11725 }
11726 }
11727
11728 if (!includeThis) {
11729 return false;
11730 }
11731
11732 kextInfo = thisKext->copyInfo(infoKeys);
11733 if (kextInfo) {
11734 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11735 }
11736 return false;
11737 });
11738 } // end block scope
11739
11740 finish:
11741 IORecursiveLockUnlock(sKextLock);
11742
11743 return result;
11744 }
11745
11746 /*********************************************************************
11747 * Any info that needs to do allocations must goto finish on alloc
11748 * failure. Info that is just a lookup should just not set the object
11749 * if the info does not exist.
11750 *********************************************************************/
11751 #define _OSKextLoadInfoDictCapacity (12)
11752
11753 OSSharedPtr<OSDictionary>
11754 OSKext::copyInfo(OSArray * infoKeys)
11755 {
11756 OSSharedPtr<OSDictionary> result;
11757 bool success = false;
11758 OSSharedPtr<OSData> headerData;
11759 OSSharedPtr<OSData> logData;
11760 OSSharedPtr<OSNumber> cpuTypeNumber;
11761 OSSharedPtr<OSNumber> cpuSubtypeNumber;
11762 OSString * versionString = NULL; // do not release
11763 OSString * bundleType = NULL; // do not release
11764 uint32_t executablePathCStringSize = 0;
11765 char * executablePathCString = NULL; // must kfree
11766 OSSharedPtr<OSString> executablePathString;
11767 OSSharedPtr<OSData> uuid;
11768 OSSharedPtr<OSArray> dependencyLoadTags;
11769 OSSharedPtr<OSCollectionIterator> metaClassIterator;
11770 OSSharedPtr<OSArray> metaClassInfo;
11771 OSSharedPtr<OSDictionary> metaClassDict;
11772 OSMetaClass * thisMetaClass = NULL; // do not release
11773 OSSharedPtr<OSString> metaClassName;
11774 OSSharedPtr<OSString> superclassName;
11775 kc_format_t kcformat;
11776 uint32_t count, i;
11777
11778 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
11779 if (!result) {
11780 goto finish;
11781 }
11782
11783
11784 /* Empty keys means no keys, but NULL is quicker to check.
11785 */
11786 if (infoKeys && !infoKeys->getCount()) {
11787 infoKeys = NULL;
11788 }
11789
11790 if (!PE_get_primary_kc_format(&kcformat)) {
11791 goto finish;
11792 }
11793
11794 /* Headers, CPU type, and CPU subtype.
11795 */
11796 if (!infoKeys ||
11797 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
11798 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
11799 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
11800 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11801 if (linkedExecutable && !isInterface()) {
11802 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
11803 linkedExecutable->getBytesNoCopy();
11804
11805 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
11806 // do not return macho header info on shipping embedded - 19095897
11807 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
11808 kernel_mach_header_t * temp_kext_mach_hdr;
11809 struct load_command * lcp;
11810
11811 headerData = OSData::withBytes(kext_mach_hdr,
11812 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
11813 if (!headerData) {
11814 goto finish;
11815 }
11816
11817 // unslide any vmaddrs we return to userspace - 10726716
11818 temp_kext_mach_hdr = (kernel_mach_header_t *)
11819 headerData->getBytesNoCopy();
11820 if (temp_kext_mach_hdr == NULL) {
11821 goto finish;
11822 }
11823
11824 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
11825 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
11826 if (lcp->cmd == LC_SEGMENT_KERNEL) {
11827 kernel_segment_command_t * segp;
11828 kernel_section_t * secp;
11829
11830 segp = (kernel_segment_command_t *) lcp;
11831 // 10543468 - if we jettisoned __LINKEDIT clear size info
11832 if (flags.jettisonLinkeditSeg) {
11833 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
11834 segp->vmsize = 0;
11835 segp->fileoff = 0;
11836 segp->filesize = 0;
11837 }
11838 }
11839
11840 #if __arm__ || __arm64__
11841 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
11842 // and unslide them to avoid vm assertion failures / kernel logging breakage.
11843 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
11844 segp->vmaddr = gVirtBase;
11845 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11846 secp->size = 0; // paranoia :)
11847 secp->addr = gVirtBase;
11848 }
11849 }
11850 #endif
11851
11852 #if 0
11853 OSKextLog(/* kext */ NULL,
11854 kOSKextLogErrorLevel |
11855 kOSKextLogGeneralFlag,
11856 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
11857 __FUNCTION__, segp->segname, segp->vmaddr,
11858 VM_KERNEL_UNSLIDE(segp->vmaddr),
11859 segp->vmsize, segp->nsects);
11860 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
11861 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
11862 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
11863 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
11864 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
11865 OSKextLog(/* kext */ NULL,
11866 kOSKextLogErrorLevel |
11867 kOSKextLogGeneralFlag,
11868 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
11869 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
11870 }
11871 #endif
11872 segp->vmaddr = ml_static_unslide(segp->vmaddr);
11873
11874 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11875 secp->addr = ml_static_unslide(secp->addr);
11876 }
11877 }
11878 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
11879 }
11880 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
11881 }
11882 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
11883
11884 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11885 osLogDataHeaderRef *header;
11886 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11887
11888 void *os_log_data = NULL;
11889 void *cstring_data = NULL;
11890 void *asan_cstring_data = NULL;
11891 unsigned long os_log_size = 0;
11892 unsigned long cstring_size = 0;
11893 unsigned long asan_cstring_size = 0;
11894 uint32_t os_log_offset = 0;
11895 uint32_t cstring_offset = 0;
11896 uint32_t asan_cstring_offset = 0;
11897 bool res;
11898
11899 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
11900 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
11901 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
11902 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
11903 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
11904 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
11905
11906 header = (osLogDataHeaderRef *) headerBytes;
11907 header->version = OS_LOG_HDR_VERSION;
11908 header->sect_count = NUM_OS_LOG_SECTIONS;
11909 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
11910 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
11911 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
11912 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
11913 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
11914 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
11915
11916
11917 logData = OSData::withValue(*header);
11918 if (!logData) {
11919 goto finish;
11920 }
11921 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11922 if (!res) {
11923 goto finish;
11924 }
11925 if (os_log_data) {
11926 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
11927 if (!res) {
11928 goto finish;
11929 }
11930 }
11931 if (cstring_data) {
11932 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
11933 if (!res) {
11934 goto finish;
11935 }
11936 }
11937 if (asan_cstring_data) {
11938 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
11939 if (!res) {
11940 goto finish;
11941 }
11942 }
11943 result->setObject(kOSBundleLogStringsKey, logData.get());
11944 }
11945
11946 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
11947 cpuTypeNumber = OSNumber::withNumber(
11948 (uint64_t) kext_mach_hdr->cputype,
11949 8 * sizeof(kext_mach_hdr->cputype));
11950 if (!cpuTypeNumber) {
11951 goto finish;
11952 }
11953 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
11954 }
11955
11956 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11957 cpuSubtypeNumber = OSNumber::withNumber(
11958 (uint64_t) kext_mach_hdr->cpusubtype,
11959 8 * sizeof(kext_mach_hdr->cpusubtype));
11960 if (!cpuSubtypeNumber) {
11961 goto finish;
11962 }
11963 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
11964 }
11965 } else {
11966 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11967 osLogDataHeaderRef *header;
11968 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11969 bool res;
11970
11971 header = (osLogDataHeaderRef *) headerBytes;
11972 header->version = OS_LOG_HDR_VERSION;
11973 header->sect_count = NUM_OS_LOG_SECTIONS;
11974 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
11975 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
11976 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
11977 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11978 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
11979 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11980
11981 logData = OSData::withValue(*header);
11982 if (!logData) {
11983 goto finish;
11984 }
11985 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11986 if (!res) {
11987 goto finish;
11988 }
11989 result->setObject(kOSBundleLogStringsKey, logData.get());
11990 }
11991 }
11992 }
11993
11994 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
11995 */
11996 result->setObject(kCFBundleIdentifierKey, bundleID.get());
11997
11998 /* kOSBundleDextUniqueIdentifierKey if present.
11999 */
12000 if (isDriverKit() && dextUniqueID != NULL) {
12001 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12002 }
12003
12004 /* CFBundlePackageType
12005 */
12006 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12007 if (bundleType) {
12008 result->setObject(kCFBundlePackageTypeKey, bundleType);
12009 }
12010
12011 /* CFBundleVersion.
12012 */
12013 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12014 versionString = OSDynamicCast(OSString,
12015 getPropertyForHostArch(kCFBundleVersionKey));
12016 if (versionString) {
12017 result->setObject(kCFBundleVersionKey, versionString);
12018 }
12019 }
12020
12021 /* OSBundleCompatibleVersion.
12022 */
12023 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12024 versionString = OSDynamicCast(OSString,
12025 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12026 if (versionString) {
12027 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12028 }
12029 }
12030
12031 /* Path.
12032 */
12033 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12034 if (path) {
12035 result->setObject(kOSBundlePathKey, path.get());
12036 }
12037 }
12038
12039
12040 /* OSBundleExecutablePath.
12041 */
12042 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12043 if (path && executableRelPath) {
12044 uint32_t pathLength = path->getLength(); // gets incremented below
12045
12046 // +1 for slash, +1 for \0
12047 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12048
12049 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12050 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12051 if (!executablePathCString) {
12052 goto finish;
12053 }
12054 strlcpy(executablePathCString, path->getCStringNoCopy(),
12055 executablePathCStringSize);
12056 executablePathCString[pathLength++] = '/';
12057 executablePathCString[pathLength++] = '\0';
12058 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12059 executablePathCStringSize);
12060
12061 executablePathString = OSString::withCString(executablePathCString);
12062
12063 if (!executablePathString) {
12064 goto finish;
12065 }
12066
12067 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12068 } else if (flags.builtin) {
12069 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12070 } else if (isDriverKit()) {
12071 if (path) {
12072 // +1 for slash, +1 for \0
12073 uint32_t pathLength = path->getLength();
12074 executablePathCStringSize = pathLength + 2;
12075
12076 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12077 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12078 if (!executablePathCString) {
12079 goto finish;
12080 }
12081 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12082 executablePathCString[pathLength++] = '/';
12083 executablePathCString[pathLength++] = '\0';
12084
12085 executablePathString = OSString::withCString(executablePathCString);
12086
12087 if (!executablePathString) {
12088 goto finish;
12089 }
12090
12091 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12092 }
12093 }
12094 }
12095
12096 /* UUID, if the kext has one.
12097 */
12098 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12099 uuid = copyUUID();
12100 if (uuid) {
12101 result->setObject(kOSBundleUUIDKey, uuid.get());
12102 }
12103 }
12104 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12105 uuid = copyTextUUID();
12106 if (uuid) {
12107 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12108 }
12109 }
12110
12111 /*
12112 * Info.plist digest
12113 */
12114 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12115 OSData *digest;
12116 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12117 if (digest) {
12118 result->setObject(kOSKextInfoPlistDigestKey, digest);
12119 }
12120 }
12121
12122 /*
12123 * Collection type
12124 */
12125 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12126 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12127 }
12128
12129 /*
12130 * Collection availability
12131 */
12132 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12133 result->setObject(kOSKextAuxKCAvailabilityKey,
12134 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12135 }
12136
12137 /*
12138 * Allows user load
12139 */
12140 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12141 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12142 if (allowUserLoad) {
12143 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12144 }
12145 }
12146
12147 /*
12148 * Bundle Dependencies (OSBundleLibraries)
12149 */
12150 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12151 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12152 if (libraries) {
12153 result->setObject(kOSBundleLibrariesKey, libraries);
12154 }
12155 }
12156
12157 /*****
12158 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12159 */
12160 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12161 result->setObject(kOSKernelResourceKey,
12162 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12163 }
12164
12165 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12166 result->setObject(kOSBundleIsInterfaceKey,
12167 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12168 }
12169
12170 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12171 result->setObject(kOSBundlePrelinkedKey,
12172 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12173 }
12174
12175 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12176 result->setObject(kOSBundleStartedKey,
12177 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12178 }
12179
12180 /* LoadTag (Index).
12181 */
12182 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12183 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12184 /* numBits */ 8 * sizeof(loadTag));
12185 if (!scratchNumber) {
12186 goto finish;
12187 }
12188 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12189 }
12190
12191 /* LoadAddress, LoadSize.
12192 */
12193 if (!infoKeys ||
12194 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12195 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12196 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12197 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12198 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12199 bool is_dext = isDriverKit();
12200 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12201 /* These go to userspace via serialization, so we don't want any doubts
12202 * about their size.
12203 */
12204 uint64_t loadAddress = 0;
12205 uint32_t loadSize = 0;
12206 uint32_t wiredSize = 0;
12207 uint64_t execLoadAddress = 0;
12208 uint32_t execLoadSize = 0;
12209
12210 /* Interfaces always report 0 load address & size.
12211 * Just the way they roll.
12212 *
12213 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12214 * xxx - shouldn't have one!
12215 */
12216
12217 if (flags.builtin || linkedExecutable) {
12218 kernel_mach_header_t *mh = NULL;
12219 kernel_segment_command_t *seg = NULL;
12220
12221 if (flags.builtin) {
12222 loadAddress = kmod_info->address;
12223 loadSize = (uint32_t)kmod_info->size;
12224 } else {
12225 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12226 loadSize = linkedExecutable->getLength();
12227 }
12228 mh = (kernel_mach_header_t *)loadAddress;
12229 loadAddress = ml_static_unslide(loadAddress);
12230
12231 /* Walk through the kext, looking for the first executable
12232 * segment in case we were asked for its size/address.
12233 */
12234 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12235 if (seg->initprot & VM_PROT_EXECUTE) {
12236 execLoadAddress = ml_static_unslide(seg->vmaddr);
12237 execLoadSize = (uint32_t)seg->vmsize;
12238 break;
12239 }
12240 }
12241
12242 /* If we have a kmod_info struct, calculated the wired size
12243 * from that. Otherwise it's the full load size.
12244 */
12245 if (kmod_info) {
12246 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12247 } else {
12248 wiredSize = loadSize;
12249 }
12250 } else if (is_dext) {
12251 /*
12252 * DriverKit userspace executables do not have a kernel linkedExecutable,
12253 * so we "fake" their address range with the LoadTag.
12254 */
12255 if (loadTag) {
12256 loadAddress = execLoadAddress = loadTag;
12257 loadSize = execLoadSize = 1;
12258 }
12259 }
12260
12261 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12262 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12263 (unsigned long long)(loadAddress),
12264 /* numBits */ 8 * sizeof(loadAddress));
12265 if (!scratchNumber) {
12266 goto finish;
12267 }
12268 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12269 }
12270 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12271 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12272 && loadAddress && loadSize) {
12273 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12274 if (!baseAddress) {
12275 goto finish;
12276 }
12277
12278 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12279 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12280 /* numBits */ 8 * sizeof(loadAddress));
12281 if (!scratchNumber) {
12282 goto finish;
12283 }
12284 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12285 }
12286 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12287 && (this == sKernelKext) && gBuiltinKmodsCount) {
12288 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12289 }
12290 }
12291
12292 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12293 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12294 (unsigned long long)(execLoadAddress),
12295 /* numBits */ 8 * sizeof(execLoadAddress));
12296 if (!scratchNumber) {
12297 goto finish;
12298 }
12299 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12300 }
12301 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12302 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12303 (unsigned long long)(loadSize),
12304 /* numBits */ 8 * sizeof(loadSize));
12305 if (!scratchNumber) {
12306 goto finish;
12307 }
12308 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12309 }
12310 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12311 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12312 (unsigned long long)(execLoadSize),
12313 /* numBits */ 8 * sizeof(execLoadSize));
12314 if (!scratchNumber) {
12315 goto finish;
12316 }
12317 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12318 }
12319 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12320 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12321 (unsigned long long)(wiredSize),
12322 /* numBits */ 8 * sizeof(wiredSize));
12323 if (!scratchNumber) {
12324 goto finish;
12325 }
12326 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12327 }
12328 }
12329 }
12330
12331 /* OSBundleDependencies. In descending order for
12332 * easy compatibility with kextstat(8).
12333 */
12334 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12335 if ((count = getNumDependencies())) {
12336 dependencyLoadTags = OSArray::withCapacity(count);
12337 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12338
12339 i = count - 1;
12340 do {
12341 OSKext * dependency = OSDynamicCast(OSKext,
12342 dependencies->getObject(i));
12343
12344 if (!dependency) {
12345 continue;
12346 }
12347 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12348 (unsigned long long)dependency->getLoadTag(),
12349 /* numBits*/ 8 * sizeof(loadTag));
12350 if (!scratchNumber) {
12351 goto finish;
12352 }
12353 dependencyLoadTags->setObject(scratchNumber.get());
12354 } while (i--);
12355 }
12356 }
12357
12358 /* OSBundleMetaClasses.
12359 */
12360 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12361 if (metaClasses && metaClasses->getCount()) {
12362 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12363 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12364 if (!metaClassIterator || !metaClassInfo) {
12365 goto finish;
12366 }
12367 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12368
12369 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12370 metaClassIterator->getNextObject()))) {
12371 metaClassDict = OSDictionary::withCapacity(3);
12372 if (!metaClassDict) {
12373 goto finish;
12374 }
12375
12376 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12377 if (thisMetaClass->getSuperClass()) {
12378 superclassName = OSString::withCString(
12379 thisMetaClass->getSuperClass()->getClassName());
12380 }
12381 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12382 8 * sizeof(unsigned int));
12383
12384 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12385 * of course.
12386 */
12387 if (!metaClassDict || !metaClassName || !scratchNumber) {
12388 goto finish;
12389 }
12390
12391 metaClassInfo->setObject(metaClassDict.get());
12392 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12393 if (superclassName) {
12394 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12395 }
12396 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12397 }
12398 }
12399 }
12400
12401 /* OSBundleRetainCount.
12402 */
12403 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12404 {
12405 int kextRetainCount = getRetainCount() - 1;
12406 if (isLoaded()) {
12407 kextRetainCount--;
12408 }
12409 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12410 (int)kextRetainCount,
12411 /* numBits*/ 8 * sizeof(int));
12412 if (scratchNumber) {
12413 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12414 }
12415 }
12416 }
12417
12418 success = true;
12419
12420 finish:
12421 if (executablePathCString) {
12422 kfree_data(executablePathCString, executablePathCStringSize);
12423 }
12424 if (!success) {
12425 result.reset();
12426 }
12427 return result;
12428 }
12429
12430 /*********************************************************************
12431 *********************************************************************/
12432 /* static */
12433 bool
12434 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12435 {
12436 bool ok;
12437 OSSharedPtr<OSKext> kext;
12438
12439 IORecursiveLockLock(sKextLock);
12440 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12441 IORecursiveLockUnlock(sKextLock);
12442
12443 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12444 return false;
12445 }
12446 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12447 kext->path->getCStringNoCopy(),
12448 kext->userExecutableRelPath->getCStringNoCopy());
12449 ok = true;
12450
12451 return ok;
12452 }
12453
12454 /*********************************************************************
12455 *********************************************************************/
12456 /* static */
12457 OSReturn
12458 OSKext::requestResource(
12459 const char * kextIdentifierCString,
12460 const char * resourceNameCString,
12461 OSKextRequestResourceCallback callback,
12462 void * context,
12463 OSKextRequestTag * requestTagOut)
12464 {
12465 OSReturn result = kOSReturnError;
12466 OSSharedPtr<OSKext> callbackKext; // looked up
12467
12468 OSKextRequestTag requestTag = -1;
12469 OSSharedPtr<OSNumber> requestTagNum;
12470 OSSharedPtr<OSDictionary> requestDict;
12471 OSSharedPtr<OSString> kextIdentifier;
12472 OSSharedPtr<OSString> resourceName;
12473
12474 OSSharedPtr<OSDictionary> callbackRecord;
12475 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12476
12477 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12478
12479 IORecursiveLockLock(sKextLock);
12480
12481 if (requestTagOut) {
12482 *requestTagOut = kOSKextRequestTagInvalid;
12483 }
12484
12485 /* If requests to user space are disabled, don't go any further */
12486 if (!sKernelRequestsEnabled) {
12487 OSKextLog(/* kext */ NULL,
12488 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12489 "Can't request resource %s for %s - requests to user space are disabled.",
12490 resourceNameCString,
12491 kextIdentifierCString);
12492 result = kOSKextReturnDisabled;
12493 goto finish;
12494 }
12495
12496 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12497 result = kOSKextReturnInvalidArgument;
12498 goto finish;
12499 }
12500
12501 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12502 if (!callbackKext) {
12503 OSKextLog(/* kext */ NULL,
12504 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12505 "Resource request has bad callback address.");
12506 result = kOSKextReturnInvalidArgument;
12507 goto finish;
12508 }
12509 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12510 OSKextLog(/* kext */ NULL,
12511 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12512 "Resource request callback is in a kext that is not started.");
12513 result = kOSKextReturnInvalidArgument;
12514 goto finish;
12515 }
12516
12517 /* Do not allow any new requests to be made on a kext that is unloading.
12518 */
12519 if (callbackKext->flags.stopping) {
12520 result = kOSKextReturnStopping;
12521 goto finish;
12522 }
12523
12524 /* If we're wrapped the next available request tag around to the negative
12525 * numbers, we can't service any more requests.
12526 */
12527 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12528 OSKextLog(/* kext */ NULL,
12529 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12530 "No more request tags available; restart required.");
12531 result = kOSKextReturnNoResources;
12532 goto finish;
12533 }
12534 requestTag = sNextRequestTag++;
12535
12536 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12537 requestDict);
12538 if (result != kOSReturnSuccess) {
12539 goto finish;
12540 }
12541
12542 kextIdentifier = OSString::withCString(kextIdentifierCString);
12543 resourceName = OSString::withCString(resourceNameCString);
12544 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12545 8 * sizeof(requestTag));
12546 if (!kextIdentifier ||
12547 !resourceName ||
12548 !requestTagNum ||
12549 !_OSKextSetRequestArgument(requestDict.get(),
12550 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12551 !_OSKextSetRequestArgument(requestDict.get(),
12552 kKextRequestArgumentNameKey, resourceName.get()) ||
12553 !_OSKextSetRequestArgument(requestDict.get(),
12554 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12555 result = kOSKextReturnNoMemory;
12556 goto finish;
12557 }
12558
12559 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12560 if (!callbackRecord) {
12561 result = kOSKextReturnNoMemory;
12562 goto finish;
12563 }
12564 // we validate callback address at call time
12565 callbackWrapper = OSValueObjectWithValue(callback);
12566 if (context) {
12567 contextWrapper = OSValueObjectWithValue(context);
12568 }
12569 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12570 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12571 result = kOSKextReturnNoMemory;
12572 goto finish;
12573 }
12574
12575 if (context) {
12576 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12577 kKextRequestArgumentContextKey, contextWrapper.get())) {
12578 result = kOSKextReturnNoMemory;
12579 goto finish;
12580 }
12581 }
12582
12583 /* Only post the requests after all the other potential failure points
12584 * have been passed.
12585 */
12586 if (!sKernelRequests->setObject(requestDict.get()) ||
12587 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12588 result = kOSKextReturnNoMemory;
12589 goto finish;
12590 }
12591
12592 OSKext::pingIOKitDaemon();
12593
12594 result = kOSReturnSuccess;
12595 if (requestTagOut) {
12596 *requestTagOut = requestTag;
12597 }
12598
12599 finish:
12600
12601 /* If we didn't succeed, yank the request & callback
12602 * from their holding arrays.
12603 */
12604 if (result != kOSReturnSuccess) {
12605 unsigned int index;
12606
12607 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12608 if (index != (unsigned int)-1) {
12609 sKernelRequests->removeObject(index);
12610 }
12611 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12612 if (index != (unsigned int)-1) {
12613 sRequestCallbackRecords->removeObject(index);
12614 }
12615 }
12616
12617 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12618
12619 IORecursiveLockUnlock(sKextLock);
12620
12621 return result;
12622 }
12623
12624 OSReturn
12625 OSKext::requestDaemonLaunch(
12626 OSString *kextIdentifier,
12627 OSString *serverName,
12628 OSNumber *serverTag,
12629 OSBoolean *reslide,
12630 IOUserServerCheckInToken * checkInToken,
12631 OSData *serverDUI)
12632 {
12633 OSReturn result = kOSReturnError;
12634 OSSharedPtr<OSDictionary> requestDict;
12635 unsigned int size = 0;
12636 const char *dextUniqueIDCString = NULL;
12637
12638 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12639 return kOSKextReturnInvalidArgument;
12640 }
12641
12642 if (serverDUI != NULL) {
12643 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12644 }
12645
12646 IORecursiveLockLock(sKextLock);
12647
12648 OSKextLog(/* kext */ NULL,
12649 kOSKextLogDebugLevel |
12650 kOSKextLogGeneralFlag,
12651 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12652 kextIdentifier->getCStringNoCopy(),
12653 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12654 serverName->getCStringNoCopy(),
12655 serverTag->unsigned64BitValue(),
12656 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12657 );
12658
12659 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12660 if (result != kOSReturnSuccess) {
12661 goto finish;
12662 }
12663
12664 if (!_OSKextSetRequestArgument(requestDict.get(),
12665 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12666 !_OSKextSetRequestArgument(requestDict.get(),
12667 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12668 !_OSKextSetRequestArgument(requestDict.get(),
12669 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12670 !_OSKextSetRequestArgument(requestDict.get(),
12671 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12672 !_OSKextSetRequestArgument(requestDict.get(),
12673 kKextRequestArgumentCheckInToken, checkInToken)) {
12674 result = kOSKextReturnNoMemory;
12675 goto finish;
12676 }
12677
12678 if (serverDUI) {
12679 if (!_OSKextSetRequestArgument(requestDict.get(),
12680 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12681 result = kOSKextReturnNoMemory;
12682 goto finish;
12683 }
12684 }
12685
12686 /* Only post the requests after all the other potential failure points
12687 * have been passed.
12688 */
12689 if (!sKernelRequests->setObject(requestDict.get())) {
12690 result = kOSKextReturnNoMemory;
12691 goto finish;
12692 }
12693 OSKext::pingIOKitDaemon();
12694
12695 result = kOSReturnSuccess;
12696 finish:
12697 IORecursiveLockUnlock(sKextLock);
12698 if (dextUniqueIDCString) {
12699 kfree_data(dextUniqueIDCString, size);
12700 }
12701 return result;
12702 }
12703
12704 OSReturn
12705 OSKext::notifyDextUpgrade(
12706 OSString *kextIdentifier,
12707 OSData *dextUniqueIdentifier)
12708 {
12709 OSReturn result = kOSReturnError;
12710 OSSharedPtr<OSDictionary> requestDict;
12711 unsigned int size = 0;
12712 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
12713 assert(dextUniqueIDCString != NULL);
12714
12715 IORecursiveLockLock(sKextLock);
12716
12717 OSKextLog(NULL,
12718 kOSKextLogDebugLevel |
12719 kOSKextLogGeneralFlag,
12720 "Notifying of dext upgrade for %s with UniqueID %s",
12721 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12722
12723 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
12724 if (result != kOSReturnSuccess) {
12725 goto finish;
12726 }
12727
12728 if (!_OSKextSetRequestArgument(requestDict.get(),
12729 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12730 !_OSKextSetRequestArgument(requestDict.get(),
12731 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
12732 result = kOSKextReturnNoMemory;
12733 goto finish;
12734 }
12735
12736 /* Only post the requests after all the other potential failure points
12737 * have been passed.
12738 */
12739 if (!sKernelRequests->setObject(requestDict.get())) {
12740 result = kOSKextReturnNoMemory;
12741 goto finish;
12742 }
12743 OSKext::pingIOKitDaemon();
12744
12745 result = kOSReturnSuccess;
12746 finish:
12747 IORecursiveLockUnlock(sKextLock);
12748
12749 if (dextUniqueIDCString != NULL) {
12750 kfree_data(dextUniqueIDCString, size);
12751 }
12752 return result;
12753 }
12754
12755 /*********************************************************************
12756 * Assumes sKextLock is held.
12757 *********************************************************************/
12758 /* static */
12759 OSReturn
12760 OSKext::dequeueCallbackForRequestTag(
12761 OSKextRequestTag requestTag,
12762 OSSharedPtr<OSDictionary> &callbackRecordOut)
12763 {
12764 OSDictionary * callbackRecordOutRaw = NULL;
12765 OSReturn result;
12766
12767 result = dequeueCallbackForRequestTag(requestTag,
12768 &callbackRecordOutRaw);
12769
12770 if (kOSReturnSuccess == result) {
12771 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12772 }
12773
12774 return result;
12775 }
12776 OSReturn
12777 OSKext::dequeueCallbackForRequestTag(
12778 OSKextRequestTag requestTag,
12779 OSDictionary ** callbackRecordOut)
12780 {
12781 OSReturn result = kOSReturnError;
12782 OSSharedPtr<OSNumber> requestTagNum;
12783
12784 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12785 8 * sizeof(requestTag));
12786 if (!requestTagNum) {
12787 goto finish;
12788 }
12789
12790 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
12791 callbackRecordOut);
12792
12793 finish:
12794 return result;
12795 }
12796
12797 /*********************************************************************
12798 * Assumes sKextLock is held.
12799 *********************************************************************/
12800 /* static */
12801 OSReturn
12802 OSKext::dequeueCallbackForRequestTag(
12803 OSNumber * requestTagNum,
12804 OSSharedPtr<OSDictionary> &callbackRecordOut)
12805 {
12806 OSDictionary * callbackRecordOutRaw = NULL;
12807 OSReturn result;
12808
12809 result = dequeueCallbackForRequestTag(requestTagNum,
12810 &callbackRecordOutRaw);
12811
12812 if (kOSReturnSuccess == result) {
12813 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12814 }
12815
12816 return result;
12817 }
12818 OSReturn
12819 OSKext::dequeueCallbackForRequestTag(
12820 OSNumber * requestTagNum,
12821 OSDictionary ** callbackRecordOut)
12822 {
12823 OSReturn result = kOSKextReturnInvalidArgument;
12824 OSDictionary * callbackRecord = NULL; // retain if matched!
12825 OSNumber * callbackTagNum = NULL; // do not release
12826 unsigned int count, i;
12827
12828 result = kOSReturnError;
12829 count = sRequestCallbackRecords->getCount();
12830 for (i = 0; i < count; i++) {
12831 callbackRecord = OSDynamicCast(OSDictionary,
12832 sRequestCallbackRecords->getObject(i));
12833 if (!callbackRecord) {
12834 goto finish;
12835 }
12836
12837 /* If we don't find a tag, we basically have a leak here. Maybe
12838 * we should just remove it.
12839 */
12840 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
12841 callbackRecord, kKextRequestArgumentRequestTagKey));
12842 if (!callbackTagNum) {
12843 goto finish;
12844 }
12845
12846 /* We could be even more paranoid and check that all the incoming
12847 * args match what's in the callback record.
12848 */
12849 if (callbackTagNum->isEqualTo(requestTagNum)) {
12850 if (callbackRecordOut) {
12851 *callbackRecordOut = callbackRecord;
12852 callbackRecord->retain();
12853 }
12854 sRequestCallbackRecords->removeObject(i);
12855 result = kOSReturnSuccess;
12856 goto finish;
12857 }
12858 }
12859 result = kOSKextReturnNotFound;
12860
12861 finish:
12862 return result;
12863 }
12864
12865
12866 /*********************************************************************
12867 * Busy timeout triage
12868 *********************************************************************/
12869 /* static */
12870 bool
12871 OSKext::pendingIOKitDaemonRequests(void)
12872 {
12873 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
12874 }
12875
12876 /*********************************************************************
12877 * Acquires and releases sKextLock
12878 *
12879 * This function is designed to be called by kernelmanagerd and driverkitd
12880 * and it gathers all codeless kext and dext personalities, and then attempts
12881 * to map a System (pageable) KC and an Auxiliary (aux) KC.
12882 *
12883 * The pageable and aux KC can be loaded only once at boot time.
12884 * Even if the pageable or aux KC fail to load - this function will
12885 * not allow a new pageable or aux KC to be installed by subsequent calls.
12886 * This is done to avoid security issues where userspace has been compromised
12887 * or the pageable kc has been tampered with and the attacker
12888 * attempts to re-load a malicious variant.
12889 * However dexts can be dynamically loaded, so this function can be used
12890 * to request the installation of a new set of dexts even after boot time.
12891 *
12892 *
12893 *
12894 * Return: if a KC fails to load the return value will contain:
12895 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
12896 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
12897 * Similarly, if the aux kc load fails, the return value will
12898 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
12899 * compose with each other and with kOSKextReturnKCLoadFailure.
12900 *********************************************************************/
12901 /* static */
12902 OSReturn
12903 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
12904 {
12905 static bool daemon_ready = false;
12906
12907 OSReturn ret = kOSKextReturnInvalidArgument;
12908 OSReturn kcerr = 0;
12909 bool start_matching = false;
12910
12911 bool allow_fileset_load = !daemon_ready;
12912 #if !(defined(__x86_64__) || defined(__i386__))
12913 /* never allow KCs full of kexts on non-x86 machines */
12914 allow_fileset_load = false;
12915 #endif
12916
12917 /*
12918 * Change with 70582300
12919 */
12920 #if 0 || !defined(VM_MAPPED_KEXTS)
12921 /*
12922 * On platforms that don't support the SystemKC or a file-backed
12923 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
12924 * needs to be queried before we load any codeless kexts or release
12925 * any 3rd party kexts to run. On platforms that support a file-backed
12926 * AuxKC, this process is done via the kext audit mechanism.
12927 */
12928
12929 printf("KextLog: waiting for kext receipt to be queried.\n");
12930 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
12931 IOSleep(30);
12932 }
12933 #endif /* !VM_MAPPED_KEXTS */
12934
12935 /*
12936 * Get the args from the request. Right now we need the file
12937 * name for the pageable and the aux kext collection file sets.
12938 */
12939 OSDictionary * requestArgs = NULL; // do not release
12940 OSString * pageable_filepath = NULL; // do not release
12941 OSString * aux_filepath = NULL; // do not release
12942 OSArray * codeless_kexts = NULL; // do not release
12943
12944 kernel_mach_header_t *akc_mh = NULL;
12945
12946 requestArgs = OSDynamicCast(OSDictionary,
12947 requestDict->getObject(kKextRequestArgumentsKey));
12948
12949 if (requestArgs == NULL) {
12950 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12951 "KextLog: No arguments in plist for loading fileset kext\n");
12952 printf("KextLog: No arguments in plist for loading fileset kext\n");
12953 return ret;
12954 }
12955
12956 ret = kOSKextReturnDisabled;
12957
12958 IORecursiveLockLock(sKextLock);
12959
12960 if (!sLoadEnabled) {
12961 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12962 "KextLog: Kext loading is disabled (attempt to load KCs).");
12963 IORecursiveLockUnlock(sKextLock);
12964 return ret;
12965 }
12966
12967 pageable_filepath = OSDynamicCast(OSString,
12968 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
12969
12970 if (allow_fileset_load && pageable_filepath != NULL) {
12971 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
12972
12973 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
12974 if (ret) {
12975 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12976 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
12977
12978 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
12979 ret = kOSKextReturnKCLoadFailure;
12980 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
12981 goto try_auxkc;
12982 }
12983 /*
12984 * Even if the AuxKC fails to load, we still want to send
12985 * the System KC personalities to the catalog for matching
12986 */
12987 start_matching = true;
12988 } else if (pageable_filepath != NULL) {
12989 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12990 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
12991 ret = kOSKextReturnUnsupported;
12992 }
12993
12994 try_auxkc:
12995 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
12996 if (akc_mh) {
12997 /*
12998 * If we try to load a deferred AuxKC, then don't ever attempt
12999 * a filesystem map of a file
13000 */
13001 allow_fileset_load = false;
13002
13003 /*
13004 * This function is only called once per boot, so we haven't
13005 * yet loaded an AuxKC. If we have registered the AuxKC mach
13006 * header, that means that the kext collection has been placed
13007 * in memory for us by the booter, and is waiting for us to
13008 * process it. Grab the deferred XML plist of info
13009 * dictionaries and add all the kexts.
13010 */
13011 OSSharedPtr<OSObject> parsedXML;
13012 OSSharedPtr<OSData> loaded_kcUUID;
13013 OSDictionary *infoDict;
13014 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13015 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13016 #if !defined(VM_MAPPED_KEXTS)
13017 /*
13018 * On platforms where we don't dynamically wire-down / page-in
13019 * kext memory, we need to maintain the invariant that if the
13020 * AuxKC in memory does not contain a kext receipt, then we
13021 * should not load any of the kexts.
13022 */
13023 size_t receipt_sz = 0;
13024 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13025 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13026 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13027 ret = kOSKextReturnKCLoadFailure;
13028 goto try_codeless;
13029 }
13030 #endif
13031 if (infoDict) {
13032 bool added;
13033 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13034 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13035 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13036 if (!loaded_kcUUID) {
13037 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13038 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13039 } else if (!added) {
13040 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13041 "KextLog: WARNING: Failed to load AuxKC from memory.");
13042 }
13043 /* only return success if the pageable load (above) was successful */
13044 if (ret != kOSKextReturnKCLoadFailure) {
13045 ret = kOSReturnSuccess;
13046 }
13047 /* the registration of the AuxKC parsed out the KC's UUID already */
13048 } else {
13049 if (daemon_ready) {
13050 /*
13051 * Complain, but don't return an error if this isn't the first time the
13052 * IOKit daemon is checking in. If the daemon ever restarts, we will
13053 * hit this case because we've already consumed the deferred personalities.
13054 * We return success here so that a call to this function from a restarted
13055 * daemon with no codeless kexts will succeed.
13056 */
13057 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13058 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13059 if (ret != kOSKextReturnKCLoadFailure) {
13060 ret = kOSReturnSuccess;
13061 }
13062 } else {
13063 /* this is a real error case */
13064 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13065 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13066 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13067 ret = kOSKextReturnKCLoadFailure;
13068 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13069 }
13070 }
13071 }
13072
13073 aux_filepath = OSDynamicCast(OSString,
13074 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13075 if (allow_fileset_load && aux_filepath != NULL) {
13076 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13077
13078 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13079 if (ret) {
13080 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13081 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13082
13083 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13084 ret = kOSKextReturnKCLoadFailure;
13085 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13086 goto try_codeless;
13087 }
13088 start_matching = true;
13089 } else if (aux_filepath != NULL) {
13090 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13091 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13092 if (ret != kOSKextReturnKCLoadFailure) {
13093 ret = kOSKextReturnUnsupported;
13094 }
13095 }
13096
13097 try_codeless:
13098 /*
13099 * Load codeless kexts last so that there is no possibilty of a
13100 * codeless kext bundle ID preventing a kext in the system KC from
13101 * loading
13102 */
13103 codeless_kexts = OSDynamicCast(OSArray,
13104 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13105 if (codeless_kexts != NULL) {
13106 uint32_t count = codeless_kexts->getCount();
13107 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13108 "KextLog: loading %d codeless kexts/dexts", count);
13109 for (uint32_t i = 0; i < count; i++) {
13110 OSDictionary *infoDict;
13111 infoDict = OSDynamicCast(OSDictionary,
13112 codeless_kexts->getObject(i));
13113 if (!infoDict) {
13114 continue;
13115 }
13116 // instantiate a new kext, and don't hold a reference
13117 // (the kext subsystem will hold one implicitly)
13118 OSKext::withCodelessInfo(infoDict, NULL);
13119 }
13120 /* ignore errors that are not KC load failures */
13121 if (ret != kOSKextReturnKCLoadFailure) {
13122 ret = kOSReturnSuccess;
13123 }
13124 start_matching = true;
13125 }
13126
13127 /* send personalities to the IOCatalog once */
13128 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13129 OSKext::sendAllKextPersonalitiesToCatalog(true);
13130 /*
13131 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13132 * things as active and start all the delayed matching: the
13133 * dext and codeless kext personalities should have all been
13134 * delivered via this one call.
13135 */
13136 if (!daemon_ready) {
13137 OSKext::setIOKitDaemonActive();
13138 OSKext::setDeferredLoadSucceeded(TRUE);
13139 IOService::iokitDaemonLaunched();
13140 }
13141 if (sOSKextWasResetAfterUserspaceReboot) {
13142 sOSKextWasResetAfterUserspaceReboot = false;
13143 OSKext::setIOKitDaemonActive();
13144 IOService::startDeferredMatches();
13145 }
13146 }
13147
13148 if (ret == kOSKextReturnKCLoadFailure) {
13149 ret |= kcerr;
13150 }
13151
13152 /*
13153 * Only allow this function to attempt to load the pageable and
13154 * aux KCs once per boot.
13155 */
13156 daemon_ready = true;
13157
13158 IORecursiveLockUnlock(sKextLock);
13159
13160 return ret;
13161 }
13162
13163 OSReturn
13164 OSKext::resetMutableSegments(void)
13165 {
13166 kernel_segment_command_t *seg = NULL;
13167 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13168 u_int index = 0;
13169 OSKextSavedMutableSegment *savedSegment = NULL;
13170 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13171 OSReturn err;
13172
13173 if (!savedMutableSegments) {
13174 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13175 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13176 err = kOSKextReturnInternalError;
13177 goto finish;
13178 }
13179
13180 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13181 if (!segmentIsMutable(seg)) {
13182 continue;
13183 }
13184 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13185 uint64_t vmsize = seg->vmsize;
13186 err = kOSKextReturnInternalError;
13187 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13188 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13189 assert(savedSegment);
13190 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13191 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13192 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13193 err = savedSegment->restoreContents(seg);
13194 if (err != kOSReturnSuccess) {
13195 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13196 }
13197 }
13198 }
13199 if (err != kOSReturnSuccess) {
13200 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13201 }
13202 }
13203 err = kOSReturnSuccess;
13204 finish:
13205 return err;
13206 }
13207
13208
13209 /*********************************************************************
13210 * Assumes sKextLock is held.
13211 *********************************************************************/
13212 /* static */
13213 OSReturn
13214 OSKext::loadKCFileSet(
13215 const char *filepath,
13216 kc_kind_t type)
13217 {
13218 #if VM_MAPPED_KEXTS
13219 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13220 OSReturn err;
13221 struct vnode *vp = NULL;
13222 void *fileset_control;
13223 off_t fsize;
13224 bool pageable = (type == KCKindPageable);
13225
13226 if ((pageable && pageableKCloaded) ||
13227 (!pageable && auxKCloaded)) {
13228 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13229 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13230
13231 return kOSKextReturnInvalidArgument;
13232 }
13233
13234 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13235 if (!pageable && !pageableKCloaded) {
13236 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13237 "Trying to load the Aux KC without loading the Pageable KC");
13238 return kOSKextReturnInvalidArgument;
13239 }
13240
13241 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13242
13243 if (fileset_control == NULL) {
13244 printf("Could not get memory control object for file %s", filepath);
13245
13246 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13247 "Could not get memory control object for file %s", filepath);
13248 return kOSKextReturnInvalidArgument;
13249 }
13250 if (vp == NULL) {
13251 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13252 "Could not find vnode for file %s", filepath);
13253 return kOSKextReturnInvalidArgument;
13254 }
13255
13256 kernel_mach_header_t *mh = NULL;
13257 uintptr_t slide = 0;
13258
13259 #if CONFIG_CSR
13260 /*
13261 * When SIP is enabled, the KC we map must be SIP-protected
13262 */
13263 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13264 struct vnode_attr va;
13265 int error;
13266 VATTR_INIT(&va);
13267 VATTR_WANTED(&va, va_flags);
13268 error = vnode_getattr(vp, &va, vfs_context_current());
13269 if (error) {
13270 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13271 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13272 err = kOSKextReturnInternalError;
13273 goto finish;
13274 }
13275 if (!(va.va_flags & SF_RESTRICTED)) {
13276 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13277 "Path to KC '%s' is not SIP-protected", filepath);
13278 err = kOSKextReturnInvalidArgument;
13279 goto finish;
13280 }
13281 }
13282 #endif
13283
13284 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13285 if (err) {
13286 printf("KextLog: mapKCFileSet returned %d\n", err);
13287
13288 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13289 "mapKCFileSet returned %d\n", err);
13290
13291 err = kOSKextReturnInvalidArgument;
13292 }
13293
13294 #if CONFIG_CSR
13295 finish:
13296 #endif
13297 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13298 assert(vp != NULL);
13299 if (err == kOSReturnSuccess) {
13300 PE_set_kc_vp(type, vp);
13301 if (pageable) {
13302 pageableKCloaded = true;
13303 } else {
13304 auxKCloaded = true;
13305 }
13306 } else {
13307 vnode_put(vp);
13308 }
13309
13310 return err;
13311 #else
13312 (void)filepath;
13313 (void)type;
13314 return kOSKextReturnUnsupported;
13315 #endif // VM_MAPPED_KEXTS
13316 }
13317
13318 #if defined(__x86_64__) || defined(__i386__)
13319 /*********************************************************************
13320 * Assumes sKextLock is held.
13321 *********************************************************************/
13322 /* static */
13323 OSReturn
13324 OSKext::mapKCFileSet(
13325 void *control,
13326 vm_size_t fsize,
13327 kernel_mach_header_t **mhp,
13328 off_t file_offset,
13329 uintptr_t *slidep,
13330 bool pageable,
13331 void *map_entry_list)
13332 {
13333 bool fileset_load = false;
13334 kern_return_t ret;
13335 OSReturn err;
13336 kernel_section_t *infoPlistSection = NULL;
13337 OSDictionary *infoDict = NULL;
13338
13339 OSSharedPtr<OSObject> parsedXML;
13340 OSSharedPtr<OSString> errorString;
13341 OSSharedPtr<OSData> loaded_kcUUID;
13342
13343 /* Check if initial load for file set */
13344 if (*mhp == NULL) {
13345 fileset_load = true;
13346
13347 /* Get a page aligned address from kext map to map the file */
13348 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13349 if (pagealigned_addr == 0) {
13350 return kOSKextReturnNoMemory;
13351 }
13352
13353 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13354
13355 /* Allocate memory for bailout mechanism */
13356 map_entry_list = allocate_kcfileset_map_entry_list();
13357 if (map_entry_list == NULL) {
13358 return kOSKextReturnNoMemory;
13359 }
13360 }
13361
13362 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13363 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13364 /* mhp and slideptr are updated by mapKCTextSegment */
13365 if (err) {
13366 if (fileset_load) {
13367 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13368 }
13369 return err;
13370 }
13371
13372 /* Initialize the kc header globals */
13373 if (fileset_load) {
13374 if (pageable) {
13375 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13376 } else {
13377 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13378 }
13379 }
13380
13381 /* Iterate through all the segments and map necessary segments */
13382 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13383 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13384 vm_map_offset_t start;
13385 kernel_mach_header_t *k_mh = NULL;
13386 kernel_segment_command_t * seg = NULL;
13387 struct fileset_entry_command *fse = NULL;
13388
13389 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13390 seg = (kernel_segment_command_t *)lcp;
13391 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13392 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13393 fse = (struct fileset_entry_command *)lcp;
13394 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13395
13396 /* Map the segments of the mach-o binary */
13397 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13398 if (err) {
13399 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13400 return kOSKextReturnInvalidArgument;
13401 }
13402 continue;
13403 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13404 /* Check if the Aux KC is built pageable style */
13405 if (!pageable && !fileset_load && !auxKCloaded) {
13406 resetAuxKCSegmentOnUnload = true;
13407 }
13408 continue;
13409 } else {
13410 continue;
13411 }
13412
13413 if (fileset_load) {
13414 if (seg->vmsize == 0) {
13415 continue;
13416 }
13417
13418 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13419 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13420 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13421 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13422 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13423 continue;
13424 }
13425 } else {
13426 if (seg->vmsize == 0) {
13427 continue;
13428 }
13429
13430 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13431 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13432 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13433 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13434 continue;
13435 }
13436 }
13437
13438 ret = vm_map_kcfileset_segment(
13439 &start, seg->vmsize,
13440 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13441
13442 if (ret != KERN_SUCCESS) {
13443 if (fileset_load) {
13444 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13445 }
13446 return kOSKextReturnInvalidArgument;
13447 }
13448 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13449 }
13450
13451 /* Return if regular mach-o */
13452 if (!fileset_load) {
13453 return 0;
13454 }
13455
13456 /*
13457 * Fixup for the Pageable KC and the Aux KC is done by
13458 * i386_slide_kext_collection_mh_addrs, but it differs in
13459 * following ways:
13460 *
13461 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13462 * The fixup of kext segments and kext load commands are done at kext
13463 * load time by calling i386_slide_individual_kext.
13464 *
13465 * AuxKC old style: Fixup all the segments and all the load commands.
13466 *
13467 * AuxKC pageable style: Same as the Pageable KC.
13468 */
13469 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13470 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13471 if (ret != KERN_SUCCESS) {
13472 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13473 return kOSKextReturnInvalidArgument;
13474 }
13475
13476 /* Get the prelink info dictionary */
13477 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13478 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13479 if (parsedXML) {
13480 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13481 }
13482
13483 if (!infoDict) {
13484 const char *errorCString = "(unknown error)";
13485
13486 if (errorString && errorString->getCStringNoCopy()) {
13487 errorCString = errorString->getCStringNoCopy();
13488 } else if (parsedXML) {
13489 errorCString = "not a dictionary";
13490 }
13491 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13492 "Error unserializing kext info plist section: %s.", errorCString);
13493 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13494 return kOSKextReturnInvalidArgument;
13495 }
13496
13497 /* Validate that the Kext Collection is prelinked to the loaded KC */
13498 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13499 if (err) {
13500 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13501 return kOSKextReturnInvalidArgument;
13502 }
13503
13504 /* Set Protection of Segments */
13505 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13506
13507 OSKext::addKextsFromKextCollection(*mhp,
13508 infoDict, kPrelinkTextSegment,
13509 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13510
13511 /* Copy in the KC UUID */
13512 if (!loaded_kcUUID) {
13513 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13514 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13515 } else if (pageable) {
13516 pageablekc_uuid_valid = TRUE;
13517 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13518 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13519 } else {
13520 auxkc_uuid_valid = TRUE;
13521 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13522 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13523 }
13524
13525 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13526
13527 return 0;
13528 }
13529
13530 /*********************************************************************
13531 * Assumes sKextLock is held.
13532 *********************************************************************/
13533 /* static */
13534 OSReturn
13535 OSKext::mapKCTextSegment(
13536 void *control,
13537 kernel_mach_header_t **mhp,
13538 off_t file_offset,
13539 uintptr_t *slidep,
13540 void *map_entry_list)
13541 {
13542 kern_return_t ret;
13543 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13544 PAGE_MASK);
13545 vm_map_offset_t load_command_map_size = 0;
13546 kernel_mach_header_t *base_mh = *mhp;
13547
13548 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13549 ret = vm_map_kcfileset_segment(
13550 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13551 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13552
13553 if (ret != KERN_SUCCESS) {
13554 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13555
13556 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13557 "Failed to map mach header of kc fileset with error %d", ret);
13558 return kOSKextReturnInvalidArgument;
13559 }
13560
13561 if (slidep) {
13562 /* Verify that it's an MH_FILESET */
13563 if (base_mh->filetype != MH_FILESET) {
13564 printf("Kext Log: mapKCTextSegment mach header filetype"
13565 " is not an MH_FILESET, it is %x", base_mh->filetype);
13566
13567 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13568 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13569
13570 /* Unmap the mach header */
13571 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13572 return kOSKextReturnInvalidArgument;
13573 }
13574 }
13575
13576 /* Map the remaining pages of load commands */
13577 if (base_mh->sizeofcmds > mach_header_map_size) {
13578 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13579 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13580
13581 /* Map the load commands */
13582 ret = vm_map_kcfileset_segment(
13583 &load_command_addr, load_command_map_size,
13584 (memory_object_control_t)control, file_offset + mach_header_map_size,
13585 (VM_PROT_READ | VM_PROT_WRITE));
13586
13587 if (ret != KERN_SUCCESS) {
13588 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13589 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13590 "Failed to map load commands of kc fileset with error %d", ret);
13591
13592 /* Unmap the mach header */
13593 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13594 return kOSKextReturnInvalidArgument;
13595 }
13596 }
13597
13598 kernel_segment_command_t *text_seg;
13599 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13600
13601 /* Calculate the slide and vm addr of mach header */
13602 if (slidep) {
13603 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13604 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13605 }
13606
13607 /* Cache the text segment size and file offset before unmapping */
13608 vm_map_offset_t text_segment_size = text_seg->vmsize;
13609 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13610 vm_prot_t text_maxprot = text_seg->maxprot;
13611
13612 /* Unmap the first page and loadcommands and map the text segment */
13613 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13614 assert(ret == KERN_SUCCESS);
13615
13616 if (load_command_map_size) {
13617 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13618 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13619 assert(ret == KERN_SUCCESS);
13620 }
13621
13622 /* Map the text segment at actual vm addr specified in fileset */
13623 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13624 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13625 if (ret != KERN_SUCCESS) {
13626 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13627 "Failed to map Text segment of kc fileset with error %d", ret);
13628 return kOSKextReturnInvalidArgument;
13629 }
13630
13631 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13632 return 0;
13633 }
13634
13635 /*********************************************************************
13636 * Assumes sKextLock is held.
13637 *********************************************************************/
13638 /* static */
13639 OSReturn
13640 OSKext::protectKCFileSet(
13641 kernel_mach_header_t *mh,
13642 kc_kind_t type)
13643 {
13644 vm_map_t kext_map = g_kext_map;
13645 kernel_segment_command_t * seg = NULL;
13646 vm_map_offset_t start = 0;
13647 vm_map_offset_t end = 0;
13648 OSReturn ret = 0;
13649
13650 /* Set VM permissions */
13651 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13652 while (seg) {
13653 start = round_page(seg->vmaddr);
13654 end = trunc_page(seg->vmaddr + seg->vmsize);
13655
13656 /*
13657 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13658 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13659 * for the Aux KC as well.
13660 */
13661 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13662 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13663 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13664 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13665 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13666 ret = OSKext_protect((kernel_mach_header_t *)mh,
13667 kext_map, start, end, seg->maxprot, TRUE, type);
13668 if (ret != KERN_SUCCESS) {
13669 printf("OSKext protect failed with error %d", ret);
13670 return kOSKextReturnInvalidArgument;
13671 }
13672
13673 ret = OSKext_protect((kernel_mach_header_t *)mh,
13674 kext_map, start, end, seg->initprot, FALSE, type);
13675 if (ret != KERN_SUCCESS) {
13676 printf("OSKext protect failed with error %d", ret);
13677 return kOSKextReturnInvalidArgument;
13678 }
13679
13680 ret = OSKext_wire((kernel_mach_header_t *)mh,
13681 kext_map, start, end, seg->initprot, FALSE, type);
13682 if (ret != KERN_SUCCESS) {
13683 printf("OSKext wire failed with error %d", ret);
13684 return kOSKextReturnInvalidArgument;
13685 }
13686 }
13687
13688 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13689 }
13690
13691 return 0;
13692 }
13693
13694 /*********************************************************************
13695 * Assumes sKextLock is held.
13696 *********************************************************************/
13697 /* static */
13698 void
13699 OSKext::freeKCFileSetcontrol(void)
13700 {
13701 PE_reset_all_kc_vp();
13702 }
13703
13704 /*********************************************************************
13705 * Assumes sKextLock is held.
13706 *
13707 * resetKCFileSetSegments: Kext start function expects data segment to
13708 * be pristine on every load, unmap the dirty segments on unload and
13709 * remap them from FileSet on disk. Remap all segments of kext since
13710 * fixups are done per kext and not per segment.
13711 *********************************************************************/
13712 OSReturn
13713 OSKext::resetKCFileSetSegments(void)
13714 {
13715 kernel_segment_command_t *seg = NULL;
13716 kernel_segment_command_t *text_seg;
13717 uint32_t text_fileoff;
13718 kernel_mach_header_t *k_mh = NULL;
13719 uintptr_t slide;
13720 struct vnode *vp = NULL;
13721 void *fileset_control = NULL;
13722 bool pageable = (kc_type == KCKindPageable);
13723 OSReturn err;
13724 kern_return_t kr;
13725
13726 /* Check the vnode reference is still available */
13727 vp = (struct vnode *)PE_get_kc_vp(kc_type);
13728 if (vp == NULL) {
13729 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13730 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
13731 return kOSKextReturnInternalError;
13732 }
13733
13734 fileset_control = ubc_getobject(vp, 0);
13735 assert(fileset_control != NULL);
13736
13737 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13738 "Kext %s resetting all segments", getIdentifierCString());
13739
13740 k_mh = (kernel_mach_header_t *)kmod_info->address;
13741 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
13742 text_fileoff = text_seg->fileoff;
13743 slide = PE_get_kc_slide(kc_type);
13744
13745 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
13746 while (seg) {
13747 if (seg->vmsize == 0) {
13748 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13749 continue;
13750 }
13751
13752 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13753 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13754 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13755 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13756 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13757 continue;
13758 }
13759
13760 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
13761 assert(kr == KERN_SUCCESS);
13762 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13763 }
13764
13765 /* Unmap the text segment */
13766 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
13767 assert(kr == KERN_SUCCESS);
13768
13769 /* Map all the segments of the kext */
13770 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
13771 if (err) {
13772 panic("Could not reset segments of a mapped kext, error %x", err);
13773 }
13774
13775 /* Update address in kmod_info, since it has been reset */
13776 if (kmod_info->address) {
13777 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
13778 }
13779
13780 return 0;
13781 }
13782
13783 /*********************************************************************
13784 * Mechanism to track all segment mapping while mapping KC fileset.
13785 *********************************************************************/
13786
13787 struct kcfileset_map_entry {
13788 vm_map_offset_t me_start;
13789 vm_map_offset_t me_size;
13790 };
13791
13792 struct kcfileset_map_entry_list {
13793 int kme_list_count;
13794 int kme_list_index;
13795 struct kcfileset_map_entry kme_list[];
13796 };
13797
13798 #define KCFILESET_MAP_ENTRY_MAX (16380)
13799
13800 static void *
13801 allocate_kcfileset_map_entry_list(void)
13802 {
13803 struct kcfileset_map_entry_list *entry_list;
13804
13805 entry_list = kalloc_type(struct kcfileset_map_entry_list,
13806 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
13807
13808 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
13809 entry_list->kme_list_index = 0;
13810 return entry_list;
13811 }
13812
13813 static void
13814 add_kcfileset_map_entry(
13815 void *map_entry_list,
13816 vm_map_offset_t start,
13817 vm_map_offset_t size)
13818 {
13819 if (map_entry_list == NULL) {
13820 return;
13821 }
13822
13823 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13824
13825 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
13826 panic("Ran out of map kc fileset list");
13827 }
13828
13829 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
13830 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
13831
13832 entry_list->kme_list_index++;
13833 }
13834
13835 static void
13836 deallocate_kcfileset_map_entry_list_and_unmap_entries(
13837 void *map_entry_list,
13838 boolean_t unmap_entries,
13839 bool pageable)
13840 {
13841 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13842
13843 if (unmap_entries) {
13844 for (int i = 0; i < entry_list->kme_list_index; i++) {
13845 kern_return_t ret;
13846 ret = vm_unmap_kcfileset_segment(
13847 &(entry_list->kme_list[i].me_start),
13848 entry_list->kme_list[i].me_size);
13849 assert(ret == KERN_SUCCESS);
13850 }
13851
13852 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
13853 }
13854
13855 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
13856 KCFILESET_MAP_ENTRY_MAX, entry_list);
13857 }
13858
13859 /*********************************************************************
13860 * Mechanism to map kext segment.
13861 *********************************************************************/
13862
13863 kern_return_t
13864 vm_map_kcfileset_segment(
13865 vm_map_offset_t *start,
13866 vm_map_offset_t size,
13867 void *control,
13868 vm_object_offset_t fileoffset,
13869 vm_prot_t max_prot)
13870 {
13871 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
13872 vmk_flags.vmkf_no_copy_on_read = 1;
13873 vmk_flags.vmkf_cs_enforcement = 0;
13874 vmk_flags.vmkf_cs_enforcement_override = 1;
13875 kern_return_t ret;
13876
13877 /* Add Write to max prot to allow fixups */
13878 max_prot = max_prot | VM_PROT_WRITE;
13879
13880 /*
13881 * Map the segments from file as COPY mappings to
13882 * make sure changes on disk to the file does not affect
13883 * mapped segments.
13884 */
13885 ret = vm_map_enter_mem_object_control(
13886 g_kext_map,
13887 start,
13888 size,
13889 (mach_vm_offset_t)0,
13890 VM_FLAGS_FIXED,
13891 vmk_flags,
13892 VM_KERN_MEMORY_OSKEXT,
13893 (memory_object_control_t)control,
13894 fileoffset,
13895 TRUE, /* copy */
13896 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
13897 VM_INHERIT_NONE);
13898
13899 return ret;
13900 }
13901
13902 kern_return_t
13903 vm_unmap_kcfileset_segment(
13904 vm_map_offset_t *start,
13905 vm_map_offset_t size)
13906 {
13907 return mach_vm_deallocate(g_kext_map, *start, size);
13908 }
13909
13910 #endif //(__x86_64__) || defined(__i386__)
13911
13912 /*********************************************************************
13913 * Assumes sKextLock is held.
13914 *********************************************************************/
13915 /* static */
13916 OSReturn
13917 OSKext::validateKCFileSetUUID(
13918 OSDictionary *infoDict,
13919 kc_kind_t type)
13920 {
13921 OSReturn ret = kOSReturnSuccess;
13922
13923 if (!kernelcache_uuid_valid) {
13924 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13925 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
13926 ret = kOSKextReturnInvalidArgument;
13927 goto finish;
13928 }
13929 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
13930 if (ret != 0) {
13931 goto finish;
13932 }
13933
13934 #if defined(__x86_64__) || defined(__i386__)
13935 /* Check if the Aux KC is prelinked to correct Pageable KC */
13936 if (type == KCKindAuxiliary) {
13937 if (!pageablekc_uuid_valid) {
13938 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13939 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
13940 ret = kOSKextReturnInvalidArgument;
13941 goto finish;
13942 }
13943 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
13944 if (ret != 0) {
13945 goto finish;
13946 }
13947 }
13948 #endif //(__x86_64__) || defined(__i386__)
13949
13950 printf("KextLog: Collection UUID matches with loaded KCs.\n");
13951 finish:
13952 return ret;
13953 }
13954
13955 /*********************************************************************
13956 * Assumes sKextLock is held.
13957 *********************************************************************/
13958 /* static */
13959 OSReturn
13960 OSKext::validateKCUUIDfromPrelinkInfo(
13961 uuid_t *loaded_kcuuid,
13962 kc_kind_t type,
13963 OSDictionary *infoDict,
13964 const char *uuid_key)
13965 {
13966 /* extract the UUID from the dictionary */
13967 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
13968 if (!prelinkinfoKCUUID) {
13969 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13970 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
13971 return kOSKextReturnInvalidArgument;
13972 }
13973
13974 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
13975 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13976 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
13977 return kOSKextReturnInvalidArgument;
13978 }
13979
13980 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
13981 prelinkinfoKCUUID->getLength())) {
13982 OSData *info_dict_uuid;
13983 uuid_string_t info_dict_uuid_str = {};
13984 uuid_string_t expected_uuid_str = {};
13985 uuid_string_t given_uuid_str = {};
13986 uuid_t given_uuid;
13987
13988 /* extract the KC UUID from the dictionary */
13989 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
13990 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
13991 uuid_t tmp_uuid;
13992 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
13993 uuid_unparse(tmp_uuid, info_dict_uuid_str);
13994 }
13995
13996 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
13997 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
13998 uuid_unparse(given_uuid, given_uuid_str);
13999
14000 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14001 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14002 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14003 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14004 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14005 if (type == KCKindPageable && sPanicOnKCMismatch) {
14006 panic("System KC UUID %s linked against %s, but %s is loaded",
14007 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14008 }
14009 return kOSKextReturnInvalidArgument;
14010 }
14011
14012 return 0;
14013 }
14014
14015 /*********************************************************************
14016 * Assumes sKextLock is held.
14017 *********************************************************************/
14018 /* static */
14019 OSReturn
14020 OSKext::dispatchResource(OSDictionary * requestDict)
14021 {
14022 OSReturn result = kOSReturnError;
14023 OSSharedPtr<OSDictionary> callbackRecord;
14024 OSNumber * requestTag = NULL; // do not release
14025 OSNumber * requestResult = NULL; // do not release
14026 OSData * dataObj = NULL; // do not release
14027 uint32_t dataLength = 0;
14028 const void * dataPtr = NULL; // do not free
14029 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14030 OSKextRequestResourceCallback callback = NULL;
14031 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14032 void * context = NULL; // do not free
14033 OSSharedPtr<OSKext> callbackKext;
14034
14035 /* Get the args from the request. Right now we need the tag
14036 * to look up the callback record, and the result for invoking the callback.
14037 */
14038 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14039 kKextRequestArgumentRequestTagKey));
14040 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14041 kKextRequestArgumentResultKey));
14042 if (!requestTag || !requestResult) {
14043 result = kOSKextReturnInvalidArgument;
14044 goto finish;
14045 }
14046
14047 /* Look for a callback record matching this request's tag.
14048 */
14049 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14050 if (result != kOSReturnSuccess) {
14051 goto finish;
14052 }
14053
14054 /*****
14055 * Get the context pointer of the callback record (if there is one).
14056 */
14057 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14058 callbackRecord.get(), kKextRequestArgumentContextKey));
14059 context = _OSKextExtractPointer(contextWrapper);
14060 if (contextWrapper && !context) {
14061 goto finish;
14062 }
14063
14064 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14065 _OSKextGetRequestArgument(callbackRecord.get(),
14066 kKextRequestArgumentCallbackKey));
14067 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14068 if (!callback) {
14069 goto finish;
14070 }
14071
14072 /* Check for a data obj. We might not have one and that's ok, that means
14073 * we didn't find the requested resource, and we still have to tell the
14074 * caller that via the callback.
14075 */
14076 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14077 kKextRequestArgumentValueKey));
14078 if (dataObj) {
14079 dataPtr = dataObj->getBytesNoCopy();
14080 dataLength = dataObj->getLength();
14081 }
14082
14083 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14084 if (!callbackKext) {
14085 OSKextLog(/* kext */ NULL,
14086 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14087 "Can't invoke callback for resource request; ");
14088 goto finish;
14089 }
14090 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14091 OSKextLog(/* kext */ NULL,
14092 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14093 "Can't invoke kext resource callback; ");
14094 goto finish;
14095 }
14096
14097 (void)callback(requestTag->unsigned32BitValue(),
14098 (OSReturn)requestResult->unsigned32BitValue(),
14099 dataPtr, dataLength, context);
14100
14101 result = kOSReturnSuccess;
14102
14103 finish:
14104 return result;
14105 }
14106
14107 /*********************************************************************
14108 * Assumes sKextLock is held.
14109 *********************************************************************/
14110 /* static */
14111 OSReturn
14112 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14113 {
14114 OSSharedPtr<OSDictionary> missingIDs;
14115 OSArray *bundleIDList = NULL; // do not release
14116
14117 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14118 requestDict, kKextRequestArgumentMissingBundleIDs));
14119 if (!bundleIDList) {
14120 return kOSKextReturnInvalidArgument;
14121 }
14122
14123 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14124 if (!missingIDs) {
14125 return kOSKextReturnNoMemory;
14126 }
14127
14128 uint32_t count, i;
14129 count = bundleIDList->getCount();
14130 for (i = 0; i < count; i++) {
14131 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14132 if (thisID) {
14133 missingIDs->setObject(thisID, kOSBooleanFalse);
14134 }
14135 }
14136
14137 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14138
14139 return kOSReturnSuccess;
14140 }
14141
14142 /*********************************************************************
14143 * Assumes sKextLock is held.
14144 *********************************************************************/
14145 /* static */
14146 OSReturn
14147 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14148 {
14149 bool loadable = true;
14150 if (!kextIdentifier) {
14151 return kOSKextReturnInvalidArgument;
14152 }
14153
14154 if (requestDict) {
14155 OSBoolean *loadableArg;
14156 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14157 requestDict, kKextRequestArgumentBundleAvailability));
14158 /* If we find the "Bundle Available" arg, and it's false, then
14159 * mark the bundle ID as _not_ loadable
14160 */
14161 if (loadableArg && !loadableArg->getValue()) {
14162 loadable = false;
14163 }
14164 }
14165
14166 if (!sNonLoadableKextsByID) {
14167 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14168 }
14169
14170 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14171
14172 OSKextLog(/* kext */ NULL,
14173 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14174 "KextLog: AuxKC bundle %s marked as %s",
14175 kextIdentifier->getCStringNoCopy(),
14176 (loadable ? "loadable" : "NOT loadable"));
14177
14178 return kOSReturnSuccess;
14179 }
14180
14181 /*********************************************************************
14182 *********************************************************************/
14183 /* static */
14184 void
14185 OSKext::invokeRequestCallback(
14186 OSDictionary * callbackRecord,
14187 OSReturn callbackResult)
14188 {
14189 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14190 OSSharedPtr<OSNumber> resultNum;
14191
14192 if (!predicate) {
14193 goto finish;
14194 }
14195
14196 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14197 8 * sizeof(callbackResult));
14198 if (!resultNum) {
14199 goto finish;
14200 }
14201
14202 /* Insert the result into the callback record and dispatch it as if it
14203 * were the reply coming down from user space.
14204 */
14205 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14206 resultNum.get());
14207
14208 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14209 /* This removes the pending callback record.
14210 */
14211 OSKext::dispatchResource(callbackRecord);
14212 }
14213
14214 finish:
14215 return;
14216 }
14217
14218 /*********************************************************************
14219 * Assumes sKextLock is held.
14220 *********************************************************************/
14221 /* static */
14222 OSReturn
14223 OSKext::cancelRequest(
14224 OSKextRequestTag requestTag,
14225 void ** contextOut)
14226 {
14227 OSReturn result = kOSKextReturnNoMemory;
14228 OSSharedPtr<OSDictionary> callbackRecord;
14229 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14230
14231 IORecursiveLockLock(sKextLock);
14232 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14233 callbackRecord);
14234 IORecursiveLockUnlock(sKextLock);
14235
14236 if (result == kOSReturnSuccess && contextOut) {
14237 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14238 _OSKextGetRequestArgument(callbackRecord.get(),
14239 kKextRequestArgumentContextKey));
14240 *contextOut = _OSKextExtractPointer(contextWrapper);
14241 }
14242
14243 return result;
14244 }
14245
14246 /*********************************************************************
14247 * Assumes sKextLock is held.
14248 *********************************************************************/
14249 void
14250 OSKext::invokeOrCancelRequestCallbacks(
14251 OSReturn callbackResult,
14252 bool invokeFlag)
14253 {
14254 unsigned int count, i;
14255
14256 count = sRequestCallbackRecords->getCount();
14257 if (!count) {
14258 goto finish;
14259 }
14260
14261 i = count - 1;
14262 do {
14263 OSDictionary * request = OSDynamicCast(OSDictionary,
14264 sRequestCallbackRecords->getObject(i));
14265
14266 if (!request) {
14267 continue;
14268 }
14269 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14270 _OSKextGetRequestArgument(request,
14271 kKextRequestArgumentCallbackKey));
14272
14273 if (!callbackWrapper) {
14274 sRequestCallbackRecords->removeObject(i);
14275 continue;
14276 }
14277
14278 vm_address_t callbackAddress = (vm_address_t)
14279 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14280
14281 if ((kmod_info->address <= callbackAddress) &&
14282 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14283 if (invokeFlag) {
14284 /* This removes the callback record.
14285 */
14286 invokeRequestCallback(request, callbackResult);
14287 } else {
14288 sRequestCallbackRecords->removeObject(i);
14289 }
14290 }
14291 } while (i--);
14292
14293 finish:
14294 return;
14295 }
14296
14297 /*********************************************************************
14298 * Assumes sKextLock is held.
14299 *********************************************************************/
14300 uint32_t
14301 OSKext::countRequestCallbacks(void)
14302 {
14303 uint32_t result = 0;
14304 unsigned int count, i;
14305
14306 count = sRequestCallbackRecords->getCount();
14307 if (!count) {
14308 goto finish;
14309 }
14310
14311 i = count - 1;
14312 do {
14313 OSDictionary * request = OSDynamicCast(OSDictionary,
14314 sRequestCallbackRecords->getObject(i));
14315
14316 if (!request) {
14317 continue;
14318 }
14319 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14320 _OSKextGetRequestArgument(request,
14321 kKextRequestArgumentCallbackKey));
14322
14323 if (!callbackWrapper) {
14324 continue;
14325 }
14326
14327 vm_address_t callbackAddress = (vm_address_t)
14328 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14329
14330 if ((kmod_info->address <= callbackAddress) &&
14331 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14332 result++;
14333 }
14334 } while (i--);
14335
14336 finish:
14337 return result;
14338 }
14339
14340 /*********************************************************************
14341 *********************************************************************/
14342 static OSReturn
14343 _OSKextCreateRequest(
14344 const char * predicate,
14345 OSSharedPtr<OSDictionary> & requestR)
14346 {
14347 OSReturn result = kOSKextReturnNoMemory;
14348 OSSharedPtr<OSDictionary> request;
14349
14350 request = OSDictionary::withCapacity(2);
14351 if (!request) {
14352 goto finish;
14353 }
14354 result = _OSDictionarySetCStringValue(request.get(),
14355 kKextRequestPredicateKey, predicate);
14356 if (result != kOSReturnSuccess) {
14357 goto finish;
14358 }
14359 result = kOSReturnSuccess;
14360
14361 finish:
14362 if (result == kOSReturnSuccess) {
14363 requestR = os::move(request);
14364 }
14365
14366 return result;
14367 }
14368
14369 /*********************************************************************
14370 *********************************************************************/
14371 static OSString *
14372 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14373 {
14374 return OSDynamicCast(OSString,
14375 requestDict->getObject(kKextRequestPredicateKey));
14376 }
14377
14378 /*********************************************************************
14379 *********************************************************************/
14380 static OSObject *
14381 _OSKextGetRequestArgument(
14382 OSDictionary * requestDict,
14383 const char * argName)
14384 {
14385 OSDictionary * args = OSDynamicCast(OSDictionary,
14386 requestDict->getObject(kKextRequestArgumentsKey));
14387 if (args) {
14388 return args->getObject(argName);
14389 }
14390 return NULL;
14391 }
14392
14393 /*********************************************************************
14394 *********************************************************************/
14395 static bool
14396 _OSKextSetRequestArgument(
14397 OSDictionary * requestDict,
14398 const char * argName,
14399 OSMetaClassBase * value)
14400 {
14401 OSDictionary * args = OSDynamicCast(OSDictionary,
14402 requestDict->getObject(kKextRequestArgumentsKey));
14403 OSSharedPtr<OSDictionary> newArgs;
14404 if (!args) {
14405 newArgs = OSDictionary::withCapacity(2);
14406 args = newArgs.get();
14407 if (!args) {
14408 goto finish;
14409 }
14410 requestDict->setObject(kKextRequestArgumentsKey, args);
14411 }
14412 if (args) {
14413 return args->setObject(argName, value);
14414 }
14415 finish:
14416 return false;
14417 }
14418
14419 /*********************************************************************
14420 *********************************************************************/
14421 template <typename T>
14422 static T *
14423 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14424 {
14425 if (!wrapper) {
14426 return nullptr;
14427 }
14428 return wrapper->getRef();
14429 }
14430
14431 /*********************************************************************
14432 *********************************************************************/
14433 static OSKextRequestResourceCallback
14434 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14435 {
14436 if (!wrapper) {
14437 return nullptr;
14438 }
14439 return wrapper->getRef();
14440 }
14441
14442
14443 /*********************************************************************
14444 *********************************************************************/
14445 static OSReturn
14446 _OSDictionarySetCStringValue(
14447 OSDictionary * dict,
14448 const char * cKey,
14449 const char * cValue)
14450 {
14451 OSReturn result = kOSKextReturnNoMemory;
14452 OSSharedPtr<const OSSymbol> key;
14453 OSSharedPtr<OSString> value;
14454
14455 key = OSSymbol::withCString(cKey);
14456 value = OSString::withCString(cValue);
14457 if (!key || !value) {
14458 goto finish;
14459 }
14460 if (dict->setObject(key.get(), value.get())) {
14461 result = kOSReturnSuccess;
14462 }
14463
14464 finish:
14465 return result;
14466 }
14467
14468 /*********************************************************************
14469 *********************************************************************/
14470 static bool
14471 _OSArrayContainsCString(
14472 OSArray * array,
14473 const char * cString)
14474 {
14475 bool result = false;
14476 OSSharedPtr<const OSSymbol> symbol;
14477 uint32_t count, i;
14478
14479 if (!array || !cString) {
14480 goto finish;
14481 }
14482
14483 symbol = OSSymbol::withCStringNoCopy(cString);
14484 if (!symbol) {
14485 goto finish;
14486 }
14487
14488 count = array->getCount();
14489 for (i = 0; i < count; i++) {
14490 OSObject * thisObject = array->getObject(i);
14491 if (symbol->isEqualTo(thisObject)) {
14492 result = true;
14493 goto finish;
14494 }
14495 }
14496
14497 finish:
14498 return result;
14499 }
14500
14501 #if CONFIG_KXLD
14502 /*********************************************************************
14503 * We really only care about boot / system start up related kexts.
14504 * We return true if we're less than REBUILD_MAX_TIME since start up,
14505 * otherwise return false.
14506 *********************************************************************/
14507 bool
14508 _OSKextInPrelinkRebuildWindow(void)
14509 {
14510 static bool outside_the_window = false;
14511 AbsoluteTime my_abstime;
14512 UInt64 my_ns;
14513 SInt32 my_secs;
14514
14515 if (outside_the_window) {
14516 return false;
14517 }
14518 clock_get_uptime(&my_abstime);
14519 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14520 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14521 if (my_secs > REBUILD_MAX_TIME) {
14522 outside_the_window = true;
14523 return false;
14524 }
14525 return true;
14526 }
14527 #endif /* CONFIG_KXLD */
14528
14529 /*********************************************************************
14530 *********************************************************************/
14531 bool
14532 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14533 {
14534 int unLoadedCount, i;
14535 bool result = false;
14536
14537 IORecursiveLockLock(sKextLock);
14538
14539 if (sUnloadedPrelinkedKexts == NULL) {
14540 goto finish;
14541 }
14542 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14543 if (unLoadedCount == 0) {
14544 goto finish;
14545 }
14546
14547 for (i = 0; i < unLoadedCount; i++) {
14548 const OSSymbol * myBundleID; // do not release
14549
14550 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14551 if (!myBundleID) {
14552 continue;
14553 }
14554 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14555 result = true;
14556 break;
14557 }
14558 }
14559 finish:
14560 IORecursiveLockUnlock(sKextLock);
14561 return result;
14562 }
14563
14564 #if PRAGMA_MARK
14565 #pragma mark Personalities (IOKit Drivers)
14566 #endif
14567 /*********************************************************************
14568 *********************************************************************/
14569 /* static */
14570 OSSharedPtr<OSArray>
14571 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14572 {
14573 OSSharedPtr<OSArray> result;
14574 OSSharedPtr<OSCollectionIterator> kextIterator;
14575 OSSharedPtr<OSArray> personalities;
14576
14577 OSString * kextID = NULL; // do not release
14578 OSKext * theKext = NULL; // do not release
14579
14580 IORecursiveLockLock(sKextLock);
14581
14582 /* Let's conservatively guess that any given kext has around 3
14583 * personalities for now.
14584 */
14585 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14586 if (!result) {
14587 goto finish;
14588 }
14589
14590 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14591 if (!kextIterator) {
14592 goto finish;
14593 }
14594
14595 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14596 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14597 if (theKext->flags.requireExplicitLoad) {
14598 OSKextLog(theKext,
14599 kOSKextLogDebugLevel |
14600 kOSKextLogLoadFlag,
14601 "Kext %s requires an explicit kextload; "
14602 "omitting its personalities.",
14603 theKext->getIdentifierCString());
14604 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14605 personalities = theKext->copyPersonalitiesArray();
14606 if (!personalities) {
14607 continue;
14608 }
14609 result->merge(personalities.get());
14610 } else {
14611 // xxx - check for better place to put this log msg
14612 OSKextLog(theKext,
14613 kOSKextLogWarningLevel |
14614 kOSKextLogLoadFlag,
14615 "Kext %s is not loadable during safe boot; "
14616 "omitting its personalities.",
14617 theKext->getIdentifierCString());
14618 }
14619 }
14620
14621 finish:
14622 IORecursiveLockUnlock(sKextLock);
14623
14624 return result;
14625 }
14626
14627 /*********************************************************************
14628 *********************************************************************/
14629 /* static */
14630 void
14631 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14632 {
14633 int numPersonalities = 0;
14634
14635 OSKextLog(/* kext */ NULL,
14636 kOSKextLogStepLevel |
14637 kOSKextLogLoadFlag,
14638 "Sending all eligible registered kexts' personalities "
14639 "to the IOCatalogue %s.",
14640 startMatching ? "and starting matching" : "but not starting matching");
14641
14642 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14643 /* filterSafeBootFlag */ true);
14644
14645 if (personalities) {
14646 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14647 numPersonalities = personalities->getCount();
14648 }
14649
14650 OSKextLog(/* kext */ NULL,
14651 kOSKextLogStepLevel |
14652 kOSKextLogLoadFlag,
14653 "%d kext personalit%s sent to the IOCatalogue; %s.",
14654 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14655 startMatching ? "matching started" : "matching not started");
14656 return;
14657 }
14658
14659 /*********************************************************************
14660 * Do not make a deep copy, just convert the IOKitPersonalities dict
14661 * to an array for sending to the IOCatalogue.
14662 *********************************************************************/
14663 OSSharedPtr<OSArray>
14664 OSKext::copyPersonalitiesArray(void)
14665 {
14666 OSSharedPtr<OSArray> result;
14667 OSDictionary * personalities = NULL; // do not release
14668 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14669
14670 OSString * personalityName = NULL; // do not release
14671 OSString * personalityBundleIdentifier = NULL; // do not release
14672
14673 personalities = OSDynamicCast(OSDictionary,
14674 getPropertyForHostArch(kIOKitPersonalitiesKey));
14675 if (!personalities) {
14676 goto finish;
14677 }
14678
14679 result = OSArray::withCapacity(personalities->getCount());
14680 if (!result) {
14681 goto finish;
14682 }
14683
14684 personalitiesIterator =
14685 OSCollectionIterator::withCollection(personalities);
14686 if (!personalitiesIterator) {
14687 goto finish;
14688 }
14689 while ((personalityName = OSDynamicCast(OSString,
14690 personalitiesIterator->getNextObject()))) {
14691 OSDictionary * personality = OSDynamicCast(OSDictionary,
14692 personalities->getObject(personalityName));
14693
14694 if (personality) {
14695 /******
14696 * If the personality doesn't have a CFBundleIdentifier, or if it
14697 * differs from the kext's, insert the kext's ID so we can find it.
14698 * The publisher ID is used to remove personalities from bundles
14699 * correctly.
14700 */
14701 personalityBundleIdentifier = OSDynamicCast(OSString,
14702 personality->getObject(kCFBundleIdentifierKey));
14703
14704 if (!personalityBundleIdentifier) {
14705 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
14706 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
14707 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
14708 }
14709 }
14710
14711 result->setObject(personality);
14712 }
14713
14714 finish:
14715 return result;
14716 }
14717
14718 /*********************************************************************
14719 * Might want to change this to a bool return?
14720 *********************************************************************/
14721 OSReturn
14722 OSKext::sendPersonalitiesToCatalog(
14723 bool startMatching,
14724 OSArray * personalityNames)
14725 {
14726 OSReturn result = kOSReturnSuccess;
14727 OSSharedPtr<OSArray> personalitiesToSend;
14728 OSDictionary * kextPersonalities = NULL; // do not release
14729 int count, i;
14730
14731 if (!sLoadEnabled) {
14732 OSKextLog(this,
14733 kOSKextLogErrorLevel |
14734 kOSKextLogLoadFlag,
14735 "Kext loading is disabled (attempt to start matching for kext %s).",
14736 getIdentifierCString());
14737 result = kOSKextReturnDisabled;
14738 goto finish;
14739 }
14740
14741 if (sSafeBoot && !isLoadableInSafeBoot()) {
14742 OSKextLog(this,
14743 kOSKextLogErrorLevel |
14744 kOSKextLogLoadFlag,
14745 "Kext %s is not loadable during safe boot; "
14746 "not sending personalities to the IOCatalogue.",
14747 getIdentifierCString());
14748 result = kOSKextReturnNotLoadable;
14749 goto finish;
14750 }
14751
14752 if (!personalityNames || !personalityNames->getCount()) {
14753 personalitiesToSend = copyPersonalitiesArray();
14754 } else {
14755 kextPersonalities = OSDynamicCast(OSDictionary,
14756 getPropertyForHostArch(kIOKitPersonalitiesKey));
14757 if (!kextPersonalities || !kextPersonalities->getCount()) {
14758 // not an error
14759 goto finish;
14760 }
14761 personalitiesToSend = OSArray::withCapacity(0);
14762 if (!personalitiesToSend) {
14763 result = kOSKextReturnNoMemory;
14764 goto finish;
14765 }
14766 count = personalityNames->getCount();
14767 for (i = 0; i < count; i++) {
14768 OSString * name = OSDynamicCast(OSString,
14769 personalityNames->getObject(i));
14770 if (!name) {
14771 continue;
14772 }
14773 OSDictionary * personality = OSDynamicCast(OSDictionary,
14774 kextPersonalities->getObject(name));
14775 if (personality) {
14776 personalitiesToSend->setObject(personality);
14777 }
14778 }
14779 }
14780 if (personalitiesToSend) {
14781 unsigned numPersonalities = personalitiesToSend->getCount();
14782 OSKextLog(this,
14783 kOSKextLogStepLevel |
14784 kOSKextLogLoadFlag,
14785 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
14786 getIdentifierCString(),
14787 numPersonalities,
14788 numPersonalities > 1 ? "ies" : "y",
14789 startMatching ? " and starting matching" : " but not starting matching");
14790 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
14791 }
14792 finish:
14793 return result;
14794 }
14795
14796 /*********************************************************************
14797 * xxx - We should allow removing the kext's declared personalities,
14798 * xxx - even with other bundle identifiers.
14799 *********************************************************************/
14800 void
14801 OSKext::removePersonalitiesFromCatalog(void)
14802 {
14803 OSSharedPtr<OSDictionary> personality;
14804
14805 personality = OSDictionary::withCapacity(1);
14806 if (!personality) {
14807 goto finish;
14808 }
14809 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
14810
14811 OSKextLog(this,
14812 kOSKextLogStepLevel |
14813 kOSKextLogLoadFlag,
14814 "Kext %s removing all personalities naming it from the IOCatalogue.",
14815 getIdentifierCString());
14816
14817 /* Have the IOCatalog remove all personalities matching this kext's
14818 * bundle ID and trigger matching anew.
14819 */
14820 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
14821
14822 finish:
14823 return;
14824 }
14825
14826 void
14827 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
14828 {
14829 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
14830 return;
14831 }
14832
14833 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
14834 if (!personalityToRemove) {
14835 return;
14836 }
14837
14838 /*
14839 * Create a personality dictionary with just the bundleID.
14840 * We will remove any personality that has a matching bundleID,
14841 * irrespective of which other keys are present on the dictionary.
14842 */
14843 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
14844 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
14845 }
14846
14847 #if PRAGMA_MARK
14848 #pragma mark Logging
14849 #endif
14850 /*********************************************************************
14851 * Do not call any function that takes sKextLock here!
14852 *********************************************************************/
14853 /* static */
14854 OSKextLogSpec
14855 OSKext::setUserSpaceLogFilter(
14856 OSKextLogSpec newUserLogFilter,
14857 bool captureFlag)
14858 {
14859 OSKextLogSpec result;
14860 bool allocError = false;
14861
14862 /* Do not call any function that takes sKextLoggingLock during
14863 * this critical block. That means do logging after.
14864 */
14865 IOLockLock(sKextLoggingLock);
14866
14867 result = sUserSpaceKextLogFilter;
14868 sUserSpaceKextLogFilter = newUserLogFilter;
14869
14870 if (newUserLogFilter && captureFlag &&
14871 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
14872 // xxx - do some measurements for a good initial capacity?
14873 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
14874 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
14875
14876 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
14877 allocError = true;
14878 }
14879 }
14880
14881 IOLockUnlock(sKextLoggingLock);
14882
14883 /* If the config flag itself is changing, log the state change
14884 * going both ways, before setting up the user-space log arrays,
14885 * so that this is only logged in the kernel.
14886 */
14887 if (result != newUserLogFilter) {
14888 OSKextLog(/* kext */ NULL,
14889 kOSKextLogDebugLevel |
14890 kOSKextLogGeneralFlag,
14891 "User-space log flags changed from 0x%x to 0x%x.",
14892 result, newUserLogFilter);
14893 }
14894 if (allocError) {
14895 OSKextLog(/* kext */ NULL,
14896 kOSKextLogErrorLevel |
14897 kOSKextLogGeneralFlag,
14898 "Failed to allocate user-space log message arrays.");
14899 }
14900
14901 return result;
14902 }
14903
14904 /*********************************************************************
14905 * Do not call any function that takes sKextLock here!
14906 *********************************************************************/
14907 /* static */
14908 OSSharedPtr<OSArray>
14909 OSKext::clearUserSpaceLogFilter(void)
14910 {
14911 OSSharedPtr<OSArray> result;
14912 OSKextLogSpec oldLogFilter;
14913 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
14914
14915 /* Do not call any function that takes sKextLoggingLock during
14916 * this critical block. That means do logging after.
14917 */
14918 IOLockLock(sKextLoggingLock);
14919
14920 result = OSArray::withCapacity(2);
14921 if (result) {
14922 result->setObject(sUserSpaceLogSpecArray.get());
14923 result->setObject(sUserSpaceLogMessageArray.get());
14924 }
14925 sUserSpaceLogSpecArray.reset();
14926 sUserSpaceLogMessageArray.reset();
14927
14928 oldLogFilter = sUserSpaceKextLogFilter;
14929 sUserSpaceKextLogFilter = newLogFilter;
14930
14931 IOLockUnlock(sKextLoggingLock);
14932
14933 /* If the config flag itself is changing, log the state change
14934 * going both ways, after tearing down the user-space log
14935 * arrays, so this is only logged within the kernel.
14936 */
14937 if (oldLogFilter != newLogFilter) {
14938 OSKextLog(/* kext */ NULL,
14939 kOSKextLogDebugLevel |
14940 kOSKextLogGeneralFlag,
14941 "User-space log flags changed from 0x%x to 0x%x.",
14942 oldLogFilter, newLogFilter);
14943 }
14944
14945 return result;
14946 }
14947
14948
14949 /*********************************************************************
14950 * Do not call any function that takes sKextLock here!
14951 *********************************************************************/
14952 /* static */
14953 OSKextLogSpec
14954 OSKext::getUserSpaceLogFilter(void)
14955 {
14956 OSKextLogSpec result;
14957
14958 IOLockLock(sKextLoggingLock);
14959 result = sUserSpaceKextLogFilter;
14960 IOLockUnlock(sKextLoggingLock);
14961
14962 return result;
14963 }
14964
14965 /*********************************************************************
14966 * This function is called by OSMetaClass during kernel C++ setup.
14967 * Be careful what you access here; assume only OSKext::initialize()
14968 * has been called.
14969 *
14970 * Do not call any function that takes sKextLock here!
14971 *********************************************************************/
14972 #define VTRESET "\033[0m"
14973
14974 #define VTBOLD "\033[1m"
14975 #define VTUNDER "\033[4m"
14976
14977 #define VTRED "\033[31m"
14978 #define VTGREEN "\033[32m"
14979 #define VTYELLOW "\033[33m"
14980 #define VTBLUE "\033[34m"
14981 #define VTMAGENTA "\033[35m"
14982 #define VTCYAN "\033[36m"
14983
14984 inline const char *
14985 colorForFlags(OSKextLogSpec flags)
14986 {
14987 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
14988
14989 switch (logLevel) {
14990 case kOSKextLogErrorLevel:
14991 return VTRED VTBOLD;
14992 case kOSKextLogWarningLevel:
14993 return VTRED;
14994 case kOSKextLogBasicLevel:
14995 return VTYELLOW VTUNDER;
14996 case kOSKextLogProgressLevel:
14997 return VTYELLOW;
14998 case kOSKextLogStepLevel:
14999 return VTGREEN;
15000 case kOSKextLogDetailLevel:
15001 return VTCYAN;
15002 case kOSKextLogDebugLevel:
15003 return VTMAGENTA;
15004 default:
15005 return ""; // white
15006 }
15007 }
15008
15009 inline bool
15010 logSpecMatch(
15011 OSKextLogSpec msgLogSpec,
15012 OSKextLogSpec logFilter)
15013 {
15014 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15015 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15016 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15017
15018 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15019 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15020 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15021
15022 /* Explicit messages always get logged.
15023 */
15024 if (msgLevel == kOSKextLogExplicitLevel) {
15025 return true;
15026 }
15027
15028 /* Warnings and errors are logged regardless of the flags.
15029 */
15030 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15031 return true;
15032 }
15033
15034 /* A verbose message that isn't for a logging-enabled kext and isn't global
15035 * does *not* get logged.
15036 */
15037 if (!msgKextGlobal && !filterKextGlobal) {
15038 return false;
15039 }
15040
15041 /* Warnings and errors are logged regardless of the flags.
15042 * All other messages must fit the flags and
15043 * have a level at or below the filter.
15044 *
15045 */
15046 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15047 return true;
15048 }
15049 return false;
15050 }
15051
15052 extern "C" {
15053 void
15054 OSKextLog(
15055 OSKext * aKext,
15056 OSKextLogSpec msgLogSpec,
15057 const char * format, ...)
15058 {
15059 va_list argList;
15060
15061 va_start(argList, format);
15062 OSKextVLog(aKext, msgLogSpec, format, argList);
15063 va_end(argList);
15064 }
15065
15066 void
15067 OSKextVLog(
15068 OSKext * aKext,
15069 OSKextLogSpec msgLogSpec,
15070 const char * format,
15071 va_list srcArgList)
15072 {
15073 extern int disableConsoleOutput;
15074
15075 bool logForKernel = false;
15076 bool logForUser = false;
15077 va_list argList;
15078 char stackBuffer[120];
15079 uint32_t length = 0;
15080 char * allocBuffer = NULL; // must kfree
15081 OSSharedPtr<OSNumber> logSpecNum;
15082 OSSharedPtr<OSString> logString;
15083 char * buffer = stackBuffer; // do not free
15084
15085 IOLockLock(sKextLoggingLock);
15086
15087 /* Set the kext/global bit in the message spec if we have no
15088 * kext or if the kext requests logging.
15089 */
15090 if (!aKext || aKext->flags.loggingEnabled) {
15091 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15092 }
15093
15094 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15095 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15096 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15097 }
15098
15099 if (!(logForKernel || logForUser)) {
15100 goto finish;
15101 }
15102
15103 /* No goto from here until past va_end()!
15104 */
15105 va_copy(argList, srcArgList);
15106 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15107 va_end(argList);
15108
15109 if (length + 1 >= sizeof(stackBuffer)) {
15110 allocBuffer = (char *)kalloc_data_tag(length + 1,
15111 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15112 if (!allocBuffer) {
15113 goto finish;
15114 }
15115
15116 /* No goto from here until past va_end()!
15117 */
15118 va_copy(argList, srcArgList);
15119 vsnprintf(allocBuffer, length + 1, format, argList);
15120 va_end(argList);
15121
15122 buffer = allocBuffer;
15123 }
15124
15125 /* If user space wants the log message, queue it up.
15126 */
15127 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15128 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15129 logString = OSString::withCString(buffer);
15130 if (logSpecNum && logString) {
15131 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15132 sUserSpaceLogMessageArray->setObject(logString.get());
15133 }
15134 }
15135
15136 /* Always log messages from the kernel according to the kernel's
15137 * log flags.
15138 */
15139 if (logForKernel) {
15140 /* If we are in console mode and have a custom log filter,
15141 * colorize the log message.
15142 */
15143 if (!disableConsoleOutput && sBootArgLogFilterFound) {
15144 const char * color = ""; // do not free
15145 color = colorForFlags(msgLogSpec);
15146 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15147 buffer, color[0] ? VTRESET : "");
15148 } else {
15149 printf("%s\n", buffer);
15150 }
15151 }
15152
15153 finish:
15154 IOLockUnlock(sKextLoggingLock);
15155
15156 if (allocBuffer) {
15157 kfree_data(allocBuffer, length + 1);
15158 }
15159 return;
15160 }
15161
15162 #if KASLR_IOREG_DEBUG
15163
15164 #define IOLOG_INDENT( the_indention ) \
15165 { \
15166 int i; \
15167 for ( i = 0; i < (the_indention); i++ ) { \
15168 IOLog(" "); \
15169 } \
15170 }
15171
15172 extern vm_offset_t vm_kernel_stext;
15173 extern vm_offset_t vm_kernel_etext;
15174 extern mach_vm_offset_t kext_alloc_base;
15175 extern mach_vm_offset_t kext_alloc_max;
15176
15177 bool ScanForAddrInObject(OSObject * theObject,
15178 int indent );
15179
15180 bool
15181 ScanForAddrInObject(OSObject * theObject,
15182 int indent)
15183 {
15184 const OSMetaClass * myTypeID;
15185 OSSharedPtr<OSCollectionIterator> myIter;
15186 OSSymbol * myKey;
15187 OSObject * myValue;
15188 bool myResult = false;
15189
15190 if (theObject == NULL) {
15191 IOLog("%s: theObject is NULL \n",
15192 __FUNCTION__);
15193 return myResult;
15194 }
15195
15196 myTypeID = OSTypeIDInst(theObject);
15197
15198 if (myTypeID == OSTypeID(OSDictionary)) {
15199 OSDictionary * myDictionary;
15200
15201 myDictionary = OSDynamicCast(OSDictionary, theObject);
15202 myIter = OSCollectionIterator::withCollection( myDictionary );
15203 if (myIter == NULL) {
15204 return myResult;
15205 }
15206
15207 // !! reset the iterator
15208 myIter->reset();
15209
15210 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15211 bool myTempResult;
15212
15213 myValue = myDictionary->getObject(myKey);
15214 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15215 if (myTempResult) {
15216 // if we ever get a true result return true
15217 myResult = true;
15218 IOLOG_INDENT(indent);
15219 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15220 }
15221 }
15222
15223 // !! release the iterator
15224 myIter.reset();
15225 } else if (myTypeID == OSTypeID(OSArray)) {
15226 OSArray * myArray;
15227
15228 myArray = OSDynamicCast(OSArray, theObject);
15229 myIter = OSCollectionIterator::withCollection(myArray);
15230 if (myIter == NULL) {
15231 return myResult;
15232 }
15233 // !! reset the iterator
15234 myIter->reset();
15235
15236 while ((myValue = myIter->getNextObject())) {
15237 bool myTempResult;
15238 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15239 if (myTempResult) {
15240 // if we ever get a true result return true
15241 myResult = true;
15242 IOLOG_INDENT(indent);
15243 IOLog("OSArray: \n");
15244 }
15245 }
15246 // !! release the iterator
15247 myIter.reset();
15248 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15249 // should we look for addresses in strings?
15250 } else if (myTypeID == OSTypeID(OSData)) {
15251 void * * myPtrPtr;
15252 unsigned int myLen;
15253 OSData * myDataObj;
15254
15255 myDataObj = OSDynamicCast(OSData, theObject);
15256 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15257 myLen = myDataObj->getLength();
15258
15259 if (myPtrPtr && myLen && myLen > 7) {
15260 int i;
15261 int myPtrCount = (myLen / sizeof(void *));
15262
15263 for (i = 0; i < myPtrCount; i++) {
15264 UInt64 numberValue = (UInt64) * (myPtrPtr);
15265
15266 if (kext_alloc_max != 0 &&
15267 numberValue >= kext_alloc_base &&
15268 numberValue < kext_alloc_max) {
15269 OSSharedPtr<OSKext> myKext;
15270 // IOLog("found OSData %p in kext map %p to %p \n",
15271 // *(myPtrPtr),
15272 // (void *) kext_alloc_base,
15273 // (void *) kext_alloc_max);
15274
15275 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15276 if (myKext) {
15277 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15278 *(myPtrPtr),
15279 myKext->getIdentifierCString());
15280 }
15281 myResult = true;
15282 }
15283 if (vm_kernel_etext != 0 &&
15284 numberValue >= vm_kernel_stext &&
15285 numberValue < vm_kernel_etext) {
15286 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15287 *(myPtrPtr),
15288 (void *) vm_kernel_stext,
15289 (void *) vm_kernel_etext);
15290 myResult = true;
15291 }
15292 myPtrPtr++;
15293 }
15294 }
15295 } else if (myTypeID == OSTypeID(OSBoolean)) {
15296 // do nothing here...
15297 } else if (myTypeID == OSTypeID(OSNumber)) {
15298 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15299
15300 UInt64 numberValue = number->unsigned64BitValue();
15301
15302 if (kext_alloc_max != 0 &&
15303 numberValue >= kext_alloc_base &&
15304 numberValue < kext_alloc_max) {
15305 OSSharedPtr<OSKext> myKext;
15306 IOLog("found OSNumber in kext map %p to %p \n",
15307 (void *) kext_alloc_base,
15308 (void *) kext_alloc_max);
15309 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15310
15311 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15312 if (myKext) {
15313 IOLog("found in kext \"%s\" \n",
15314 myKext->getIdentifierCString());
15315 }
15316
15317 myResult = true;
15318 }
15319 if (vm_kernel_etext != 0 &&
15320 numberValue >= vm_kernel_stext &&
15321 numberValue < vm_kernel_etext) {
15322 IOLog("found OSNumber in kernel text segment %p to %p \n",
15323 (void *) vm_kernel_stext,
15324 (void *) vm_kernel_etext);
15325 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15326 myResult = true;
15327 }
15328 }
15329 #if 0
15330 else {
15331 const OSMetaClass* myMetaClass = NULL;
15332
15333 myMetaClass = theObject->getMetaClass();
15334 if (myMetaClass) {
15335 IOLog("class %s \n", myMetaClass->getClassName());
15336 } else {
15337 IOLog("Unknown object \n" );
15338 }
15339 }
15340 #endif
15341
15342 return myResult;
15343 }
15344 #endif // KASLR_KEXT_DEBUG
15345 }; /* extern "C" */
15346
15347 #if PRAGMA_MARK
15348 #pragma mark Backtrace Dump & kmod_get_info() support
15349 #endif
15350 /*********************************************************************
15351 * This function must be safe to call in panic context.
15352 *********************************************************************/
15353 /* static */
15354 void
15355 OSKext::printKextsInBacktrace(
15356 vm_offset_t * addr __unused,
15357 unsigned int cnt __unused,
15358 int (* printf_func)(const char *fmt, ...) __unused,
15359 uint32_t flags __unused)
15360 {
15361 addr64_t summary_page = 0;
15362 addr64_t last_summary_page = 0;
15363 bool found_kmod = false;
15364 u_int i = 0;
15365
15366 if (kPrintKextsLock & flags) {
15367 if (!sKextSummariesLock) {
15368 return;
15369 }
15370 IOLockLock(sKextSummariesLock);
15371 }
15372
15373 if (!gLoadedKextSummaries) {
15374 (*printf_func)(" can't perform kext scan: no kext summary");
15375 goto finish;
15376 }
15377
15378 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15379 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15380 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15381 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15382 (*printf_func)(" can't perform kext scan: "
15383 "missing kext summary page %p", summary_page);
15384 goto finish;
15385 }
15386 }
15387
15388 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15389 OSKextLoadedKextSummary * summary;
15390
15391 summary = gLoadedKextSummaries->summaries + i;
15392 if (!summary->address) {
15393 continue;
15394 }
15395
15396 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15397 continue;
15398 }
15399
15400 if (!found_kmod) {
15401 if (!(kPrintKextsTerse & flags)) {
15402 (*printf_func)(" Kernel Extensions in backtrace:\n");
15403 }
15404 found_kmod = true;
15405 }
15406
15407 printSummary(summary, printf_func, flags);
15408 }
15409
15410 finish:
15411 if (kPrintKextsLock & flags) {
15412 IOLockUnlock(sKextSummariesLock);
15413 }
15414
15415 return;
15416 }
15417
15418 /*********************************************************************
15419 * This function must be safe to call in panic context.
15420 *********************************************************************/
15421 /* static */
15422 boolean_t
15423 OSKext::summaryIsInBacktrace(
15424 OSKextLoadedKextSummary * summary,
15425 vm_offset_t * addr,
15426 unsigned int cnt)
15427 {
15428 u_int i = 0;
15429
15430 for (i = 0; i < cnt; i++) {
15431 vm_offset_t kscan_addr = addr[i];
15432 #if __has_feature(ptrauth_calls)
15433 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15434 #endif /* __has_feature(ptrauth_calls) */
15435 if ((kscan_addr >= summary->text_exec_address) &&
15436 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15437 return TRUE;
15438 }
15439 }
15440
15441 return FALSE;
15442 }
15443
15444 /*
15445 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15446 * sKextSummariesLock held.
15447 */
15448 OSKextLoadedKextSummary *
15449 OSKext::summaryForAddress(uintptr_t addr)
15450 {
15451 #if __has_feature(ptrauth_calls)
15452 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15453 #endif /* __has_feature(ptrauth_calls) */
15454 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15455 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15456 if (!summary->address) {
15457 continue;
15458 }
15459
15460 #if VM_MAPPED_KEXTS
15461 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15462 * support split kexts, but we also may unmap the kexts, which can
15463 * race with the above codepath (see OSKext::unload). As such,
15464 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15465 */
15466 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15467 return summary;
15468 }
15469 #else
15470 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15471 kernel_segment_command_t *seg;
15472
15473 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15474 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15475 return summary;
15476 }
15477 }
15478 #endif
15479 }
15480
15481 /* addr did not map to any kext */
15482 return NULL;
15483 }
15484
15485 /* static */
15486 void *
15487 OSKext::kextForAddress(const void *address)
15488 {
15489 void * image = NULL;
15490 OSKextActiveAccount * active;
15491 OSKext * kext = NULL;
15492 uint32_t baseIdx;
15493 uint32_t lim;
15494 uintptr_t addr = (uintptr_t) address;
15495 size_t i;
15496
15497 if (!addr) {
15498 return NULL;
15499 }
15500 #if __has_feature(ptrauth_calls)
15501 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15502 #endif /* __has_feature(ptrauth_calls) */
15503
15504 if (sKextAccountsCount) {
15505 lck_ticket_lock(sKextAccountsLock, LCK_GRP_NULL);
15506 // bsearch sKextAccounts list
15507 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15508 active = &sKextAccounts[baseIdx + (lim >> 1)];
15509 if ((addr >= active->address) && (addr < active->address_end)) {
15510 kext = active->account->kext;
15511 if (kext && kext->kmod_info) {
15512 image = (void *) kext->kmod_info->address;
15513 }
15514 break;
15515 } else if (addr > active->address) {
15516 // move right
15517 baseIdx += (lim >> 1) + 1;
15518 lim--;
15519 }
15520 // else move left
15521 }
15522 lck_ticket_unlock(sKextAccountsLock);
15523 }
15524 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
15525 image = (void *) &_mh_execute_header;
15526 }
15527 if (!image && gLoadedKextSummaries) {
15528 IOLockLock(sKextSummariesLock);
15529 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15530 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15531 if (addr >= summary->address && addr < summary->address + summary->size) {
15532 image = (void *)summary->address;
15533 }
15534 }
15535 IOLockUnlock(sKextSummariesLock);
15536 }
15537
15538 return image;
15539 }
15540
15541 /*
15542 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15543 * Safe to call in panic context.
15544 */
15545 static OSKextLoadedKextSummary *
15546 findSummary(uint32_t tagID)
15547 {
15548 OSKextLoadedKextSummary * summary;
15549 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15550 summary = gLoadedKextSummaries->summaries + i;
15551 if (summary->loadTag == tagID) {
15552 return summary;
15553 }
15554 }
15555 return NULL;
15556 }
15557
15558 /*********************************************************************
15559 * This function must be safe to call in panic context.
15560 *********************************************************************/
15561 void
15562 OSKext::printSummary(
15563 OSKextLoadedKextSummary * summary,
15564 int (* printf_func)(const char *fmt, ...),
15565 uint32_t flags)
15566 {
15567 kmod_reference_t * kmod_ref = NULL;
15568 uuid_string_t uuid;
15569 char version[kOSKextVersionMaxLength];
15570 uint64_t tmpAddr;
15571 uint64_t tmpSize;
15572 OSKextLoadedKextSummary *dependencySummary;
15573
15574 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15575 strlcpy(version, "unknown version", sizeof(version));
15576 }
15577 (void) uuid_unparse(summary->uuid, uuid);
15578
15579 #if defined(__arm__) || defined(__arm64__)
15580 tmpAddr = summary->text_exec_address;
15581 tmpSize = summary->text_exec_size;
15582 #else
15583 tmpAddr = summary->address;
15584 tmpSize = summary->size;
15585 #endif
15586 if (kPrintKextsUnslide & flags) {
15587 tmpAddr = ml_static_unslide(tmpAddr);
15588 }
15589 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15590 (kPrintKextsTerse & flags) ? "" : " ",
15591 summary->name, version, uuid,
15592 tmpAddr, tmpAddr + tmpSize - 1);
15593
15594 if (kPrintKextsTerse & flags) {
15595 return;
15596 }
15597
15598 /* print dependency info */
15599 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15600 kmod_ref;
15601 kmod_ref = kmod_ref->next) {
15602 kmod_info_t * rinfo;
15603
15604 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15605 (*printf_func)(" kmod dependency scan stopped "
15606 "due to missing dependency page: %p\n",
15607 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15608 break;
15609 }
15610 rinfo = kmod_ref->info;
15611
15612 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15613 (*printf_func)(" kmod dependency scan stopped "
15614 "due to missing kmod page: %p\n",
15615 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15616 break;
15617 }
15618
15619 if (!rinfo->address) {
15620 continue; // skip fake entries for built-ins
15621 }
15622
15623 dependencySummary = findSummary(rinfo->id);
15624 uuid[0] = 0x00;
15625 tmpAddr = rinfo->address;
15626 tmpSize = rinfo->size;
15627 if (dependencySummary) {
15628 (void) uuid_unparse(dependencySummary->uuid, uuid);
15629 #if defined(__arm__) || defined(__arm64__)
15630 tmpAddr = dependencySummary->text_exec_address;
15631 tmpSize = dependencySummary->text_exec_size;
15632 #endif
15633 }
15634
15635 if (kPrintKextsUnslide & flags) {
15636 tmpAddr = ml_static_unslide(tmpAddr);
15637 }
15638 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15639 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15640 }
15641 return;
15642 }
15643
15644
15645 #if !defined(__arm__) && !defined(__arm64__)
15646 /*******************************************************************************
15647 * substitute() looks at an input string (a pointer within a larger buffer)
15648 * for a match to a substring, and on match it writes the marker & substitution
15649 * character to an output string, updating the scan (from) and
15650 * output (to) indexes as appropriate.
15651 *******************************************************************************/
15652 static int substitute(
15653 const char * scan_string,
15654 char * string_out,
15655 uint32_t * to_index,
15656 uint32_t * from_index,
15657 const char * substring,
15658 char marker,
15659 char substitution);
15660
15661 /* string_out must be at least KMOD_MAX_NAME bytes.
15662 */
15663 static int
15664 substitute(
15665 const char * scan_string,
15666 char * string_out,
15667 uint32_t * to_index,
15668 uint32_t * from_index,
15669 const char * substring,
15670 char marker,
15671 char substitution)
15672 {
15673 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
15674
15675 /* On a substring match, append the marker (if there is one) and then
15676 * the substitution character, updating the output (to) index accordingly.
15677 * Then update the input (from) length by the length of the substring
15678 * that got replaced.
15679 */
15680 if (!strncmp(scan_string, substring, substring_length)) {
15681 if (marker) {
15682 string_out[(*to_index)++] = marker;
15683 }
15684 string_out[(*to_index)++] = substitution;
15685 (*from_index) += substring_length;
15686 return 1;
15687 }
15688 return 0;
15689 }
15690
15691 /*******************************************************************************
15692 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
15693 * KMOD_MAX_NAME characters and performs various substitutions of common
15694 * prefixes & substrings as defined by tables in kext_panic_report.h.
15695 *******************************************************************************/
15696 static void compactIdentifier(
15697 const char * identifier,
15698 char * identifier_out,
15699 char ** identifier_out_end);
15700
15701 static void
15702 compactIdentifier(
15703 const char * identifier,
15704 char * identifier_out,
15705 char ** identifier_out_end)
15706 {
15707 uint32_t from_index, to_index;
15708 uint32_t scan_from_index = 0;
15709 uint32_t scan_to_index = 0;
15710 subs_entry_t * subs_entry = NULL;
15711 int did_sub = 0;
15712
15713 from_index = to_index = 0;
15714 identifier_out[0] = '\0';
15715
15716 /* Replace certain identifier prefixes with shorter @+character sequences.
15717 * Check the return value of substitute() so we only replace the prefix.
15718 */
15719 for (subs_entry = &kext_identifier_prefix_subs[0];
15720 subs_entry->substring && !did_sub;
15721 subs_entry++) {
15722 did_sub = substitute(identifier, identifier_out,
15723 &scan_to_index, &scan_from_index,
15724 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
15725 }
15726 did_sub = 0;
15727
15728 /* Now scan through the identifier looking for the common substrings
15729 * and replacing them with shorter !+character sequences via substitute().
15730 */
15731 for (/* see above */;
15732 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
15733 /* see loop */) {
15734 const char * scan_string = &identifier[scan_from_index];
15735
15736 did_sub = 0;
15737
15738 if (scan_from_index) {
15739 for (subs_entry = &kext_identifier_substring_subs[0];
15740 subs_entry->substring && !did_sub;
15741 subs_entry++) {
15742 did_sub = substitute(scan_string, identifier_out,
15743 &scan_to_index, &scan_from_index,
15744 subs_entry->substring, '!', subs_entry->substitute);
15745 }
15746 }
15747
15748 /* If we didn't substitute, copy the input character to the output.
15749 */
15750 if (!did_sub) {
15751 identifier_out[scan_to_index++] = identifier[scan_from_index++];
15752 }
15753 }
15754
15755 identifier_out[scan_to_index] = '\0';
15756 if (identifier_out_end) {
15757 *identifier_out_end = &identifier_out[scan_to_index];
15758 }
15759
15760 return;
15761 }
15762 #endif /* !defined(__arm__) && !defined(__arm64__) */
15763
15764 /*******************************************************************************
15765 * assemble_identifier_and_version() adds to a string buffer a compacted
15766 * bundle identifier followed by a version string.
15767 *******************************************************************************/
15768
15769 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
15770 */
15771 static size_t assemble_identifier_and_version(
15772 kmod_info_t * kmod_info,
15773 char * identPlusVers,
15774 size_t bufSize);
15775
15776 static size_t
15777 assemble_identifier_and_version(
15778 kmod_info_t * kmod_info,
15779 char * identPlusVers,
15780 size_t bufSize)
15781 {
15782 size_t result = 0;
15783
15784 #if defined(__arm__) || defined(__arm64__)
15785 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
15786 #else
15787 compactIdentifier(kmod_info->name, identPlusVers, NULL);
15788 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
15789 #endif
15790 identPlusVers[result++] = '\t'; // increment for real char
15791 identPlusVers[result] = '\0'; // don't increment for nul char
15792 result = strlcat(identPlusVers, kmod_info->version, bufSize);
15793 if (result >= bufSize) {
15794 identPlusVers[bufSize - 1] = '\0';
15795 result = bufSize - 1;
15796 }
15797
15798 return result;
15799 }
15800
15801 /*******************************************************************************
15802 * Assumes sKextLock is held.
15803 *******************************************************************************/
15804 /* static */
15805 int
15806 OSKext::saveLoadedKextPanicListTyped(
15807 const char * prefix,
15808 int invertFlag,
15809 int libsFlag,
15810 char * paniclist,
15811 uint32_t list_size)
15812 {
15813 int result = -1;
15814 unsigned int count, i;
15815
15816 count = sLoadedKexts->getCount();
15817 if (!count) {
15818 goto finish;
15819 }
15820
15821 i = count - 1;
15822 do {
15823 OSObject * rawKext = sLoadedKexts->getObject(i);
15824 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
15825 int match;
15826 size_t identPlusVersLength;
15827 size_t tempLen;
15828 char identPlusVers[2 * KMOD_MAX_NAME];
15829
15830 if (!rawKext) {
15831 printf("OSKext::saveLoadedKextPanicListTyped - "
15832 "NULL kext in loaded kext list; continuing\n");
15833 continue;
15834 }
15835
15836 if (!theKext) {
15837 printf("OSKext::saveLoadedKextPanicListTyped - "
15838 "Kext type cast failed in loaded kext list; continuing\n");
15839 continue;
15840 }
15841
15842 /* Skip all built-in kexts.
15843 */
15844 if (theKext->isKernelComponent()) {
15845 continue;
15846 }
15847
15848 kmod_info_t * kmod_info = theKext->kmod_info;
15849
15850 /* Filter for kmod name (bundle identifier).
15851 */
15852 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
15853 if ((match && invertFlag) || (!match && !invertFlag)) {
15854 continue;
15855 }
15856
15857 /* Filter for libraries (kexts that have a compatible version).
15858 */
15859 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
15860 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
15861 continue;
15862 }
15863
15864 if (!kmod_info ||
15865 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
15866 printf("kext scan stopped due to missing kmod_info page: %p\n",
15867 kmod_info);
15868 goto finish;
15869 }
15870
15871 identPlusVersLength = assemble_identifier_and_version(kmod_info,
15872 identPlusVers,
15873 sizeof(identPlusVers));
15874 if (!identPlusVersLength) {
15875 printf("error saving loaded kext info\n");
15876 goto finish;
15877 }
15878
15879 /* make sure everything fits and we null terminate.
15880 */
15881 tempLen = strlcat(paniclist, identPlusVers, list_size);
15882 if (tempLen >= list_size) {
15883 // panic list is full, keep it and null terminate
15884 paniclist[list_size - 1] = 0x00;
15885 result = 0;
15886 goto finish;
15887 }
15888 tempLen = strlcat(paniclist, "\n", list_size);
15889 if (tempLen >= list_size) {
15890 // panic list is full, keep it and null terminate
15891 paniclist[list_size - 1] = 0x00;
15892 result = 0;
15893 goto finish;
15894 }
15895 } while (i--);
15896
15897 result = 0;
15898 finish:
15899
15900 return result;
15901 }
15902
15903 /*********************************************************************
15904 *********************************************************************/
15905 /* static */
15906 void
15907 OSKext::saveLoadedKextPanicList(void)
15908 {
15909 char * newlist = NULL;
15910 uint32_t newlist_size = 0;
15911
15912 newlist_size = KEXT_PANICLIST_SIZE;
15913 newlist = (char *)kalloc_data_tag(newlist_size,
15914 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15915
15916 if (!newlist) {
15917 OSKextLog(/* kext */ NULL,
15918 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
15919 "Couldn't allocate kext panic log buffer.");
15920 goto finish;
15921 }
15922
15923 newlist[0] = '\0';
15924
15925 // non-"com.apple." kexts
15926 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
15927 /* libs? */ -1, newlist, newlist_size) != 0) {
15928 goto finish;
15929 }
15930 // "com.apple." nonlibrary kexts
15931 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
15932 /* libs? */ 0, newlist, newlist_size) != 0) {
15933 goto finish;
15934 }
15935 // "com.apple." library kexts
15936 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
15937 /* libs? */ 1, newlist, newlist_size) != 0) {
15938 goto finish;
15939 }
15940
15941 if (loaded_kext_paniclist) {
15942 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
15943 }
15944 loaded_kext_paniclist = newlist;
15945 newlist = NULL;
15946 loaded_kext_paniclist_size = newlist_size;
15947
15948 finish:
15949 if (newlist) {
15950 kfree_data(newlist, newlist_size);
15951 }
15952 return;
15953 }
15954
15955 /*********************************************************************
15956 * Assumes sKextLock is held.
15957 *********************************************************************/
15958 void
15959 OSKext::savePanicString(bool isLoading)
15960 {
15961 u_long len;
15962
15963 if (!kmod_info) {
15964 return; // do not goto finish here b/c of lock
15965 }
15966
15967 len = assemble_identifier_and_version( kmod_info,
15968 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
15969 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
15970 if (!len) {
15971 printf("error saving unloaded kext info\n");
15972 goto finish;
15973 }
15974
15975 if (isLoading) {
15976 last_loaded_strlen = len;
15977 last_loaded_address = (void *)kmod_info->address;
15978 last_loaded_size = kmod_info->size;
15979 clock_get_uptime(&last_loaded_timestamp);
15980 } else {
15981 last_unloaded_strlen = len;
15982 last_unloaded_address = (void *)kmod_info->address;
15983 last_unloaded_size = kmod_info->size;
15984 clock_get_uptime(&last_unloaded_timestamp);
15985 }
15986
15987 finish:
15988 return;
15989 }
15990
15991 /*********************************************************************
15992 *********************************************************************/
15993 /* static */
15994 void
15995 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
15996 {
15997 if (last_loaded_strlen) {
15998 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
15999 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16000 last_loaded_strlen, last_loaded_str_buf,
16001 last_loaded_address, last_loaded_size);
16002 }
16003
16004 if (last_unloaded_strlen) {
16005 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16006 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16007 last_unloaded_strlen, last_unloaded_str_buf,
16008 last_unloaded_address, last_unloaded_size);
16009 }
16010
16011 printf_func("loaded kexts:\n");
16012 if (loaded_kext_paniclist &&
16013 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16014 loaded_kext_paniclist[0]) {
16015 printf_func("%.*s",
16016 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16017 loaded_kext_paniclist);
16018 } else {
16019 printf_func("(none)\n");
16020 }
16021 return;
16022 }
16023
16024 /*********************************************************************
16025 * Assumes sKextLock is held.
16026 *********************************************************************/
16027 /* static */
16028 void
16029 OSKext::updateLoadedKextSummaries(void)
16030 {
16031 kern_return_t result = KERN_FAILURE;
16032 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16033 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16034 OSKext *aKext;
16035 vm_map_offset_t start, end;
16036 size_t summarySize = 0;
16037 size_t size;
16038 u_int count;
16039 u_int maxKexts;
16040 u_int i, j;
16041 OSKextActiveAccount * accountingList;
16042 OSKextActiveAccount * prevAccountingList;
16043 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16044
16045 prevAccountingList = NULL;
16046 prevAccountingListCount = 0;
16047
16048 #if DEVELOPMENT || DEBUG
16049 if (IORecursiveLockHaveLock(sKextLock) == false) {
16050 panic("sKextLock must be held");
16051 }
16052 #endif
16053
16054 IOLockLock(sKextSummariesLock);
16055
16056 count = sLoadedKexts->getCount();
16057 for (i = 0, maxKexts = 0; i < count; ++i) {
16058 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16059 maxKexts += (aKext && aKext->isExecutable());
16060 }
16061
16062 if (!maxKexts) {
16063 goto finish;
16064 }
16065 if (maxKexts < kOSKextTypicalLoadCount) {
16066 maxKexts = kOSKextTypicalLoadCount;
16067 }
16068
16069 /* Calculate the size needed for the new summary headers.
16070 */
16071
16072 size = sizeof(*gLoadedKextSummaries);
16073 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16074 size = round_page(size);
16075
16076 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16077 if (gLoadedKextSummaries) {
16078 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16079 gLoadedKextSummaries = NULL;
16080 gLoadedKextSummariesTimestamp = mach_absolute_time();
16081 sLoadedKextSummariesAllocSize = 0;
16082 }
16083 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16084 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16085 if (result != KERN_SUCCESS) {
16086 goto finish;
16087 }
16088 summaryHeader = summaryHeaderAlloc;
16089 summarySize = size;
16090 } else {
16091 summaryHeader = gLoadedKextSummaries;
16092 summarySize = sLoadedKextSummariesAllocSize;
16093
16094 start = (vm_map_offset_t) summaryHeader;
16095 end = start + summarySize;
16096 result = vm_map_protect(kernel_map,
16097 start,
16098 end,
16099 VM_PROT_DEFAULT,
16100 FALSE);
16101 if (result != KERN_SUCCESS) {
16102 goto finish;
16103 }
16104 }
16105
16106 /* Populate the summary header.
16107 */
16108
16109 bzero(summaryHeader, summarySize);
16110 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16111 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16112
16113 /* Populate each kext summary.
16114 */
16115
16116 count = sLoadedKexts->getCount();
16117 accountingListAlloc = 0;
16118 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16119 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16120 if (!aKext || !aKext->isExecutable()) {
16121 continue;
16122 }
16123
16124 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16125 summaryHeader->numSummaries++;
16126 accountingListAlloc++;
16127 }
16128
16129 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16130 accountingListCount = 0;
16131 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16132 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16133 if (!aKext || !aKext->isExecutable()) {
16134 continue;
16135 }
16136
16137 OSKextActiveAccount activeAccount;
16138 aKext->updateActiveAccount(&activeAccount);
16139 // order by address
16140 for (idx = 0; idx < accountingListCount; idx++) {
16141 if (activeAccount.address < accountingList[idx].address) {
16142 break;
16143 }
16144 }
16145 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16146 accountingList[idx] = activeAccount;
16147 accountingListCount++;
16148 }
16149 assert(accountingListCount == accountingListAlloc);
16150 /* Write protect the buffer and move it into place.
16151 */
16152
16153 start = (vm_map_offset_t) summaryHeader;
16154 end = start + summarySize;
16155
16156 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
16157 if (result != KERN_SUCCESS) {
16158 goto finish;
16159 }
16160
16161 gLoadedKextSummaries = summaryHeader;
16162 gLoadedKextSummariesTimestamp = mach_absolute_time();
16163 sLoadedKextSummariesAllocSize = summarySize;
16164 summaryHeaderAlloc = NULL;
16165
16166 /* Call the magic breakpoint function through a static function pointer so
16167 * the compiler can't optimize the function away.
16168 */
16169 if (sLoadedKextSummariesUpdated) {
16170 (*sLoadedKextSummariesUpdated)();
16171 }
16172
16173 lck_ticket_lock(sKextAccountsLock, LCK_GRP_NULL);
16174 prevAccountingList = sKextAccounts;
16175 prevAccountingListCount = sKextAccountsCount;
16176 sKextAccounts = accountingList;
16177 sKextAccountsCount = accountingListCount;
16178 lck_ticket_unlock(sKextAccountsLock);
16179
16180 finish:
16181 IOLockUnlock(sKextSummariesLock);
16182
16183 /* If we had to allocate a new buffer but failed to generate the summaries,
16184 * free that now.
16185 */
16186 if (summaryHeaderAlloc) {
16187 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16188 }
16189 if (prevAccountingList) {
16190 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16191 }
16192
16193 return;
16194 }
16195
16196 /*********************************************************************
16197 *********************************************************************/
16198 void
16199 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16200 {
16201 OSSharedPtr<OSData> uuid;
16202
16203 strlcpy(summary->name, getIdentifierCString(),
16204 sizeof(summary->name));
16205
16206 uuid = copyUUID();
16207 if (uuid) {
16208 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16209 }
16210
16211 if (flags.builtin) {
16212 // this value will stop lldb from parsing the mach-o header
16213 // summary->address = UINT64_MAX;
16214 // summary->size = 0;
16215 summary->address = kmod_info->address;
16216 summary->size = kmod_info->size;
16217 } else {
16218 summary->address = kmod_info->address;
16219 summary->size = kmod_info->size;
16220 }
16221 summary->version = getVersion();
16222 summary->loadTag = kmod_info->id;
16223 summary->flags = 0;
16224 summary->reference_list = (uint64_t) kmod_info->reference_list;
16225
16226 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16227 if (summary->text_exec_address == 0) {
16228 // Fallback to __TEXT
16229 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16230 }
16231 return;
16232 }
16233
16234 /*********************************************************************
16235 *********************************************************************/
16236
16237 void
16238 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16239 {
16240 kernel_mach_header_t *hdr = NULL;
16241 kernel_segment_command_t *seg = NULL;
16242
16243 bzero(accountp, sizeof(*accountp));
16244
16245 hdr = (kernel_mach_header_t *)kmod_info->address;
16246 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16247 /*
16248 * If this kext supports split segments (or is in a new
16249 * MH_FILESET kext collection), use the first
16250 * executable segment as the range for instructions
16251 * (and thus for backtracing.
16252 */
16253 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16254 if (seg->initprot & VM_PROT_EXECUTE) {
16255 break;
16256 }
16257 }
16258 }
16259 if (seg) {
16260 accountp->address = seg->vmaddr;
16261 if (accountp->address) {
16262 accountp->address_end = seg->vmaddr + seg->vmsize;
16263 }
16264 } else {
16265 /* For non-split kexts and for kexts without executable
16266 * segments, just use the kmod_info range (as the kext
16267 * is either all in one range or should not show up in
16268 * instruction backtraces).
16269 */
16270 accountp->address = kmod_info->address;
16271 if (accountp->address) {
16272 accountp->address_end = kmod_info->address + kmod_info->size;
16273 }
16274 }
16275
16276 accountp->account = this->account;
16277 }
16278
16279 bool
16280 OSKext::isDriverKit(void)
16281 {
16282 OSString *bundleType;
16283
16284 if (infoDict) {
16285 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16286 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16287 return TRUE;
16288 }
16289 }
16290 return FALSE;
16291 }
16292
16293 bool
16294 OSKext::isInFileset(void)
16295 {
16296 if (!kmod_info) {
16297 goto check_prelinked;
16298 }
16299
16300 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16301 return true;
16302 }
16303
16304 check_prelinked:
16305 if (isPrelinked()) {
16306 /*
16307 * If we haven't setup kmod_info yet, but we know
16308 * we're loading a prelinked kext in an MH_FILESET KC,
16309 * then return true
16310 */
16311 kc_format_t kc_format;
16312 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16313 return true;
16314 }
16315 }
16316 return false;
16317 }
16318
16319 OSSharedPtr<OSDextStatistics>
16320 OSKext::copyDextStatistics(void)
16321 {
16322 return dextStatistics;
16323 }
16324
16325 bool
16326 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16327 {
16328 kern_return_t result;
16329 if (!super::init()) {
16330 return false;
16331 }
16332 if (seg == nullptr) {
16333 return false;
16334 }
16335 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16336 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16337 if (result != KERN_SUCCESS) {
16338 return false;
16339 }
16340 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16341 savedSegment = seg;
16342 vmsize = seg->vmsize;
16343 vmaddr = seg->vmaddr;
16344 return true;
16345 }
16346
16347 OSSharedPtr<OSKextSavedMutableSegment>
16348 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16349 {
16350 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16351 if (me && !me->initWithSegment(seg)) {
16352 return nullptr;
16353 }
16354 return me;
16355 }
16356
16357 void
16358 OSKextSavedMutableSegment::free(void)
16359 {
16360 if (data) {
16361 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16362 }
16363 }
16364
16365 vm_offset_t
16366 OSKextSavedMutableSegment::getVMAddr() const
16367 {
16368 return vmaddr;
16369 }
16370
16371 vm_offset_t
16372 OSKextSavedMutableSegment::getVMSize() const
16373 {
16374 return vmsize;
16375 }
16376
16377 OSReturn
16378 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16379 {
16380 if (seg != savedSegment) {
16381 return kOSKextReturnInvalidArgument;
16382 }
16383 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16384 return kOSKextReturnInvalidArgument;
16385 }
16386 memcpy((void *)seg->vmaddr, data, vmsize);
16387 return kOSReturnSuccess;
16388 }
16389
16390 extern "C" kern_return_t
16391 OSKextSetReceiptQueried(void)
16392 {
16393 OSKextLog(/* kext */ NULL,
16394 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16395 "Setting kext receipt as queried");
16396
16397 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16398 return KERN_SUCCESS;
16399 }
16400
16401 extern "C" const vm_allocation_site_t *
16402 OSKextGetAllocationSiteForCaller(uintptr_t address)
16403 {
16404 OSKextActiveAccount * active;
16405 vm_allocation_site_t * site;
16406 vm_allocation_site_t * releasesite;
16407
16408 uint32_t baseIdx;
16409 uint32_t lim;
16410 #if __has_feature(ptrauth_calls)
16411 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16412 #endif /* __has_feature(ptrauth_calls) */
16413
16414 lck_ticket_lock(sKextAccountsLock, LCK_GRP_NULL);
16415 site = releasesite = NULL;
16416
16417 // bsearch sKextAccounts list
16418 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16419 active = &sKextAccounts[baseIdx + (lim >> 1)];
16420 if ((address >= active->address) && (address < active->address_end)) {
16421 site = &active->account->site;
16422 if (!site->tag) {
16423 vm_tag_alloc_locked(site, &releasesite);
16424 }
16425 break;
16426 } else if (address > active->address) {
16427 // move right
16428 baseIdx += (lim >> 1) + 1;
16429 lim--;
16430 }
16431 // else move left
16432 }
16433 lck_ticket_unlock(sKextAccountsLock);
16434 if (releasesite) {
16435 kern_allocation_name_release(releasesite);
16436 }
16437
16438 return site;
16439 }
16440
16441 #if DEVELOPMENT || DEBUG
16442 extern "C" void
16443 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16444 {
16445 OSKextActiveAccount * active;
16446
16447 uint32_t baseIdx;
16448 uint32_t lim;
16449 #if __has_feature(ptrauth_calls)
16450 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16451 #endif /* __has_feature(ptrauth_calls) */
16452
16453 lck_ticket_lock(sKextAccountsLock, LCK_GRP_NULL);
16454
16455 // bsearch sKextAccounts list
16456 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16457 active = &sKextAccounts[baseIdx + (lim >> 1)];
16458 if ((address >= active->address) && (address < active->address_end)) {
16459 cb(&active->account->task_refgrp);
16460 break;
16461 } else if (address > active->address) {
16462 // move right
16463 baseIdx += (lim >> 1) + 1;
16464 lim--;
16465 }
16466 // else move left
16467 }
16468 lck_ticket_unlock(sKextAccountsLock);
16469 }
16470 #endif /* DEVELOPMENT || DEBUG */
16471
16472 extern "C" uint32_t
16473 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16474 {
16475 OSKextAccount * account = (typeof(account))site;
16476 const char * kname;
16477
16478 if (name) {
16479 if (account->kext) {
16480 kname = account->kext->getIdentifierCString();
16481 } else {
16482 kname = "<>";
16483 }
16484 strlcpy(name, kname, namelen);
16485 }
16486
16487 return account->loadTag;
16488 }
16489
16490 extern "C" void
16491 OSKextFreeSite(vm_allocation_site_t * site)
16492 {
16493 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16494 IOFreeType(freeAccount, OSKextAccount);
16495 }
16496
16497 /*********************************************************************
16498 *********************************************************************/
16499
16500 #if CONFIG_IMAGEBOOT
16501 int
16502 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16503 {
16504 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16505 if (!kext) {
16506 return 1;
16507 }
16508
16509 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16510 if (uuid_data) {
16511 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16512 return 0;
16513 }
16514
16515 return 1;
16516 }
16517 #endif
16518
16519
16520
16521 class OSDextCrash : public OSObject {
16522 OSDeclareDefaultStructors(OSDextCrash);
16523 public:
16524 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16525 uint64_t getTimestamp();
16526
16527 private:
16528 virtual bool initWithTimestamp(uint64_t timestamp);
16529 uint64_t fTimestamp;
16530 };
16531
16532 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16533
16534 OSSharedPtr<OSDextCrash>
16535 OSDextCrash::withTimestamp(uint64_t timestamp)
16536 {
16537 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16538 if (!result->initWithTimestamp(timestamp)) {
16539 return NULL;
16540 }
16541 return result;
16542 }
16543
16544 bool
16545 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16546 {
16547 if (!OSObject::init()) {
16548 return false;
16549 }
16550 fTimestamp = timestamp;
16551 return true;
16552 }
16553
16554 uint64_t
16555 OSDextCrash::getTimestamp()
16556 {
16557 return fTimestamp;
16558 }
16559
16560 OSSharedPtr<OSDextStatistics>
16561 OSDextStatistics::create()
16562 {
16563 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16564 if (!result->init()) {
16565 return NULL;
16566 }
16567 return result;
16568 }
16569
16570 bool
16571 OSDextStatistics::init()
16572 {
16573 if (!OSObject::init()) {
16574 return false;
16575 }
16576
16577 lock = IOLockAlloc();
16578 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16579 return true;
16580 }
16581
16582 void
16583 OSDextStatistics::free()
16584 {
16585 if (lock) {
16586 IOLockFree(lock);
16587 }
16588 crashes.reset();
16589 OSObject::free();
16590 }
16591
16592 OSDextCrashPolicy
16593 OSDextStatistics::recordCrash()
16594 {
16595 size_t i = 0;
16596 uint64_t timestamp = mach_continuous_time();
16597 uint64_t interval;
16598 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16599 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16600 OSDextCrashPolicy policy;
16601
16602 IOLockLock(lock);
16603 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16604 for (i = 0; i < crashes->getCount();) {
16605 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16606 assert(current != NULL);
16607 if (current->getTimestamp() < lastTimestamp) {
16608 crashes->removeObject(i);
16609 } else {
16610 i++;
16611 }
16612 }
16613
16614 crashes->setObject(crash);
16615
16616 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16617 policy = kOSDextCrashPolicyReboot;
16618 } else {
16619 policy = kOSDextCrashPolicyNone;
16620 }
16621
16622 IOLockUnlock(lock);
16623
16624 return policy;
16625 }
16626
16627 size_t
16628 OSDextStatistics::getCrashCount()
16629 {
16630 size_t result = 0;
16631 IOLockLock(lock);
16632 result = crashes->getCount();
16633 IOLockUnlock(lock);
16634 return result;
16635 }
16636
16637 static int
16638 sysctl_willuserspacereboot
16639 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16640 {
16641 int new_value = 0, old_value = 0, changed = 0;
16642 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
16643 if (error) {
16644 return error;
16645 }
16646 if (changed) {
16647 OSKext::willUserspaceReboot();
16648 }
16649 return 0;
16650 }
16651
16652 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16653 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16654 NULL, 0, sysctl_willuserspacereboot, "I", "");
16655